// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory, IWebHostEnvironment hostingEnvironment) { // Log hosting environment { ILogger logger = loggerFactory.CreateLogger("Startup"); logger.LogInformation("Using content root: {0}", hostingEnvironment.ContentRootPath); logger.LogInformation("Using web root: {0}", hostingEnvironment.WebRootPath); } // Startup checks if (!app.RunStartupChecks()) { return; } // HTTP pipeline configuration app.UseHttps(); app.UseMiddleware <SiteUrlDetectionService.Middleware>(); app.UseRouting(); app.UseAuthentication(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseWhen( ctx => ctx.Request.Path.StartsWithSegments("/build") || ctx.Request.Path.StartsWithSegments("/sw-es5.js") || ctx.Request.Path.StartsWithSegments("/sw-es2017.js") || ctx.Request.Path.StartsWithSegments("/__webpack_hmr"), spaApp => { spaApp.UseSpa(spa => { const int port = 8080; Process.Start(new ProcessStartInfo { FileName = "node.exe", Arguments = $"dev-server.js --port={port}", WorkingDirectory = hostingEnvironment.ContentRootPath, UseShellExecute = true, WindowStyle = ProcessWindowStyle.Minimized }); spa.UseProxyToSpaDevelopmentServer($"http://localhost:{port}/"); }); } ); } else { app.UseExceptionHandler("/"); } app.UseResponseCompression(); app.UseSimpleUrlRemap("/browserconfig.xml", "/images/tiles/manifest-microsoft.xml"); app.UseSimpleUrlRemap("/sw-es5.js", "/build/es5/sw-es5.js"); app.UseSimpleUrlRemap("/sw-es2017.js", "/build/es2017/sw-es2017.js"); app.AddWildcardPatternRewrite("/build"); app.UseStaticFiles(new StaticFileOptions { ContentTypeProvider = new FileExtensionContentTypeProvider { // TODO: Remove when https://github.com/aspnet/AspNetCore/issues/2442 is done Mappings = { [".webmanifest"] = "application/manifest+json" } }, OnPrepareResponse = context => { // Enable aggressive caching behavior - but be sure that requests from service workers must be properly addressed const int expireTimeInDays = 7 * 4; ResponseHeaders headers = context.Context.Response.GetTypedHeaders(); headers.Expires = DateTimeOffset.Now.AddDays(expireTimeInDays); headers.CacheControl = new CacheControlHeaderValue { MaxAge = TimeSpan.FromDays(expireTimeInDays), MustRevalidate = true, Public = true, MaxStale = true, MaxStaleLimit = TimeSpan.FromSeconds(5) }; } }); // Let's encrypt support app.UseRouter(r => { r.MapGet(".well-known/acme-challenge/{id}", async(request, response, routeData) => { string id = routeData.Values["id"] as string; if (id != Path.GetFileName(id)) { return; // Prevent injection attack } string file = Path.Combine(env.WebRootPath, ".well-known", "acme-challenge", id); await response.SendFileAsync(file); }); }); // Hangfire app.UseHangfireServer(); app.UseHangfireDashboard("/_internal/jobs", new DashboardOptions { AppPath = "/", DisplayStorageConnectionString = false, Authorization = new IDashboardAuthorizationFilter[] { new DiagnosticsHangfireDashboardAuthorizationFilter(), } }); // SPA bootstrapper app.UseEndpoints(endpoints => { // SignalR hub endpoints.MapHub <AppOwnerHub>("/extern/connect/app-owner"); // MVC api controllers endpoints.MapControllers(); // If we still reached this at this point the ko-template was not found: // Trigger an failure instead of sending the app bootstrapper which causes all kinds of havoc. endpoints.MapFailedRoute("ko-templates/{*.}"); endpoints.MapFailedRoute("build/{*.}"); // Any non-matched web api calls should fail as well endpoints.MapFailedRoute("api/{*.}"); // We only match one controller since we will want // all requests to go to the controller which renders // the initial view / SPA bootstrapper. endpoints.MapFallbackToController("{*.}", "Index", "Home"); }); // Configure recurring jobs AppInsightsJobFilterAttribute.Register(app.ApplicationServices.GetService <TelemetryClient>()); RecurringJob.AddOrUpdate <MonthlyDigestInvocationJob>(x => x.Execute(), Cron.Daily(10)); }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IHostingEnvironment hostingEnvironment) { // Log hosting environment { ILogger logger = loggerFactory.CreateLogger("Startup"); logger.LogInformation("Using content root: {0}", hostingEnvironment.ContentRootPath); logger.LogInformation("Using web root: {0}", hostingEnvironment.WebRootPath); } // Startup checks if (!app.RunStartupChecks()) { return; } // HTTP pipeline configuration app.UseHttps(); app.UseMiddleware <SiteUrlDetectionService.Middleware>(); app.UseAuthentication(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions { HotModuleReplacement = true }); } else { app.UseExceptionHandler("/"); } app.UseSignalR(builder => { builder.MapHub <AppOwnerHub>("/extern/connect/app-owner"); }); app.UseResponseCompression(); app.UseSimpleUrlRemap("/browserconfig.xml", "/images/tiles/manifest-microsoft.xml"); app.UseSimpleUrlRemap("/sw-es5.js", "/build/es5/sw-es5.js"); app.UseSimpleUrlRemap("/sw-es2017.js", "/build/es2017/sw-es2017.js"); app.AddWildcardPatternRewrite("/build"); app.UseStaticFiles(new StaticFileOptions { ContentTypeProvider = new FileExtensionContentTypeProvider { Mappings = { [".webmanifest"] = "application/manifest+json" } }, OnPrepareResponse = context => { // Enable aggressive caching behavior - but be sure that requests from service workers must be properly addressed const int expireTimeInDays = 7 * 4; ResponseHeaders headers = context.Context.Response.GetTypedHeaders(); headers.Expires = DateTimeOffset.Now.AddDays(expireTimeInDays); headers.CacheControl = new CacheControlHeaderValue { MaxAge = TimeSpan.FromDays(expireTimeInDays), MustRevalidate = true, Public = true, MaxStale = true, MaxStaleLimit = TimeSpan.FromSeconds(5) }; } }); // Let's encrypt support app.UseRouter(r => { r.MapGet(".well-known/acme-challenge/{id}", async(request, response, routeData) => { string id = routeData.Values["id"] as string; if (id != Path.GetFileName(id)) { return; // Prevent injection attack } string file = Path.Combine(env.WebRootPath, ".well-known", "acme-challenge", id); await response.SendFileAsync(file); }); }); // Hangfire app.UseHangfireServer(); app.UseHangfireDashboard("/_internal/jobs", new DashboardOptions { AppPath = "/", DisplayStorageConnectionString = false, Authorization = new IDashboardAuthorizationFilter[] { new DiagnosticsHangfireDashboardAuthorizationFilter(), } }); // SPA bootstrapper app.UseMvc(routes => { // If we still reached this at this point the ko-template was not found: // Trigger an failure instead of sending the app bootstrapper which causes all kinds of havoc. routes.MapFailedRoute("ko-templates/{*.}"); routes.MapFailedRoute("build/{*.}"); // Any non-matched web api calls should fail as well routes.MapFailedRoute("api/{*.}"); // We only match one controller since we will want // all requests to go to the controller which renders // the initial view / SPA bootstrapper. routes.MapRoute( name: "default", template: "{*.}", defaults: new { controller = "Home", action = "Index" }); }); // Configure recurring jobs AppInsightsJobFilterAttribute.Register(app.ApplicationServices.GetService <TelemetryClient>()); RecurringJob.AddOrUpdate <MonthlyDigestInvocationJob>(x => x.Execute(), Cron.Daily(10)); }