2020-03-24 18:18:25 +01:00
|
|
|
using System;
|
2020-05-12 15:44:14 +10:00
|
|
|
using System.Net;
|
2020-03-24 18:18:25 +01:00
|
|
|
using Microsoft.AspNetCore.Builder;
|
2020-05-08 17:30:30 +10:00
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
2020-05-12 15:18:55 +10:00
|
|
|
using Serilog.Context;
|
|
|
|
|
using Smidge;
|
2020-08-31 22:46:17 +10:00
|
|
|
using Smidge.Nuglify;
|
2020-03-29 22:35:52 +02:00
|
|
|
using StackExchange.Profiling;
|
2020-05-08 17:30:30 +10:00
|
|
|
using Umbraco.Core;
|
2020-10-26 10:47:14 +00:00
|
|
|
using Umbraco.Core.Composing;
|
2020-05-12 15:18:55 +10:00
|
|
|
using Umbraco.Core.Hosting;
|
2020-10-26 10:47:14 +00:00
|
|
|
using Umbraco.Core.Runtime;
|
2020-05-12 15:18:55 +10:00
|
|
|
using Umbraco.Infrastructure.Logging.Serilog.Enrichers;
|
2020-03-24 18:18:25 +01:00
|
|
|
using Umbraco.Web.Common.Middleware;
|
|
|
|
|
|
2020-05-07 10:08:23 +02:00
|
|
|
namespace Umbraco.Extensions
|
2020-03-24 18:18:25 +01:00
|
|
|
{
|
2020-05-12 15:44:14 +10:00
|
|
|
|
2020-05-12 10:21:40 +10:00
|
|
|
public static class ApplicationBuilderExtensions
|
2020-03-24 18:18:25 +01:00
|
|
|
{
|
2020-05-12 10:21:40 +10:00
|
|
|
/// <summary>
|
|
|
|
|
/// Returns true if Umbraco <see cref="IRuntimeState"/> is greater than <see cref="RuntimeLevel.BootFailed"/>
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="app"></param>
|
|
|
|
|
/// <returns></returns>
|
2020-05-08 17:36:59 +10:00
|
|
|
public static bool UmbracoCanBoot(this IApplicationBuilder app)
|
|
|
|
|
{
|
|
|
|
|
var runtime = app.ApplicationServices.GetRequiredService<IRuntime>();
|
|
|
|
|
// can't continue if boot failed
|
|
|
|
|
return runtime.State.Level > RuntimeLevel.BootFailed;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-12 15:18:55 +10:00
|
|
|
/// <summary>
|
|
|
|
|
/// Start Umbraco
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="app"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public static IApplicationBuilder UseUmbracoCore(this IApplicationBuilder app)
|
|
|
|
|
{
|
|
|
|
|
if (app == null) throw new ArgumentNullException(nameof(app));
|
|
|
|
|
|
2020-05-19 14:51:05 +10:00
|
|
|
if (!app.UmbracoCanBoot()) return app;
|
2020-05-12 15:18:55 +10:00
|
|
|
|
2020-05-19 14:51:05 +10:00
|
|
|
var runtime = app.ApplicationServices.GetRequiredService<IRuntime>();
|
2020-10-26 10:47:14 +00:00
|
|
|
|
2020-05-14 22:50:27 +10:00
|
|
|
// Register a listener for application shutdown in order to terminate the runtime
|
|
|
|
|
var hostLifetime = app.ApplicationServices.GetRequiredService<IApplicationShutdownRegistry>();
|
|
|
|
|
var runtimeShutdown = new CoreRuntimeShutdown(runtime, hostLifetime);
|
|
|
|
|
hostLifetime.RegisterObject(runtimeShutdown);
|
2020-05-12 15:18:55 +10:00
|
|
|
|
2020-05-14 22:50:27 +10:00
|
|
|
// Register our global threadabort enricher for logging
|
|
|
|
|
var threadAbortEnricher = app.ApplicationServices.GetRequiredService<ThreadAbortExceptionEnricher>();
|
|
|
|
|
LogContext.Push(threadAbortEnricher); // NOTE: We are not in a using clause because we are not removing it, it is on the global context
|
2020-10-26 10:47:14 +00:00
|
|
|
|
2020-05-14 22:50:27 +10:00
|
|
|
// Start the runtime!
|
2020-10-27 10:53:01 +00:00
|
|
|
runtime.Start(app.ApplicationServices);
|
2020-05-12 15:18:55 +10:00
|
|
|
|
|
|
|
|
return app;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-12 10:21:40 +10:00
|
|
|
/// <summary>
|
|
|
|
|
/// Enables middlewares required to run Umbraco
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="app"></param>
|
|
|
|
|
/// <returns></returns>
|
2020-05-08 17:30:30 +10:00
|
|
|
// TODO: Could be internal or part of another call - this is a required system so should't be 'opt-in'
|
2020-05-12 10:21:40 +10:00
|
|
|
public static IApplicationBuilder UseUmbracoRouting(this IApplicationBuilder app)
|
2020-03-24 18:18:25 +01:00
|
|
|
{
|
2020-05-08 17:30:30 +10:00
|
|
|
if (app == null) throw new ArgumentNullException(nameof(app));
|
2020-03-24 18:18:25 +01:00
|
|
|
|
2020-05-14 22:50:27 +10:00
|
|
|
if (!app.UmbracoCanBoot())
|
|
|
|
|
{
|
2020-05-19 14:51:05 +10:00
|
|
|
app.UseMiddleware<BootFailedMiddleware>();
|
2020-05-14 22:50:27 +10:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
app.UseMiddleware<UmbracoRequestMiddleware>();
|
|
|
|
|
app.UseMiddleware<MiniProfilerMiddleware>();
|
2020-06-02 17:48:08 +10:00
|
|
|
|
|
|
|
|
// TODO: Both of these need to be done before any endpoints but after UmbracoRequestMiddleware
|
|
|
|
|
// because they rely on an UmbracoContext. But should they be here?
|
|
|
|
|
app.UseAuthentication();
|
|
|
|
|
app.UseAuthorization();
|
2020-05-14 22:50:27 +10:00
|
|
|
}
|
2020-05-19 14:51:05 +10:00
|
|
|
|
2020-03-24 18:18:25 +01:00
|
|
|
return app;
|
|
|
|
|
}
|
2020-05-12 15:18:55 +10:00
|
|
|
|
2020-05-14 22:50:27 +10:00
|
|
|
/// <summary>
|
|
|
|
|
/// Adds request based serilog enrichers to the LogContext for each request
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="app"></param>
|
|
|
|
|
/// <returns></returns>
|
2020-05-12 15:18:55 +10:00
|
|
|
public static IApplicationBuilder UseUmbracoRequestLogging(this IApplicationBuilder app)
|
|
|
|
|
{
|
|
|
|
|
if (app == null) throw new ArgumentNullException(nameof(app));
|
|
|
|
|
|
|
|
|
|
if (!app.UmbracoCanBoot()) return app;
|
|
|
|
|
|
|
|
|
|
app.UseMiddleware<UmbracoRequestLoggingMiddleware>();
|
|
|
|
|
|
|
|
|
|
return app;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Enables runtime minification for Umbraco
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="app"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public static IApplicationBuilder UseUmbracoRuntimeMinification(this IApplicationBuilder app)
|
|
|
|
|
{
|
|
|
|
|
if (app == null) throw new ArgumentNullException(nameof(app));
|
|
|
|
|
|
|
|
|
|
if (!app.UmbracoCanBoot()) return app;
|
|
|
|
|
|
|
|
|
|
app.UseSmidge();
|
2020-08-31 22:46:17 +10:00
|
|
|
app.UseSmidgeNuglify();
|
2020-05-12 15:18:55 +10:00
|
|
|
|
|
|
|
|
return app;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Ensures the runtime is shutdown when the application is shutting down
|
|
|
|
|
/// </summary>
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-24 18:18:25 +01:00
|
|
|
}
|
2020-03-29 22:35:52 +02:00
|
|
|
|
2020-03-24 18:18:25 +01:00
|
|
|
}
|