From bcaede22f17e9be061b4cf82c58a9424c9d4d76b Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 12 May 2020 15:18:55 +1000 Subject: [PATCH] Cleans up ext methods and where they are located and what they call to ensure dependencies are taken care of, cleans up Startup, moves routing appropriately --- .../UmbracoServiceProviderFactory.cs | 14 ++- src/Umbraco.Tests.Integration/RuntimeTests.cs | 2 +- .../Testing/UmbracoIntegrationTest.cs | 2 +- .../AspNetCoreHttpContextAccessor.cs | 16 --- .../UmbracoApplicationBuilderExtensions.cs | 111 ------------------ ...oBackOfficeApplicationBuilderExtensions.cs | 40 +++++++ .../ApplicationBuilderExtensions.cs | 111 ++++++++++++++++++ .../UmbracoWebServiceCollectionExtensions.cs | 4 + .../UmbracoRequestLoggingMiddleware.cs | 14 +-- .../Middleware/UmbracoRequestMiddleware.cs | 18 +-- src/Umbraco.Web.UI.NetCore/Startup.cs | 57 +-------- ...racoWebsiteApplicationBuilderExtensions.cs | 6 +- 12 files changed, 195 insertions(+), 200 deletions(-) delete mode 100644 src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreHttpContextAccessor.cs delete mode 100644 src/Umbraco.Web.BackOffice/AspNetCore/UmbracoApplicationBuilderExtensions.cs create mode 100644 src/Umbraco.Web.BackOffice/Extensions/UmbracoBackOfficeApplicationBuilderExtensions.cs rename src/Umbraco.Web.Website/{AspNetCore => Extensions}/UmbracoWebsiteApplicationBuilderExtensions.cs (66%) diff --git a/src/Umbraco.Infrastructure/Composing/UmbracoServiceProviderFactory.cs b/src/Umbraco.Infrastructure/Composing/UmbracoServiceProviderFactory.cs index b8fad4828c..9efbaee7f1 100644 --- a/src/Umbraco.Infrastructure/Composing/UmbracoServiceProviderFactory.cs +++ b/src/Umbraco.Infrastructure/Composing/UmbracoServiceProviderFactory.cs @@ -1,9 +1,11 @@ using LightInject; using LightInject.Microsoft.DependencyInjection; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; using System; +using Umbraco.Composing; using Umbraco.Core.Composing.LightInject; +using Umbraco.Core.Configuration; +using Umbraco.Core.IO; namespace Umbraco.Core.Composing { @@ -75,6 +77,16 @@ namespace Umbraco.Core.Composing public IServiceProvider CreateServiceProvider(IServiceContainer containerBuilder) { var provider = containerBuilder.CreateServiceProvider(_services); + + // after cross wiring, configure "Current" + Current.Initialize( + _container.GetInstance(), + _container.GetInstance(), + _container.GetInstance(), + _container.GetInstance(), + _container.GetInstance(), + _container.GetInstance()); + return provider; } diff --git a/src/Umbraco.Tests.Integration/RuntimeTests.cs b/src/Umbraco.Tests.Integration/RuntimeTests.cs index 13a54206fa..69119b7984 100644 --- a/src/Umbraco.Tests.Integration/RuntimeTests.cs +++ b/src/Umbraco.Tests.Integration/RuntimeTests.cs @@ -15,9 +15,9 @@ using Umbraco.Tests.Common; using Umbraco.Tests.Integration.Extensions; using Umbraco.Tests.Integration.Implementations; using Umbraco.Tests.Integration.Testing; -using Umbraco.Web.BackOffice.AspNetCore; using Umbraco.Web.Common.AspNetCore; using Umbraco.Extensions; +using Umbraco.Web.BackOffice.Extensions; namespace Umbraco.Tests.Integration { diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index c7f1270fc6..d479ad7213 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -17,8 +17,8 @@ using Umbraco.Core.Strings; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Extensions; using Umbraco.Tests.Integration.Implementations; -using Umbraco.Web.BackOffice.AspNetCore; using Umbraco.Extensions; +using Umbraco.Web.BackOffice.Extensions; namespace Umbraco.Tests.Integration.Testing { diff --git a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreHttpContextAccessor.cs b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreHttpContextAccessor.cs deleted file mode 100644 index 696005f2fb..0000000000 --- a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreHttpContextAccessor.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.AspNetCore.Http; - -namespace Umbraco.Web.BackOffice.AspNetCore -{ - internal class AspNetCoreHttpContextAccessor //: IHttpContextAccessor - { - private readonly IHttpContextAccessor _httpContextAccessor; - - public AspNetCoreHttpContextAccessor(IHttpContextAccessor httpContextAccessor) - { - _httpContextAccessor = httpContextAccessor; - } - - public HttpContext HttpContext => _httpContextAccessor.HttpContext; - } -} diff --git a/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoApplicationBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoApplicationBuilderExtensions.cs deleted file mode 100644 index e886ccc9e5..0000000000 --- a/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoApplicationBuilderExtensions.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System; -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.DependencyInjection; -using Serilog.Context; -using Smidge; -using Umbraco.Core; -using Umbraco.Core.Configuration; -using Umbraco.Core.Hosting; -using Umbraco.Extensions; -using Umbraco.Infrastructure.Logging.Serilog.Enrichers; -using Umbraco.Web.Common.Middleware; - -namespace Umbraco.Web.BackOffice.AspNetCore -{ - public static class UmbracoApplicationBuilderExtensions - { - public static IApplicationBuilder UseUmbracoBackOffice(this IApplicationBuilder app) - { - if (app == null) throw new ArgumentNullException(nameof(app)); - - if (!app.UmbracoCanBoot()) return app; - - // TODO: start the back office - - return app; - } - - /// - /// 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; - } - - /// - /// 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); - } - - } - } - - public static IApplicationBuilder UseUmbracoRequestLogging(this IApplicationBuilder app) - { - if (app == null) throw new ArgumentNullException(nameof(app)); - - if (!app.UmbracoCanBoot()) return app; - - app.UseMiddleware(); - - return app; - } - - public static IApplicationBuilder UseUmbracoRuntimeMinification(this IApplicationBuilder app) - { - if (app == null) throw new ArgumentNullException(nameof(app)); - - if (!app.UmbracoCanBoot()) return app; - - app.UseSmidge(); - - return app; - } - } -} diff --git a/src/Umbraco.Web.BackOffice/Extensions/UmbracoBackOfficeApplicationBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/UmbracoBackOfficeApplicationBuilderExtensions.cs new file mode 100644 index 0000000000..8043e645b7 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/Extensions/UmbracoBackOfficeApplicationBuilderExtensions.cs @@ -0,0 +1,40 @@ +using System; +using Microsoft.AspNetCore.Builder; +using SixLabors.ImageSharp.Web.DependencyInjection; +using Umbraco.Extensions; + +namespace Umbraco.Web.BackOffice.Extensions +{ + public static class UmbracoBackOfficeApplicationBuilderExtensions + { + public static IApplicationBuilder UseUmbracoBackOffice(this IApplicationBuilder app) + { + if (app == null) throw new ArgumentNullException(nameof(app)); + + if (!app.UmbracoCanBoot()) return app; + + app.UseEndpoints(endpoints => + { + // TODO: This is temporary, 'umbraco' cannot be hard coded, needs to use GetUmbracoMvcArea() + // but actually we need to route all back office stuff in a back office area like we do in v8 + + endpoints.MapControllerRoute("Backoffice", "/umbraco/{Action}", new + { + Controller = "BackOffice", + Action = "Default" + }); + }); + + app.UseUmbracoRuntimeMinification(); + + // 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 UseUmbracoWebsite too? + app.UseImageSharp(); + app.UseStaticFiles(); + + return app; + } + + + } +} diff --git a/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs b/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs index 47cee99264..da68e4d634 100644 --- a/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs @@ -1,8 +1,12 @@ using System; 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 @@ -21,6 +25,59 @@ namespace Umbraco.Extensions return runtime.State.Level > RuntimeLevel.BootFailed; } + /// + /// Enables the Umbraco installer + /// + /// + /// + public static IApplicationBuilder UseUmbracoInstaller(this IApplicationBuilder app) + { + app.UseEndpoints(endpoints => + { + // TODO: Fix this routing with an area + endpoints.MapControllerRoute("Install", "/install/{controller}/{Action}", defaults: new { Area = "Install" }); + + //TODO register routing correct: Name must be like this + endpoints.MapControllerRoute("umbraco-api-UmbracoInstall-InstallApi", "/install/api/{Action}", defaults: new { Area = "Install", Controller = "InstallApi" }); + }); + + return app; + } + + /// + /// 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 /// @@ -37,6 +94,60 @@ namespace Umbraco.Extensions 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); + } + + } + } } } diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs index fb7d379ae5..559730bdc3 100644 --- a/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs @@ -20,6 +20,7 @@ using Smidge.Nuglify; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Web.Common.ApplicationModels; +using Umbraco.Web.Common.Middleware; using Umbraco.Web.Common.ModelBinding; namespace Umbraco.Extensions @@ -33,6 +34,9 @@ namespace Umbraco.Extensions /// public static IServiceCollection AddUmbracoWebComponents(this IServiceCollection services) { + services.AddTransient(); + services.AddTransient(); + services.TryAddSingleton(); services.ConfigureOptions(); services.TryAddEnumerable(ServiceDescriptor.Transient()); diff --git a/src/Umbraco.Web.Common/Middleware/UmbracoRequestLoggingMiddleware.cs b/src/Umbraco.Web.Common/Middleware/UmbracoRequestLoggingMiddleware.cs index b1d2d01f9d..803eb95d62 100644 --- a/src/Umbraco.Web.Common/Middleware/UmbracoRequestLoggingMiddleware.cs +++ b/src/Umbraco.Web.Common/Middleware/UmbracoRequestLoggingMiddleware.cs @@ -8,30 +8,28 @@ using Umbraco.Core.Logging.Serilog.Enrichers; namespace Umbraco.Web.Common.Middleware { - public class UmbracoRequestLoggingMiddleware + public class UmbracoRequestLoggingMiddleware : IMiddleware { - readonly RequestDelegate _next; private readonly HttpSessionIdEnricher _sessionIdEnricher; private readonly HttpRequestNumberEnricher _requestNumberEnricher; private readonly HttpRequestIdEnricher _requestIdEnricher; - public UmbracoRequestLoggingMiddleware(RequestDelegate next, + public UmbracoRequestLoggingMiddleware( HttpSessionIdEnricher sessionIdEnricher, HttpRequestNumberEnricher requestNumberEnricher, HttpRequestIdEnricher requestIdEnricher) { - _next = next; _sessionIdEnricher = sessionIdEnricher; _requestNumberEnricher = requestNumberEnricher; _requestIdEnricher = requestIdEnricher; } - public async Task Invoke(HttpContext httpContext) + public async Task InvokeAsync(HttpContext context, RequestDelegate next) { // do not process if client-side request - if (new Uri(httpContext.Request.GetEncodedUrl(), UriKind.RelativeOrAbsolute).IsClientSideRequest()) + if (new Uri(context.Request.GetEncodedUrl(), UriKind.RelativeOrAbsolute).IsClientSideRequest()) { - await _next(httpContext); + await next(context); return; } @@ -42,7 +40,7 @@ namespace Umbraco.Web.Common.Middleware using (LogContext.Push(_requestNumberEnricher)) using (LogContext.Push(_requestIdEnricher)) { - await _next(httpContext); + await next(context); } } } diff --git a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs index 85cf6607cc..e1662e834f 100644 --- a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs +++ b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs @@ -5,46 +5,46 @@ using Microsoft.AspNetCore.Http.Extensions; using Umbraco.Web.Common.Lifetime; using Umbraco.Core; using Umbraco.Core.Logging; +using System.Threading; namespace Umbraco.Web.Common.Middleware { + /// /// Manages Umbraco request objects and their lifetime /// - public class UmbracoRequestMiddleware + public class UmbracoRequestMiddleware : IMiddleware { - private readonly RequestDelegate _next; private readonly ILogger _logger; private readonly IUmbracoRequestLifetimeManager _umbracoRequestLifetimeManager; private readonly IUmbracoContextFactory _umbracoContextFactory; - public UmbracoRequestMiddleware(RequestDelegate next, + public UmbracoRequestMiddleware( ILogger logger, IUmbracoRequestLifetimeManager umbracoRequestLifetimeManager, IUmbracoContextFactory umbracoContextFactory) { - _next = next; _logger = logger; _umbracoRequestLifetimeManager = umbracoRequestLifetimeManager; _umbracoContextFactory = umbracoContextFactory; } - public async Task InvokeAsync(HttpContext context) + public async Task InvokeAsync(HttpContext context, RequestDelegate next) { // do not process if client-side request if (new Uri(context.Request.GetEncodedUrl(), UriKind.RelativeOrAbsolute).IsClientSideRequest()) { - await _next(context); + await next(context); return; } var umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext(); - + try { try - { + { _umbracoRequestLifetimeManager.InitRequest(context); } catch (Exception ex) @@ -53,7 +53,7 @@ namespace Umbraco.Web.Common.Middleware _logger.Error(ex); } - await _next(context); + await next(context); _umbracoRequestLifetimeManager.EndRequest(context); } diff --git a/src/Umbraco.Web.UI.NetCore/Startup.cs b/src/Umbraco.Web.UI.NetCore/Startup.cs index bd23ef4229..1ad434fdd7 100644 --- a/src/Umbraco.Web.UI.NetCore/Startup.cs +++ b/src/Umbraco.Web.UI.NetCore/Startup.cs @@ -1,30 +1,12 @@ using System; -using System.Collections.Generic; -using System.Data.Common; -using System.Data.SqlClient; -using System.IO; -using System.Reflection; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Newtonsoft.Json.Serialization; -using Umbraco.Composing; -using Umbraco.Core; -using Umbraco.Core.Configuration; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence; -using Umbraco.Core.Persistence.SqlSyntax; -using Umbraco.Web.BackOffice.AspNetCore; using Umbraco.Extensions; -using Umbraco.Web.Common.Filters; -using Umbraco.Web.Website.AspNetCore; -using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; - +using Umbraco.Web.Website.Extensions; +using Umbraco.Web.BackOffice.Extensions; namespace Umbraco.Web.UI.BackOffice { @@ -62,24 +44,11 @@ namespace Umbraco.Web.UI.BackOffice { options.ShouldProfile = request => false; // WebProfiler determine and start profiling. We should not use the MiniProfilerMiddleware to also profile }); - - //Finally initialize Current - // TODO: This should be moved to the UmbracoServiceProviderFactory when the container is cross-wired and then don't use the overload above to `out var factory` - Current.Initialize( - factory.GetInstance (), - factory.GetInstance(), - factory.GetInstance(), - factory.GetInstance(), - factory.GetInstance(), - factory.GetInstance() - ); - } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app) { - //app.UseMiniProfiler(); if (_env.IsDevelopment()) { @@ -89,29 +58,15 @@ namespace Umbraco.Web.UI.BackOffice app.UseStatusCodePages(); app.UseRouting(); - - app.UseUmbracoRouting(); app.UseUmbracoCore(); + app.UseUmbracoRouting(); app.UseUmbracoRequestLogging(); app.UseUmbracoWebsite(); - app.UseUmbracoBackOffice(); - app.UseUmbracoRuntimeMinification(); - + app.UseUmbracoBackOffice(); + app.UseUmbracoInstaller(); app.UseEndpoints(endpoints => - { - endpoints.MapControllerRoute("Backoffice", "/umbraco/{Action}", new - { - Controller = "BackOffice", - Action = "Default" - }); - - // TODO: Fix this routing with an area - endpoints.MapControllerRoute("Install", "/install/{controller}/{Action}", defaults:new { Area = "Install"}); - - //TODO register routing correct: Name must be like this - endpoints.MapControllerRoute("umbraco-api-UmbracoInstall-InstallApi", "/install/api/{Action}", defaults:new { Area = "Install", Controller = "InstallApi"}); - + { endpoints.MapControllerRoute( name: "default", pattern: "{controller}/{action=Index}/{id?}"); diff --git a/src/Umbraco.Web.Website/AspNetCore/UmbracoWebsiteApplicationBuilderExtensions.cs b/src/Umbraco.Web.Website/Extensions/UmbracoWebsiteApplicationBuilderExtensions.cs similarity index 66% rename from src/Umbraco.Web.Website/AspNetCore/UmbracoWebsiteApplicationBuilderExtensions.cs rename to src/Umbraco.Web.Website/Extensions/UmbracoWebsiteApplicationBuilderExtensions.cs index 2fc8f70f2e..f6a54b8b0a 100644 --- a/src/Umbraco.Web.Website/AspNetCore/UmbracoWebsiteApplicationBuilderExtensions.cs +++ b/src/Umbraco.Web.Website/Extensions/UmbracoWebsiteApplicationBuilderExtensions.cs @@ -4,10 +4,11 @@ using Microsoft.Extensions.DependencyInjection; using SixLabors.ImageSharp.Web.DependencyInjection; using Umbraco.Core; using Umbraco.Extensions; +using Umbraco.Web.Common.Middleware; -namespace Umbraco.Web.Website.AspNetCore +namespace Umbraco.Web.Website.Extensions { - public static class UmbracoBackOfficeApplicationBuilderExtensions + public static class UmbracoWebsiteApplicationBuilderExtensions { public static IApplicationBuilder UseUmbracoWebsite(this IApplicationBuilder app) { @@ -16,6 +17,7 @@ namespace Umbraco.Web.Website.AspNetCore if (!app.UmbracoCanBoot()) return app; // 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();