diff --git a/src/Umbraco.Core/Composing/RuntimeHashPaths.cs b/src/Umbraco.Core/Composing/RuntimeHashPaths.cs index 8b5af064af..c5a994c9a6 100644 --- a/src/Umbraco.Core/Composing/RuntimeHashPaths.cs +++ b/src/Umbraco.Core/Composing/RuntimeHashPaths.cs @@ -11,7 +11,12 @@ namespace Umbraco.Core.Composing private readonly List _paths = new List(); private readonly Dictionary _files = new Dictionary(); - public void AddFolder(DirectoryInfo pathInfo) => _paths.Add(pathInfo); + public RuntimeHashPaths AddFolder(DirectoryInfo pathInfo) + { + _paths.Add(pathInfo); + return this; + } + public void AddFile(FileInfo fileInfo, bool scanFileContent = false) => _files.Add(fileInfo, scanFileContent); public IEnumerable GetFolders() => _paths; diff --git a/src/Umbraco.Tests.Integration/RuntimeTests.cs b/src/Umbraco.Tests.Integration/RuntimeTests.cs index c30adc7e72..274e3d6ad9 100644 --- a/src/Umbraco.Tests.Integration/RuntimeTests.cs +++ b/src/Umbraco.Tests.Integration/RuntimeTests.cs @@ -64,7 +64,7 @@ namespace Umbraco.Tests.Integration var builder = new UmbracoBuilder(services, hostContext.Configuration, testHelper.ConsoleLoggerFactory); builder.AddConfiguration(); - builder.AddUmbracoCore(webHostEnvironment, GetType().Assembly, AppCaches.NoCache, testHelper.GetLoggingConfiguration(), hostContext.Configuration, UmbracoCoreServiceCollectionExtensions.ConfigureSomeMorebits); + builder.AddUmbracoCore(webHostEnvironment, GetType().Assembly, AppCaches.NoCache, testHelper.GetLoggingConfiguration(), hostContext.Configuration); }); var host = await hostBuilder.StartAsync(); @@ -104,7 +104,7 @@ namespace Umbraco.Tests.Integration var builder = new UmbracoBuilder(services, hostContext.Configuration, testHelper.ConsoleLoggerFactory); builder.AddConfiguration() - .AddUmbracoCore(webHostEnvironment, GetType().Assembly, AppCaches.NoCache, testHelper.GetLoggingConfiguration(), hostContext.Configuration, UmbracoCoreServiceCollectionExtensions.ConfigureSomeMorebits) + .AddUmbracoCore(webHostEnvironment, GetType().Assembly, AppCaches.NoCache, testHelper.GetLoggingConfiguration(), hostContext.Configuration) .Build(); services.AddRouting(); // LinkGenerator diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs index c797d5f37b..3595db8541 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs @@ -1,11 +1,10 @@ -using System; +using Moq; +using Umbraco.Core; using Umbraco.Core.Builder; using Umbraco.Core.Cache; using Umbraco.Core.Runtime; using Umbraco.Extensions; using Umbraco.Tests.Integration.Implementations; -using Umbraco.Tests.Integration.Testing; -using Umbraco.Web.Common.Builder; namespace Umbraco.Tests.Integration.TestServerTest { @@ -18,30 +17,17 @@ namespace Umbraco.Tests.Integration.TestServerTest /// public static IUmbracoBuilder AddTestCore(this IUmbracoBuilder builder, TestHelper testHelper) { - - return builder.AddUmbracoCore( + builder.AddUmbracoCore( testHelper.GetWebHostEnvironment(), typeof(UmbracoBuilderExtensions).Assembly, AppCaches.NoCache, // Disable caches in integration tests testHelper.GetLoggingConfiguration(), - builder.Config, - // TODO: Yep that's extremely ugly - (lambdaBuilder, globalSettings, connectionStrings, umbVersion, ioHelper, profiler, hostingEnv, typeFinder, appCaches, dbProviderFactoryCreator) => - { - UmbracoIntegrationTest.ConfigureSomeMorebitsForTests( - lambdaBuilder, - globalSettings, - connectionStrings, - umbVersion, - ioHelper, - profiler, - hostingEnv, - typeFinder, - appCaches, - dbProviderFactoryCreator, - testHelper.MainDom); // SimpleMainDom - - }); + builder.Config); + + builder.Services.AddUnique(Mock.Of()); + builder.Services.AddUnique(testHelper.MainDom); + + return builder; } } } diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index 07217caccb..0c45fa4841 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -162,111 +162,7 @@ namespace Umbraco.Tests.Integration.Testing }); return hostBuilder; } - - /// - /// Creates a instance for testing and registers an event handler for database install - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public void ConfigureSomeMorebitsForTests( - IUmbracoBuilder builder, - GlobalSettings globalSettings, - ConnectionStrings connectionStrings, - IUmbracoVersion umbracoVersion, - IIOHelper ioHelper, - IProfiler profiler, - Core.Hosting.IHostingEnvironment hostingEnvironment, - ITypeFinder typeFinder, - AppCaches appCaches, - IDbProviderFactoryCreator dbProviderFactoryCreator) - { - ConfigureSomeMorebitsForTests( - builder, - globalSettings, - connectionStrings, - umbracoVersion, - ioHelper, - profiler, - hostingEnvironment, - typeFinder, - appCaches, - dbProviderFactoryCreator, - TestHelper.MainDom // SimpleMainDom - ); - } - - /// - /// Creates a instance for testing and registers an event handler for database install - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// The event handler used for DB installation - /// - /// - public static void ConfigureSomeMorebitsForTests( - IUmbracoBuilder builder, - GlobalSettings globalSettings, - ConnectionStrings connectionStrings, - IUmbracoVersion umbracoVersion, - IIOHelper ioHelper, - IProfiler profiler, - Core.Hosting.IHostingEnvironment hostingEnvironment, - ITypeFinder typeFinder, - AppCaches appCaches, - IDbProviderFactoryCreator dbProviderFactoryCreator, - IMainDom mainDom) - { - // TODO: Don't do this, UmbracoBuilder ctor should handle it... - builder.TypeLoader = new TypeLoader(typeFinder, appCaches.RuntimeCache, - new DirectoryInfo(hostingEnvironment.LocalTempPath), - builder.BuilderLoggerFactory.CreateLogger(), - new ProfilingLogger(builder.BuilderLoggerFactory.CreateLogger(),profiler) ); - - var logger = builder.BuilderLoggerFactory.CreateLogger(); - builder.Services.AddUnique(Mock.Of()); - builder.Services.AddUnique(profiler); - builder.Services.AddUnique(new ProfilingLogger(logger, profiler)); - builder.Services.AddUnique(mainDom); - builder.Services.AddUnique(appCaches); - builder.Services.AddUnique(appCaches.RequestCache); - builder.Services.AddUnique(builder.TypeLoader); - builder.Services.AddUnique(typeFinder); - builder.Services.AddUnique(ioHelper); - builder.Services.AddUnique(umbracoVersion); - builder.Services.AddUnique(dbProviderFactoryCreator); - builder.Services.AddUnique(hostingEnvironment); - builder.Services.AddUnique(); - - // after bootstrapping we let the container wire up for us. - builder.Services.AddUnique(); - builder.Services.AddUnique(factory => factory.GetRequiredService().SqlContext); - builder.Services.AddUnique(factory => factory.GetRequiredService().BulkSqlInsertProvider); - - // re-create the state object with the essential services - builder.Services.AddUnique(); - } - + #endregion #region IStartup @@ -286,10 +182,12 @@ namespace Umbraco.Tests.Integration.Testing GetType().Assembly, GetAppCaches(), TestHelper.GetLoggingConfiguration(), - Configuration, - ConfigureSomeMorebitsForTests + Configuration ); + builder.Services.AddUnique(Mock.Of()); + builder.Services.AddUnique(TestHelper.MainDom); + services.AddSignalR(); builder.AddWebComponents(); diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironmentWithoutOptionsMonitor.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironmentWithoutOptionsMonitor.cs new file mode 100644 index 0000000000..a2b441c29d --- /dev/null +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironmentWithoutOptionsMonitor.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Options; +using Umbraco.Core; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; + +namespace Umbraco.Web.Common.AspNetCore +{ + public class AspNetCoreHostingEnvironmentWithoutOptionsMonitor : Core.Hosting.IHostingEnvironment + { + + private HostingSettings _hostingSettings; + private readonly IWebHostEnvironment _webHostEnvironment; + + private string _localTempPath; + + public AspNetCoreHostingEnvironmentWithoutOptionsMonitor(HostingSettings hostingSettings, IWebHostEnvironment webHostEnvironment) + { + _hostingSettings = hostingSettings ?? throw new ArgumentNullException(nameof(hostingSettings)); + _webHostEnvironment = webHostEnvironment ?? throw new ArgumentNullException(nameof(webHostEnvironment)); + + SiteName = webHostEnvironment.ApplicationName; + ApplicationId = AppDomain.CurrentDomain.Id.ToString(); + ApplicationPhysicalPath = webHostEnvironment.ContentRootPath; + + IISVersion = new Version(0, 0); // TODO not necessary IIS + } + + + public bool IsHosted { get; } = true; + public string SiteName { get; } + public string ApplicationId { get; } + public string ApplicationPhysicalPath { get; } + public string ApplicationServerAddress { get; } + + //TODO how to find this, This is a server thing, not application thing. + public string ApplicationVirtualPath => _hostingSettings.ApplicationVirtualPath?.EnsureStartsWith('/') ?? "/"; + public bool IsDebugMode => _hostingSettings.Debug; + + 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 = MapPathContentRoot("~/App_Data/TEMP"); + } + } + } + + public string MapPathWebRoot(string path) + { + var newPath = path.TrimStart('~', '/').Replace('/', Path.DirectorySeparatorChar); + return Path.Combine(_webHostEnvironment.WebRootPath, newPath); + } + + public string MapPathContentRoot(string path) + { + var newPath = path.TrimStart('~', '/').Replace('/', Path.DirectorySeparatorChar); + return Path.Combine(_webHostEnvironment.ContentRootPath, newPath); + } + + public string ToAbsolute(string virtualPath) + { + if (!virtualPath.StartsWith("~/") && !virtualPath.StartsWith("/")) + throw new InvalidOperationException($"The value {virtualPath} for parameter {nameof(virtualPath)} must start with ~/ or /"); + + // will occur if it starts with "/" + if (Uri.IsWellFormedUriString(virtualPath, UriKind.Absolute)) + return virtualPath; + + var fullPath = ApplicationVirtualPath.EnsureEndsWith('/') + virtualPath.TrimStart("~/").TrimStart("/"); + + return fullPath; + } + } +} diff --git a/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs index 2c769837dc..1aab7695a2 100644 --- a/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs @@ -18,6 +18,7 @@ using Smidge.Nuglify; using Umbraco.Core; using Umbraco.Core.Builder; using Umbraco.Core.Cache; +using Umbraco.Core.Composing; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.Models.Validation; using Umbraco.Core.Logging; @@ -47,6 +48,8 @@ namespace Umbraco.Web.Common.Builder services.AddLogger(loggingConfig, config); loggerFactory ??= LoggerFactory.Create(cfg => cfg.AddSerilog(Log.Logger, false)); + + return new UmbracoBuilder(services, config, loggerFactory); } @@ -103,8 +106,7 @@ namespace Umbraco.Web.Common.Builder Assembly.GetEntryAssembly(), appCaches, loggingConfig, - builder.Config, - UmbracoCoreServiceCollectionExtensions.ConfigureSomeMorebits); + builder.Config); return builder; } diff --git a/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs b/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs index 36d4ddbd42..596c42e3b3 100644 --- a/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs @@ -42,6 +42,9 @@ namespace Umbraco.Extensions if (!app.UmbracoCanBoot()) return app; + var hostingEnvironment = app.ApplicationServices.GetRequiredService(); + AppDomain.CurrentDomain.SetData("DataDirectory", hostingEnvironment?.MapPathContentRoot(Core.Constants.SystemDirectories.Data)); + var runtime = app.ApplicationServices.GetRequiredService(); // Register a listener for application shutdown in order to terminate the runtime diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs index 66bcdaa6fb..c2a570e082 100644 --- a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Data.Common; using System.Data.SqlClient; +using System.Drawing; using System.IO; using System.Reflection; using System.Runtime.InteropServices; @@ -9,6 +10,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Serilog; @@ -46,18 +48,14 @@ namespace Umbraco.Extensions /// /// /// - /// Weird hack for tests, won't exist much longer /// - /// Shouldn't exist public static IUmbracoBuilder AddUmbracoCore( this IUmbracoBuilder builder, IWebHostEnvironment webHostEnvironment, Assembly entryAssembly, AppCaches appCaches, ILoggingConfiguration loggingConfiguration, - IConfiguration configuration, - //TODO: Yep that's extremely ugly - Action configureSomeMoreBits) + IConfiguration configuration) { if (builder is null) throw new ArgumentNullException(nameof(builder)); if (entryAssembly is null) throw new ArgumentNullException(nameof(entryAssembly)); @@ -88,39 +86,71 @@ namespace Umbraco.Extensions builder.Services.AddSingleton(dbProviderFactoryCreator); - // TODO: We should not be doing this at all. - var serviceProvider = builder.Services.BuildServiceProvider(); + builder.Services.AddUnique(); + builder.Services.AddLogger(loggingConfiguration, configuration); // TODO: remove this line + var loggerFactory = builder.BuilderLoggerFactory; - // Switching to IOptions vs IOptionsMonitor was rejected previously as it prevents setting IsDebug true without a restart - var hostingSettings = serviceProvider.GetService>(); // <--- We are now building ServiceProvider just for this line - var hostingEnvironment = new AspNetCoreHostingEnvironment(hostingSettings, webHostEnvironment); - var ioHelper = new IOHelper(hostingEnvironment); - var profiler = GetWebProfiler(hostingEnvironment); + var profiler = GetWebProfiler(configuration); + builder.Services.AddUnique(profiler); + + var profilingLogger = new ProfilingLogger(builder.BuilderLoggerFactory.CreateLogger(), profiler); + builder.Services.AddUnique(profilingLogger); + + var typeFinder = CreateTypeFinder(loggerFactory, webHostEnvironment, entryAssembly, builder.Config); + builder.Services.AddUnique(typeFinder); + + var typeLoader = CreateTypeLoader(typeFinder, webHostEnvironment, loggerFactory, profilingLogger, appCaches.RuntimeCache, configuration); + builder.TypeLoader = typeLoader; + builder.Services.AddUnique(typeLoader); builder.Services.AddUnique(); - builder.Services.AddLogger(loggingConfiguration, configuration); - var loggerFactory = builder.BuilderLoggerFactory; + // after bootstrapping we let the container wire up for us. + builder.Services.AddUnique(); + builder.Services.AddUnique(factory => factory.GetRequiredService().SqlContext); + builder.Services.AddUnique(factory => factory.GetRequiredService().BulkSqlInsertProvider); - var typeFinderSettings = builder.Config.GetSection(Core.Constants.Configuration.ConfigTypeFinder).Get() ?? new TypeFinderSettings(); - var typeFinder = CreateTypeFinder(loggerFactory, profiler, webHostEnvironment, entryAssembly, Options.Create(typeFinderSettings)); - var globalSettings = builder.Config.GetSection(Core.Constants.Configuration.ConfigGlobal).Get() ?? new GlobalSettings(); - var connectionStrings = builder.Config.GetSection("ConnectionStrings").Get(opt => opt.BindNonPublicProperties = true) ?? new ConnectionStrings(); + builder.Services.AddUnique(appCaches); + builder.Services.AddUnique(appCaches.RequestCache); + builder.Services.AddUnique(); - configureSomeMoreBits( - builder, - globalSettings, - connectionStrings, - new UmbracoVersion(), - ioHelper, - profiler, - hostingEnvironment, - typeFinder, - appCaches, - dbProviderFactoryCreator); + builder.Services.AddUnique(dbProviderFactoryCreator); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + builder.Services.AddUnique(factory => + { + var globalSettings = factory.GetRequiredService>().Value; + var connectionStrings = factory.GetRequiredService>().Value; + var hostingEnvironment = factory.GetRequiredService(); + + var dbCreator = factory.GetRequiredService() + ; var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + + return globalSettings.MainDomLock.Equals("SqlMainDomLock") || isWindows == false + ? (IMainDomLock)new SqlMainDomLock(builder.BuilderLoggerFactory.CreateLogger(), builder.BuilderLoggerFactory, globalSettings, connectionStrings, dbCreator, hostingEnvironment) + : new MainDomSemaphoreLock(builder.BuilderLoggerFactory.CreateLogger(), hostingEnvironment); + }); + + builder.Services.AddUnique(); + + builder.Services.AddUnique(new AspNetCoreBootPermissionsChecker()); builder.AddComposers(); + var exceptionLogger = builder.BuilderLoggerFactory.CreateLogger(); + AppDomain.CurrentDomain.UnhandledException += (_, args) => + { + var exception = (Exception)args.ExceptionObject; + var isTerminating = args.IsTerminating; // always true? + + var msg = "Unhandled exception in AppDomain"; + if (isTerminating) msg += " (terminating)"; + msg += "."; + exceptionLogger.LogError(exception, msg); + }; + return builder; } @@ -238,82 +268,6 @@ namespace Umbraco.Extensions return services; } - private static ITypeFinder CreateTypeFinder(ILoggerFactory loggerFactory, IProfiler profiler, IWebHostEnvironment webHostEnvironment, Assembly entryAssembly, IOptions typeFinderSettings) - { - var runtimeHashPaths = new RuntimeHashPaths(); - runtimeHashPaths.AddFolder(new DirectoryInfo(Path.Combine(webHostEnvironment.ContentRootPath, "bin"))); - var runtimeHash = new RuntimeHash(new ProfilingLogger(loggerFactory.CreateLogger("RuntimeHash"), profiler), runtimeHashPaths); - return new TypeFinder(loggerFactory.CreateLogger(), new DefaultUmbracoAssemblyProvider(entryAssembly), runtimeHash, new TypeFinderConfig(typeFinderSettings)); - } - - internal static void ConfigureSomeMorebits( - IUmbracoBuilder builder, - GlobalSettings globalSettings, - ConnectionStrings connectionStrings, - IUmbracoVersion umbracoVersion, - IIOHelper ioHelper, - IProfiler profiler, - IHostingEnvironment hostingEnvironment, - ITypeFinder typeFinder, - AppCaches appCaches, - IDbProviderFactoryCreator dbProviderFactoryCreator) - { - // Determine if we should use the sql main dom or the default - var appSettingMainDomLock = globalSettings.MainDomLock; - - var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - var mainDomLock = appSettingMainDomLock == "SqlMainDomLock" || isWindows == false - ? (IMainDomLock)new SqlMainDomLock(builder.BuilderLoggerFactory.CreateLogger(), builder.BuilderLoggerFactory, globalSettings, connectionStrings, dbProviderFactoryCreator, hostingEnvironment) - : new MainDomSemaphoreLock(builder.BuilderLoggerFactory.CreateLogger(), hostingEnvironment); - - var mainDom = new MainDom(builder.BuilderLoggerFactory.CreateLogger(), mainDomLock); - - - var logger = builder.BuilderLoggerFactory.CreateLogger(); - var profilingLogger = new ProfilingLogger(logger, profiler); - - AppDomain.CurrentDomain.SetData("DataDirectory", hostingEnvironment?.MapPathContentRoot(Constants.SystemDirectories.Data)); - - // application environment - AppDomain.CurrentDomain.UnhandledException += (_, args) => - { - var exception = (Exception)args.ExceptionObject; - var isTerminating = args.IsTerminating; // always true? - - var msg = "Unhandled exception in AppDomain"; - if (isTerminating) msg += " (terminating)"; - msg += "."; - logger.LogError(exception, msg); - }; - - // TODO: Don't do this, UmbracoBuilder ctor should handle it... - builder.TypeLoader = new TypeLoader(typeFinder, appCaches.RuntimeCache, - new DirectoryInfo(hostingEnvironment.LocalTempPath), - builder.BuilderLoggerFactory.CreateLogger(), profilingLogger); - - builder.Services.AddUnique(new AspNetCoreBootPermissionsChecker()); - builder.Services.AddUnique(profiler); - builder.Services.AddUnique(profilingLogger); - builder.Services.AddUnique(mainDom); - builder.Services.AddUnique(appCaches); - builder.Services.AddUnique(appCaches.RequestCache); - builder.Services.AddUnique(builder.TypeLoader); - builder.Services.AddUnique(typeFinder); - builder.Services.AddUnique(ioHelper); - builder.Services.AddUnique(umbracoVersion); - builder.Services.AddUnique(dbProviderFactoryCreator); - builder.Services.AddUnique(hostingEnvironment); - builder.Services.AddUnique(); - - // after bootstrapping we let the container wire up for us. - builder.Services.AddUnique(); - builder.Services.AddUnique(factory => factory.GetRequiredService().SqlContext); - builder.Services.AddUnique(factory => factory.GetRequiredService().BulkSqlInsertProvider); - - // re-create the state object with the essential services - builder.Services.AddUnique(); - } - /// /// Create and configure the logger @@ -357,10 +311,11 @@ namespace Umbraco.Extensions return services; } - private static IProfiler GetWebProfiler(Umbraco.Core.Hosting.IHostingEnvironment hostingEnvironment) + private static IProfiler GetWebProfiler(IConfiguration config) { + var isDebug = config.GetValue($"{Constants.Configuration.ConfigHosting}:Debug"); // create and start asap to profile boot - if (!hostingEnvironment.IsDebugMode) + if (!isDebug) { // 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 @@ -373,6 +328,43 @@ namespace Umbraco.Extensions return webProfiler; } + private static ITypeFinder CreateTypeFinder(ILoggerFactory loggerFactory, IWebHostEnvironment webHostEnvironment, Assembly entryAssembly, IConfiguration config) + { + var profiler = GetWebProfiler(config); + + var typeFinderSettings = config.GetSection(Core.Constants.Configuration.ConfigTypeFinder).Get() ?? new TypeFinderSettings(); + + var runtimeHashPaths = new RuntimeHashPaths().AddFolder(new DirectoryInfo(Path.Combine(webHostEnvironment.ContentRootPath, "bin"))); + var runtimeHash = new RuntimeHash(new ProfilingLogger(loggerFactory.CreateLogger("RuntimeHash"), profiler), runtimeHashPaths); + + return new TypeFinder( + loggerFactory.CreateLogger(), + new DefaultUmbracoAssemblyProvider(entryAssembly), + runtimeHash, + new TypeFinderConfig(Options.Create(typeFinderSettings)) + ); + } + + private static TypeLoader CreateTypeLoader( + ITypeFinder typeFinder, + IWebHostEnvironment webHostEnvironment, + ILoggerFactory loggerFactory, + IProfilingLogger profilingLogger, + IAppPolicyCache runtimeCache, + IConfiguration configuration) + { + var hostingSettings = configuration.GetSection(Core.Constants.Configuration.ConfigHosting).Get() ?? new HostingSettings(); + var hostingEnvironment = new AspNetCoreHostingEnvironmentWithoutOptionsMonitor(hostingSettings, webHostEnvironment); + + return new TypeLoader( + typeFinder, + runtimeCache, + new DirectoryInfo(hostingEnvironment.LocalTempPath), + loggerFactory.CreateLogger(), + profilingLogger + ); + } + private class AspNetCoreBootPermissionsChecker : IUmbracoBootPermissionChecker { public void ThrowIfNotPermissions()