Cleans up some unused code, fixes a merge issue causing duplicate runtimes to be created, register essential does what it's supposed to do, don't mix things with the webruntime.

This commit is contained in:
Shannon
2020-03-24 14:48:32 +11:00
parent 59f0edc074
commit d0a204b984
12 changed files with 140 additions and 130 deletions
@@ -46,12 +46,6 @@ namespace Umbraco.Core
/// <remarks>This is eg "http://www.example.com".</remarks>
Uri ApplicationUrl { get; }
/// <summary>
/// Gets the Umbraco application virtual path.
/// </summary>
/// <remarks>This is either "/" or eg "/virtual".</remarks>
string ApplicationVirtualPath { get; }
/// <summary>
/// Gets the runtime level of execution.
/// </summary>
@@ -1,6 +1,7 @@
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
@@ -15,6 +16,9 @@ namespace Umbraco.Core
/// <summary>
/// Registers essential services.
/// </summary>
/// <remarks>
/// These services are all either created by the runtime or used to construct the runtime
/// </remarks>
public static void RegisterEssentials(this Composition composition,
ILogger logger, IProfiler profiler, IProfilingLogger profilingLogger,
IMainDom mainDom,
@@ -25,8 +29,10 @@ namespace Umbraco.Core
ITypeFinder typeFinder,
IIOHelper ioHelper,
IUmbracoVersion umbracoVersion,
IDbProviderFactoryCreator dbProviderFactoryCreator)
{
IDbProviderFactoryCreator dbProviderFactoryCreator,
IHostingEnvironment hostingEnvironment,
IBackOfficeInfo backOfficeInfo)
{
composition.RegisterUnique(logger);
composition.RegisterUnique(profiler);
composition.RegisterUnique(profilingLogger);
@@ -42,6 +48,8 @@ namespace Umbraco.Core
composition.RegisterUnique(umbracoVersion);
composition.RegisterUnique(dbProviderFactoryCreator);
composition.RegisterUnique(factory => factory.GetInstance<IUmbracoDatabaseFactory>().BulkSqlInsertProvider);
composition.RegisterUnique(hostingEnvironment);
composition.RegisterUnique(backOfficeInfo);
}
}
}
@@ -69,7 +69,7 @@ namespace Umbraco.Core.Runtime
Configs.Global(),
new Lazy<IMainDom>(() => mainDom),
new Lazy<IServerRegistrar>(() => _factory.GetInstance<IServerRegistrar>()),
UmbracoVersion,HostingEnvironment, BackOfficeInfo)
UmbracoVersion, HostingEnvironment, BackOfficeInfo)
{
Level = RuntimeLevel.Boot
};
@@ -82,7 +82,6 @@ namespace Umbraco.Core.Runtime
protected IBackOfficeInfo BackOfficeInfo { get; }
public IDbProviderFactoryCreator DbProviderFactoryCreator { get; }
//public IBulkSqlInsertProvider BulkSqlInsertProvider { get; }
/// <summary>
/// Gets the profiler.
@@ -176,21 +175,9 @@ namespace Umbraco.Core.Runtime
// type finder/loader
var typeLoader = new TypeLoader(IOHelper, TypeFinder, appCaches.RuntimeCache, new DirectoryInfo(HostingEnvironment.LocalTempPath), ProfilingLogger);
// runtime state
// beware! must use '() => _factory.GetInstance<T>()' and NOT '_factory.GetInstance<T>'
// as the second one captures the current value (null) and therefore fails
_state = new RuntimeState(Logger,
Configs.Global(),
new Lazy<IMainDom>(() => _factory.GetInstance<IMainDom>()),
new Lazy<IServerRegistrar>(() => _factory.GetInstance<IServerRegistrar>()),
UmbracoVersion, HostingEnvironment, BackOfficeInfo)
{
Level = RuntimeLevel.Boot
};
// create the composition
composition = new Composition(register, typeLoader, ProfilingLogger, _state, Configs, IOHelper, appCaches);
composition.RegisterEssentials(Logger, Profiler, ProfilingLogger, MainDom, appCaches, databaseFactory, typeLoader, _state, TypeFinder, IOHelper, UmbracoVersion, DbProviderFactoryCreator);
composition.RegisterEssentials(Logger, Profiler, ProfilingLogger, MainDom, appCaches, databaseFactory, typeLoader, _state, TypeFinder, IOHelper, UmbracoVersion, DbProviderFactoryCreator, HostingEnvironment, BackOfficeInfo);
// run handlers
RuntimeOptions.DoRuntimeEssentials(composition, appCaches, typeLoader, databaseFactory);
@@ -43,8 +43,6 @@ namespace Umbraco.Core
_umbracoVersion = umbracoVersion;
_hostingEnvironment = hostingEnvironment;
_backOfficeInfo = backOfficeInfo;
ApplicationVirtualPath = _hostingEnvironment.ApplicationVirtualPath;
}
/// <summary>
@@ -84,9 +82,6 @@ namespace Umbraco.Core
/// <inheritdoc />
public Uri ApplicationUrl { get; private set; }
/// <inheritdoc />
public string ApplicationVirtualPath { get; }
/// <inheritdoc />
public string CurrentMigrationState { get; internal set; }
@@ -37,7 +37,7 @@ namespace Umbraco.Tests.Integration
var testHelper = new TestHelper();
var runtimeState = Mock.Of<IRuntimeState>();
var umbracoDatabaseFactory = Mock.Of<IUmbracoDatabaseFactory>();
var dbProviderFactoryCreator = Mock.Of<IDbProviderFactoryCreator>();
var dbProviderFactoryCreator = Mock.Of<IDbProviderFactoryCreator>();
var typeLoader = testHelper.GetMockedTypeLoader();
// Register in the container
@@ -45,7 +45,8 @@ namespace Umbraco.Tests.Integration
testHelper.Logger, runtimeState, testHelper.GetConfigs(), testHelper.IOHelper, testHelper.AppCaches);
composition.RegisterEssentials(testHelper.Logger, testHelper.Profiler, testHelper.Logger, testHelper.MainDom,
testHelper.AppCaches, umbracoDatabaseFactory, typeLoader, runtimeState, testHelper.GetTypeFinder(),
testHelper.IOHelper, testHelper.GetUmbracoVersion(), dbProviderFactoryCreator);
testHelper.IOHelper, testHelper.GetUmbracoVersion(), dbProviderFactoryCreator,
testHelper.GetHostingEnvironment(), testHelper.GetBackOfficeInfo());
// Cross wire - this would be called by the Host Builder at the very end of ConfigureServices
var lightInjectServiceProvider = serviceProviderFactory.CreateServiceProvider(umbracoContainer.Container);
@@ -1,38 +0,0 @@
using Microsoft.Extensions.Hosting;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Umbraco.Tests.Integration
{
/// <summary>
/// Executes arbitrary code on start/end
/// </summary>
public class DelegateHostedService : IHostedService
{
private readonly Action _start;
private readonly Action _end;
public static DelegateHostedService Create(Action start, Action end) => new DelegateHostedService(start, end);
private DelegateHostedService(Action start, Action end)
{
_start = start;
_end = end;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_start();
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
_end?.Invoke();
return Task.CompletedTask;
}
}
}
+76 -42
View File
@@ -9,6 +9,7 @@ using Moq;
using NUnit.Framework;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Composing.LightInject;
@@ -28,6 +29,13 @@ namespace Umbraco.Tests.Integration
[TestFixture]
public class RuntimeTests
{
[TearDown]
public void TearDown()
{
MyComponent.Reset();
MyComposer.Reset();
}
[OneTimeTearDown]
public void FixtureTearDown()
{
@@ -73,12 +81,11 @@ namespace Umbraco.Tests.Integration
/// Calling AddUmbracoCore to configure the container and boot the core runtime within a generic host
/// </summary>
[Test]
public void AddUmbracoCore()
public async Task AddUmbracoCore()
{
var umbracoContainer = GetUmbracoContainer(out var serviceProviderFactory);
var host = Host.CreateDefaultBuilder()
.UseTestLifetime()
var hostBuilder = new HostBuilder()
.UseUmbraco(serviceProviderFactory)
.ConfigureServices((hostContext, services) =>
{
@@ -89,38 +96,61 @@ namespace Umbraco.Tests.Integration
// Add it!
services.AddUmbracoConfiguration();
services.AddUmbracoCore(umbracoContainer, GetType().Assembly);
});
// Run tests
services.AddHostedService(x => DelegateHostedService.Create(() =>
{
// assert results
var runtimeState = umbracoContainer.GetInstance<IRuntimeState>();
var mainDom = umbracoContainer.GetInstance<IMainDom>();
var host = await hostBuilder.StartAsync();
Assert.IsTrue(mainDom.IsMainDom);
Assert.IsNull(runtimeState.BootFailedException);
Assert.AreEqual(RuntimeLevel.Install, runtimeState.Level);
Assert.IsTrue(MyComposer.IsComposed);
// assert results
var runtimeState = umbracoContainer.GetInstance<IRuntimeState>();
var mainDom = umbracoContainer.GetInstance<IMainDom>();
}, null));
})
.Build();
Assert.IsTrue(mainDom.IsMainDom);
Assert.IsNull(runtimeState.BootFailedException);
Assert.AreEqual(RuntimeLevel.Install, runtimeState.Level);
Assert.IsTrue(MyComponent.IsInit);
Assert.IsFalse(MyComponent.IsTerminated);
// NOTE: host.Run() could be used but that requires more work by manually calling IHostApplicationLifetime.StopApplication(). In these cases we don't need to wind down.
host.Start();
await host.StopAsync();
Assert.IsTrue(MyComponent.IsTerminated);
}
[Ignore("This test just shows that resolving services from the container before the host is done resolves 2 different instances")]
[Test]
public void UseUmbracoCore()
public async Task BuildServiceProvider()
{
var umbracoContainer = GetUmbracoContainer(out var serviceProviderFactory);
IHostApplicationLifetime lifetime1 = null;
var hostBuilder = new HostBuilder()
.UseUmbraco(serviceProviderFactory)
.ConfigureServices((hostContext, services) =>
{
lifetime1 = services.BuildServiceProvider().GetRequiredService<IHostApplicationLifetime>();
});
var host = await hostBuilder.StartAsync();
var lifetime2 = host.Services.GetRequiredService<IHostApplicationLifetime>();
lifetime1.StopApplication();
Assert.IsTrue(lifetime1.ApplicationStopping.IsCancellationRequested);
Assert.AreEqual(lifetime1.ApplicationStopping.IsCancellationRequested, lifetime2.ApplicationStopping.IsCancellationRequested);
}
[Test]
public async Task UseUmbracoCore()
{
var umbracoContainer = GetUmbracoContainer(out var serviceProviderFactory);
var testHelper = new TestHelper();
var host = Host.CreateDefaultBuilder()
var hostBuilder = new HostBuilder()
//TODO: Need to have a configured umb version for the runtime state
.UseLocalDb(Path.Combine(testHelper.CurrentAssemblyDirectory, "LocalDb"))
.UseTestLifetime()
//.UseTestLifetime()
.UseUmbraco(serviceProviderFactory)
.ConfigureServices((hostContext, services) =>
{
@@ -129,33 +159,26 @@ namespace Umbraco.Tests.Integration
// Add it!
services.AddUmbracoConfiguration();
services.AddUmbracoCore(umbracoContainer, GetType().Assembly);
});
// Run tests
services.AddHostedService(x => DelegateHostedService.Create(() =>
{
var runtimeState = (RuntimeState)umbracoContainer.GetInstance<IRuntimeState>();
Assert.AreEqual(RuntimeLevel.Install, runtimeState.Level);
var host = await hostBuilder.StartAsync();
var dbBuilder = umbracoContainer.GetInstance<DatabaseBuilder>();
Assert.IsNotNull(dbBuilder);
var runtimeState = (RuntimeState)umbracoContainer.GetInstance<IRuntimeState>();
Assert.AreEqual(RuntimeLevel.Install, runtimeState.Level);
var canConnect = dbBuilder.CanConnectToDatabase;
Assert.IsTrue(canConnect);
var dbBuilder = umbracoContainer.GetInstance<DatabaseBuilder>();
Assert.IsNotNull(dbBuilder);
var dbResult = dbBuilder.CreateSchemaAndData();
Assert.IsTrue(dbResult.Success);
var canConnect = dbBuilder.CanConnectToDatabase;
Assert.IsTrue(canConnect);
var dbFactory = umbracoContainer.GetInstance<IUmbracoDatabaseFactory>();
var profilingLogger = umbracoContainer.GetInstance<IProfilingLogger>();
runtimeState.DetermineRuntimeLevel(dbFactory, profilingLogger);
Assert.AreEqual(RuntimeLevel.Run, runtimeState.Level);
var dbResult = dbBuilder.CreateSchemaAndData();
Assert.IsTrue(dbResult.Success);
}, null));
})
.Build();
// NOTE: host.Run() could be used but that requires more work by manually calling IHostApplicationLifetime.StopApplication(). In these cases we don't need to wind down.
host.Start();
var dbFactory = umbracoContainer.GetInstance<IUmbracoDatabaseFactory>();
var profilingLogger = umbracoContainer.GetInstance<IProfilingLogger>();
runtimeState.DetermineRuntimeLevel(dbFactory, profilingLogger);
Assert.AreEqual(RuntimeLevel.Run, runtimeState.Level);
}
private LightInjectContainer GetUmbracoContainer(out UmbracoServiceProviderFactory serviceProviderFactory)
@@ -181,6 +204,11 @@ namespace Umbraco.Tests.Integration
IsComposed = true;
}
public static void Reset()
{
IsComposed = false;
}
public static bool IsComposed { get; private set; }
}
@@ -205,6 +233,12 @@ namespace Umbraco.Tests.Integration
{
IsTerminated = true;
}
public static void Reset()
{
IsTerminated = false;
IsInit = false;
}
}
}
@@ -80,7 +80,7 @@ namespace Umbraco.Tests.Runtimes
// create the register and the composition
var register = TestHelper.GetRegister();
var composition = new Composition(register, typeLoader, profilingLogger, runtimeState, configs, ioHelper, appCaches);
composition.RegisterEssentials(logger, profiler, profilingLogger, mainDom, appCaches, databaseFactory, typeLoader, runtimeState, typeFinder, ioHelper, umbracoVersion, TestHelper.DbProviderFactoryCreator);
composition.RegisterEssentials(logger, profiler, profilingLogger, mainDom, appCaches, databaseFactory, typeLoader, runtimeState, typeFinder, ioHelper, umbracoVersion, TestHelper.DbProviderFactoryCreator, hostingEnvironment, backOfficeInfo);
// create the core runtime and have it compose itself
var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, typeFinder);
@@ -275,7 +275,7 @@ namespace Umbraco.Tests.Runtimes
var register = TestHelper.GetRegister();
var composition = new Composition(register, typeLoader, profilingLogger, runtimeState, configs, ioHelper, appCaches);
var umbracoVersion = TestHelper.GetUmbracoVersion();
composition.RegisterEssentials(logger, profiler, profilingLogger, mainDom, appCaches, databaseFactory, typeLoader, runtimeState, typeFinder, ioHelper, umbracoVersion, TestHelper.DbProviderFactoryCreator);
composition.RegisterEssentials(logger, profiler, profilingLogger, mainDom, appCaches, databaseFactory, typeLoader, runtimeState, typeFinder, ioHelper, umbracoVersion, TestHelper.DbProviderFactoryCreator, hostingEnvironment, backOfficeInfo);
// create the core runtime and have it compose itself
var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, typeFinder);
@@ -1,5 +1,7 @@
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Umbraco.Web.BackOffice.AspNetCore
{
@@ -7,12 +9,10 @@ namespace Umbraco.Web.BackOffice.AspNetCore
{
public static IApplicationBuilder UseUmbracoBackOffice(this IApplicationBuilder app)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
if (app == null) throw new ArgumentNullException(nameof(app));
return app;
}
}
}
@@ -6,14 +6,11 @@ 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.Configuration.UmbracoSettings;
using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Logging.Serilog;
@@ -24,9 +21,13 @@ namespace Umbraco.Web.BackOffice.AspNetCore
{
public static class UmbracoBackOfficeServiceCollectionExtensions
public static class UmbracoCoreServiceCollectionExtensions
{
/// <summary>
/// Adds the Umbraco Configuration requirements
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddUmbracoConfiguration(this IServiceCollection services)
{
var serviceProvider = services.BuildServiceProvider();
@@ -45,13 +46,10 @@ namespace Umbraco.Web.BackOffice.AspNetCore
/// <summary>
/// Adds the Umbraco Back Core requirements
/// Adds the Umbraco Back Core requirements
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
/// <remarks>
/// Must be called after all services are added to the application because we are cross-wiring the container (currently)
/// </remarks>
public static IServiceCollection AddUmbracoCore(this IServiceCollection services)
{
if (!UmbracoServiceProviderFactory.IsActive)
@@ -62,6 +60,13 @@ namespace Umbraco.Web.BackOffice.AspNetCore
return services.AddUmbracoCore(umbContainer, Assembly.GetEntryAssembly());
}
/// <summary>
/// Adds the Umbraco Back Core requirements
/// </summary>
/// <param name="services"></param>
/// <param name="umbContainer"></param>
/// <param name="entryAssembly"></param>
/// <returns></returns>
public static IServiceCollection AddUmbracoCore(this IServiceCollection services, IRegister umbContainer, Assembly entryAssembly)
{
if (services is null) throw new ArgumentNullException(nameof(services));
@@ -90,6 +95,8 @@ namespace Umbraco.Web.BackOffice.AspNetCore
backOfficeInfo,
typeFinder);
hostingEnvironment.RegisterObject(new CoreRuntimeShutdown(coreRuntime));
var factory = coreRuntime.Boot(umbContainer);
return services;
@@ -124,8 +131,8 @@ namespace Umbraco.Web.BackOffice.AspNetCore
out ILogger logger, out Configs configs, out IIOHelper ioHelper, out Core.Hosting.IHostingEnvironment hostingEnvironment,
out IBackOfficeInfo backOfficeInfo, out IProfiler profiler)
{
// TODO: This isn't the best to have to resolve the services now but to avoid this will
// require quite a lot of re-work.
// TODO: Resolving services before the Host is done configuring this way means that the services resolved
// are not going to be the same instances that are going to be used within the application!
var serviceProvider = services.BuildServiceProvider();
var httpContextAccessor = serviceProvider.GetRequiredService<IHttpContextAccessor>();
@@ -162,5 +169,29 @@ namespace Umbraco.Web.BackOffice.AspNetCore
// nothing to check
}
}
/// <summary>
/// Ensures the runtime is shutdown when the application is shutting down
/// </summary>
private class CoreRuntimeShutdown : IRegisteredObject
{
public CoreRuntimeShutdown(IRuntime runtime)
{
_runtime = runtime;
}
private bool _completed = false;
private readonly IRuntime _runtime;
public void Stop(bool immediate)
{
if (!_completed)
{
_completed = true;
_runtime.Terminate();
}
}
}
}
}
@@ -72,8 +72,6 @@ namespace Umbraco.Web.Runtime
composition.Register<IRequestAccessor, AspNetRequestAccessor>(Lifetime.Singleton);
composition.Register<IHostingEnvironment, AspNetHostingEnvironment>();
composition.Register<IBackOfficeInfo, AspNetBackOfficeInfo>();
composition.Register<IUmbracoApplicationLifetime, AspNetUmbracoApplicationLifetime>(Lifetime.Singleton);
composition.Register<IPasswordHasher, AspNetPasswordHasher>();
composition.Register<IFilePermissionHelper, FilePermissionHelper>(Lifetime.Singleton);
+1 -1
View File
@@ -585,4 +585,4 @@
</None>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
</Project>