From ec169d17d7bdeccb1c2058a5f093d5baeaa411a7 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Wed, 20 Nov 2019 10:20:20 +0100 Subject: [PATCH] Refactored CoreRuntime to inject a IUmbracoBootPermissionChecker, instead of using system.web to test this it self. Also moved some logging from CoreWebsite into WebRuntime, that used hosting information --- .../Runtime/IUmbracoBootPermissionChecker.cs | 7 ++ src/Umbraco.Core/Runtime/CoreRuntime.cs | 31 +++------ .../Routing/RenderRouteHandlerTests.cs | 3 +- .../Runtimes/CoreRuntimeTests.cs | 17 +++-- src/Umbraco.Tests/Runtimes/StandaloneTests.cs | 4 +- .../AspNetUmbracoBootPermissionChecker.cs | 13 ++++ src/Umbraco.Web/Runtime/WebRuntime.cs | 68 ++++++++++++------- src/Umbraco.Web/Umbraco.Web.csproj | 1 + src/Umbraco.Web/UmbracoApplication.cs | 4 +- src/Umbraco.Web/UmbracoApplicationBase.cs | 11 +-- 10 files changed, 98 insertions(+), 61 deletions(-) create mode 100644 src/Umbraco.Abstractions/Runtime/IUmbracoBootPermissionChecker.cs create mode 100644 src/Umbraco.Web/Runtime/AspNetUmbracoBootPermissionChecker.cs diff --git a/src/Umbraco.Abstractions/Runtime/IUmbracoBootPermissionChecker.cs b/src/Umbraco.Abstractions/Runtime/IUmbracoBootPermissionChecker.cs new file mode 100644 index 0000000000..4e48a8b030 --- /dev/null +++ b/src/Umbraco.Abstractions/Runtime/IUmbracoBootPermissionChecker.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Runtime +{ + public interface IUmbracoBootPermissionChecker + { + void ThrowIfNotPermissions(); + } +} diff --git a/src/Umbraco.Core/Runtime/CoreRuntime.cs b/src/Umbraco.Core/Runtime/CoreRuntime.cs index 98d245c04e..c24df00167 100644 --- a/src/Umbraco.Core/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntime.cs @@ -2,8 +2,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Web; -using System.Web.Hosting; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; @@ -26,13 +24,17 @@ namespace Umbraco.Core.Runtime private ComponentCollection _components; private IFactory _factory; private RuntimeState _state; + private readonly IUmbracoBootPermissionChecker _umbracoBootPermissionChecker; - public CoreRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger) + public CoreRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IProfiler profiler, IUmbracoBootPermissionChecker umbracoBootPermissionChecker) { IOHelper = ioHelper; Configs = configs; UmbracoVersion = umbracoVersion ; + Profiler = profiler; + + _umbracoBootPermissionChecker = umbracoBootPermissionChecker; Logger = logger; // runtime state @@ -56,7 +58,7 @@ namespace Umbraco.Core.Runtime /// /// Gets the profiler. /// - protected IProfiler Profiler { get; private set; } + protected IProfiler Profiler { get; set; } /// /// Gets the profiling logger. @@ -84,12 +86,6 @@ namespace Umbraco.Core.Runtime // create and register the essential services // ie the bare minimum required to boot - // loggers - var profiler = Profiler = GetProfiler(); - if (profiler == null) - throw new InvalidOperationException($"The object returned from {nameof(GetProfiler)} cannot be null"); - - var profilingLogger = ProfilingLogger = new ProfilingLogger(Logger, profiler); TypeFinder = GetTypeFinder(); if (TypeFinder == null) @@ -105,16 +101,13 @@ namespace Umbraco.Core.Runtime // objects. var umbracoVersion = new UmbracoVersion(); + var profilingLogger = ProfilingLogger = new ProfilingLogger(Logger, Profiler); using (var timer = profilingLogger.TraceDuration( $"Booting Umbraco {umbracoVersion.SemanticVersion.ToSemanticString()}.", "Booted.", "Boot failed.")) { - Logger.Info("Booting site '{HostingSiteName}', app '{HostingApplicationID}', path '{HostingPhysicalPath}', server '{MachineName}'.", - HostingEnvironment.SiteName, - HostingEnvironment.ApplicationID, - HostingEnvironment.ApplicationPhysicalPath, - NetworkHelper.MachineName); + Logger.Info("Booting Core"); Logger.Debug("Runtime: {Runtime}", GetType().FullName); // application environment @@ -137,7 +130,7 @@ namespace Umbraco.Core.Runtime try { // throws if not full-trust - new AspNetHostingPermission(AspNetHostingPermissionLevel.Unrestricted).Demand(); + _umbracoBootPermissionChecker.ThrowIfNotPermissions(); // run handlers RuntimeOptions.DoRuntimeBoot(ProfilingLogger); @@ -331,12 +324,6 @@ namespace Umbraco.Core.Runtime protected virtual IEnumerable GetComposerTypes(TypeLoader typeLoader) => typeLoader.GetTypes(); - /// - /// Gets a profiler. - /// - protected virtual IProfiler GetProfiler() - => new LogProfiler(Logger); - /// /// Gets a /// diff --git a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs index cfc42d3670..2f446b36d5 100644 --- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs +++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs @@ -51,11 +51,10 @@ namespace Umbraco.Tests.Routing public class TestRuntime : WebRuntime { public TestRuntime(UmbracoApplicationBase umbracoApplication, Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger) - : base(umbracoApplication, configs, umbracoVersion, ioHelper, Mock.Of()) + : base(umbracoApplication, configs, umbracoVersion, ioHelper, Mock.Of(), Mock.Of()) { } - protected override IProfiler GetProfiler() => Mock.Of(); } protected override void Compose() diff --git a/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs b/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs index 93c931c93d..564a98a4b3 100644 --- a/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs +++ b/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs @@ -20,6 +20,7 @@ using Umbraco.Core.Scoping; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Web; +using Umbraco.Web.Runtime; namespace Umbraco.Tests.Runtimes { @@ -80,7 +81,7 @@ namespace Umbraco.Tests.Runtimes // test application public class TestUmbracoApplication : UmbracoApplicationBase { - public TestUmbracoApplication() : base(new DebugDiagnosticsLogger(new MessageTemplates()), GetConfigs()) + public TestUmbracoApplication() : base(new DebugDiagnosticsLogger(new MessageTemplates()), GetConfigs(), IOHelper.Default, GetProfiler()) { } @@ -92,23 +93,27 @@ namespace Umbraco.Tests.Runtimes return configs; } + private static IProfiler GetProfiler() + { + return new TestProfiler(); + } + public IRuntime Runtime { get; private set; } - protected override IRuntime GetRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger) + protected override IRuntime GetRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IProfiler profiler) { - return Runtime = new TestRuntime(configs, umbracoVersion, ioHelper, logger); + return Runtime = new TestRuntime(configs, umbracoVersion, ioHelper, logger, profiler); } } // test runtime public class TestRuntime : CoreRuntime { - public TestRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger) - :base(configs, umbracoVersion, ioHelper, logger) + public TestRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IProfiler profiler) + :base(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker()) { } - protected override IProfiler GetProfiler() => new TestProfiler(); // must override the database factory // else BootFailedException because U cannot connect to the configured db diff --git a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs index 119211225a..4ad97cafc3 100644 --- a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs +++ b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs @@ -75,7 +75,7 @@ namespace Umbraco.Tests.Runtimes composition.RegisterEssentials(logger, profiler, profilingLogger, mainDom, appCaches, databaseFactory, typeLoader, runtimeState, typeFinder, ioHelper, umbracoVersion); // create the core runtime and have it compose itself - var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger);coreRuntime.Compose(composition); + var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker());coreRuntime.Compose(composition); // determine actual runtime level runtimeState.DetermineRuntimeLevel(databaseFactory, logger); @@ -268,7 +268,7 @@ namespace Umbraco.Tests.Runtimes composition.RegisterEssentials(logger, profiler, profilingLogger, mainDom, appCaches, databaseFactory, typeLoader, runtimeState, typeFinder, ioHelper, umbracoVersion); // create the core runtime and have it compose itself - var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger); + var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker()); coreRuntime.Compose(composition); // get the components diff --git a/src/Umbraco.Web/Runtime/AspNetUmbracoBootPermissionChecker.cs b/src/Umbraco.Web/Runtime/AspNetUmbracoBootPermissionChecker.cs new file mode 100644 index 0000000000..fdf8b53852 --- /dev/null +++ b/src/Umbraco.Web/Runtime/AspNetUmbracoBootPermissionChecker.cs @@ -0,0 +1,13 @@ +using System.Web; +using Umbraco.Core.Runtime; + +namespace Umbraco.Web.Runtime +{ + public class AspNetUmbracoBootPermissionChecker : IUmbracoBootPermissionChecker + { + public void ThrowIfNotPermissions() + { + new AspNetHostingPermission(AspNetHostingPermissionLevel.Unrestricted).Demand(); + } + } +} diff --git a/src/Umbraco.Web/Runtime/WebRuntime.cs b/src/Umbraco.Web/Runtime/WebRuntime.cs index bd17907cc9..44e6ba6e9f 100644 --- a/src/Umbraco.Web/Runtime/WebRuntime.cs +++ b/src/Umbraco.Web/Runtime/WebRuntime.cs @@ -1,4 +1,6 @@ using System.Web; +using System.Web.Hosting; +using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; @@ -18,52 +20,72 @@ namespace Umbraco.Web.Runtime public class WebRuntime : CoreRuntime { private readonly UmbracoApplicationBase _umbracoApplication; - private IProfiler _webProfiler; private BuildManagerTypeFinder _typeFinder; /// /// Initializes a new instance of the class. /// /// - public WebRuntime(UmbracoApplicationBase umbracoApplication, Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger): - base(configs, umbracoVersion, ioHelper, logger) + public WebRuntime(UmbracoApplicationBase umbracoApplication, Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IProfiler profiler): + base(configs, umbracoVersion, ioHelper, logger, profiler ,new AspNetUmbracoBootPermissionChecker()) { _umbracoApplication = umbracoApplication; + + Profiler = GetWebProfiler(); + } + + private IProfiler GetWebProfiler() + { + // create and start asap to profile boot + if (!State.Debug) + { + // 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(); + webProfiler.Start(); + + return webProfiler; } /// public override IFactory Boot(IRegister register) { - // create and start asap to profile boot - if (State.Debug) + + var profilingLogger = new ProfilingLogger(Logger, Profiler); + var umbracoVersion = new UmbracoVersion(); + using (var timer = profilingLogger.TraceDuration( + $"Booting Umbraco {umbracoVersion.SemanticVersion.ToSemanticString()}.", + "Booted.", + "Boot failed.")) { - _webProfiler = new WebProfiler(); - _webProfiler.Start(); - } - else - { - // 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 - _webProfiler = new VoidProfiler(); + Logger.Info("Booting site '{HostingSiteName}', app '{HostingApplicationID}', path '{HostingPhysicalPath}', server '{MachineName}'.", + HostingEnvironment.SiteName, + HostingEnvironment.ApplicationID, + HostingEnvironment.ApplicationPhysicalPath, + NetworkHelper.MachineName); + Logger.Debug("Runtime: {Runtime}", GetType().FullName); + + var factory = base.Boot(register); + + // now (and only now) is the time to switch over to perWebRequest scopes. + // up until that point we may not have a request, and scoped services would + // fail to resolve - but we run Initialize within a factory scope - and then, + // here, we switch the factory to bind scopes to requests + factory.EnablePerWebRequestScope(); + + return factory; } - var factory = base.Boot(register); - // now (and only now) is the time to switch over to perWebRequest scopes. - // up until that point we may not have a request, and scoped services would - // fail to resolve - but we run Initialize within a factory scope - and then, - // here, we switch the factory to bind scopes to requests - factory.EnablePerWebRequestScope(); - - return factory; } #region Getters protected override ITypeFinder GetTypeFinder() => _typeFinder ?? (_typeFinder = new BuildManagerTypeFinder(IOHelper, Logger, new BuildManagerTypeFinder.TypeFinderConfig())); - protected override IProfiler GetProfiler() => _webProfiler; - protected override AppCaches GetAppCaches() => new AppCaches( // we need to have the dep clone runtime cache provider to ensure // all entities are cached properly (cloned in and cloned out) diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index a732dfeb10..cd0a345f62 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -252,6 +252,7 @@ + diff --git a/src/Umbraco.Web/UmbracoApplication.cs b/src/Umbraco.Web/UmbracoApplication.cs index ec620cdb8d..52273be007 100644 --- a/src/Umbraco.Web/UmbracoApplication.cs +++ b/src/Umbraco.Web/UmbracoApplication.cs @@ -13,9 +13,9 @@ namespace Umbraco.Web /// public class UmbracoApplication : UmbracoApplicationBase { - protected override IRuntime GetRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger) + protected override IRuntime GetRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IProfiler profiler) { - return new WebRuntime(this, configs, umbracoVersion, ioHelper, logger); + return new WebRuntime(this, configs, umbracoVersion, ioHelper, logger, profiler); } /// diff --git a/src/Umbraco.Web/UmbracoApplicationBase.cs b/src/Umbraco.Web/UmbracoApplicationBase.cs index c0e56579b6..530eaceb20 100644 --- a/src/Umbraco.Web/UmbracoApplicationBase.cs +++ b/src/Umbraco.Web/UmbracoApplicationBase.cs @@ -22,26 +22,29 @@ namespace Umbraco.Web public readonly ILogger _logger; private readonly Configs _configs; private readonly IIOHelper _ioHelper; + private readonly IProfiler _profiler; protected UmbracoApplicationBase() { _logger = SerilogLogger.CreateWithDefaultConfiguration(); _ioHelper = IOHelper.Default; _configs = new ConfigsFactory(_ioHelper).Create(); + _profiler = new LogProfiler(_logger); } - protected UmbracoApplicationBase(ILogger logger, Configs configs) + protected UmbracoApplicationBase(ILogger logger, Configs configs, IIOHelper ioHelper, IProfiler profiler) { _logger = logger; _configs = configs; - _ioHelper = IOHelper.Default; + _ioHelper = ioHelper; + _profiler = profiler; } /// /// Gets a runtime. /// - protected abstract IRuntime GetRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger); + protected abstract IRuntime GetRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IProfiler profiler); /// /// Gets the application register. @@ -86,7 +89,7 @@ namespace Umbraco.Web // create the register for the application, and boot // the boot manager is responsible for registrations var register = GetRegister(globalSettings); - _runtime = GetRuntime(_configs, umbracoVersion, _ioHelper, _logger); + _runtime = GetRuntime(_configs, umbracoVersion, _ioHelper, _logger, _profiler); _runtime.Boot(register); }