Moved files from backoffice into Common + Introduced AspNetCoreComponent to invoke the Umbraco Application Init event
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Hosting;
|
||||
|
||||
namespace Umbraco.Web.Common.AspNetCore
|
||||
{
|
||||
public class AspNetCoreApplicationShutdownRegistry : IApplicationShutdownRegistry
|
||||
{
|
||||
private readonly IHostApplicationLifetime _hostApplicationLifetime;
|
||||
private readonly ConcurrentDictionary<IRegisteredObject, RegisteredObjectWrapper> _registeredObjects =
|
||||
new ConcurrentDictionary<IRegisteredObject, RegisteredObjectWrapper>();
|
||||
|
||||
public AspNetCoreApplicationShutdownRegistry(IHostApplicationLifetime hostApplicationLifetime)
|
||||
{
|
||||
_hostApplicationLifetime = hostApplicationLifetime;
|
||||
}
|
||||
|
||||
public void RegisterObject(IRegisteredObject registeredObject)
|
||||
{
|
||||
var wrapped = new RegisteredObjectWrapper(registeredObject);
|
||||
if (!_registeredObjects.TryAdd(registeredObject, wrapped))
|
||||
{
|
||||
throw new InvalidOperationException("Could not register object");
|
||||
}
|
||||
|
||||
var cancellationTokenRegistration = _hostApplicationLifetime.ApplicationStopping.Register(() => wrapped.Stop(true));
|
||||
wrapped.CancellationTokenRegistration = cancellationTokenRegistration;
|
||||
}
|
||||
|
||||
public void UnregisterObject(IRegisteredObject registeredObject)
|
||||
{
|
||||
if (_registeredObjects.TryGetValue(registeredObject, out var wrapped))
|
||||
{
|
||||
wrapped.CancellationTokenRegistration.Unregister();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class RegisteredObjectWrapper
|
||||
{
|
||||
private readonly IRegisteredObject _inner;
|
||||
|
||||
public RegisteredObjectWrapper(IRegisteredObject inner)
|
||||
{
|
||||
_inner = inner;
|
||||
}
|
||||
|
||||
public CancellationTokenRegistration CancellationTokenRegistration { get; set; }
|
||||
|
||||
public void Stop(bool immediate)
|
||||
{
|
||||
_inner.Stop(immediate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Web.Common.AspNetCore
|
||||
{
|
||||
public class AspNetCoreBackOfficeInfo : IBackOfficeInfo
|
||||
{
|
||||
public AspNetCoreBackOfficeInfo(IGlobalSettings globalSettings)
|
||||
{
|
||||
GetAbsoluteUrl = globalSettings.UmbracoPath;
|
||||
}
|
||||
|
||||
public string GetAbsoluteUrl { get; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Web.Common.AspNetCore
|
||||
{
|
||||
public class AspNetCoreHostingEnvironment : Umbraco.Core.Hosting.IHostingEnvironment
|
||||
{
|
||||
|
||||
|
||||
private readonly IHostingSettings _hostingSettings;
|
||||
private readonly IWebHostEnvironment _webHostEnvironment;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
private string _localTempPath;
|
||||
|
||||
public AspNetCoreHostingEnvironment(IHostingSettings hostingSettings, IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_hostingSettings = hostingSettings ?? throw new ArgumentNullException(nameof(hostingSettings));
|
||||
_webHostEnvironment = webHostEnvironment;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
|
||||
SiteName = webHostEnvironment.ApplicationName;
|
||||
ApplicationId = AppDomain.CurrentDomain.Id.ToString();
|
||||
ApplicationPhysicalPath = webHostEnvironment.ContentRootPath;
|
||||
|
||||
ApplicationVirtualPath = "/"; //TODO how to find this, This is a server thing, not application thing.
|
||||
IISVersion = new Version(0, 0); // TODO not necessary IIS
|
||||
IsDebugMode = _hostingSettings.DebugMode;
|
||||
}
|
||||
|
||||
public bool IsHosted { get; } = true;
|
||||
public string SiteName { get; }
|
||||
public string ApplicationId { get; }
|
||||
public string ApplicationPhysicalPath { get; }
|
||||
|
||||
public string ApplicationVirtualPath { get; }
|
||||
public bool IsDebugMode { get; }
|
||||
|
||||
public Version IISVersion { get; }
|
||||
public string LocalTempPath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_localTempPath != null)
|
||||
return _localTempPath;
|
||||
|
||||
switch (_hostingSettings.LocalTempStorageLocation)
|
||||
{
|
||||
case LocalTempStorage.AspNetTemp:
|
||||
|
||||
// TODO: I don't think this is correct? but also we probably can remove AspNetTemp as an option entirely
|
||||
// since this is legacy and we shouldn't use it
|
||||
return _localTempPath = System.IO.Path.Combine(Path.GetTempPath(), ApplicationId, "UmbracoData");
|
||||
|
||||
case LocalTempStorage.EnvironmentTemp:
|
||||
|
||||
// environment temp is unique, we need a folder per site
|
||||
|
||||
// use a hash
|
||||
// combine site name and application id
|
||||
// site name is a Guid on Cloud
|
||||
// application id is eg /LM/W3SVC/123456/ROOT
|
||||
// the combination is unique on one server
|
||||
// and, if a site moves from worker A to B and then back to A...
|
||||
// hopefully it gets a new Guid or new application id?
|
||||
|
||||
var hashString = SiteName + "::" + ApplicationId;
|
||||
var hash = hashString.GenerateHash();
|
||||
var siteTemp = System.IO.Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", hash);
|
||||
|
||||
return _localTempPath = siteTemp;
|
||||
|
||||
//case LocalTempStorage.Default:
|
||||
//case LocalTempStorage.Unknown:
|
||||
default:
|
||||
return _localTempPath = MapPath("~/App_Data/TEMP");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string MapPath(string path)
|
||||
{
|
||||
var newPath = path.TrimStart('~', '/').Replace('/', Path.DirectorySeparatorChar);
|
||||
return Path.Combine(_webHostEnvironment.WebRootPath, newPath);
|
||||
}
|
||||
|
||||
// TODO: Need to take into account 'root' here
|
||||
public string ToAbsolute(string virtualPath, string root)
|
||||
{
|
||||
if (Uri.TryCreate(virtualPath, UriKind.Absolute, out _))
|
||||
{
|
||||
return virtualPath;
|
||||
}
|
||||
|
||||
var segment = new PathString(virtualPath.Substring(1));
|
||||
var applicationPath = _httpContextAccessor.HttpContext.Request.PathBase;
|
||||
|
||||
return applicationPath.Add(segment).Value;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
17
src/Umbraco.Web.Common/AspNetCore/AspNetCoreIpResolver.cs
Normal file
17
src/Umbraco.Web.Common/AspNetCore/AspNetCoreIpResolver.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Umbraco.Net;
|
||||
|
||||
namespace Umbraco.Web.Common.AspNetCore
|
||||
{
|
||||
public class AspNetIpResolver : IIpResolver
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public AspNetIpResolver(IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public string GetCurrentRequestIpAddress() => _httpContextAccessor?.HttpContext?.Connection?.RemoteIpAddress?.ToString() ?? string.Empty;
|
||||
}
|
||||
}
|
||||
13
src/Umbraco.Web.Common/AspNetCore/AspNetCoreMarchal.cs
Normal file
13
src/Umbraco.Web.Common/AspNetCore/AspNetCoreMarchal.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Umbraco.Core.Diagnostics;
|
||||
|
||||
namespace Umbraco.Web.Common.AspNetCore
|
||||
{
|
||||
|
||||
public class AspNetCoreMarchal : IMarchal
|
||||
{
|
||||
// This thing is not available in net standard, but exists in both .Net 4 and .Net Core 3
|
||||
public IntPtr GetExceptionPointers() => Marshal.GetExceptionPointers();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Umbraco.Net;
|
||||
|
||||
namespace Umbraco.Web.Common.AspNetCore
|
||||
{
|
||||
internal class AspNetCoreSessionIdResolver : ISessionIdResolver
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public AspNetCoreSessionIdResolver(IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
|
||||
public string SessionId
|
||||
{
|
||||
get
|
||||
{
|
||||
var httpContext = _httpContextAccessor?.HttpContext;
|
||||
// If session isn't enabled this will throw an exception so we check
|
||||
var sessionFeature = httpContext?.Features.Get<ISessionFeature>();
|
||||
return sessionFeature != null
|
||||
? httpContext?.Session?.Id
|
||||
: "0";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,6 @@ namespace Umbraco.Web.Common.AspNetCore
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_hostApplicationLifetime = hostApplicationLifetime;
|
||||
|
||||
hostApplicationLifetime.ApplicationStarted.Register(() =>
|
||||
{
|
||||
ApplicationInit?.Invoke(this, EventArgs.Empty);
|
||||
});
|
||||
}
|
||||
|
||||
public bool IsRestarting { get; set; }
|
||||
@@ -39,6 +34,10 @@ namespace Umbraco.Web.Common.AspNetCore
|
||||
_hostApplicationLifetime.StopApplication();
|
||||
}
|
||||
|
||||
public void InvokeApplicationInit()
|
||||
{
|
||||
ApplicationInit?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
public event EventHandler ApplicationInit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
using System;
|
||||
using System.Data.Common;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Umbraco.Composing;
|
||||
using Umbraco.Configuration;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Logging.Serilog;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Runtime;
|
||||
using Umbraco.Web.Common.Runtime.Profiler;
|
||||
|
||||
namespace Umbraco.Web.Common.AspNetCore
|
||||
{
|
||||
public static class UmbracoCoreServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds the Umbraco Configuration requirements
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="configuration"></param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddUmbracoConfiguration(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
if (configuration == null) throw new ArgumentNullException(nameof(configuration));
|
||||
|
||||
var configsFactory = new AspNetCoreConfigsFactory(configuration);
|
||||
|
||||
var configs = configsFactory.Create();
|
||||
|
||||
services.AddSingleton(configs);
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds the Umbraco Back Core requirements
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="webHostEnvironment"></param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddUmbracoCore(this IServiceCollection services, IWebHostEnvironment webHostEnvironment)
|
||||
{
|
||||
if (!UmbracoServiceProviderFactory.IsActive)
|
||||
throw new InvalidOperationException("Ensure to add UseUmbraco() in your Program.cs after ConfigureWebHostDefaults to enable Umbraco's service provider factory");
|
||||
|
||||
var umbContainer = UmbracoServiceProviderFactory.UmbracoContainer;
|
||||
|
||||
return services.AddUmbracoCore(webHostEnvironment, umbContainer, Assembly.GetEntryAssembly());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the Umbraco Back Core requirements
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="webHostEnvironment"></param>
|
||||
/// <param name="umbContainer"></param>
|
||||
/// <param name="entryAssembly"></param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddUmbracoCore(this IServiceCollection services, IWebHostEnvironment webHostEnvironment, IRegister umbContainer, Assembly entryAssembly)
|
||||
{
|
||||
if (services is null) throw new ArgumentNullException(nameof(services));
|
||||
var container = umbContainer;
|
||||
if (container is null) throw new ArgumentNullException(nameof(container));
|
||||
if (entryAssembly is null) throw new ArgumentNullException(nameof(entryAssembly));
|
||||
|
||||
// Special case! The generic host adds a few default services but we need to manually add this one here NOW because
|
||||
// we resolve it before the host finishes configuring in the call to CreateCompositionRoot
|
||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
|
||||
CreateCompositionRoot(services, webHostEnvironment, out var logger, out var configs, out var ioHelper, out var hostingEnvironment, out var backOfficeInfo, out var profiler);
|
||||
|
||||
var globalSettings = configs.Global();
|
||||
var umbracoVersion = new UmbracoVersion(globalSettings);
|
||||
|
||||
// TODO: Currently we are not passing in any TypeFinderConfig (with ITypeFinderSettings) which we should do, however
|
||||
// this is not critical right now and would require loading in some config before boot time so just leaving this as-is for now.
|
||||
var typeFinder = new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(entryAssembly));
|
||||
|
||||
var coreRuntime = GetCoreRuntime(
|
||||
configs,
|
||||
umbracoVersion,
|
||||
ioHelper,
|
||||
logger,
|
||||
profiler,
|
||||
hostingEnvironment,
|
||||
backOfficeInfo,
|
||||
typeFinder);
|
||||
|
||||
var factory = coreRuntime.Configure(container);
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
private static IRuntime GetCoreRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger,
|
||||
IProfiler profiler, Core.Hosting.IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo,
|
||||
ITypeFinder typeFinder)
|
||||
{
|
||||
var connectionStringConfig = configs.ConnectionStrings()[Constants.System.UmbracoConnectionName];
|
||||
var dbProviderFactoryCreator = new SqlServerDbProviderFactoryCreator(
|
||||
connectionStringConfig?.ProviderName,
|
||||
DbProviderFactories.GetFactory);
|
||||
|
||||
// Determine if we should use the sql main dom or the default
|
||||
var globalSettings = configs.Global();
|
||||
var connStrings = configs.ConnectionStrings();
|
||||
var appSettingMainDomLock = globalSettings.MainDomLock;
|
||||
var mainDomLock = appSettingMainDomLock == "SqlMainDomLock"
|
||||
? (IMainDomLock)new SqlMainDomLock(logger, globalSettings, connStrings, dbProviderFactoryCreator)
|
||||
: new MainDomSemaphoreLock(logger, hostingEnvironment);
|
||||
|
||||
var mainDom = new MainDom(logger, mainDomLock);
|
||||
|
||||
var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetCoreBootPermissionsChecker(),
|
||||
hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom, typeFinder);
|
||||
|
||||
return coreRuntime;
|
||||
}
|
||||
|
||||
private static void CreateCompositionRoot(IServiceCollection services, IWebHostEnvironment webHostEnvironment,
|
||||
out ILogger logger, out Configs configs, out IIOHelper ioHelper, out Core.Hosting.IHostingEnvironment hostingEnvironment,
|
||||
out IBackOfficeInfo backOfficeInfo, out IProfiler profiler)
|
||||
{
|
||||
// TODO: We need to avoid this, surely there's a way? See ContainerTests.BuildServiceProvider_Before_Host_Is_Configured
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
|
||||
var httpContextAccessor = serviceProvider.GetRequiredService<IHttpContextAccessor>();
|
||||
|
||||
configs = serviceProvider.GetService<Configs>();
|
||||
if (configs == null)
|
||||
throw new InvalidOperationException($"Could not resolve type {typeof(Configs)} from the container, ensure {nameof(AddUmbracoConfiguration)} is called before calling {nameof(AddUmbracoCore)}");
|
||||
|
||||
var hostingSettings = configs.Hosting();
|
||||
var coreDebug = configs.CoreDebug();
|
||||
var globalSettings = configs.Global();
|
||||
|
||||
hostingEnvironment = new AspNetCoreHostingEnvironment(hostingSettings, webHostEnvironment, httpContextAccessor);
|
||||
ioHelper = new IOHelper(hostingEnvironment, globalSettings);
|
||||
logger = SerilogLogger.CreateWithDefaultConfiguration(hostingEnvironment,
|
||||
new AspNetCoreSessionIdResolver(httpContextAccessor),
|
||||
// TODO: We need to avoid this, surely there's a way? See ContainerTests.BuildServiceProvider_Before_Host_Is_Configured
|
||||
() => services.BuildServiceProvider().GetService<IRequestCache>(), coreDebug, ioHelper,
|
||||
new AspNetCoreMarchal());
|
||||
|
||||
backOfficeInfo = new AspNetCoreBackOfficeInfo(globalSettings);
|
||||
profiler = GetWebProfiler(hostingEnvironment, httpContextAccessor);
|
||||
|
||||
Current.Initialize(logger, configs, ioHelper, hostingEnvironment, backOfficeInfo, profiler);
|
||||
}
|
||||
|
||||
private static IProfiler GetWebProfiler(Umbraco.Core.Hosting.IHostingEnvironment hostingEnvironment, IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
// create and start asap to profile boot
|
||||
if (!hostingEnvironment.IsDebugMode)
|
||||
{
|
||||
// should let it be null, that's how MiniProfiler is meant to work,
|
||||
// but our own IProfiler expects an instance so let's get one
|
||||
return new VoidProfiler();
|
||||
}
|
||||
|
||||
var webProfiler = new WebProfiler(httpContextAccessor);
|
||||
webProfiler.Start();
|
||||
|
||||
return webProfiler;
|
||||
}
|
||||
private class AspNetCoreBootPermissionsChecker : IUmbracoBootPermissionChecker
|
||||
{
|
||||
public void ThrowIfNotPermissions()
|
||||
{
|
||||
// nothing to check
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
11
src/Umbraco.Web.Common/Lifetime/IUmbracoRequestLifetime.cs
Normal file
11
src/Umbraco.Web.Common/Lifetime/IUmbracoRequestLifetime.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Umbraco.Web.Common.Lifetime
|
||||
{
|
||||
public interface IUmbracoRequestLifetime
|
||||
{
|
||||
event EventHandler<HttpContext> RequestStart;
|
||||
event EventHandler<HttpContext> RequestEnd;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Umbraco.Web.Common.Lifetime
|
||||
{
|
||||
public interface IUmbracoRequestLifetimeManager
|
||||
{
|
||||
void InitRequest(HttpContext context);
|
||||
void EndRequest(HttpContext context);
|
||||
}
|
||||
}
|
||||
21
src/Umbraco.Web.Common/Lifetime/UmbracoRequestLifetime.cs
Normal file
21
src/Umbraco.Web.Common/Lifetime/UmbracoRequestLifetime.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Umbraco.Web.Common.Lifetime
|
||||
{
|
||||
public class UmbracoRequestLifetime : IUmbracoRequestLifetime, IUmbracoRequestLifetimeManager
|
||||
{
|
||||
public event EventHandler<HttpContext> RequestStart;
|
||||
public event EventHandler<HttpContext> RequestEnd;
|
||||
|
||||
public void InitRequest(HttpContext context)
|
||||
{
|
||||
RequestStart?.Invoke(this, context);
|
||||
}
|
||||
|
||||
public void EndRequest(HttpContext context)
|
||||
{
|
||||
RequestEnd?.Invoke(this, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Umbraco.Web.Common.Lifetime;
|
||||
|
||||
namespace Umbraco.Web.Common.Middleware
|
||||
{
|
||||
@@ -22,31 +23,4 @@ namespace Umbraco.Web.Common.Middleware
|
||||
}
|
||||
}
|
||||
|
||||
public interface IUmbracoRequestLifetime
|
||||
{
|
||||
event EventHandler<HttpContext> RequestStart;
|
||||
event EventHandler<HttpContext> RequestEnd;
|
||||
}
|
||||
|
||||
public class UmbracoRequestLifetime : IUmbracoRequestLifetime, IUmbracoRequestLifetimeManager
|
||||
{
|
||||
public event EventHandler<HttpContext> RequestStart;
|
||||
public event EventHandler<HttpContext> RequestEnd;
|
||||
|
||||
public void InitRequest(HttpContext context)
|
||||
{
|
||||
RequestStart?.Invoke(this, context);
|
||||
}
|
||||
|
||||
public void EndRequest(HttpContext context)
|
||||
{
|
||||
RequestEnd?.Invoke(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IUmbracoRequestLifetimeManager
|
||||
{
|
||||
void InitRequest(HttpContext context);
|
||||
void EndRequest(HttpContext context);
|
||||
}
|
||||
}
|
||||
|
||||
29
src/Umbraco.Web.Common/Runtime/AspNetCoreComponent.cs
Normal file
29
src/Umbraco.Web.Common/Runtime/AspNetCoreComponent.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Net;
|
||||
|
||||
namespace Umbraco.Web.Common.Runtime
|
||||
{
|
||||
public sealed class AspNetCoreComponent : IComponent
|
||||
{
|
||||
private readonly IHostApplicationLifetime _hostApplicationLifetime;
|
||||
private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime;
|
||||
|
||||
public AspNetCoreComponent(IHostApplicationLifetime hostApplicationLifetime, IUmbracoApplicationLifetime umbracoApplicationLifetime)
|
||||
{
|
||||
_hostApplicationLifetime = hostApplicationLifetime;
|
||||
_umbracoApplicationLifetime = umbracoApplicationLifetime;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_hostApplicationLifetime.ApplicationStarted.Register(() => {
|
||||
_umbracoApplicationLifetime.InvokeApplicationInit();
|
||||
});
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs
Normal file
37
src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Net;
|
||||
using Umbraco.Core.Runtime;
|
||||
using Umbraco.Web.Common.AspNetCore;
|
||||
using Umbraco.Web.Common.Lifetime;
|
||||
|
||||
namespace Umbraco.Web.Common.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds/replaces AspNetCore specific services
|
||||
/// </summary>
|
||||
[ComposeBefore(typeof(ICoreComposer))]
|
||||
[ComposeAfter(typeof(CoreInitialComposer))]
|
||||
public class AspNetCoreComposer : ComponentComposer<AspNetCoreComponent>, IComposer
|
||||
{
|
||||
public new void Compose(Composition composition)
|
||||
{
|
||||
base.Compose(composition);
|
||||
|
||||
// AspNetCore specific services
|
||||
composition.RegisterUnique<IHttpContextAccessor, HttpContextAccessor>();
|
||||
|
||||
// Our own netcore implementations
|
||||
composition.RegisterUnique<IUmbracoApplicationLifetime, AspNetCoreUmbracoApplicationLifetime>();
|
||||
composition.RegisterUnique<IApplicationShutdownRegistry, AspNetCoreApplicationShutdownRegistry>();
|
||||
|
||||
// The umbraco request lifetime
|
||||
var umbracoRequestLifetime = new UmbracoRequestLifetime();
|
||||
composition.RegisterUnique<IUmbracoRequestLifetimeManager>(factory => umbracoRequestLifetime);
|
||||
composition.RegisterUnique<IUmbracoRequestLifetime>(factory => umbracoRequestLifetime);
|
||||
composition.RegisterUnique<IUmbracoApplicationLifetime, AspNetCoreUmbracoApplicationLifetime>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Web.Common.Runtime.Profiler
|
||||
{
|
||||
public sealed class WebInitialComponent : IComponent
|
||||
{
|
||||
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Net;
|
||||
using Umbraco.Web.Common.AspNetCore;
|
||||
using Umbraco.Web.Common.Middleware;
|
||||
|
||||
namespace Umbraco.Web.Common.Runtime.Profiler
|
||||
{
|
||||
public class WebInitialComposer : ComponentComposer<WebInitialComponent>, ICoreComposer
|
||||
{
|
||||
|
||||
public override void Compose(Composition composition)
|
||||
{
|
||||
base.Compose(composition);
|
||||
|
||||
var umbracoRequestLifetime = new UmbracoRequestLifetime();
|
||||
|
||||
composition.RegisterUnique<IUmbracoRequestLifetimeManager>(factory => umbracoRequestLifetime);
|
||||
composition.RegisterUnique<IUmbracoRequestLifetime>(factory => umbracoRequestLifetime);
|
||||
composition.RegisterUnique<IUmbracoApplicationLifetime, AspNetCoreUmbracoApplicationLifetime>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,10 +22,15 @@ namespace Umbraco.Web.Common.Runtime.Profiler
|
||||
// create our own provider, which can provide a profiler even during boot
|
||||
_provider = new WebProfilerProvider();
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
|
||||
MiniProfiler.DefaultOptions.ProfilerProvider = _provider;
|
||||
}
|
||||
|
||||
public string Render() => MiniProfiler.Current
|
||||
.RenderIncludes(_httpContextAccessor.HttpContext, RenderPosition.Right).ToString();
|
||||
public string Render()
|
||||
{
|
||||
return MiniProfiler.Current
|
||||
.RenderIncludes(_httpContextAccessor.HttpContext, RenderPosition.Right).ToString();
|
||||
}
|
||||
|
||||
public IDisposable Step(string name) => MiniProfiler.Current?.Step(name);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Net;
|
||||
using Umbraco.Web.Common.Lifetime;
|
||||
using Umbraco.Web.Common.Middleware;
|
||||
|
||||
namespace Umbraco.Web.Common.Runtime.Profiler
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Umbraco.Configuration\Umbraco.Configuration.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Infrastructure\Umbraco.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user