From 7ec3afa5ff3db3b37fa60a478d5524511b792974 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 9 Jul 2021 15:31:01 -0600 Subject: [PATCH] Adds new ctor to runtime hash class. Adds startup objects to the IUmbracoBuilder that are not otherwise available during configuration. --- .../Composing/RuntimeHashPaths.cs | 21 ++++++++++++++- src/Umbraco.Core/Composing/TypeLoader.cs | 14 ++++++---- .../DependencyInjection/IUmbracoBuilder.cs | 20 ++++++++++++++ .../DependencyInjection/UmbracoBuilder.cs | 27 ++++++++++++++++--- src/Umbraco.Core/Logging/ProfilingLogger.cs | 2 +- .../TypeLoaderBenchmarks.cs | 4 +-- src/Umbraco.Tests.Common/TestHelperBase.cs | 2 +- .../Testing/UmbracoIntegrationTest.cs | 5 ++-- .../Umbraco.Core/Components/ComponentTests.cs | 4 +-- .../Composing/ComposingTestBase.cs | 6 +---- .../Umbraco.Core/Composing/TypeLoaderTests.cs | 2 +- .../UmbracoBuilderExtensions.cs | 8 +++--- .../Extensions/ServiceCollectionExtensions.cs | 23 +++++++--------- 13 files changed, 96 insertions(+), 42 deletions(-) diff --git a/src/Umbraco.Core/Composing/RuntimeHashPaths.cs b/src/Umbraco.Core/Composing/RuntimeHashPaths.cs index 12a878ee94..eac2f83bcd 100644 --- a/src/Umbraco.Core/Composing/RuntimeHashPaths.cs +++ b/src/Umbraco.Core/Composing/RuntimeHashPaths.cs @@ -1,5 +1,6 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; +using System.Reflection; namespace Umbraco.Cms.Core.Composing { @@ -17,6 +18,24 @@ namespace Umbraco.Cms.Core.Composing return this; } + /// + /// Creates a runtime hash based on the assembly provider + /// + /// + /// + public RuntimeHashPaths AddAssemblies(IAssemblyProvider assemblyProvider) + { + foreach (Assembly assembly in assemblyProvider.Assemblies) + { + // TODO: We need to test this on a published website + if (!assembly.IsDynamic && assembly.Location != null) + { + AddFile(new FileInfo(assembly.Location)); + } + } + return this; + } + public void AddFile(FileInfo fileInfo, bool scanFileContent = false) => _files.Add(fileInfo, scanFileContent); public IEnumerable GetFolders() => _paths; diff --git a/src/Umbraco.Core/Composing/TypeLoader.cs b/src/Umbraco.Core/Composing/TypeLoader.cs index 39b70b831b..fa66780914 100644 --- a/src/Umbraco.Core/Composing/TypeLoader.cs +++ b/src/Umbraco.Core/Composing/TypeLoader.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; -using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Text; using System.Threading; @@ -55,8 +54,8 @@ namespace Umbraco.Cms.Core.Composing /// Files storage location. /// A profiling logger. /// - public TypeLoader(ITypeFinder typeFinder, IAppPolicyCache runtimeCache, DirectoryInfo localTempPath, ILogger logger, IProfilingLogger profilingLogger, IEnumerable assembliesToScan = null) - : this(typeFinder, runtimeCache, localTempPath, logger, profilingLogger, true, assembliesToScan) + public TypeLoader(ITypeFinder typeFinder, IAppPolicyCache runtimeCache, DirectoryInfo localTempPath, ILogger logger, IProfiler profiler, IEnumerable assembliesToScan = null) + : this(typeFinder, runtimeCache, localTempPath, logger, profiler, true, assembliesToScan) { } /// @@ -68,13 +67,18 @@ namespace Umbraco.Cms.Core.Composing /// A profiling logger. /// Whether to detect changes using hashes. /// - public TypeLoader(ITypeFinder typeFinder, IAppPolicyCache runtimeCache, DirectoryInfo localTempPath, ILogger logger, IProfilingLogger profilingLogger, bool detectChanges, IEnumerable assembliesToScan = null) + public TypeLoader(ITypeFinder typeFinder, IAppPolicyCache runtimeCache, DirectoryInfo localTempPath, ILogger logger, IProfiler profiler, bool detectChanges, IEnumerable assembliesToScan = null) { + if (profiler is null) + { + throw new ArgumentNullException(nameof(profiler)); + } + TypeFinder = typeFinder ?? throw new ArgumentNullException(nameof(typeFinder)); _runtimeCache = runtimeCache ?? throw new ArgumentNullException(nameof(runtimeCache)); _localTempPath = localTempPath; _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _profilingLogger = profilingLogger ?? throw new ArgumentNullException(nameof(profilingLogger)); + _profilingLogger = new ProfilingLogger(logger, profiler); _assemblies = assembliesToScan; _fileBasePath = new Lazy(GetFileBasePath); diff --git a/src/Umbraco.Core/DependencyInjection/IUmbracoBuilder.cs b/src/Umbraco.Core/DependencyInjection/IUmbracoBuilder.cs index 0b65c3443c..738cfed26e 100644 --- a/src/Umbraco.Core/DependencyInjection/IUmbracoBuilder.cs +++ b/src/Umbraco.Core/DependencyInjection/IUmbracoBuilder.cs @@ -1,7 +1,10 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.Logging; namespace Umbraco.Cms.Core.DependencyInjection { @@ -10,7 +13,24 @@ namespace Umbraco.Cms.Core.DependencyInjection IServiceCollection Services { get; } IConfiguration Config { get; } TypeLoader TypeLoader { get; } + + /// + /// A Logger factory created specifically for the . This is NOT the same + /// instance that will be resolved from DI. Use only if required during configuration. + /// ILoggerFactory BuilderLoggerFactory { get; } + + /// + /// A hosting environment created specifically for the . This is NOT the same + /// instance that will be resolved from DI. Use only if required during configuration. + /// + /// + /// This may be null. + /// + IHostingEnvironment BuilderHostingEnvironment { get; } + + IProfiler Profiler { get; } + AppCaches AppCaches { get; } TBuilder WithCollectionBuilder() where TBuilder : ICollectionBuilder, new(); void Build(); } diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs index 5dd2499624..648af8f082 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs @@ -52,23 +52,41 @@ namespace Umbraco.Cms.Core.DependencyInjection public TypeLoader TypeLoader { get; } + /// public ILoggerFactory BuilderLoggerFactory { get; } + /// + public IHostingEnvironment BuilderHostingEnvironment { get; } + + public IProfiler Profiler { get; } + + public AppCaches AppCaches { get; } + /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class primarily for testing. /// public UmbracoBuilder(IServiceCollection services, IConfiguration config, TypeLoader typeLoader) - : this(services, config, typeLoader, NullLoggerFactory.Instance) + : this(services, config, typeLoader, NullLoggerFactory.Instance, new NoopProfiler(), AppCaches.Disabled, null) { } /// /// Initializes a new instance of the class. /// - public UmbracoBuilder(IServiceCollection services, IConfiguration config, TypeLoader typeLoader, ILoggerFactory loggerFactory) + public UmbracoBuilder( + IServiceCollection services, + IConfiguration config, + TypeLoader typeLoader, + ILoggerFactory loggerFactory, + IProfiler profiler, + AppCaches appCaches, + IHostingEnvironment hostingEnvironment) { Services = services; Config = config; BuilderLoggerFactory = loggerFactory; + BuilderHostingEnvironment = hostingEnvironment; + Profiler = profiler; + AppCaches = appCaches; TypeLoader = typeLoader; AddCoreServices(); @@ -106,6 +124,9 @@ namespace Umbraco.Cms.Core.DependencyInjection private void AddCoreServices() { + Services.AddSingleton(AppCaches); + Services.AddSingleton(Profiler); + // Register as singleton to allow injection everywhere. Services.AddSingleton(p => p.GetService); Services.AddSingleton(); diff --git a/src/Umbraco.Core/Logging/ProfilingLogger.cs b/src/Umbraco.Core/Logging/ProfilingLogger.cs index 9c66c95d24..0e340baf90 100644 --- a/src/Umbraco.Core/Logging/ProfilingLogger.cs +++ b/src/Umbraco.Core/Logging/ProfilingLogger.cs @@ -21,7 +21,7 @@ namespace Umbraco.Cms.Core.Logging /// /// Initializes a new instance of the class. /// - public ProfilingLogger(ILogger logger, IProfiler profiler) + public ProfilingLogger(ILogger logger, IProfiler profiler) { Logger = logger ?? throw new ArgumentNullException(nameof(logger)); Profiler = profiler ?? throw new ArgumentNullException(nameof(profiler)); diff --git a/src/Umbraco.Tests.Benchmarks/TypeLoaderBenchmarks.cs b/src/Umbraco.Tests.Benchmarks/TypeLoaderBenchmarks.cs index 380e3fca99..00d6820302 100644 --- a/src/Umbraco.Tests.Benchmarks/TypeLoaderBenchmarks.cs +++ b/src/Umbraco.Tests.Benchmarks/TypeLoaderBenchmarks.cs @@ -30,7 +30,7 @@ namespace Umbraco.Tests.Benchmarks cache, null, new NullLogger(), - new ProfilingLogger(new NullLogger(), new NoopProfiler())); + new NoopProfiler()); // populate the cache cache.Insert( @@ -43,7 +43,7 @@ namespace Umbraco.Tests.Benchmarks NoAppCache.Instance, null, new NullLogger(), - new ProfilingLogger(new NullLogger(), new NoopProfiler())); + new NoopProfiler()); } /// diff --git a/src/Umbraco.Tests.Common/TestHelperBase.cs b/src/Umbraco.Tests.Common/TestHelperBase.cs index 79f5e4d578..ec76e0ba08 100644 --- a/src/Umbraco.Tests.Common/TestHelperBase.cs +++ b/src/Umbraco.Tests.Common/TestHelperBase.cs @@ -50,7 +50,7 @@ namespace Umbraco.Cms.Tests.Common public ITypeFinder GetTypeFinder() => _typeFinder; public TypeLoader GetMockedTypeLoader() => - new TypeLoader(Mock.Of(), Mock.Of(), new DirectoryInfo(GetHostingEnvironment().MapPathContentRoot(Constants.SystemDirectories.TempData)), Mock.Of>(), Mock.Of()); + new TypeLoader(Mock.Of(), Mock.Of(), new DirectoryInfo(GetHostingEnvironment().MapPathContentRoot(Constants.SystemDirectories.TempData)), Mock.Of>(), Mock.Of()); //// public Configs GetConfigs() => GetConfigsFactory().Create(); diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index b3a168e119..bb4be6f368 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -202,14 +202,15 @@ namespace Umbraco.Cms.Tests.Integration.Testing services.AddRequiredNetCoreServices(TestHelper, webHostEnvironment); // Add it! + Core.Hosting.IHostingEnvironment hostingEnvironment = TestHelper.GetHostingEnvironment(); TypeLoader typeLoader = services.AddTypeLoader( GetType().Assembly, - TestHelper.GetHostingEnvironment(), + hostingEnvironment, TestHelper.ConsoleLoggerFactory, AppCaches.NoCache, Configuration, TestHelper.Profiler); - var builder = new UmbracoBuilder(services, Configuration, typeLoader, TestHelper.ConsoleLoggerFactory); + var builder = new UmbracoBuilder(services, Configuration, typeLoader, TestHelper.ConsoleLoggerFactory, TestHelper.Profiler, AppCaches.NoCache, hostingEnvironment); builder.Services.AddLogger(TestHelper.GetHostingEnvironment(), TestHelper.GetLoggingConfiguration(), Configuration); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs index 11fee778e2..bd8fc3103f 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs @@ -78,7 +78,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Components private static IServiceCollection MockRegister() => new ServiceCollection(); - private static TypeLoader MockTypeLoader() => new TypeLoader(Mock.Of(), Mock.Of(), new DirectoryInfo(TestHelper.GetHostingEnvironment().MapPathContentRoot(Constants.SystemDirectories.TempData)), Mock.Of>(), Mock.Of()); + private static TypeLoader MockTypeLoader() => new TypeLoader(Mock.Of(), Mock.Of(), new DirectoryInfo(TestHelper.GetHostingEnvironment().MapPathContentRoot(Constants.SystemDirectories.TempData)), Mock.Of>(), Mock.Of()); [Test] public void Boot1A() @@ -438,7 +438,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Components public void AllComposers() { ITypeFinder typeFinder = TestHelper.GetTypeFinder(); - var typeLoader = new TypeLoader(typeFinder, AppCaches.Disabled.RuntimeCache, new DirectoryInfo(TestHelper.GetHostingEnvironment().MapPathContentRoot(Constants.SystemDirectories.TempData)), Mock.Of>(), Mock.Of()); + var typeLoader = new TypeLoader(typeFinder, AppCaches.Disabled.RuntimeCache, new DirectoryInfo(TestHelper.GetHostingEnvironment().MapPathContentRoot(Constants.SystemDirectories.TempData)), Mock.Of>(), Mock.Of()); IServiceCollection register = MockRegister(); var builder = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/ComposingTestBase.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/ComposingTestBase.cs index 17f271888b..3a38f0db11 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/ComposingTestBase.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/ComposingTestBase.cs @@ -19,15 +19,11 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Composing { protected TypeLoader TypeLoader { get; private set; } - protected IProfilingLogger ProfilingLogger { get; private set; } - [SetUp] public void Initialize() { - ProfilingLogger = new ProfilingLogger(Mock.Of>(), Mock.Of()); - var typeFinder = TestHelper.GetTypeFinder(); - TypeLoader = new TypeLoader(typeFinder, NoAppCache.Instance, new DirectoryInfo(TestHelper.GetHostingEnvironment().MapPathContentRoot(Constants.SystemDirectories.TempData)), Mock.Of>(), ProfilingLogger, false, AssembliesToScan); + TypeLoader = new TypeLoader(typeFinder, NoAppCache.Instance, new DirectoryInfo(TestHelper.GetHostingEnvironment().MapPathContentRoot(Constants.SystemDirectories.TempData)), Mock.Of>(), Mock.Of(), false, AssembliesToScan); } protected virtual IEnumerable AssembliesToScan diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs index 794665c79d..e81fcfdabd 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs @@ -51,7 +51,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Composing NoAppCache.Instance, new DirectoryInfo(TestHelper.GetHostingEnvironment().MapPathContentRoot(Constants.SystemDirectories.TempData)), Mock.Of>(), - new ProfilingLogger(Mock.Of>(), Mock.Of()), + Mock.Of(), false, assemblies); } diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index b4273446f9..5f9027db46 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -101,12 +101,10 @@ namespace Umbraco.Extensions services.AddSingleton(httpContextAccessor); var requestCache = new HttpContextRequestAppCache(httpContextAccessor); - var appCaches = AppCaches.Create(requestCache); - services.AddUnique(appCaches); + var appCaches = AppCaches.Create(requestCache); IProfiler profiler = GetWebProfiler(config); - services.AddUnique(profiler); - + ILoggerFactory loggerFactory = LoggerFactory.Create(cfg => cfg.AddSerilog(Log.Logger, false)); TypeLoader typeLoader = services.AddTypeLoader(Assembly.GetEntryAssembly(), tempHostingEnvironment, loggerFactory, appCaches, config, profiler); @@ -114,7 +112,7 @@ namespace Umbraco.Extensions // other start filters are applied (depending on the ordering of IStartupFilters in DI). services.AddTransient(); - return new UmbracoBuilder(services, config, typeLoader, loggerFactory); + return new UmbracoBuilder(services, config, typeLoader, loggerFactory, profiler, appCaches, tempHostingEnvironment); } /// diff --git a/src/Umbraco.Web.Common/Extensions/ServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/ServiceCollectionExtensions.cs index 16a83543ef..d5a02027a2 100644 --- a/src/Umbraco.Web.Common/Extensions/ServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/ServiceCollectionExtensions.cs @@ -65,23 +65,19 @@ namespace Umbraco.Extensions ILoggerFactory loggerFactory, Assembly entryAssembly, IConfiguration config, - IProfilingLogger profilingLogger) + IProfiler profiler) { TypeFinderSettings typeFinderSettings = config.GetSection(Cms.Core.Constants.Configuration.ConfigTypeFinder).Get() ?? new TypeFinderSettings(); var assemblyProvider = new DefaultUmbracoAssemblyProvider(entryAssembly, loggerFactory); - var runtimeHashPaths = new RuntimeHashPaths(); - foreach(Assembly assembly in assemblyProvider.Assemblies) - { - // TODO: We need to test this on a published website - if (!assembly.IsDynamic && assembly.Location != null) - { - runtimeHashPaths.AddFile(new FileInfo(assembly.Location)); - } - } + RuntimeHashPaths runtimeHashPaths = new RuntimeHashPaths().AddAssemblies(assemblyProvider); - var runtimeHash = new RuntimeHash(profilingLogger, runtimeHashPaths); + var runtimeHash = new RuntimeHash( + new ProfilingLogger( + loggerFactory.CreateLogger(), + profiler), + runtimeHashPaths); var typeFinder = new TypeFinder( loggerFactory.CreateLogger(), @@ -104,15 +100,14 @@ namespace Umbraco.Extensions IConfiguration configuration, IProfiler profiler) { - var profilingLogger = new ProfilingLogger(loggerFactory.CreateLogger(), profiler); - var typeFinder = services.AddTypeFinder(loggerFactory, entryAssembly, configuration, profilingLogger); + ITypeFinder typeFinder = services.AddTypeFinder(loggerFactory, entryAssembly, configuration, profiler); var typeLoader = new TypeLoader( typeFinder, appCaches.RuntimeCache, new DirectoryInfo(hostingEnvironment.LocalTempPath), loggerFactory.CreateLogger(), - profilingLogger + profiler ); services.AddUnique(typeLoader);