private static void ConfigureHangfire(WebApplication app) { if (!app.Configuration.GetValue <bool>(Constants.HangfireEnabled)) { return; } var dashboardOptions = new DashboardOptions { Authorization = new[] { new HangfireAuthorisationFilter(app.Configuration.GetSection("AdOptions")["AdminUserGroup"]) }, DisplayStorageConnectionString = false, }; app.UseHangfireDashboard("/hangfire", dashboardOptions); GlobalJobFilters.Filters.Add(new AutomaticRetryAttribute { Attempts = 0 }); var scheduledJobConfig = new ScheduledJobsConfig(); app.Configuration.GetSection(Constants.ScheduledJobsConfig).Bind(scheduledJobConfig); HangfireJobScheduler.ScheduleRecurringJobs(scheduledJobConfig); }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public static void Configure(WebApplication app) { if (app.Environment.IsDevelopment()) { app.UseForwardedHeaders(); app.UseDeveloperExceptionPage(); // TODO Find an alternative for using webpack middleware in dotnet 5.0 // app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions // { // HotModuleReplacement = true, ConfigFile = "webpack.dev.js" // }); // We only need to turn this on in development, as in production this // This behaviour is by default provided by the nginx ingress // (see https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#server-side-https-enforcement-through-redirect) // (also see HSTS setting below) app.UseHttpsRedirection(); } else { app.UseForwardedHeaders(); app.UseStatusCodePagesWithReExecute("/errors/{0}"); app.UseExceptionHandler("/errors/500"); // 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.UseStaticFiles(); if (!app.Environment.IsEnvironment("CI")) { /* * Making this conditional is the result of serilog not playing nicely with WebApplicationFactory * used by the ui tests, see: https://github.com/serilog/serilog-aspnetcore/issues/105 * Using env directly as check is an unsatisfying solution, but configuration values were not picked up consistently correctly here. */ app.UseSerilogRequestLogging(options => // Needs to be before MVC handlers { options.MessageTemplate = "HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms ({RequestId})"; // 400s get thrown e.g. on antiforgery token validation failures. In those cases we don't have // an exception logged in Sentry, so we want to log at Warning level to make sure we are able to // identify and cure false positives. // Otherwise setting to Information to prevent duplicated exceptions in sentry. options.GetLevel = (context, _, __) => context.Response.StatusCode == StatusCodes.Status400BadRequest ? LogEventLevel.Warning : LogEventLevel.Information; }); } app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseCookiePolicy(); app.UseSession(); app.UseMiddleware <MsOfficeLinkPrefetchMiddleware>(); if (!app.Environment.IsEnvironment("CI")) { app.UseMiddleware <ActivityDetectionMiddleware>(); } if (app.Configuration.GetValue <bool>(Constants.AuditEnabledConfigValue)) { app.UseMiddleware <AuditGetRequestMiddleWare>(); } app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); endpoints.MapControllers(); }); ConfigureHangfire(app); var cultureInfo = new CultureInfo("en-GB"); CultureInfo.DefaultThreadCurrentUICulture = cultureInfo; CultureInfo.DefaultThreadCurrentCulture = cultureInfo; }
/// <summary> /// Builds the <see cref="WebApplication"/>. /// </summary> /// <returns>A configured <see cref="WebApplication"/>.</returns> public WebApplication Build() { WebApplication sourcePipeline = null; _hostBuilder.ConfigureWebHostDefaults(web => { _webHostBuilder.ExecuteActions(web); web.Configure(destinationPipeline => { // The endpoints were already added on the outside if (sourcePipeline.DataSources.Count > 0) { // The user did not register the routing middleware so wrap the entire // destination pipeline in UseRouting() and UseEndpoints(), essentially: // destination.UseRouting() // destination.Run(source) // destination.UseEndpoints() if (sourcePipeline.RouteBuilder == null) { destinationPipeline.UseRouting(); // Copy the route data sources over to the destination pipeline, this should be available since we just called // UseRouting() var routes = (IEndpointRouteBuilder)destinationPipeline.Properties[WebApplication.EndpointRouteBuilder]; foreach (var ds in sourcePipeline.DataSources) { routes.DataSources.Add(ds); } // Chain the execution of the source pipeline into the destination pipeline destinationPipeline.Use(next => { sourcePipeline.Run(next); return(sourcePipeline.Build()); }); // Add a UseEndpoints at the end destinationPipeline.UseEndpoints(e => { }); } else { // Since we register routes into the source pipeline's route builder directly, // if the user called UseRouting, we need to copy the data sources foreach (var ds in sourcePipeline.DataSources) { sourcePipeline.RouteBuilder.DataSources.Add(ds); } // We then implicitly call UseEndpoints at the end of the pipeline sourcePipeline.UseEndpoints(_ => { }); // Wire the source pipeline to run in the destination pipeline destinationPipeline.Run(sourcePipeline.Build()); } } else { // Wire the source pipeline to run in the destination pipeline destinationPipeline.Run(sourcePipeline.Build()); } // Copy the properties to the destination app builder foreach (var item in sourcePipeline.Properties) { destinationPipeline.Properties[item.Key] = item.Value; } }); }); _hostBuilder.ConfigureServices(services => { foreach (var s in Services) { services.Add(s); } }); _hostBuilder.ConfigureAppConfiguration(builder => { foreach (var s in Configuration.Sources) { builder.Sources.Add(s); } }); _hostBuilder.ConfigureHostConfiguration(builder => { foreach (var s in HostConfiguration.Sources) { builder.Sources.Add(s); } }); var host = _hostBuilder.Build(); return(sourcePipeline = new WebApplication(host)); }