Files
Umbraco-CMS/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs

209 lines
7.2 KiB
C#
Raw Normal View History

using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Serilog.Context;
2020-12-08 16:33:50 +11:00
using SixLabors.ImageSharp.Web.DependencyInjection;
using Smidge;
using Smidge.Nuglify;
using StackExchange.Profiling;
using Umbraco.Core;
using Umbraco.Core.Hosting;
using Umbraco.Infrastructure.Logging.Serilog.Enrichers;
using Umbraco.Web.Common.Middleware;
using Umbraco.Web.PublishedCache.NuCache;
namespace Umbraco.Extensions
{
2020-12-08 16:33:50 +11:00
/// <summary>
/// <see cref="IApplicationBuilder"/> extensions for Umbraco
/// </summary>
public static class ApplicationBuilderExtensions
{
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)
{
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();
// 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.UseRequestLocalization();
app.UseAuthentication();
app.UseAuthorization();
// Must be called after UseRouting and before UseEndpoints
app.UseSession();
// Must come after the above!
app.UseUmbracoInstaller();
return app;
}
/// <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-08 16:33:50 +11:00
IRuntime runtime = app.ApplicationServices.GetRequiredService<IRuntime>();
2020-05-08 17:36:59 +10:00
// can't continue if boot failed
return runtime.State.Level > RuntimeLevel.BootFailed;
}
/// <summary>
/// Start Umbraco
/// </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-12-08 16:33:50 +11:00
if (!app.UmbracoCanBoot())
{
return app;
}
2020-12-08 16:33:50 +11:00
IHostingEnvironment hostingEnvironment = app.ApplicationServices.GetRequiredService<IHostingEnvironment>();
AppDomain.CurrentDomain.SetData("DataDirectory", hostingEnvironment?.MapPathContentRoot(Constants.SystemDirectories.Data));
2020-12-08 16:33:50 +11:00
IRuntime runtime = app.ApplicationServices.GetRequiredService<IRuntime>();
Netcore: Alternate approach for MSDI refactor (#9247) * Doesn't make much sense to have Concrete on IRegister, only on IFactory * Handle FilesTreeController requires IFileSystem of type PhysicalFileSystem * Handle registration of default MediaFileSystem without using RegisterUniqueFor * Remove RegisterFor / RegisterUniqueFor from IRegister * Switch over from LightInject to wrappers around MSDI * Made mapper dependencies more explicit * Remove registration for AngularJsonMediaTypeFormatter It's dependencies aren't registered so container validation fails * Resolve lifetime issue for EnsureValidSessionId by service locating else resolve scoped in singleton * Make registration more explicit for backoffice UserManager * Make install step registrations more explicit * Disable service provider validation so site can launch Maybe this is a problem maybe not, we build about 8000 service providers so maybe everything is fine later... * Further cleanup of IFactory interface * Further cleanup of IRegister interface * Revert "Make registration more explicit for backoffice UserManager" This reverts commit 7215fe836103c597cd0873c66737a79b91ed4c49. * Resolve issue where NewInstallStep would fail to reset password for "SuperUser" Before MSDI, somehow BackOfficeIdentityOptions would be configured with token provider map from IdentityBuilder.AddDefaultTokenProviders. After switchover those config actions are lost. Subclass IdentityBuilder to ensure BackOfficeIdentityOptions doesn't miss config setup upstream. * Initialize current. * Add todo to turn container validation back on. * Migrated ScopeFileSystemsTests to integration tests Signed-off-by: Bjarke Berg <mail@bergmania.dk> * Resolve issue where MediaFileSystem was skipping ShadowFileSystem * Attempt to fix ScopeFileSystemsTests on azure devops Signed-off-by: Bjarke Berg <mail@bergmania.dk> * Be interesting to know what the actual full path is in pipeline. * Clarify intent of CreateMediaTest Doesn't help resolve weird UnauthorizedAccessException but it cuts so much cognitive overhead for the future. * Use ILoggerfactory rather than mock for the manually constructed file PhysicalFileSystem * Maybe resolve failing test on azure pipeline. Co-authored-by: Bjarke Berg <mail@bergmania.dk>
2020-10-26 10:47:14 +00:00
// Register a listener for application shutdown in order to terminate the runtime
2020-12-08 16:33:50 +11:00
IApplicationShutdownRegistry hostLifetime = app.ApplicationServices.GetRequiredService<IApplicationShutdownRegistry>();
var runtimeShutdown = new CoreRuntimeShutdown(runtime, hostLifetime);
hostLifetime.RegisterObject(runtimeShutdown);
// Register our global threadabort enricher for logging
2020-12-08 16:33:50 +11:00
ThreadAbortExceptionEnricher 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
StaticApplicationLogging.Initialize(app.ApplicationServices.GetRequiredService<ILoggerFactory>());
// Start the runtime!
runtime.Start();
return app;
}
/// <summary>
/// Enables middlewares required to run Umbraco
/// </summary>
2020-12-08 16:33:50 +11:00
/// <remarks>
/// Must occur before UseRouting
/// </remarks>
public static IApplicationBuilder UseUmbracoRouting(this IApplicationBuilder app)
{
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));
}
if (!app.UmbracoCanBoot())
{
app.UseMiddleware<BootFailedMiddleware>();
}
else
{
app.UseMiddleware<UmbracoRequestMiddleware>();
app.UseMiddleware<MiniProfilerMiddleware>();
}
return app;
}
/// <summary>
/// Adds request based serilog enrichers to the LogContext for each request
/// </summary>
public static IApplicationBuilder UseUmbracoRequestLogging(this IApplicationBuilder app)
{
2020-12-08 16:33:50 +11:00
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>
public static IApplicationBuilder UseUmbracoRuntimeMinification(this IApplicationBuilder app)
{
2020-12-08 16:33:50 +11:00
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
2020-12-08 16:33:50 +11:00
if (!app.UmbracoCanBoot())
{
return app;
}
app.UseSmidge();
app.UseSmidgeNuglify();
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);
}
}
}
}
}