How to tell when a self-hosted ASP.NET Core application is ready to receive requests? - asp.net-core

I need to launch worker processes that communicate using ASP.NET Core Web API. I need to know when I can start sending requests to that process. The only options I see so far are to have the worker call the parent process API when it has finished configuring or poll the worker with an "are you alive" request.
Is there any built in mechanism for this? Any better patterns or designs?

In general, after the application is started successfully, you will be able to send request.
For Application Start event, you could try IHostApplicationLifetime in .net core 3.0, if you are using previous version, you could try IApplicationLifetime which will be obsolete in future version.
Here is a demo which is used to register event while application is started.
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews().AddNewtonsoftJson();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime hostApplicationLifetime)
{
hostApplicationLifetime.ApplicationStarted.Register(() => {
Console.WriteLine("Application is Started");
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}

Related

Blazor Server get current logged user when EF DbContext execute select data query

I build blazor server multi tenant application and I wants to use HasQueryFilter in entity framework DbContext for predefined filter with TenantId. Ofcourse I have connected User with tenant. I created CurrentTenatnProvider which has method GetCurrentTenatnId. In this mehtod i use AuthentificationStateProvider and call GetAuthenticationStateAsync(). Ofcourse i get the error ''GetAuthenticationStateAsync was called before SetAuthenticationState". I Cannot use IHttpContextAccessor because in Azure app I get null reference exception.
Is there any other possibility how to get CurrentUser in time when DbContext execute select data query?
I was thinking about cache CurrnetUser but there is problem with cache key.CurrentTenatnProvider service is registered as scoped service. There is Id attribute which is set in constructor. And then is used as cache key. But this approach does not working and I get the same error.
It si possible get signal-r connection identificator and use it as cache key?
I spended 2 days with test lots of combination and read lots of documentation but unfortunately I didn't find any solution. I will be very grateful for any advice.
I have done this a few ways but the simplest way I could find was retrieving my user from the database in the MainLayout.razor file during OnInitializedAsync() and passing it in a fixed cascading parameter <CascadingValue Name="CurrentUser" IsFixed="true" Value="UserId">. From there, I could reference it where needed in any child component.
finally I found solution! From my view it is bug! Problem is because services.AddDbContextFactory is registered as Singleton. I create my own implementation of IDbContext factory and register it as Scoped. After this change everything’s works perfect. When I change registration scope of DbContextFactory to singleton, I get the error: GetAuthenticationStateAsync was called before SetAuthenticationState.
My DbContextFactory
public class BlazorContextFactory<TContext> : IDbContextFactory<TContext> where TContext : DbContext
{
private readonly IServiceProvider provider;
public BlazorContextFactory(IServiceProvider provider)
{
this.provider = provider;
}
public TContext CreateDbContext()
{
if (provider == null)
{
throw new InvalidOperationException(
$"You must configure an instance of IServiceProvider");
}
return ActivatorUtilities.CreateInstance<TContext>(provider);
}
}
My StartUp
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<ApplicationDbContext>();
services.AddScoped<IDbContextFactory<ApplicationDbContext>, BlazorContextFactory<ApplicationDbContext>>();
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
services.AddSingleton<WeatherForecastService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
I hope it's help other peoples! I spend 6 days with this problem :(

How to resolve Request to Long error in Asp.Net Core Azure B2C Configuraiton?

I am new to Asp.Net Core identity.
I have configured the startup as per below. When I run the code in a normal and incognito browser I get the below error.
I have cleared cookies as previous questions have suggested. What is interesting is a high number of cookies get created when loading the sign screen.
My issue is similar to those described in the below old articles. Both solutions seem outdated.
https://www.javaer101.com/en/article/18781756.html
https://blog.bitscry.com/2018/09/19/azure-ad-request-too-long/
using d365fl.DocumentGenerator.blazor_frontend.Data;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Identity.Web;
using Microsoft.IdentityModel.Logging;
namespace d365fl.DocumentGenerator.blazor_frontend
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
ConfigureIdentiy(services);
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddSingleton<WeatherForecastService>();
}
private void ConfigureIdentiy(IServiceCollection services)
{
services.AddMicrosoftIdentityWebAppAuthentication(Configuration, "AzureAdB2C");
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.Configure<OpenIdConnectOptions>(Configuration.GetSection("AzureAdB2C"));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
IdentityModelEventSource.ShowPII = true;
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
}
EDIT 1 - HTTP Request from Developer Toolbar
EDIT 2 - Screen Shot of Cookie data from Developer Toolbar / Network Tab
As we discussed in the comment, the issue is cause by too many cookies.
Please clear your cookies and modify your code to avoid endless loops and back and forth requests.
See this answer for more details.

how to auto-start/warm up .net core web app hosted in IIS

I have a .net core (3.1) web app which is hosted on IIS. I cannot figure out how to run a piece of code before the first request. I have done the following:
set the 'start mode' of the app pool = "AlwaysRunning" and "Idle time-out" = 0
set the 'preload enabled' = true on the web site
What i am missing is where/how i register the code/service that i would like to run before the first request comes in?
thanks in advance
What i am missing is where/how i register the code/service that i would like to run before the first request comes in?
If you want to call one of your mvc or web api after the application has start up completely to warm up your web application. You could try to use IHostApplicationLifetime's ApplicationStarted method.
This method will be called after the application started immediately.
You could inject IHostApplicationLifetime into Configure() method , then write the callback for ApplicationStarted that would be triggered when the application host has fully started.
More details, you could refer to below example:
Register httpclient service in Startup.cs ConfigureServices method
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient();
services.AddControllersWithViews();
}
Add lifetime.ApplicationStarted.Register callback in Configure method:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime lifetime)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Default}/{action=Index}/{id?}");
});
IHttpClientFactory httpClientFactory = app.ApplicationServices.GetService(typeof(IHttpClientFactory)) as IHttpClientFactory;
lifetime.ApplicationStarted.Register(onApplicationStartedAsync(httpClientFactory).Wait);
}
private async Task<Action> onApplicationStartedAsync(IHttpClientFactory httpClientFactory)
{
var httpclient = httpClientFactory.CreateClient();
var httpMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost:5000/api/values");
var httpresponse = await httpclient.SendAsync(httpMessage);
if (httpresponse.IsSuccessStatusCode)
{
string res = await httpresponse.Content.ReadAsStringAsync();
}
return null;
}
Result:

Why am I looking at JSON, not my nice Swagger UI?

I've installed swashbuckle on on a clean asp.net core web api project following these instructions. My startup class is below. You can see I've added AddSwaggerGen(), UseSwagger() and UseSwaggerUI().
When I visit https://localhost:44334/swagger/v1/swagger.json, instead of seeing the swagger UI I expect, I've got a pile of JSON, starting {"swagger":"2.0","info":{"version":"v1","title":"MoqOcr"}...
What am I missing ?
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// sby
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "MoqOcr", Version = "v1" });
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
// sby
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
c.RoutePrefix = string.Empty;
});
//app.UseHttpsRedirection();
app.UseMvc();
}
}
I have checked your configuration for Swagger in Startup.cs and there seemed no unexpected thing to setup swagger to me. The only thing that pops in my mind is that you are mistaken the SwaggerEndpoint setting which indicates to you (I suppose) that you can access your Swagger UI from that url but it holds a json to build and configure that UI page. Fair enough but you should try https://localhost:44334/swagger
or https://localhost:44334/swagger/index.html to see your Swagger UI page. Hope this solves your problem.

Asp.net core site hangs after about 50 requests

I use asp net core 2.0 and faced very strange behavior (at least I see it locally with IIS express). I open site page then press Refresh button about 50 times and site starts hanging, processing of request takes about 40 seconds. Then after about 5 minutes of idle I refresh page again and everything works fast. Next ~50 requests and again it hangs. I'm very confused with that and don't have ideas what is the reason and how to troubleshoot it. I removed all things from code and rest only base code and it's still reproducable.
My Startup class looks so:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
//public void ConfigureServices(IServiceCollection services)
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
return services.BuildServiceProvider();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Use(async delegate(HttpContext context, Func<Task> next)
{
await next.Invoke();
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
Controller actions don't do anything they just return View. In debugging I often see that it hangs on "await next.Invoke();" line (I've added this delegate only for debugging) but I'm not sure that problem is exactly in action executing.
Maybe anybody knows what can be a reason or how I can troubleshoot it?
Looks like the problem was solved in unexpected way - I updated Visual Studio and as I saw IIS was also updated together with it.