2020-03-24 18:18:25 +01:00
using System ;
2020-12-16 16:31:23 +11:00
using System.IO ;
2020-03-24 18:18:25 +01:00
using Microsoft.AspNetCore.Builder ;
2021-01-08 11:29:07 +11:00
using Microsoft.AspNetCore.Localization ;
2020-05-08 17:30:30 +10:00
using Microsoft.Extensions.DependencyInjection ;
2020-12-16 16:31:23 +11:00
using Microsoft.Extensions.Options ;
2020-05-12 15:18:55 +10:00
using Serilog.Context ;
2020-12-08 16:33:50 +11:00
using SixLabors.ImageSharp.Web.DependencyInjection ;
2020-05-12 15:18:55 +10:00
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-12-16 16:31:23 +11:00
using Umbraco.Core.Configuration.Models ;
2020-12-21 16:44:50 +11:00
using Umbraco.Core.Hosting ;
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-12-16 16:31:23 +11:00
using Umbraco.Web.Common.Plugins ;
2020-03-24 18:18:25 +01:00
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-12-08 16:33:50 +11:00
/// <summary>
/// <see cref="IApplicationBuilder"/> extensions for Umbraco
/// </summary>
2020-05-12 10:21:40 +10:00
public static class ApplicationBuilderExtensions
2020-03-24 18:18:25 +01:00
{
2020-12-08 16:33:50 +11:00
/// <summary>
/// Configures and use services required for using Umbraco
/// </summary>
public static IApplicationBuilder UseUmbraco ( this IApplicationBuilder app )
{
2021-01-04 12:01:52 +11:00
// TODO: Should we do some checks like this to verify that the corresponding "Add" methods have been called for the
// corresponding "Use" methods?
// https://github.com/dotnet/aspnetcore/blob/b795ac3546eb3e2f47a01a64feb3020794ca33bb/src/Mvc/Mvc.Core/src/Builder/MvcApplicationBuilderExtensions.cs#L132
2020-12-08 16:33:50 +11:00
if ( app = = null )
{
throw new ArgumentNullException ( nameof ( app ) ) ;
}
app . UseUmbracoCore ( ) ;
app . UseUmbracoRequestLogging ( ) ;
// We need to add this before UseRouting so that the UmbracoContext and other middlewares are executed
// before endpoint routing middleware.
app . UseUmbracoRouting ( ) ;
app . UseStatusCodePages ( ) ;
// Important we handle image manipulations before the static files, otherwise the querystring is just ignored.
// TODO: Since we are dependent on these we need to register them but what happens when we call this multiple times since we are dependent on this for UseUmbracoBackOffice too?
app . UseImageSharp ( ) ;
app . UseStaticFiles ( ) ;
2020-12-16 16:31:23 +11:00
app . UseUmbracoPlugins ( ) ;
2020-12-08 16:33:50 +11:00
// UseRouting adds endpoint routing middleware, this means that middlewares registered after this one
// will execute after endpoint routing. The ordering of everything is quite important here, see
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-5.0
// where we need to have UseAuthentication and UseAuthorization proceeding this call but before
// endpoints are defined.
app . UseRouting ( ) ;
app . UseAuthentication ( ) ;
app . UseAuthorization ( ) ;
2021-01-08 11:29:07 +11:00
// This must come after auth because the culture is based on the auth'd user
app . UseRequestLocalization ( ) ;
2020-12-08 16:33:50 +11:00
// Must be called after UseRouting and before UseEndpoints
app . UseSession ( ) ;
// Must come after the above!
app . UseUmbracoInstaller ( ) ;
return app ;
}
2020-05-12 10:21:40 +10:00
/// <summary>
/// Returns true if Umbraco <see cref="IRuntimeState"/> is greater than <see cref="RuntimeLevel.BootFailed"/>
/// </summary>
2020-05-08 17:36:59 +10:00
public static bool UmbracoCanBoot ( this IApplicationBuilder app )
{
2020-12-15 15:20:36 +00:00
var state = app . ApplicationServices . GetRequiredService < IRuntimeState > ( ) ;
2020-12-08 16:33:50 +11:00
2020-05-08 17:36:59 +10:00
// can't continue if boot failed
2020-12-15 15:20:36 +00:00
return state . Level > RuntimeLevel . BootFailed ;
2020-05-08 17:36:59 +10:00
}
2020-05-12 15:18:55 +10:00
/// <summary>
2020-12-21 16:44:50 +11:00
/// Enables core Umbraco functionality
2020-05-12 15:18:55 +10:00
/// </summary>
public static IApplicationBuilder UseUmbracoCore ( this IApplicationBuilder app )
{
2020-12-08 16:33:50 +11:00
if ( app = = null )
{
throw new ArgumentNullException ( nameof ( app ) ) ;
}
2020-05-12 15:18:55 +10:00
2020-12-08 16:33:50 +11:00
if ( ! app . UmbracoCanBoot ( ) )
{
return app ;
}
2020-05-12 15:18:55 +10:00
2020-05-14 22:50:27 +10:00
// Register our global threadabort enricher for logging
2020-12-08 16:33:50 +11:00
ThreadAbortExceptionEnricher threadAbortEnricher = app . ApplicationServices . GetRequiredService < ThreadAbortExceptionEnricher > ( ) ;
2020-05-14 22:50:27 +10:00
LogContext . Push ( threadAbortEnricher ) ; // NOTE: We are not in a using clause because we are not removing it, it is on the global context
2020-11-10 08:50:47 +00:00
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>
2020-12-08 16:33:50 +11:00
/// <remarks>
/// Must occur before UseRouting
/// </remarks>
2020-05-12 10:21:40 +10:00
public static IApplicationBuilder UseUmbracoRouting ( this IApplicationBuilder app )
2020-03-24 18:18:25 +01:00
{
2020-12-08 16:33:50 +11:00
// TODO: This method could be internal or part of another call - this is a required system so should't be 'opt-in'
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-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>
2020-05-12 15:18:55 +10:00
public static IApplicationBuilder UseUmbracoRequestLogging ( this IApplicationBuilder app )
{
2020-12-08 16:33:50 +11:00
if ( app = = null )
{
throw new ArgumentNullException ( nameof ( app ) ) ;
}
2020-05-12 15:18:55 +10:00
if ( ! app . UmbracoCanBoot ( ) ) return app ;
app . UseMiddleware < UmbracoRequestLoggingMiddleware > ( ) ;
return app ;
}
/// <summary>
/// Enables runtime minification for Umbraco
/// </summary>
public static IApplicationBuilder UseUmbracoRuntimeMinification ( this IApplicationBuilder app )
{
2020-12-08 16:33:50 +11:00
if ( app = = null )
{
throw new ArgumentNullException ( nameof ( app ) ) ;
}
2020-05-12 15:18:55 +10:00
2020-12-08 16:33:50 +11:00
if ( ! app . UmbracoCanBoot ( ) )
{
return app ;
}
2020-05-12 15:18:55 +10:00
app . UseSmidge ( ) ;
2020-08-31 22:46:17 +10:00
app . UseSmidgeNuglify ( ) ;
2020-05-12 15:18:55 +10:00
return app ;
}
2020-12-16 16:31:23 +11:00
public static IApplicationBuilder UseUmbracoPlugins ( this IApplicationBuilder app )
{
var hostingEnvironment = app . ApplicationServices . GetRequiredService < IHostingEnvironment > ( ) ;
var umbracoPluginSettings = app . ApplicationServices . GetRequiredService < IOptions < UmbracoPluginSettings > > ( ) ;
var pluginFolder = hostingEnvironment . MapPathContentRoot ( Constants . SystemDirectories . AppPlugins ) ;
// Ensure the plugin folder exists
Directory . CreateDirectory ( pluginFolder ) ;
var fileProvider = new UmbracoPluginPhysicalFileProvider (
pluginFolder ,
umbracoPluginSettings ) ;
app . UseStaticFiles ( new StaticFileOptions
{
FileProvider = fileProvider ,
RequestPath = Constants . SystemDirectories . AppPlugins
} ) ;
return app ;
}
2020-03-24 18:18:25 +01:00
}
2020-03-29 22:35:52 +02:00
2020-03-24 18:18:25 +01:00
}