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

This commit is contained in:
Shannon
2020-05-12 15:18:55 +10:00
parent 4107ccdb12
commit bcaede22f1
12 changed files with 195 additions and 200 deletions

View File

@@ -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<Umbraco.Core.Logging.ILogger>(),
_container.GetInstance<Configs>(),
_container.GetInstance<IIOHelper>(),
_container.GetInstance<Umbraco.Core.Hosting.IHostingEnvironment>(),
_container.GetInstance<IBackOfficeInfo>(),
_container.GetInstance<Umbraco.Core.Logging.IProfiler>());
return provider;
}

View File

@@ -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
{

View File

@@ -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
{

View File

@@ -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;
}
}

View File

@@ -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;
}
/// <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));
if (app.UmbracoCanBoot())
{
var runtime = app.ApplicationServices.GetRequiredService<IRuntime>();
// 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);
// 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
// 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;
}
/// <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);
}
}
}
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;
}
public static IApplicationBuilder UseUmbracoRuntimeMinification(this IApplicationBuilder app)
{
if (app == null) throw new ArgumentNullException(nameof(app));
if (!app.UmbracoCanBoot()) return app;
app.UseSmidge();
return app;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
/// <summary>
/// Enables the Umbraco installer
/// </summary>
/// <param name="app"></param>
/// <returns></returns>
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;
}
/// <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));
if (app.UmbracoCanBoot())
{
var runtime = app.ApplicationServices.GetRequiredService<IRuntime>();
// 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);
// 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
// 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;
}
/// <summary>
/// Enables middlewares required to run Umbraco
/// </summary>
@@ -37,6 +94,60 @@ namespace Umbraco.Extensions
app.UseMiddleware<MiniProfilerMiddleware>();
return app;
}
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();
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);
}
}
}
}
}

View File

@@ -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
/// <returns></returns>
public static IServiceCollection AddUmbracoWebComponents(this IServiceCollection services)
{
services.AddTransient<UmbracoRequestLoggingMiddleware>();
services.AddTransient<UmbracoRequestMiddleware>();
services.TryAddSingleton<UmbracoJsonModelBinder>();
services.ConfigureOptions<UmbracoMvcConfigureOptions>();
services.TryAddEnumerable(ServiceDescriptor.Transient<IApplicationModelProvider, UmbracoApiBehaviorApplicationModelProvider>());

View File

@@ -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);
}
}
}

View File

@@ -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
{
/// <summary>
/// Manages Umbraco request objects and their lifetime
/// </summary>
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<UmbracoRequestMiddleware>(ex);
}
await _next(context);
await next(context);
_umbracoRequestLifetimeManager.EndRequest(context);
}

View File

@@ -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<ILogger> (),
factory.GetInstance<Configs>(),
factory.GetInstance<IIOHelper>(),
factory.GetInstance<IHostingEnvironment>(),
factory.GetInstance<IBackOfficeInfo>(),
factory.GetInstance<IProfiler>()
);
}
// 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?}");

View File

@@ -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();