/// <summary> /// Adds the default set of UI middleware. /// </summary> /// <remarks> /// * Developer exception page /// * SSL termination support with X-Forwarded-Proto header /// * Swagger UI dashboard /// * Built-in React dev server /// * AspNetCore authentication /// * Request localization /// * Default AspNetCore routing /// </remarks> /// <example> /// <code> /// // Default configureSpa: /// spa => /// { /// spa.Options.SourcePath = "ClientApp"; /// spa.UseReactDevelopmentServer("start"); /// } /// </code> /// </example> /// <param name="app">The framework <see cref="IApplicationBuilder"/></param> /// <param name="container">The application composition root</param> /// <param name="env"> /// The framework <see cref="IHostingEnvironment"/> used to /// determine whether to enable environment-specific middleware /// </param> /// <param name="diagnosticListener">The DiagnosticListener used by the Framework</param> /// <param name="useSwagger"> /// Optional: Specify `true` to enable Swagger dashboard UI at `/swagger`. /// (Default: `true`) /// </param> /// <param name="useSpa"> /// Optional: Specify `true` to enable React SPA dev server in development mode. /// (Default: `true`) /// </param> /// <param name="useAuthentication"> /// Optional: Specify `true` to enable AspNetCore Authentication. /// (Default: `true`) /// </param> /// <param name="configureSpa"> /// Optional: An <c>Action</c> of type <see cref="ISpaBuilder" /> used configure the /// React SPA dev server. /// (Default: see remarks for default action) /// </param> /// <param name="localizationOptions"> /// Optional: Specify <see cref="RequestLocalizationOptions" /> if your MVC application requires /// localization. /// </param> /// <returns>The framework <see cref="IApplicationBuilder"/></returns> public static IApplicationBuilder UseDefaultUiMiddleware( this IApplicationBuilder app, Container container, IHostingEnvironment env, DiagnosticListener diagnosticListener = null, bool useSwagger = true, bool useSpa = true, bool useAuthentication = true, Action <ISpaBuilder> configureSpa = null, RequestLocalizationOptions localizationOptions = null ) { // Super important that this is first, otherwise all the middleware that is registered after this point // will have the incorrect IP address. app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.All }); var isDevelopment = env.IsDevelopment(); var isProduction = env.IsProduction(); if (isDevelopment && diagnosticListener != null) { // https://andrewlock.net/understanding-your-middleware-pipeline-with-the-middleware-analysis-package/ diagnosticListener.LogMiddlewareDiagnosticsToConsole(); } app.Properties["analysis.NextMiddlewareName"] = nameof(CorrelationIdMiddleware); app.UseCorrelationId(); // app.Use((c, next) => container.GetInstance<SerilogEnricherMiddleware>().Invoke(c, next)); app.Properties["analysis.NextMiddlewareName"] = nameof(RequestLoggingMiddleware); app.Use((c, next) => container.GetInstance <RequestLoggingMiddleware>().Invoke(c, next)); if (!isProduction) { app.UseDeveloperExceptionPage(); } app.UseResponseCompression(); app.UseGlobalExceptionHandler(x => { x.ContentType = "application/json"; if (!isProduction) { x.ResponseBody(e => JsonConvert.SerializeObject(new { message = e.Message, exception = e.ToString() })); } else // if production do not include stack { x.ResponseBody(e => JsonConvert.SerializeObject(new { message = e.Message, })); } x.OnError((exception, httpContext) => { var logger = container.GetInstance <IEventLogger <ExceptionHandlerConfiguration> >(); logger.AlertEvent("UnhandledApiException", exception); return(Task.CompletedTask); }); }); app.UseHealthAllEndpoints(); if (useSwagger) { app .UseSwagger() .UseSwaggerUI(options => { options.SwaggerEndpoint("/swagger/v1/swagger.json", "HTTP API V1"); }); } app.UseStaticFiles(); if (useSpa) { app.UseSpaStaticFiles(); } if (useAuthentication) { app.UseAuthentication(); } // Localization needs to be after auth in case it reads from user info if (localizationOptions != null) { app.UseRequestLocalization(localizationOptions); } app.UseMvcWithDefaultRoute(); if (useSpa && isDevelopment) { // Only configure React dev server if in Development app.MapWhen(IsSpaRoute, spaApp => { // Only configure React dev server if in Development UseSpaWithoutIndexHtml(spaApp, configureSpa ?? ConfigureSpaDefaults); }); } return(app); }