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

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:

Related

CORS issue with PUT request from reactjs to asp.netCore api

I am working on a Reactjs app with Asp.netCore API with Sql database
deployed to IIS server.
All the operation is working except PUT operation on the task
it break with CORS error and the request is not reaching the backend, I tested it locally and it's working fine. Tested using Postman and it's working too even the deployed version is working with postman. I can't figure out what's the issue or from where I should start debugging.
startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(o => o.AddPolicy(name: CorsPolicy, builder =>
{
builder.WithOrigins(FrontEnd_URL).SetIsOriginAllowed((host) =>
true).AllowAnyHeader().AllowAnyMethod().AllowCredentials();
}));
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseCors(CorsPolicy);
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapHub<TrelloHub>("/trello");
});
}
TaskController
[Route("/api/tasks")]
[ApiController]
public class TasksController : Controller
{
private readonly IMapper _mapper;
private readonly ITaskService _taskService;
public TasksController(ITaskService taskService , IMapper mapper)
{
_mapper = mapper;
_taskService = taskService;
}
[HttpPut("{id:int}", Name = "UpdateTask")]
public async Task<String> UpadateTask([FromBody]TaskDto taskdto, int id)
{
var taskModel = _mapper.Map<Task>(taskdto);
return await _taskService.UpadateTask(id , taskModel);
}
}
first check IIS server logs. it can help you a lot, also look at the request headers of the reactjs client origin: header exactly and add it to the allowed origins

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.

Asp.net Web API .NET Core 3.1 and Azure AD - system.unauthorizedaccessexception: neither scope or roles claim was found in the bearer token

I am trying to secure my Web Api with Azure AD. This application will be accessed by a console app, and the token will be generated from a client id / secret. I followed the quickstart from https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-v2-aspnet-core-web-api .
After obtaining a client token and sending through the bearer auth header, I am getting an error
System.UnauthorizedAccessException: IDW10201: Neither scope or roles claim was found in the bearer token.
I'm obtaining an access token with this code:
public static async Task<string> GetAccessToken(string aadInstance, string aadTenant, string aadClientId, string aadClientSecret, string apiResourceId)
{
string authority = aadInstance.TrimEnd('/') + "/" + aadTenant;
var app = ConfidentialClientApplicationBuilder.Create(apiResourceId)
.WithClientId(aadClientId)
.WithClientSecret(aadClientSecret)
.WithAuthority(authority)
.Build();
var tokenrequest = app.AcquireTokenForClient(new string[] { "api://resourceid/.default" });
var tokenresult = await tokenrequest.ExecuteAsync();
return tokenresult.AccessToken;
}
My startup code in the web api looks like this:
public void ConfigureServices(IServiceCollection services)
{
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(Configuration);
later in the startup...
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseOpenApi();
app.UseSwaggerUi3();
}
It turns out that the setup in Azure AD was missing a role that needed to be added to the manifest as well as the permissions to the api of the client application, as per step 8 in https://dotnetplaybook.com/secure-a-net-core-api-using-bearer-authentication/
Unfortunately the MS documentation doesn't put this part in the quick start.

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

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?}");
});
}
}

Redirect to HTTPS in Blazor

I have a blazor app.
I hosted it on server and have access with https.
But when i do redirect (in one controller), happens exception.
Startap.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseResponseCompression();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseMvc(routes =>
{
routes.MapRoute(name: "default", template: "{controller}/{action}/{id?}");
});
app.Map("/schedule", subdirApp =>
{
subdirApp.UseBlazor<Client.Startup>();
});
}
And method in controller
[HttpGet]
[Route("***")]
public IActionResult Return()
{
FileStream fs = new FileStream(_filePath, FileMode.Open);
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
List<ScheduleEntity> _list = (List<ScheduleEntity>)formatter.Deserialize(fs);
foreach (var x in _list)
Schedules.Add(x);
fs.Close();
return Redirect("~//schedule");
}
Exception
Please, help me
These API responses can be a bit misleading. Without seeing the rest of your code around the configuration of endpoints, I suspect this might be a CORS issue with the API.
Try adding the following code to the public void Configure(IApplicationBuilder app, IHostingEnvironment env) method in your API's Startup.cs class:
app.UseCors(opts => opts
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
);
The fetch response may be due to the request preflight being rejected.
Having said that, the first exception message is saying you're trying to load insecure content, so I'd also check your Blazor front-end app's configuration to see what the API client is requesting and ensure the API endpoint certificate is valid?