using System; using System.Net; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Serilog.Context; using Smidge; using StackExchange.Profiling; using Umbraco.Core; using Umbraco.Core.Hosting; using Umbraco.Infrastructure.Logging.Serilog.Enrichers; using Umbraco.Web.Common.Middleware; namespace Umbraco.Extensions { public static class ApplicationBuilderExtensions { /// /// Returns true if Umbraco is greater than /// /// /// public static bool UmbracoCanBoot(this IApplicationBuilder app) { var runtime = app.ApplicationServices.GetRequiredService(); // can't continue if boot failed return runtime.State.Level > RuntimeLevel.BootFailed; } /// /// Start Umbraco /// /// /// public static IApplicationBuilder UseUmbracoCore(this IApplicationBuilder app) { if (app == null) throw new ArgumentNullException(nameof(app)); if (app.UmbracoCanBoot()) { var runtime = app.ApplicationServices.GetRequiredService(); // Register a listener for application shutdown in order to terminate the runtime var hostLifetime = app.ApplicationServices.GetRequiredService(); var runtimeShutdown = new CoreRuntimeShutdown(runtime, hostLifetime); hostLifetime.RegisterObject(runtimeShutdown); // Register our global threadabort enricher for logging var threadAbortEnricher = app.ApplicationServices.GetRequiredService(); LogContext.Push(threadAbortEnricher); // NOTE: We are not in a using clause because we are not removing it, it is on the global context // Start the runtime! runtime.Start(); } else { // TODO: Register simple middleware to show the error like we used to in UmbracoModule? Or maybe that's part of a UseUmbracoWebsite/backoffice type thing .. probably :) } return app; } /// /// Enables middlewares required to run Umbraco /// /// /// // TODO: Could be internal or part of another call - this is a required system so should't be 'opt-in' public static IApplicationBuilder UseUmbracoRouting(this IApplicationBuilder app) { if (app == null) throw new ArgumentNullException(nameof(app)); if (!app.UmbracoCanBoot()) return app; app.UseMiddleware(); app.UseMiddleware(); return app; } public static IApplicationBuilder UseUmbracoRequestLogging(this IApplicationBuilder app) { if (app == null) throw new ArgumentNullException(nameof(app)); if (!app.UmbracoCanBoot()) return app; app.UseMiddleware(); return app; } /// /// Enables runtime minification for Umbraco /// /// /// public static IApplicationBuilder UseUmbracoRuntimeMinification(this IApplicationBuilder app) { if (app == null) throw new ArgumentNullException(nameof(app)); if (!app.UmbracoCanBoot()) return app; app.UseSmidge(); return app; } /// /// Ensures the runtime is shutdown when the application is shutting down /// private class CoreRuntimeShutdown : IRegisteredObject { public CoreRuntimeShutdown(IRuntime runtime, IApplicationShutdownRegistry hostLifetime) { _runtime = runtime; _hostLifetime = hostLifetime; } private bool _completed = false; private readonly IRuntime _runtime; private readonly IApplicationShutdownRegistry _hostLifetime; public void Stop(bool immediate) { if (!_completed) { _completed = true; _runtime.Terminate(); _hostLifetime.UnregisterObject(this); } } } } }