From 0241649f7ff2d43d04bc607d422c4eb811cbcbc2 Mon Sep 17 00:00:00 2001 From: Paul Johnson Date: Fri, 20 Nov 2020 12:24:16 +0000 Subject: [PATCH] Cleanup AddUmbraco & AddUmbracoCore --- src/Umbraco.Core/Cache/AppCaches.cs | 8 + src/Umbraco.Tests.Integration/RuntimeTests.cs | 8 +- .../UmbracoBuilderExtensions.cs | 7 +- .../UmbracoTestServerTestBase.cs | 7 +- .../Testing/UmbracoIntegrationTest.cs | 13 +- .../Extensions/UmbracoBuilderExtensions.cs | 5 +- .../Builder/UmbracoBuilderExtensions.cs | 232 ++++++++++++--- .../UmbracoCoreServiceCollectionExtensions.cs | 270 ++---------------- src/Umbraco.Web.UI.NetCore/Startup.cs | 6 +- 9 files changed, 245 insertions(+), 311 deletions(-) diff --git a/src/Umbraco.Core/Cache/AppCaches.cs b/src/Umbraco.Core/Cache/AppCaches.cs index 8930320447..2d482756c1 100644 --- a/src/Umbraco.Core/Cache/AppCaches.cs +++ b/src/Umbraco.Core/Cache/AppCaches.cs @@ -64,5 +64,13 @@ namespace Umbraco.Core.Cache /// search through all keys on a global scale. /// public IsolatedCaches IsolatedCaches { get; } + + public static AppCaches Create(IRequestCache requestCache) + { + return new AppCaches( + new DeepCloneAppCache(new ObjectCacheAppCache()), + requestCache, + new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache()))); + } } } diff --git a/src/Umbraco.Tests.Integration/RuntimeTests.cs b/src/Umbraco.Tests.Integration/RuntimeTests.cs index 8b924715e5..31c6e3155d 100644 --- a/src/Umbraco.Tests.Integration/RuntimeTests.cs +++ b/src/Umbraco.Tests.Integration/RuntimeTests.cs @@ -61,13 +61,13 @@ namespace Umbraco.Tests.Integration services.AddRequiredNetCoreServices(testHelper, webHostEnvironment); // Add it! - var typeLoader = UmbracoCoreServiceCollectionExtensions.CreateTypeLoader(GetType().Assembly, webHostEnvironment, + var typeLoader = services.AddTypeLoader(GetType().Assembly, webHostEnvironment, testHelper.ConsoleLoggerFactory, AppCaches.NoCache, hostContext.Configuration); var builder = new UmbracoBuilder(services, hostContext.Configuration, typeLoader, testHelper.ConsoleLoggerFactory); builder.Services.AddUnique(AppCaches.NoCache); builder.AddConfiguration(); - builder.AddUmbracoCore(webHostEnvironment, GetType().Assembly, testHelper.GetLoggingConfiguration(), hostContext.Configuration); + builder.AddUmbracoCore(); }); var host = await hostBuilder.StartAsync(); @@ -105,14 +105,14 @@ namespace Umbraco.Tests.Integration // Add it! - var typeLoader = UmbracoCoreServiceCollectionExtensions.CreateTypeLoader(GetType().Assembly, + var typeLoader = services.AddTypeLoader(GetType().Assembly, webHostEnvironment, testHelper.ConsoleLoggerFactory, AppCaches.NoCache, hostContext.Configuration); var builder = new UmbracoBuilder(services, hostContext.Configuration, typeLoader, testHelper.ConsoleLoggerFactory); builder.Services.AddUnique(AppCaches.NoCache); builder.AddConfiguration() - .AddUmbracoCore(webHostEnvironment, GetType().Assembly, testHelper.GetLoggingConfiguration(), hostContext.Configuration) + .AddUmbracoCore() .Build(); services.AddRouting(); // LinkGenerator diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs index 806e5ffa1d..07637169e2 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs @@ -5,6 +5,7 @@ using Umbraco.Core.Cache; using Umbraco.Core.Runtime; using Umbraco.Extensions; using Umbraco.Tests.Integration.Implementations; +using Umbraco.Web.Common.Builder; namespace Umbraco.Tests.Integration.TestServerTest { @@ -17,11 +18,7 @@ namespace Umbraco.Tests.Integration.TestServerTest /// public static IUmbracoBuilder AddTestCore(this IUmbracoBuilder builder, TestHelper testHelper) { - builder.AddUmbracoCore( - testHelper.GetWebHostEnvironment(), - typeof(UmbracoBuilderExtensions).Assembly, - testHelper.GetLoggingConfiguration(), - builder.Config); + builder.AddUmbracoCore(); builder.Services.AddUnique(AppCaches.NoCache); diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs index 76424a253d..5d43d7c8d1 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs @@ -130,9 +130,12 @@ namespace Umbraco.Tests.Integration.TestServerTest public override void ConfigureServices(IServiceCollection services) { - var umbracoBuilder = services.AddUmbraco(TestHelper.GetWebHostEnvironment(), Configuration, assembly: GetType().Assembly); + var typeLoader = services.AddTypeLoader(GetType().Assembly, TestHelper.GetWebHostEnvironment(), + TestHelper.ConsoleLoggerFactory, AppCaches.NoCache, Configuration); + + var builder = new UmbracoBuilder(services, Configuration, typeLoader); - umbracoBuilder + builder .AddConfiguration() .AddTestCore(TestHelper) // This is the important one! .AddWebComponents() diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index 862371c10c..7d3f8886f7 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -174,17 +174,14 @@ namespace Umbraco.Tests.Integration.Testing // Add it! - var typeLoader = UmbracoCoreServiceCollectionExtensions.CreateTypeLoader(GetType().Assembly, webHostEnvironment, TestHelper.ConsoleLoggerFactory, AppCaches.NoCache, Configuration); + var typeLoader = services.AddTypeLoader(GetType().Assembly, webHostEnvironment, TestHelper.ConsoleLoggerFactory, AppCaches.NoCache, Configuration); var builder = new UmbracoBuilder(services, Configuration, typeLoader, TestHelper.ConsoleLoggerFactory); - + + builder.Services.AddLogger(TestHelper.GetLoggingConfiguration(), Configuration); + builder.AddConfiguration() - .AddUmbracoCore( - webHostEnvironment, - GetType().Assembly, - TestHelper.GetLoggingConfiguration(), - Configuration - ); + .AddUmbracoCore(); builder.Services.AddUnique(GetAppCaches()); diff --git a/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs index b88cf010e3..dbbb14dc96 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs @@ -1,5 +1,4 @@ using System; -using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.DependencyInjection; using Umbraco.Core.Builder; @@ -11,11 +10,11 @@ namespace Umbraco.Extensions { public static class UmbracoBuilderExtensions { - public static IUmbracoBuilder AddAllBackOfficeComponents(this IUmbracoBuilder builder, IWebHostEnvironment webHostEnvironment) + public static IUmbracoBuilder AddAllBackOfficeComponents(this IUmbracoBuilder builder) { return builder .AddConfiguration() - .AddCore(webHostEnvironment) + .AddUmbracoCore() .AddWebComponents() .AddRuntimeMinifier() .AddBackOffice() diff --git a/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs index 973c617511..408baf0b4f 100644 --- a/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs @@ -5,8 +5,12 @@ using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Data.SqlClient; using System.IO; using System.Reflection; +using System.Runtime.InteropServices; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -19,13 +23,22 @@ using Umbraco.Core; using Umbraco.Core.Builder; using Umbraco.Core.Cache; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.Models.Validation; +using Umbraco.Core.IO; using Umbraco.Core.Logging; +using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.SqlSyntax; +using Umbraco.Core.Runtime; using Umbraco.Extensions; +using Umbraco.Infrastructure.HostedServices; +using Umbraco.Infrastructure.HostedServices.ServerRegistration; using Umbraco.Web.Common.ApplicationModels; +using Umbraco.Web.Common.AspNetCore; using Umbraco.Web.Common.Filters; using Umbraco.Web.Common.ModelBinders; +using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; namespace Umbraco.Web.Common.Builder { @@ -35,37 +48,129 @@ namespace Umbraco.Web.Common.Builder public static IUmbracoBuilder AddUmbraco( this IServiceCollection services, IWebHostEnvironment webHostEnvironment, - IConfiguration config, - ILoggingConfiguration loggingConfig = null, - ILoggerFactory loggerFactory = null, - Assembly assembly = null) + IConfiguration config) { if (services is null) throw new ArgumentNullException(nameof(services)); if (config is null) throw new ArgumentNullException(nameof(config)); - services.AddLazySupport(); - - loggingConfig ??= new LoggingConfiguration(Path.Combine(webHostEnvironment.ContentRootPath, "umbraco", "logs")); + var loggingConfig = new LoggingConfiguration(Path.Combine(webHostEnvironment.ContentRootPath, "umbraco", "logs")); + services.AddSingleton(loggingConfig); services.AddLogger(loggingConfig, config); - loggerFactory ??= LoggerFactory.Create(cfg => cfg.AddSerilog(Log.Logger, false)); - assembly ??= Assembly.GetEntryAssembly(); IHttpContextAccessor httpContextAccessor = new HttpContextAccessor(); - services.AddSingleton(httpContextAccessor); + services.AddSingleton(httpContextAccessor); var requestCache = new GenericDictionaryRequestAppCache(() => httpContextAccessor.HttpContext?.Items); - var appCaches = new AppCaches( - new DeepCloneAppCache(new ObjectCacheAppCache()), - requestCache, - new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache()))); - + var appCaches = AppCaches.Create(requestCache); services.AddUnique(appCaches); - var typeLoader = UmbracoCoreServiceCollectionExtensions.CreateTypeLoader(assembly, webHostEnvironment, loggerFactory, appCaches, config); + var loggerFactory = LoggerFactory.Create(cfg => cfg.AddSerilog(Log.Logger, false)); + var typeLoader = services.AddTypeLoader(Assembly.GetEntryAssembly(), webHostEnvironment, loggerFactory, appCaches, config); return new UmbracoBuilder(services, config, typeLoader, loggerFactory); } + /// Composes Composers + public static IUmbracoBuilder AddUmbracoCore(this IUmbracoBuilder builder) + { + if (builder is null) throw new ArgumentNullException(nameof(builder)); + + builder.Services.AddLazySupport(); + + // Add service session + // This can be overwritten by the user by adding their own call to AddSession + // since the last call of AddSession take precedence + builder.Services.AddSession(options => + { + options.Cookie.Name = "UMB_SESSION"; + options.Cookie.HttpOnly = true; + }); + + var syntaxProviders = new List(); + var insertProviders = new List(); + var databaseCreators = new List(); + + // Add supported databases + builder.Services.AddUmbracoSqlCeSupport(syntaxProviders, insertProviders, databaseCreators); + builder.Services.AddUmbracoSqlServerSupport(syntaxProviders, insertProviders, databaseCreators); + + builder.Services.AddUnique(factory => factory.GetRequiredService().RuntimeCache); + builder.Services.AddUnique(factory => factory.GetRequiredService().RequestCache); + + var dbProviderFactoryCreator = new DbProviderFactoryCreator( + DbProviderFactories.GetFactory, + syntaxProviders, + insertProviders, + databaseCreators); + + builder.Services.AddSingleton(dbProviderFactoryCreator); + + builder.Services.AddUnique(); + + var profiler = UmbracoCoreServiceCollectionExtensions.GetWebProfiler(builder.Config); + builder.Services.AddUnique(profiler); + + builder.Services.AddUnique(); + builder.Services.AddUnique(builder.TypeLoader); + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + builder.Services.AddUnique(factory => factory.GetRequiredService().SqlContext); + builder.Services.AddUnique(factory => factory.GetRequiredService().BulkSqlInsertProvider); + + builder.Services.AddUnique(); + + 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 UmbracoCoreServiceCollectionExtensions.AspNetCoreBootPermissionsChecker()); + + builder.AddComposers(); + + var exceptionLogger = builder.BuilderLoggerFactory.CreateLogger(); + + // This probably shouldn't live here. + 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; + } + + public static IUmbracoBuilder AddComposers(this IUmbracoBuilder builder) + { + var composerTypes = builder.TypeLoader.GetTypes(); + var enableDisable = builder.TypeLoader.GetAssemblyAttributes(typeof(EnableComposerAttribute), typeof(DisableComposerAttribute)); + new Composers(builder, composerTypes, enableDisable, builder.BuilderLoggerFactory.CreateLogger()).Compose(); + + return builder; + } + public static IUmbracoBuilder AddConfiguration(this IUmbracoBuilder builder) { // Register configuration validators. @@ -101,30 +206,22 @@ namespace Umbraco.Web.Common.Builder return builder; } - public static IUmbracoBuilder AddCore(this IUmbracoBuilder builder, IWebHostEnvironment webHostEnvironment) - { - var loggingConfig = new LoggingConfiguration(Path.Combine(webHostEnvironment.ContentRootPath, "umbraco", "logs")); - - - builder.Services.AddSingleton(loggingConfig); - - builder.AddUmbracoCore(webHostEnvironment, - Assembly.GetEntryAssembly(), - loggingConfig, - builder.Config); - - return builder; - } public static IUmbracoBuilder AddHostedServices(this IUmbracoBuilder builder) { - builder.Services.AddUmbracoHostedServices(); + builder.Services.AddHostedService(); + builder.Services.AddHostedService(); + builder.Services.AddHostedService(); + builder.Services.AddHostedService(); + builder.Services.AddHostedService(); + builder.Services.AddHostedService(); + builder.Services.AddHostedService(); return builder; } public static IUmbracoBuilder AddHttpClients(this IUmbracoBuilder builder) { - builder.Services.AddUmbracoHttpClients(); + builder.Services.AddHttpClient(); return builder; } @@ -189,5 +286,76 @@ namespace Umbraco.Web.Common.Builder return builder; } + + /// + /// Adds SqlCe support for Umbraco + /// + private static void AddUmbracoSqlCeSupport( + this IServiceCollection services, + ICollection syntaxProviders, + ICollection insertProviders, + ICollection databaseCreators) + { + try + { + var binFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + if (binFolder != null) + { + var dllPath = Path.Combine(binFolder, "Umbraco.Persistance.SqlCe.dll"); + var umbSqlCeAssembly = Assembly.LoadFrom(dllPath); + + var sqlCeSyntaxProviderType = umbSqlCeAssembly.GetType("Umbraco.Persistance.SqlCe.SqlCeSyntaxProvider"); + var sqlCeBulkSqlInsertProviderType = umbSqlCeAssembly.GetType("Umbraco.Persistance.SqlCe.SqlCeBulkSqlInsertProvider"); + var sqlCeEmbeddedDatabaseCreatorType = umbSqlCeAssembly.GetType("Umbraco.Persistance.SqlCe.SqlCeEmbeddedDatabaseCreator"); + + if (!(sqlCeSyntaxProviderType is null || sqlCeBulkSqlInsertProviderType is null || sqlCeEmbeddedDatabaseCreatorType is null)) + { + services.AddSingleton(typeof(ISqlSyntaxProvider), sqlCeSyntaxProviderType); + services.AddSingleton(typeof(IBulkSqlInsertProvider), sqlCeBulkSqlInsertProviderType); + services.AddSingleton(typeof(IEmbeddedDatabaseCreator), sqlCeEmbeddedDatabaseCreatorType); + + syntaxProviders.Add((ISqlSyntaxProvider)Activator.CreateInstance(sqlCeSyntaxProviderType)); + insertProviders.Add((IBulkSqlInsertProvider)Activator.CreateInstance(sqlCeBulkSqlInsertProviderType)); + databaseCreators.Add((IEmbeddedDatabaseCreator)Activator.CreateInstance(sqlCeEmbeddedDatabaseCreatorType)); + } + + var sqlCeAssembly = Assembly.LoadFrom(Path.Combine(binFolder, "System.Data.SqlServerCe.dll")); + + var sqlCe = sqlCeAssembly.GetType("System.Data.SqlServerCe.SqlCeProviderFactory"); + if (!(sqlCe is null)) + { + DbProviderFactories.RegisterFactory(Core.Constants.DbProviderNames.SqlCe, sqlCe); + } + } + } + catch + { + // Ignore if SqlCE is not available + } + } + + /// + /// Adds Sql Server support for Umbraco + /// + private static void AddUmbracoSqlServerSupport( + this IServiceCollection services, + ICollection syntaxProviders, + ICollection insertProviders, + ICollection databaseCreators) + { + DbProviderFactories.RegisterFactory(Core.Constants.DbProviderNames.SqlServer, SqlClientFactory.Instance); + + var syntaxProvider = new SqlServerSyntaxProvider(); + var insertProvider = new SqlServerBulkSqlInsertProvider(); + var databaseCreator = new NoopEmbeddedDatabaseCreator(); + + services.AddSingleton(syntaxProvider); + services.AddSingleton(insertProvider); + services.AddSingleton(databaseCreator); + + syntaxProviders.Add(syntaxProvider); + insertProviders.Add(insertProvider); + databaseCreators.Add(databaseCreator); + } } } diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs index fb2affd045..463a087f39 100644 --- a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs @@ -1,274 +1,30 @@ -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; 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; using Serilog.Extensions.Hosting; using Umbraco.Core; -using Umbraco.Core.Builder; using Umbraco.Core.Cache; using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Configuration.Models.Validation; -using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Logging.Serilog; -using Umbraco.Core.Persistence; -using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Runtime; -using Umbraco.Infrastructure.HostedServices; -using Umbraco.Infrastructure.HostedServices.ServerRegistration; using Umbraco.Web.Common.AspNetCore; using Umbraco.Web.Common.Profiler; -using ConnectionStrings = Umbraco.Core.Configuration.Models.ConnectionStrings; -using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; namespace Umbraco.Extensions { public static class UmbracoCoreServiceCollectionExtensions { - /// - /// Adds the Umbraco Back Core requirements - /// - /// - /// - /// - /// - /// - /// - /// - public static IUmbracoBuilder AddUmbracoCore( - this IUmbracoBuilder builder, - IWebHostEnvironment webHostEnvironment, - Assembly entryAssembly, - ILoggingConfiguration loggingConfiguration, - IConfiguration configuration) - { - if (builder is null) throw new ArgumentNullException(nameof(builder)); - if (entryAssembly is null) throw new ArgumentNullException(nameof(entryAssembly)); - - builder.Services.AddLazySupport(); - - // Add service session - // This can be overwritten by the user by adding their own call to AddSession - // since the last call of AddSession take precedence - builder.Services.AddSession(options => - { - options.Cookie.Name = "UMB_SESSION"; - options.Cookie.HttpOnly = true; - }); - var syntaxProviders = new List(); - var insertProviders = new List(); - var databaseCreators = new List(); - - // Add supported databases - builder.Services.AddUmbracoSqlCeSupport(syntaxProviders, insertProviders, databaseCreators); - builder.Services.AddUmbracoSqlServerSupport(syntaxProviders, insertProviders, databaseCreators); - - builder.Services.AddUnique(factory => factory.GetRequiredService().RuntimeCache); - builder.Services.AddUnique(factory => factory.GetRequiredService().RequestCache); - - var dbProviderFactoryCreator = new DbProviderFactoryCreator( - DbProviderFactories.GetFactory, - syntaxProviders, - insertProviders, - databaseCreators); - - builder.Services.AddSingleton(dbProviderFactoryCreator); - - builder.Services.AddUnique(); - builder.Services.AddLogger(loggingConfiguration, configuration); // TODO: remove this line - var loggerFactory = builder.BuilderLoggerFactory; - - var profiler = GetWebProfiler(configuration); - builder.Services.AddUnique(profiler); - - - var typeFinder = CreateTypeFinder(loggerFactory, webHostEnvironment, entryAssembly, builder.Config); - - builder.Services.AddUnique(); - builder.Services.AddUnique(typeFinder); - builder.Services.AddUnique(builder.TypeLoader); - 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); - - builder.Services.AddUnique(); - - 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; - } - - public static IUmbracoBuilder AddComposers(this IUmbracoBuilder builder) - { - var composerTypes = builder.TypeLoader.GetTypes(); - var enableDisable = builder.TypeLoader.GetAssemblyAttributes(typeof(EnableComposerAttribute), typeof(DisableComposerAttribute)); - new Composers(builder, composerTypes, enableDisable, builder.BuilderLoggerFactory.CreateLogger()).Compose(); - - return builder; - } - - /// - /// Adds SqlCe support for Umbraco - /// - private static IServiceCollection AddUmbracoSqlCeSupport( - this IServiceCollection services, - ICollection syntaxProviders, - ICollection insertProviders, - ICollection databaseCreators) - { - try - { - var binFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - if (binFolder != null) - { - var dllPath = Path.Combine(binFolder, "Umbraco.Persistance.SqlCe.dll"); - var umbSqlCeAssembly = Assembly.LoadFrom(dllPath); - - var sqlCeSyntaxProviderType = umbSqlCeAssembly.GetType("Umbraco.Persistance.SqlCe.SqlCeSyntaxProvider"); - var sqlCeBulkSqlInsertProviderType = umbSqlCeAssembly.GetType("Umbraco.Persistance.SqlCe.SqlCeBulkSqlInsertProvider"); - var sqlCeEmbeddedDatabaseCreatorType = umbSqlCeAssembly.GetType("Umbraco.Persistance.SqlCe.SqlCeEmbeddedDatabaseCreator"); - - if (!(sqlCeSyntaxProviderType is null || sqlCeBulkSqlInsertProviderType is null || sqlCeEmbeddedDatabaseCreatorType is null)) - { - services.AddSingleton(typeof(ISqlSyntaxProvider), sqlCeSyntaxProviderType); - services.AddSingleton(typeof(IBulkSqlInsertProvider), sqlCeBulkSqlInsertProviderType); - services.AddSingleton(typeof(IEmbeddedDatabaseCreator), sqlCeEmbeddedDatabaseCreatorType); - - syntaxProviders.Add((ISqlSyntaxProvider)Activator.CreateInstance(sqlCeSyntaxProviderType)); - insertProviders.Add((IBulkSqlInsertProvider)Activator.CreateInstance(sqlCeBulkSqlInsertProviderType)); - databaseCreators.Add((IEmbeddedDatabaseCreator)Activator.CreateInstance(sqlCeEmbeddedDatabaseCreatorType)); - } - - var sqlCeAssembly = Assembly.LoadFrom(Path.Combine(binFolder, "System.Data.SqlServerCe.dll")); - - var sqlCe = sqlCeAssembly.GetType("System.Data.SqlServerCe.SqlCeProviderFactory"); - if (!(sqlCe is null)) - { - DbProviderFactories.RegisterFactory(Core.Constants.DbProviderNames.SqlCe, sqlCe); - } - } - } - catch - { - // Ignore if SqlCE is not available - } - - return services; - } - - /// - /// Adds Sql Server support for Umbraco - /// - public static IServiceCollection AddUmbracoSqlServerSupport( - this IServiceCollection services, - ICollection syntaxProviders, - ICollection insertProviders, - ICollection databaseCreators) - { - DbProviderFactories.RegisterFactory(Core.Constants.DbProviderNames.SqlServer, SqlClientFactory.Instance); - - var syntaxProvider = new SqlServerSyntaxProvider(); - var insertProvider = new SqlServerBulkSqlInsertProvider(); - var databaseCreator = new NoopEmbeddedDatabaseCreator(); - - services.AddSingleton(syntaxProvider); - services.AddSingleton(insertProvider); - services.AddSingleton(databaseCreator); - - syntaxProviders.Add(syntaxProvider); - insertProviders.Add(insertProvider); - databaseCreators.Add(databaseCreator); - - return services; - } - - /// - /// Adds hosted services for Umbraco. - /// - /// - /// - public static IServiceCollection AddUmbracoHostedServices(this IServiceCollection services) - { - services.AddHostedService(); - services.AddHostedService(); - services.AddHostedService(); - services.AddHostedService(); - services.AddHostedService(); - - services.AddHostedService(); - services.AddHostedService(); - - return services; - } - - /// - /// Adds HTTP clients for Umbraco. - /// - /// - /// - public static IServiceCollection AddUmbracoHttpClients(this IServiceCollection services) - { - services.AddHttpClient(); - return services; - } - - + /// /// Create and configure the logger /// - /// public static IServiceCollection AddLogger( this IServiceCollection services, ILoggingConfiguration loggingConfiguration, @@ -280,7 +36,6 @@ namespace Umbraco.Extensions // This is nessasary to pick up all the loggins to MS ILogger. Log.Logger = logger.SerilogLog; - // Wire up all the bits that serilog needs. We need to use our own code since the Serilog ext methods don't cater to our needs since // we don't want to use the global serilog `Log` object and we don't have our own ILogger implementation before the HostBuilder runs which // is the only other option that these ext methods allow. @@ -307,7 +62,7 @@ namespace Umbraco.Extensions return services; } - private static IProfiler GetWebProfiler(IConfiguration config) + internal static IProfiler GetWebProfiler(IConfiguration config) { var isDebug = config.GetValue($"{Constants.Configuration.ConfigHosting}:Debug"); // create and start asap to profile boot @@ -324,7 +79,7 @@ namespace Umbraco.Extensions return webProfiler; } - internal static ITypeFinder CreateTypeFinder(ILoggerFactory loggerFactory, IWebHostEnvironment webHostEnvironment, Assembly entryAssembly, IConfiguration config) + internal static ITypeFinder AddTypeFinder(this IServiceCollection services, ILoggerFactory loggerFactory, IWebHostEnvironment webHostEnvironment, Assembly entryAssembly, IConfiguration config) { var profiler = GetWebProfiler(config); @@ -333,37 +88,46 @@ namespace Umbraco.Extensions var runtimeHashPaths = new RuntimeHashPaths().AddFolder(new DirectoryInfo(Path.Combine(webHostEnvironment.ContentRootPath, "bin"))); var runtimeHash = new RuntimeHash(new ProfilingLogger(loggerFactory.CreateLogger(), profiler), runtimeHashPaths); - return new TypeFinder( + var typeFinder = new TypeFinder( loggerFactory.CreateLogger(), new DefaultUmbracoAssemblyProvider(entryAssembly), runtimeHash, new TypeFinderConfig(Options.Create(typeFinderSettings)) ); + + services.AddUnique(typeFinder); + + return typeFinder; } - internal static TypeLoader CreateTypeLoader( + internal static TypeLoader AddTypeLoader( + this IServiceCollection services, Assembly entryAssembly, IWebHostEnvironment webHostEnvironment, ILoggerFactory loggerFactory, AppCaches appCaches, IConfiguration configuration) { - var typeFinder = CreateTypeFinder(loggerFactory, webHostEnvironment, entryAssembly, configuration); + var typeFinder = services.AddTypeFinder(loggerFactory, webHostEnvironment, entryAssembly, configuration); var hostingSettings = configuration.GetSection(Core.Constants.Configuration.ConfigHosting).Get() ?? new HostingSettings(); var hostingEnvironment = new AspNetCoreHostingEnvironmentWithoutOptionsMonitor(hostingSettings, webHostEnvironment); var profilingLogger = new ProfilingLogger(loggerFactory.CreateLogger(), GetWebProfiler(configuration)); - return new TypeLoader( + var typeLoader = new TypeLoader( typeFinder, appCaches.RuntimeCache, new DirectoryInfo(hostingEnvironment.LocalTempPath), loggerFactory.CreateLogger(), profilingLogger ); + + services.AddUnique(typeLoader); + + return typeLoader; } - private class AspNetCoreBootPermissionsChecker : IUmbracoBootPermissionChecker + internal class AspNetCoreBootPermissionsChecker : IUmbracoBootPermissionChecker { public void ThrowIfNotPermissions() { diff --git a/src/Umbraco.Web.UI.NetCore/Startup.cs b/src/Umbraco.Web.UI.NetCore/Startup.cs index 4f3c0ce18c..ca62523c4d 100644 --- a/src/Umbraco.Web.UI.NetCore/Startup.cs +++ b/src/Umbraco.Web.UI.NetCore/Startup.cs @@ -32,12 +32,10 @@ namespace Umbraco.Web.UI.NetCore // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { - var umbracoBuilder = services.AddUmbraco(_env, _config); - umbracoBuilder - .AddAllBackOfficeComponents(_env) + services.AddUmbraco(_env, _config) + .AddAllBackOfficeComponents() .AddUmbracoWebsite() .Build(); - } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.