diff --git a/.gitignore b/.gitignore
index 8ff5a8ef25..5390da67dd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -166,3 +166,4 @@ build/temp/
/src/ApiDocs/api/*
/src/Umbraco.Web.UI.NetCore/wwwroot/Media/*
/src/Umbraco.Web.UI.NetCore/wwwroot/is-cache/*
+/src/Umbraco.Tests.Integration/App_Data/*
diff --git a/src/Umbraco.Core/Composing/Composition.cs b/src/Umbraco.Core/Composing/Composition.cs
index 9a696c2dc0..05c7554eab 100644
--- a/src/Umbraco.Core/Composing/Composition.cs
+++ b/src/Umbraco.Core/Composing/Composition.cs
@@ -33,13 +33,13 @@ namespace Umbraco.Core.Composing
/// An IOHelper
public Composition(IRegister register, TypeLoader typeLoader, IProfilingLogger logger, IRuntimeState runtimeState, Configs configs, IIOHelper ioHelper, AppCaches appCaches)
{
- _register = register;
- TypeLoader = typeLoader;
- Logger = logger;
- RuntimeState = runtimeState;
- Configs = configs;
- IOHelper = ioHelper;
- AppCaches = appCaches;
+ _register = register ?? throw new ArgumentNullException(nameof(register));
+ TypeLoader = typeLoader ?? throw new ArgumentNullException(nameof(typeLoader));
+ Logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ RuntimeState = runtimeState ?? throw new ArgumentNullException(nameof(runtimeState));
+ Configs = configs ?? throw new ArgumentNullException(nameof(configs));
+ IOHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper));
+ AppCaches = appCaches ?? throw new ArgumentNullException(nameof(appCaches));
}
#region Services
diff --git a/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs b/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs
index 61d7cff240..f7c81d6d7e 100644
--- a/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs
+++ b/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs
@@ -18,6 +18,7 @@ namespace Umbraco.Core.Composing
{
"Umbraco.Core",
"Umbraco.Web",
+ "Umbraco.Web.BackOffice",
"Umbraco.Infrastructure",
"Umbraco.PublishedCache.NuCache",
"Umbraco.ModelsBuilder.Embedded",
diff --git a/src/Umbraco.Core/Hosting/IApplicationShutdownRegistry.cs b/src/Umbraco.Core/Hosting/IApplicationShutdownRegistry.cs
new file mode 100644
index 0000000000..93441f1a47
--- /dev/null
+++ b/src/Umbraco.Core/Hosting/IApplicationShutdownRegistry.cs
@@ -0,0 +1,8 @@
+namespace Umbraco.Core.Hosting
+{
+ public interface IApplicationShutdownRegistry
+ {
+ void RegisterObject(IRegisteredObject registeredObject);
+ void UnregisterObject(IRegisteredObject registeredObject);
+ }
+}
diff --git a/src/Umbraco.Core/Hosting/IHostingEnvironment.cs b/src/Umbraco.Core/Hosting/IHostingEnvironment.cs
index 5b97d8e4f3..b12ffbc138 100644
--- a/src/Umbraco.Core/Hosting/IHostingEnvironment.cs
+++ b/src/Umbraco.Core/Hosting/IHostingEnvironment.cs
@@ -19,8 +19,5 @@ namespace Umbraco.Core.Hosting
Version IISVersion { get; }
string MapPath(string path);
string ToAbsolute(string virtualPath, string root);
-
- void RegisterObject(IRegisteredObject registeredObject);
- void UnregisterObject(IRegisteredObject registeredObject);
}
}
diff --git a/src/Umbraco.Core/Net/IUmbracoApplicationLifetime.cs b/src/Umbraco.Core/Net/IUmbracoApplicationLifetime.cs
index 10d5b10955..3e5361a1c1 100644
--- a/src/Umbraco.Core/Net/IUmbracoApplicationLifetime.cs
+++ b/src/Umbraco.Core/Net/IUmbracoApplicationLifetime.cs
@@ -1,5 +1,6 @@
namespace Umbraco.Net
{
+ // TODO: This shouldn't be in this namespace?
public interface IUmbracoApplicationLifetime
{
///
diff --git a/src/Umbraco.Core/Runtime/IMainDom.cs b/src/Umbraco.Core/Runtime/IMainDom.cs
index 444fc1c7d0..93a560ff7d 100644
--- a/src/Umbraco.Core/Runtime/IMainDom.cs
+++ b/src/Umbraco.Core/Runtime/IMainDom.cs
@@ -1,4 +1,5 @@
using System;
+using Umbraco.Core.Hosting;
// TODO: Can't change namespace due to breaking changes, change in netcore
namespace Umbraco.Core
@@ -16,10 +17,17 @@ namespace Umbraco.Core
/// Gets a value indicating whether the current domain is the main domain.
///
///
- /// When the first call is made to this there will generally be some logic executed to acquire a distributed lock lease.
+ /// Acquire must be called first else this will always return false
///
bool IsMainDom { get; }
+ ///
+ /// Tries to acquire the MainDom, returns true if successful else false
+ ///
+ ///
+ ///
+ bool Acquire(IApplicationShutdownRegistry hostingEnvironment);
+
///
/// Registers a resource that requires the current AppDomain to be the main domain to function.
///
diff --git a/src/Umbraco.Core/Runtime/MainDom.cs b/src/Umbraco.Core/Runtime/MainDom.cs
index 2c56852095..81db1b700d 100644
--- a/src/Umbraco.Core/Runtime/MainDom.cs
+++ b/src/Umbraco.Core/Runtime/MainDom.cs
@@ -21,7 +21,7 @@ namespace Umbraco.Core.Runtime
#region Vars
private readonly ILogger _logger;
- private readonly IHostingEnvironment _hostingEnvironment;
+ private IApplicationShutdownRegistry _hostingEnvironment;
private readonly IMainDomLock _mainDomLock;
// our own lock for local consistency
@@ -42,17 +42,25 @@ namespace Umbraco.Core.Runtime
#region Ctor
// initializes a new instance of MainDom
- public MainDom(ILogger logger, IHostingEnvironment hostingEnvironment, IMainDomLock systemLock)
+ public MainDom(ILogger logger, IMainDomLock systemLock)
{
- hostingEnvironment.RegisterObject(this);
-
_logger = logger;
- _hostingEnvironment = hostingEnvironment;
_mainDomLock = systemLock;
}
#endregion
+ public bool Acquire(IApplicationShutdownRegistry hostingEnvironment)
+ {
+ _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));
+
+ return LazyInitializer.EnsureInitialized(ref _isMainDom, ref _isInitialized, ref _locko, () =>
+ {
+ hostingEnvironment.RegisterObject(this);
+ return Acquire();
+ });
+ }
+
///
/// Registers a resource that requires the current AppDomain to be the main domain to function.
///
@@ -180,10 +188,9 @@ namespace Umbraco.Core.Runtime
/// Gets a value indicating whether the current domain is the main domain.
///
///
- /// The lazy initializer call will only call the Acquire callback when it's not been initialized, else it will just return
- /// the value from _isMainDom which means when we set _isMainDom to false again after being signaled, this will return false;
+ /// Acquire must be called first else this will always return false
///
- public bool IsMainDom => LazyInitializer.EnsureInitialized(ref _isMainDom, ref _isInitialized, ref _locko, () => Acquire());
+ public bool IsMainDom => _isMainDom;
// IRegisteredObject
void IRegisteredObject.Stop(bool immediate)
@@ -193,7 +200,7 @@ namespace Umbraco.Core.Runtime
// The web app is stopping, need to wind down
Dispose(true);
- _hostingEnvironment.UnregisterObject(this);
+ _hostingEnvironment?.UnregisterObject(this);
}
#region IDisposable Support
diff --git a/src/Umbraco.Core/Scheduling/KeepAlive.cs b/src/Umbraco.Core/Scheduling/KeepAlive.cs
index 515251b105..1c4ef075ae 100644
--- a/src/Umbraco.Core/Scheduling/KeepAlive.cs
+++ b/src/Umbraco.Core/Scheduling/KeepAlive.cs
@@ -11,18 +11,22 @@ namespace Umbraco.Web.Scheduling
{
public class KeepAlive : RecurringTaskBase
{
- private readonly IRuntimeState _runtime;
+ private readonly IRuntimeState _runtimeState;
+ private readonly IMainDom _mainDom;
private readonly IKeepAliveSettings _keepAliveSettings;
private readonly IProfilingLogger _logger;
+ private readonly IServerRegistrar _serverRegistrar;
private static HttpClient _httpClient;
public KeepAlive(IBackgroundTaskRunner runner, int delayMilliseconds, int periodMilliseconds,
- IRuntimeState runtime, IKeepAliveSettings keepAliveSettings, IProfilingLogger logger)
+ IRuntimeState runtimeState, IMainDom mainDom, IKeepAliveSettings keepAliveSettings, IProfilingLogger logger, IServerRegistrar serverRegistrar)
: base(runner, delayMilliseconds, periodMilliseconds)
{
- _runtime = runtime;
+ _runtimeState = runtimeState;
+ _mainDom = mainDom;
_keepAliveSettings = keepAliveSettings;
_logger = logger;
+ _serverRegistrar = serverRegistrar;
if (_httpClient == null)
_httpClient = new HttpClient();
}
@@ -30,7 +34,7 @@ namespace Umbraco.Web.Scheduling
public override async Task PerformRunAsync(CancellationToken token)
{
// not on replicas nor unknown role servers
- switch (_runtime.ServerRole)
+ switch (_serverRegistrar.GetCurrentServerRole())
{
case ServerRole.Replica:
_logger.Debug("Does not run on replica servers.");
@@ -41,7 +45,7 @@ namespace Umbraco.Web.Scheduling
}
// ensure we do not run if not main domain, but do NOT lock it
- if (_runtime.IsMainDom == false)
+ if (_mainDom.IsMainDom == false)
{
_logger.Debug("Does not run if not MainDom.");
return false; // do NOT repeat, going down
@@ -54,7 +58,7 @@ namespace Umbraco.Web.Scheduling
{
if (keepAlivePingUrl.Contains("{umbracoApplicationUrl}"))
{
- var umbracoAppUrl = _runtime.ApplicationUrl.ToString();
+ var umbracoAppUrl = _runtimeState.ApplicationUrl.ToString();
if (umbracoAppUrl.IsNullOrWhiteSpace())
{
_logger.Warn("No umbracoApplicationUrl for service (yet), skip.");
diff --git a/src/Umbraco.Core/Scheduling/TempFileCleanup.cs b/src/Umbraco.Core/Scheduling/TempFileCleanup.cs
index aefaf605db..90bf4ee9eb 100644
--- a/src/Umbraco.Core/Scheduling/TempFileCleanup.cs
+++ b/src/Umbraco.Core/Scheduling/TempFileCleanup.cs
@@ -14,26 +14,26 @@ namespace Umbraco.Web.Scheduling
{
private readonly DirectoryInfo[] _tempFolders;
private readonly TimeSpan _age;
- private readonly IRuntimeState _runtime;
+ private readonly IMainDom _mainDom;
private readonly IProfilingLogger _logger;
public TempFileCleanup(IBackgroundTaskRunner runner, int delayMilliseconds, int periodMilliseconds,
IEnumerable tempFolders, TimeSpan age,
- IRuntimeState runtime, IProfilingLogger logger)
+ IMainDom mainDom, IProfilingLogger logger)
: base(runner, delayMilliseconds, periodMilliseconds)
{
//SystemDirectories.TempFileUploads
_tempFolders = tempFolders.ToArray();
_age = age;
- _runtime = runtime;
+ _mainDom = mainDom;
_logger = logger;
}
public override bool PerformRun()
{
// ensure we do not run if not main domain
- if (_runtime.IsMainDom == false)
+ if (_mainDom.IsMainDom == false)
{
_logger.Debug("Does not run if not MainDom.");
return false; // do NOT repeat, going down
diff --git a/src/Umbraco.Core/Services/IRuntime.cs b/src/Umbraco.Core/Services/IRuntime.cs
index e846342dbc..4715068073 100644
--- a/src/Umbraco.Core/Services/IRuntime.cs
+++ b/src/Umbraco.Core/Services/IRuntime.cs
@@ -13,13 +13,15 @@ namespace Umbraco.Core
///
/// The application register.
/// The application factory.
- IFactory Boot(IRegister register);
+ IFactory Configure(IRegister register);
///
/// Gets the runtime state.
///
IRuntimeState State { get; }
+ void Start();
+
///
/// Terminates the runtime.
///
diff --git a/src/Umbraco.Core/Services/IRuntimeState.cs b/src/Umbraco.Core/Services/IRuntimeState.cs
index 38da246cc1..4b5e26651b 100644
--- a/src/Umbraco.Core/Services/IRuntimeState.cs
+++ b/src/Umbraco.Core/Services/IRuntimeState.cs
@@ -25,33 +25,12 @@ namespace Umbraco.Core
///
SemVersion SemanticVersion { get; }
- ///
- /// Gets a value indicating whether the application is running in debug mode.
- ///
- bool Debug { get; }
-
- ///
- /// Gets a value indicating whether the runtime is the current main domain.
- ///
- bool IsMainDom { get; }
-
- ///
- /// Get the server's current role.
- ///
- ServerRole ServerRole { get; }
-
///
/// Gets the Umbraco application url.
///
/// This is eg "http://www.example.com".
Uri ApplicationUrl { get; }
- ///
- /// Gets the Umbraco application virtual path.
- ///
- /// This is either "/" or eg "/virtual".
- string ApplicationVirtualPath { get; }
-
///
/// Gets the runtime level of execution.
///
@@ -77,6 +56,5 @@ namespace Umbraco.Core
///
BootFailedException BootFailedException { get; }
- IMainDom MainDom { get; }
}
}
diff --git a/src/Umbraco.Core/SimpleMainDom.cs b/src/Umbraco.Core/SimpleMainDom.cs
index 87cc7bcff1..e6bdda67d7 100644
--- a/src/Umbraco.Core/SimpleMainDom.cs
+++ b/src/Umbraco.Core/SimpleMainDom.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Umbraco.Core.Hosting;
namespace Umbraco.Core
{
@@ -16,6 +17,9 @@ namespace Umbraco.Core
///
public bool IsMainDom { get; private set; } = true;
+ // always acquire
+ public bool Acquire(IApplicationShutdownRegistry hostingEnvironment) => true;
+
///
public bool Register(Action release, int weight = 100)
=> Register(null, release, weight);
diff --git a/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs
index 78b9589a2e..70b79fbeb0 100644
--- a/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs
+++ b/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs
@@ -28,17 +28,18 @@ namespace Umbraco.Web
private readonly IRequestAccessor _requestAccessor;
public BatchedDatabaseServerMessenger(
- IRuntimeState runtime,
+ IMainDom mainDom,
IUmbracoDatabaseFactory databaseFactory,
IScopeProvider scopeProvider,
ISqlContext sqlContext,
IProfilingLogger proflog,
+ IServerRegistrar serverRegistrar,
DatabaseServerMessengerOptions options,
IHostingEnvironment hostingEnvironment,
CacheRefresherCollection cacheRefreshers,
IRequestCache requestCache,
IRequestAccessor requestAccessor)
- : base(runtime, scopeProvider, sqlContext, proflog, true, options, hostingEnvironment, cacheRefreshers)
+ : base(mainDom, scopeProvider, sqlContext, proflog, serverRegistrar, true, options, hostingEnvironment, cacheRefreshers)
{
_databaseFactory = databaseFactory;
_requestCache = requestCache;
diff --git a/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs b/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs
index 2a24e6f318..6c745f3877 100644
--- a/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs
+++ b/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs
@@ -91,7 +91,6 @@ namespace Umbraco.Web.Compose
private readonly BackgroundTaskRunner _processTaskRunner;
private bool _started;
private IBackgroundTask[] _tasks;
- private IndexRebuilder _indexRebuilder;
private readonly IRequestAccessor _requestAccessor;
public DatabaseServerRegistrarAndMessengerComponent(
@@ -100,14 +99,12 @@ namespace Umbraco.Web.Compose
IServerMessenger serverMessenger,
IServerRegistrationService registrationService,
ILogger logger,
- IHostingEnvironment hostingEnvironment,
- IndexRebuilder indexRebuilder,
+ IApplicationShutdownRegistry hostingEnvironment,
IRequestAccessor requestAccessor)
{
_runtime = runtime;
_logger = logger;
_registrationService = registrationService;
- _indexRebuilder = indexRebuilder;
_requestAccessor = requestAccessor;
// create task runner for DatabaseServerRegistrar
diff --git a/src/Umbraco.Infrastructure/Compose/ManifestWatcherComponent.cs b/src/Umbraco.Infrastructure/Compose/ManifestWatcherComponent.cs
index d4e22bbfde..a2ee650595 100644
--- a/src/Umbraco.Infrastructure/Compose/ManifestWatcherComponent.cs
+++ b/src/Umbraco.Infrastructure/Compose/ManifestWatcherComponent.cs
@@ -10,7 +10,7 @@ namespace Umbraco.Core.Compose
{
public sealed class ManifestWatcherComponent : IComponent
{
- private readonly IRuntimeState _runtimeState;
+ private readonly IHostingEnvironment _hosting;
private readonly ILogger _logger;
private readonly IIOHelper _ioHelper;
private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime;
@@ -19,9 +19,9 @@ namespace Umbraco.Core.Compose
// package.manifest chances and restarts the application on any change
private ManifestWatcher _mw;
- public ManifestWatcherComponent(IRuntimeState runtimeState, ILogger logger, IIOHelper ioHelper, IUmbracoApplicationLifetime umbracoApplicationLifetime)
+ public ManifestWatcherComponent(IHostingEnvironment hosting, ILogger logger, IIOHelper ioHelper, IUmbracoApplicationLifetime umbracoApplicationLifetime)
{
- _runtimeState = runtimeState;
+ _hosting = hosting;
_logger = logger;
_ioHelper = ioHelper;
_umbracoApplicationLifetime = umbracoApplicationLifetime;
@@ -29,7 +29,7 @@ namespace Umbraco.Core.Compose
public void Initialize()
{
- if (_runtimeState.Debug == false) return;
+ if (_hosting.IsDebugMode == false) return;
//if (ApplicationContext.Current.IsConfigured == false || GlobalSettings.DebugMode == false)
// return;
diff --git a/src/Umbraco.Infrastructure/Composing/HostBuilderExtensions.cs b/src/Umbraco.Infrastructure/Composing/HostBuilderExtensions.cs
index d5355c136f..2099778185 100644
--- a/src/Umbraco.Infrastructure/Composing/HostBuilderExtensions.cs
+++ b/src/Umbraco.Infrastructure/Composing/HostBuilderExtensions.cs
@@ -13,8 +13,9 @@ namespace Umbraco.Core.Composing
///
///
public static IHostBuilder UseUmbraco(this IHostBuilder builder)
- {
- return builder.UseServiceProviderFactory(new UmbracoServiceProviderFactory());
- }
+ => builder.UseUmbraco(new UmbracoServiceProviderFactory());
+
+ public static IHostBuilder UseUmbraco(this IHostBuilder builder, UmbracoServiceProviderFactory umbracoServiceProviderFactory)
+ => builder.UseServiceProviderFactory(umbracoServiceProviderFactory);
}
}
diff --git a/src/Umbraco.Infrastructure/CompositionExtensions_Essentials.cs b/src/Umbraco.Infrastructure/CompositionExtensions_Essentials.cs
index eb74d37590..02e5a6f5ee 100644
--- a/src/Umbraco.Infrastructure/CompositionExtensions_Essentials.cs
+++ b/src/Umbraco.Infrastructure/CompositionExtensions_Essentials.cs
@@ -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
///
/// Registers essential services.
///
+ ///
+ /// These services are all either created by the runtime or used to construct the runtime
+ ///
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().BulkSqlInsertProvider);
+ composition.RegisterUnique(hostingEnvironment);
+ composition.RegisterUnique(backOfficeInfo);
}
}
}
diff --git a/src/Umbraco.Infrastructure/Intall/InstallHelper.cs b/src/Umbraco.Infrastructure/Intall/InstallHelper.cs
index a5b4f71d8e..cf4b174cde 100644
--- a/src/Umbraco.Infrastructure/Intall/InstallHelper.cs
+++ b/src/Umbraco.Infrastructure/Intall/InstallHelper.cs
@@ -9,10 +9,10 @@ using Umbraco.Core.Cookie;
using Umbraco.Core.Logging;
using Umbraco.Core.Migrations.Install;
using Umbraco.Core.Models;
+using Umbraco.Net;
using Umbraco.Core.Persistence;
using Umbraco.Core.Serialization;
using Umbraco.Core.Services;
-using Umbraco.Net;
using Umbraco.Web.Install.Models;
namespace Umbraco.Web.Install
diff --git a/src/Umbraco.Infrastructure/Intall/InstallSteps/StarterKitInstallStep.cs b/src/Umbraco.Infrastructure/Intall/InstallSteps/StarterKitInstallStep.cs
index cc269408f4..4e14da30b7 100644
--- a/src/Umbraco.Infrastructure/Intall/InstallSteps/StarterKitInstallStep.cs
+++ b/src/Umbraco.Infrastructure/Intall/InstallSteps/StarterKitInstallStep.cs
@@ -2,8 +2,8 @@
using System.IO;
using System.Linq;
using System.Threading.Tasks;
-using Umbraco.Core.Services;
using Umbraco.Net;
+using Umbraco.Core.Services;
using Umbraco.Web.Install.Models;
namespace Umbraco.Web.Install.InstallSteps
diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs
index 17192fd69b..8d5922028c 100644
--- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs
+++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs
@@ -46,7 +46,7 @@ namespace Umbraco.Core.Migrations.Install
IIOHelper ioHelper,
IUmbracoVersion umbracoVersion,
IDbProviderFactoryCreator dbProviderFactoryCreator,
- IConfigManipulator configManipulator)
+ IConfigManipulator configManipulator)
{
_scopeProvider = scopeProvider;
_globalSettings = globalSettings;
diff --git a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs
index 9318b223df..1bf954e4c1 100644
--- a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs
+++ b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs
@@ -44,7 +44,7 @@ namespace Umbraco.Core.Runtime
public override void Compose(Composition composition)
{
base.Compose(composition);
-
+
// composers
composition
.ComposeRepositories()
@@ -120,10 +120,11 @@ namespace Umbraco.Core.Runtime
// project
composition.RegisterUnique(factory
=> new DatabaseServerMessenger(
- factory.GetInstance(),
+ factory.GetInstance(),
factory.GetInstance(),
factory.GetInstance(),
factory.GetInstance(),
+ factory.GetInstance(),
true, new DatabaseServerMessengerOptions(),
factory.GetInstance(),
factory.GetInstance()
@@ -176,6 +177,8 @@ namespace Umbraco.Core.Runtime
// Grid config is not a real config file as we know them
composition.RegisterUnique();
+ // Config manipulator
+ composition.RegisterUnique();
}
}
}
diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
index 6c1a06ab6b..139e9e9b67 100644
--- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
+++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
-using System.Reflection;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
@@ -12,7 +11,6 @@ using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Mappers;
-using Umbraco.Core.Sync;
namespace Umbraco.Core.Runtime
{
@@ -25,12 +23,11 @@ namespace Umbraco.Core.Runtime
{
private ComponentCollection _components;
private IFactory _factory;
- private RuntimeState _state;
+ private readonly RuntimeState _state;
private readonly IUmbracoBootPermissionChecker _umbracoBootPermissionChecker;
private readonly IGlobalSettings _globalSettings;
private readonly IConnectionStrings _connectionStrings;
-
public CoreRuntime(
Configs configs,
IUmbracoVersion umbracoVersion,
@@ -65,11 +62,7 @@ namespace Umbraco.Core.Runtime
// runtime state
// beware! must use '() => _factory.GetInstance()' and NOT '_factory.GetInstance'
// as the second one captures the current value (null) and therefore fails
- _state = new RuntimeState(Logger,
- Configs.Global(),
- new Lazy(() => mainDom),
- new Lazy(() => _factory.GetInstance()),
- UmbracoVersion,HostingEnvironment, BackOfficeInfo)
+ _state = new RuntimeState(Logger, Configs.Global(), UmbracoVersion, BackOfficeInfo)
{
Level = RuntimeLevel.Boot
};
@@ -81,13 +74,13 @@ namespace Umbraco.Core.Runtime
protected ILogger Logger { get; }
protected IBackOfficeInfo BackOfficeInfo { get; }
+
public IDbProviderFactoryCreator DbProviderFactoryCreator { get; }
- //public IBulkSqlInsertProvider BulkSqlInsertProvider { get; }
///
/// Gets the profiler.
///
- protected IProfiler Profiler { get; set; }
+ protected IProfiler Profiler { get; }
///
/// Gets the profiling logger.
@@ -110,11 +103,13 @@ namespace Umbraco.Core.Runtime
///
public IRuntimeState State => _state;
- public IMainDom MainDom { get; private set; }
+ public IMainDom MainDom { get; }
///
- public virtual IFactory Boot(IRegister register)
+ public virtual IFactory Configure(IRegister register)
{
+ if (register is null) throw new ArgumentNullException(nameof(register));
+
// create and register the essential services
// ie the bare minimum required to boot
@@ -139,25 +134,24 @@ namespace Umbraco.Core.Runtime
// application environment
ConfigureUnhandledException();
- ConfigureApplicationRootPath();
-
- Boot(register, timer);
+ return _factory = Configure(register, timer);
}
-
- return _factory;
}
///
- /// Boots the runtime within a timer.
+ /// Configure the runtime within a timer.
///
- protected virtual IFactory Boot(IRegister register, DisposableTimer timer)
+ private IFactory Configure(IRegister register, DisposableTimer timer)
{
+ if (register is null) throw new ArgumentNullException(nameof(register));
+ if (timer is null) throw new ArgumentNullException(nameof(timer));
+
Composition composition = null;
+ IFactory factory = null;
try
{
- // throws if not full-trust
- _umbracoBootPermissionChecker.ThrowIfNotPermissions();
+
// run handlers
RuntimeOptions.DoRuntimeBoot(ProfilingLogger);
@@ -171,31 +165,12 @@ 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()' and NOT '_factory.GetInstance'
- // as the second one captures the current value (null) and therefore fails
- _state = new RuntimeState(Logger,
- Configs.Global(),
- new Lazy(() => _factory.GetInstance()),
- new Lazy(() => _factory.GetInstance()),
- 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);
-
- // register runtime-level services
- // there should be none, really - this is here "just in case"
- Compose(composition);
-
- // acquire the main domain - if this fails then anything that should be registered with MainDom will not operate
- AcquireMainDom(MainDom);
+ // register ourselves (TODO: Should we put this in RegisterEssentials?)
+ composition.Register(_ => this, Lifetime.Singleton);
// determine our runtime level
DetermineRuntimeLevel(databaseFactory, ProfilingLogger);
@@ -213,13 +188,7 @@ namespace Umbraco.Core.Runtime
composers.Compose();
// create the factory
- _factory = composition.CreateFactory();
-
- // create & initialize the components
- _components = _factory.GetInstance();
- _components.Initialize();
-
-
+ factory = composition.CreateFactory();
}
catch (Exception e)
{
@@ -236,11 +205,11 @@ namespace Umbraco.Core.Runtime
// if something goes wrong above, we may end up with no factory
// meaning nothing can get the runtime state, etc - so let's try
// to make sure we have a factory
- if (_factory == null)
+ if (factory == null)
{
try
{
- _factory = composition?.CreateFactory();
+ factory = composition?.CreateFactory();
}
catch { /* yea */ }
}
@@ -254,7 +223,29 @@ namespace Umbraco.Core.Runtime
// throw a BootFailedException for every requests.
}
- return _factory;
+ return factory;
+ }
+
+ public void Start()
+ {
+ // throws if not full-trust
+ _umbracoBootPermissionChecker.ThrowIfNotPermissions();
+
+ ConfigureApplicationRootPath();
+
+ // run handlers
+ RuntimeOptions.DoRuntimeEssentials(_factory);
+
+ var hostingEnvironmentLifetime = _factory.TryGetInstance();
+ if (hostingEnvironmentLifetime == null)
+ throw new InvalidOperationException($"An instance of {typeof(IApplicationShutdownRegistry)} could not be resolved from the container, ensure that one if registered in your runtime before calling {nameof(IRuntime)}.{nameof(Start)}");
+
+ // acquire the main domain - if this fails then anything that should be registered with MainDom will not operate
+ AcquireMainDom(MainDom, _factory.GetInstance());
+
+ // create & initialize the components
+ _components = _factory.GetInstance();
+ _components.Initialize();
}
protected virtual void ConfigureUnhandledException()
@@ -281,13 +272,13 @@ namespace Umbraco.Core.Runtime
IOHelper.SetRootDirectory(path);
}
- private bool AcquireMainDom(IMainDom mainDom)
+ private bool AcquireMainDom(IMainDom mainDom, IApplicationShutdownRegistry applicationShutdownRegistry)
{
using (var timer = ProfilingLogger.DebugDuration("Acquiring MainDom.", "Acquired."))
{
try
{
- return mainDom.IsMainDom;
+ return mainDom.Acquire(applicationShutdownRegistry);
}
catch
{
@@ -346,12 +337,6 @@ namespace Umbraco.Core.Runtime
_components?.Terminate();
}
- ///
- /// Composes the runtime.
- ///
- public virtual void Compose(Composition composition)
- {
- }
#region Getters
@@ -392,5 +377,6 @@ namespace Umbraco.Core.Runtime
#endregion
+
}
}
diff --git a/src/Umbraco.Infrastructure/Runtime/WebRuntime.cs b/src/Umbraco.Infrastructure/Runtime/WebRuntime.cs
index 2f45a3e437..fc2a019023 100644
--- a/src/Umbraco.Infrastructure/Runtime/WebRuntime.cs
+++ b/src/Umbraco.Infrastructure/Runtime/WebRuntime.cs
@@ -40,7 +40,7 @@ namespace Umbraco.Web.Runtime
}
///
- public override IFactory Boot(IRegister register)
+ public override IFactory Configure(IRegister register)
{
var profilingLogger = new ProfilingLogger(Logger, Profiler);
@@ -57,7 +57,7 @@ namespace Umbraco.Web.Runtime
NetworkHelper.MachineName);
Logger.Debug("Runtime: {Runtime}", GetType().FullName);
- var factory = base.Boot(register);
+ var factory = base.Configure(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
diff --git a/src/Umbraco.Infrastructure/RuntimeOptions.cs b/src/Umbraco.Infrastructure/RuntimeOptions.cs
index 23abd474a4..562a7e3c5c 100644
--- a/src/Umbraco.Infrastructure/RuntimeOptions.cs
+++ b/src/Umbraco.Infrastructure/RuntimeOptions.cs
@@ -16,7 +16,7 @@ namespace Umbraco.Core
public static class RuntimeOptions
{
private static List> _onBoot;
- private static List> _onEssentials;
+ private static List> _onEssentials;
///
/// Executes the RuntimeBoot handlers.
@@ -33,13 +33,13 @@ namespace Umbraco.Core
///
/// Executes the RuntimeEssentials handlers.
///
- internal static void DoRuntimeEssentials(Composition composition, AppCaches appCaches, TypeLoader typeLoader, IUmbracoDatabaseFactory databaseFactory)
+ internal static void DoRuntimeEssentials(IFactory factory)
{
if (_onEssentials== null)
return;
foreach (var action in _onEssentials)
- action(composition, appCaches, typeLoader, databaseFactory);
+ action(factory);
}
///
@@ -64,10 +64,10 @@ namespace Umbraco.Core
/// essential things (AppCaches, a TypeLoader, and a database factory) but
/// before anything else.
///
- public static void OnRuntimeEssentials(Action action)
+ public static void OnRuntimeEssentials(Action action)
{
if (_onEssentials == null)
- _onEssentials = new List>();
+ _onEssentials = new List>();
_onEssentials.Add(action);
}
}
diff --git a/src/Umbraco.Infrastructure/RuntimeState.cs b/src/Umbraco.Infrastructure/RuntimeState.cs
index eadb9fed21..e0099c5e7e 100644
--- a/src/Umbraco.Infrastructure/RuntimeState.cs
+++ b/src/Umbraco.Infrastructure/RuntimeState.cs
@@ -22,46 +22,22 @@ namespace Umbraco.Core
private readonly ILogger _logger;
private readonly IGlobalSettings _globalSettings;
private readonly ConcurrentHashSet _applicationUrls = new ConcurrentHashSet();
- private readonly Lazy _mainDom;
- private readonly Lazy _serverRegistrar;
private readonly IUmbracoVersion _umbracoVersion;
- private readonly IHostingEnvironment _hostingEnvironment;
private readonly IBackOfficeInfo _backOfficeInfo;
///
/// Initializes a new instance of the class.
///
public RuntimeState(ILogger logger, IGlobalSettings globalSettings,
- Lazy mainDom, Lazy serverRegistrar, IUmbracoVersion umbracoVersion,
- IHostingEnvironment hostingEnvironment,
+ IUmbracoVersion umbracoVersion,
IBackOfficeInfo backOfficeInfo)
{
_logger = logger;
_globalSettings = globalSettings;
- _mainDom = mainDom;
- _serverRegistrar = serverRegistrar;
_umbracoVersion = umbracoVersion;
- _hostingEnvironment = hostingEnvironment;
_backOfficeInfo = backOfficeInfo;
-
- ApplicationVirtualPath = _hostingEnvironment.ApplicationVirtualPath;
}
- ///
- /// Gets the server registrar.
- ///
- ///
- /// This is NOT exposed in the interface.
- ///
- private IServerRegistrar ServerRegistrar => _serverRegistrar.Value;
-
- ///
- /// Gets the application MainDom.
- ///
- ///
- /// This is NOT exposed in the interface as MainDom is internal.
- ///
- public IMainDom MainDom => _mainDom.Value;
///
public Version Version => _umbracoVersion.Current;
@@ -72,26 +48,14 @@ namespace Umbraco.Core
///
public SemVersion SemanticVersion => _umbracoVersion.SemanticVersion;
- ///
- public bool Debug => _hostingEnvironment.IsDebugMode;
-
- ///
- public bool IsMainDom => MainDom.IsMainDom;
-
- ///
- public ServerRole ServerRole => ServerRegistrar.GetCurrentServerRole();
-
///
public Uri ApplicationUrl { get; private set; }
///
- public string ApplicationVirtualPath { get; }
+ public string CurrentMigrationState { get; private set; }
///
- public string CurrentMigrationState { get; internal set; }
-
- ///
- public string FinalMigrationState { get; internal set; }
+ public string FinalMigrationState { get; private set; }
///
public RuntimeLevel Level { get; internal set; } = RuntimeLevel.Unknown;
@@ -253,7 +217,7 @@ namespace Umbraco.Core
Reason = RuntimeLevelReason.UpgradeMigrations;
}
- protected virtual bool EnsureUmbracoUpgradeState(IUmbracoDatabaseFactory databaseFactory, ILogger logger)
+ private bool EnsureUmbracoUpgradeState(IUmbracoDatabaseFactory databaseFactory, ILogger logger)
{
var upgrader = new Upgrader(new UmbracoPlan(_umbracoVersion, _globalSettings));
var stateValueKey = upgrader.StateValueKey;
diff --git a/src/Umbraco.Infrastructure/Scheduling/BackgroundTaskRunner.cs b/src/Umbraco.Infrastructure/Scheduling/BackgroundTaskRunner.cs
index 0b5b81319f..2cda289591 100644
--- a/src/Umbraco.Infrastructure/Scheduling/BackgroundTaskRunner.cs
+++ b/src/Umbraco.Infrastructure/Scheduling/BackgroundTaskRunner.cs
@@ -81,7 +81,7 @@ namespace Umbraco.Web.Scheduling
private readonly string _logPrefix;
private readonly BackgroundTaskRunnerOptions _options;
private readonly ILogger _logger;
- private readonly IHostingEnvironment _hostingEnvironment;
+ private readonly IApplicationShutdownRegistry _hostingEnvironment;
private readonly object _locker = new object();
private readonly BufferBlock _tasks = new BufferBlock(new DataflowBlockOptions());
@@ -105,7 +105,7 @@ namespace Umbraco.Web.Scheduling
/// A logger.
/// The hosting environment
/// An optional main domain hook.
- public BackgroundTaskRunner(ILogger logger, IHostingEnvironment hostingEnvironment, MainDomHook hook = null)
+ public BackgroundTaskRunner(ILogger logger, IApplicationShutdownRegistry hostingEnvironment, MainDomHook hook = null)
: this(typeof(T).FullName, new BackgroundTaskRunnerOptions(), logger, hostingEnvironment, hook)
{ }
@@ -116,7 +116,7 @@ namespace Umbraco.Web.Scheduling
/// A logger.
/// The hosting environment
/// An optional main domain hook.
- public BackgroundTaskRunner(string name, ILogger logger, IHostingEnvironment hostingEnvironment, MainDomHook hook = null)
+ public BackgroundTaskRunner(string name, ILogger logger, IApplicationShutdownRegistry hostingEnvironment, MainDomHook hook = null)
: this(name, new BackgroundTaskRunnerOptions(), logger, hostingEnvironment, hook)
{ }
@@ -127,7 +127,7 @@ namespace Umbraco.Web.Scheduling
/// A logger.
/// The hosting environment
/// An optional main domain hook.
- public BackgroundTaskRunner(BackgroundTaskRunnerOptions options, ILogger logger, IHostingEnvironment hostingEnvironment, MainDomHook hook = null)
+ public BackgroundTaskRunner(BackgroundTaskRunnerOptions options, ILogger logger, IApplicationShutdownRegistry hostingEnvironment, MainDomHook hook = null)
: this(typeof(T).FullName, options, logger, hostingEnvironment, hook)
{ }
@@ -139,7 +139,7 @@ namespace Umbraco.Web.Scheduling
/// A logger.
/// The hosting environment
/// An optional main domain hook.
- public BackgroundTaskRunner(string name, BackgroundTaskRunnerOptions options, ILogger logger, IHostingEnvironment hostingEnvironment, MainDomHook hook = null)
+ public BackgroundTaskRunner(string name, BackgroundTaskRunnerOptions options, ILogger logger, IApplicationShutdownRegistry hostingEnvironment, MainDomHook hook = null)
{
_options = options ?? throw new ArgumentNullException(nameof(options));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
diff --git a/src/Umbraco.Infrastructure/Scheduling/HealthCheckNotifier.cs b/src/Umbraco.Infrastructure/Scheduling/HealthCheckNotifier.cs
index 04c1571b3b..e7692b851a 100644
--- a/src/Umbraco.Infrastructure/Scheduling/HealthCheckNotifier.cs
+++ b/src/Umbraco.Infrastructure/Scheduling/HealthCheckNotifier.cs
@@ -11,22 +11,27 @@ namespace Umbraco.Web.Scheduling
{
public class HealthCheckNotifier : RecurringTaskBase
{
- private readonly IRuntimeState _runtimeState;
+ private readonly IMainDom _mainDom;
private readonly HealthCheckCollection _healthChecks;
private readonly HealthCheckNotificationMethodCollection _notifications;
private readonly IProfilingLogger _logger;
private readonly IHealthChecksSettings _healthChecksSettingsConfig;
+ private readonly IServerRegistrar _serverRegistrar;
+ private readonly IRuntimeState _runtimeState;
public HealthCheckNotifier(IBackgroundTaskRunner runner, int delayMilliseconds, int periodMilliseconds,
HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications,
- IRuntimeState runtimeState, IProfilingLogger logger, IHealthChecksSettings healthChecksSettingsConfig)
+ IMainDom mainDom, IProfilingLogger logger, IHealthChecksSettings healthChecksSettingsConfig, IServerRegistrar serverRegistrar,
+ IRuntimeState runtimeState)
: base(runner, delayMilliseconds, periodMilliseconds)
{
_healthChecks = healthChecks;
_notifications = notifications;
- _runtimeState = runtimeState;
+ _mainDom = mainDom;
_logger = logger;
_healthChecksSettingsConfig = healthChecksSettingsConfig;
+ _serverRegistrar = serverRegistrar;
+ _runtimeState = runtimeState;
}
public override async Task PerformRunAsync(CancellationToken token)
@@ -34,7 +39,7 @@ namespace Umbraco.Web.Scheduling
if (_runtimeState.Level != RuntimeLevel.Run)
return true; // repeat...
- switch (_runtimeState.ServerRole)
+ switch (_serverRegistrar.GetCurrentServerRole())
{
case ServerRole.Replica:
_logger.Debug("Does not run on replica servers.");
@@ -45,7 +50,7 @@ namespace Umbraco.Web.Scheduling
}
// ensure we do not run if not main domain, but do NOT lock it
- if (_runtimeState.IsMainDom == false)
+ if (_mainDom.IsMainDom == false)
{
_logger.Debug("Does not run if not MainDom.");
return false; // do NOT repeat, going down
diff --git a/src/Umbraco.Infrastructure/Scheduling/LogScrubber.cs b/src/Umbraco.Infrastructure/Scheduling/LogScrubber.cs
index 563d79a193..aaf09dbe8f 100644
--- a/src/Umbraco.Infrastructure/Scheduling/LogScrubber.cs
+++ b/src/Umbraco.Infrastructure/Scheduling/LogScrubber.cs
@@ -11,17 +11,19 @@ namespace Umbraco.Web.Scheduling
public class LogScrubber : RecurringTaskBase
{
- private readonly IRuntimeState _runtime;
+ private readonly IMainDom _mainDom;
+ private readonly IServerRegistrar _serverRegistrar;
private readonly IAuditService _auditService;
private readonly ILoggingSettings _settings;
private readonly IProfilingLogger _logger;
private readonly IScopeProvider _scopeProvider;
public LogScrubber(IBackgroundTaskRunner runner, int delayMilliseconds, int periodMilliseconds,
- IRuntimeState runtime, IAuditService auditService, ILoggingSettings settings, IScopeProvider scopeProvider, IProfilingLogger logger)
+ IMainDom mainDom, IServerRegistrar serverRegistrar, IAuditService auditService, ILoggingSettings settings, IScopeProvider scopeProvider, IProfilingLogger logger)
: base(runner, delayMilliseconds, periodMilliseconds)
{
- _runtime = runtime;
+ _mainDom = mainDom;
+ _serverRegistrar = serverRegistrar;
_auditService = auditService;
_settings = settings;
_scopeProvider = scopeProvider;
@@ -53,7 +55,7 @@ namespace Umbraco.Web.Scheduling
public override bool PerformRun()
{
- switch (_runtime.ServerRole)
+ switch (_serverRegistrar.GetCurrentServerRole())
{
case ServerRole.Replica:
_logger.Debug("Does not run on replica servers.");
@@ -64,7 +66,7 @@ namespace Umbraco.Web.Scheduling
}
// ensure we do not run if not main domain, but do NOT lock it
- if (_runtime.IsMainDom == false)
+ if (_mainDom.IsMainDom == false)
{
_logger.Debug("Does not run if not MainDom.");
return false; // do NOT repeat, going down
diff --git a/src/Umbraco.Infrastructure/Scheduling/ScheduledPublishing.cs b/src/Umbraco.Infrastructure/Scheduling/ScheduledPublishing.cs
index b074704033..fea16999fd 100644
--- a/src/Umbraco.Infrastructure/Scheduling/ScheduledPublishing.cs
+++ b/src/Umbraco.Infrastructure/Scheduling/ScheduledPublishing.cs
@@ -10,16 +10,20 @@ namespace Umbraco.Web.Scheduling
public class ScheduledPublishing : RecurringTaskBase
{
private readonly IRuntimeState _runtime;
+ private readonly IMainDom _mainDom;
+ private readonly IServerRegistrar _serverRegistrar;
private readonly IContentService _contentService;
private readonly IUmbracoContextFactory _umbracoContextFactory;
private readonly ILogger _logger;
private readonly IServerMessenger _serverMessenger;
public ScheduledPublishing(IBackgroundTaskRunner runner, int delayMilliseconds, int periodMilliseconds,
- IRuntimeState runtime, IContentService contentService, IUmbracoContextFactory umbracoContextFactory, ILogger logger, IServerMessenger serverMessenger)
+ IRuntimeState runtime, IMainDom mainDom, IServerRegistrar serverRegistrar, IContentService contentService, IUmbracoContextFactory umbracoContextFactory, ILogger logger, IServerMessenger serverMessenger)
: base(runner, delayMilliseconds, periodMilliseconds)
{
_runtime = runtime;
+ _mainDom = mainDom;
+ _serverRegistrar = serverRegistrar;
_contentService = contentService;
_umbracoContextFactory = umbracoContextFactory;
_logger = logger;
@@ -31,7 +35,7 @@ namespace Umbraco.Web.Scheduling
if (Suspendable.ScheduledPublishing.CanRun == false)
return true; // repeat, later
- switch (_runtime.ServerRole)
+ switch (_serverRegistrar.GetCurrentServerRole())
{
case ServerRole.Replica:
_logger.Debug("Does not run on replica servers.");
@@ -42,7 +46,7 @@ namespace Umbraco.Web.Scheduling
}
// ensure we do not run if not main domain, but do NOT lock it
- if (_runtime.IsMainDom == false)
+ if (_mainDom.IsMainDom == false)
{
_logger.Debug("Does not run if not MainDom.");
return false; // do NOT repeat, going down
diff --git a/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs b/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs
index c8ff67579a..30d0bc7e4a 100644
--- a/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs
+++ b/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs
@@ -26,10 +26,12 @@ namespace Umbraco.Web.Scheduling
private const int OneHourMilliseconds = 3600000;
private readonly IRuntimeState _runtime;
+ private readonly IMainDom _mainDom;
+ private readonly IServerRegistrar _serverRegistrar;
private readonly IContentService _contentService;
private readonly IAuditService _auditService;
private readonly IProfilingLogger _logger;
- private readonly IHostingEnvironment _hostingEnvironment;
+ private readonly IApplicationShutdownRegistry _hostingEnvironment;
private readonly IScopeProvider _scopeProvider;
private readonly HealthCheckCollection _healthChecks;
private readonly HealthCheckNotificationMethodCollection _notifications;
@@ -43,7 +45,6 @@ namespace Umbraco.Web.Scheduling
private BackgroundTaskRunner _keepAliveRunner;
private BackgroundTaskRunner _publishingRunner;
- private BackgroundTaskRunner _tasksRunner;
private BackgroundTaskRunner _scrubberRunner;
private BackgroundTaskRunner _fileCleanupRunner;
private BackgroundTaskRunner _healthCheckRunner;
@@ -52,15 +53,17 @@ namespace Umbraco.Web.Scheduling
private object _locker = new object();
private IBackgroundTask[] _tasks;
- public SchedulerComponent(IRuntimeState runtime,
+ public SchedulerComponent(IRuntimeState runtime, IMainDom mainDom, IServerRegistrar serverRegistrar,
IContentService contentService, IAuditService auditService,
HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications,
IScopeProvider scopeProvider, IUmbracoContextFactory umbracoContextFactory, IProfilingLogger logger,
- IHostingEnvironment hostingEnvironment, IHealthChecksSettings healthChecksSettingsConfig,
+ IApplicationShutdownRegistry hostingEnvironment, IHealthChecksSettings healthChecksSettingsConfig,
IIOHelper ioHelper, IServerMessenger serverMessenger, IRequestAccessor requestAccessor,
ILoggingSettings loggingSettings, IKeepAliveSettings keepAliveSettings)
{
_runtime = runtime;
+ _mainDom = mainDom;
+ _serverRegistrar = serverRegistrar;
_contentService = contentService;
_auditService = auditService;
_scopeProvider = scopeProvider;
@@ -83,7 +86,6 @@ namespace Umbraco.Web.Scheduling
// backgrounds runners are web aware, if the app domain dies, these tasks will wind down correctly
_keepAliveRunner = new BackgroundTaskRunner("KeepAlive", _logger, _hostingEnvironment);
_publishingRunner = new BackgroundTaskRunner("ScheduledPublishing", _logger, _hostingEnvironment);
- _tasksRunner = new BackgroundTaskRunner("ScheduledTasks", _logger, _hostingEnvironment);
_scrubberRunner = new BackgroundTaskRunner("LogScrubber", _logger, _hostingEnvironment);
_fileCleanupRunner = new BackgroundTaskRunner("TempFileCleanup", _logger, _hostingEnvironment);
_healthCheckRunner = new BackgroundTaskRunner("HealthCheckNotifier", _logger, _hostingEnvironment);
@@ -138,7 +140,7 @@ namespace Umbraco.Web.Scheduling
{
// ping/keepalive
// on all servers
- var task = new KeepAlive(_keepAliveRunner, DefaultDelayMilliseconds, FiveMinuteMilliseconds, _runtime, keepAliveSettings, _logger);
+ var task = new KeepAlive(_keepAliveRunner, DefaultDelayMilliseconds, FiveMinuteMilliseconds, _runtime, _mainDom, keepAliveSettings, _logger, _serverRegistrar);
_keepAliveRunner.TryAdd(task);
return task;
}
@@ -147,7 +149,7 @@ namespace Umbraco.Web.Scheduling
{
// scheduled publishing/unpublishing
// install on all, will only run on non-replica servers
- var task = new ScheduledPublishing(_publishingRunner, DefaultDelayMilliseconds, OneMinuteMilliseconds, _runtime, _contentService, _umbracoContextFactory, _logger, _serverMessenger);
+ var task = new ScheduledPublishing(_publishingRunner, DefaultDelayMilliseconds, OneMinuteMilliseconds, _runtime, _mainDom, _serverRegistrar, _contentService, _umbracoContextFactory, _logger, _serverMessenger);
_publishingRunner.TryAdd(task);
return task;
}
@@ -173,7 +175,7 @@ namespace Umbraco.Web.Scheduling
}
var periodInMilliseconds = healthCheckSettingsConfig.NotificationSettings.PeriodInHours * 60 * 60 * 1000;
- var task = new HealthCheckNotifier(_healthCheckRunner, delayInMilliseconds, periodInMilliseconds, healthChecks, notifications, _runtime, logger, _healthChecksSettingsConfig);
+ var task = new HealthCheckNotifier(_healthCheckRunner, delayInMilliseconds, periodInMilliseconds, healthChecks, notifications, _mainDom, logger, _healthChecksSettingsConfig, _serverRegistrar, _runtime);
_healthCheckRunner.TryAdd(task);
return task;
}
@@ -182,7 +184,7 @@ namespace Umbraco.Web.Scheduling
{
// log scrubbing
// install on all, will only run on non-replica servers
- var task = new LogScrubber(_scrubberRunner, DefaultDelayMilliseconds, LogScrubber.GetLogScrubbingInterval(), _runtime, _auditService, settings, _scopeProvider, _logger);
+ var task = new LogScrubber(_scrubberRunner, DefaultDelayMilliseconds, LogScrubber.GetLogScrubbingInterval(), _mainDom, _serverRegistrar, _auditService, settings, _scopeProvider, _logger);
_scrubberRunner.TryAdd(task);
return task;
}
@@ -194,7 +196,7 @@ namespace Umbraco.Web.Scheduling
var task = new TempFileCleanup(_fileCleanupRunner, DefaultDelayMilliseconds, OneHourMilliseconds,
new[] { new DirectoryInfo(_ioHelper.MapPath(Constants.SystemDirectories.TempFileUploads)) },
TimeSpan.FromDays(1), //files that are over a day old
- _runtime, _logger);
+ _mainDom, _logger);
_scrubberRunner.TryAdd(task);
return task;
}
diff --git a/src/Umbraco.Infrastructure/Search/BackgroundIndexRebuilder.cs b/src/Umbraco.Infrastructure/Search/BackgroundIndexRebuilder.cs
index 2c964a2723..1946e2041b 100644
--- a/src/Umbraco.Infrastructure/Search/BackgroundIndexRebuilder.cs
+++ b/src/Umbraco.Infrastructure/Search/BackgroundIndexRebuilder.cs
@@ -18,10 +18,10 @@ namespace Umbraco.Web.Search
private readonly IndexRebuilder _indexRebuilder;
private readonly IMainDom _mainDom;
private readonly IProfilingLogger _logger;
- private readonly IHostingEnvironment _hostingEnvironment;
+ private readonly IApplicationShutdownRegistry _hostingEnvironment;
private static BackgroundTaskRunner _rebuildOnStartupRunner;
- public BackgroundIndexRebuilder(IMainDom mainDom, IProfilingLogger logger, IHostingEnvironment hostingEnvironment, IndexRebuilder indexRebuilder)
+ public BackgroundIndexRebuilder(IMainDom mainDom, IProfilingLogger logger, IApplicationShutdownRegistry hostingEnvironment, IndexRebuilder indexRebuilder)
{
_mainDom = mainDom;
_logger = logger;
@@ -32,8 +32,6 @@ namespace Umbraco.Web.Search
///
/// Called to rebuild empty indexes on startup
///
- ///
- ///
///
///
public void RebuildIndexes(bool onlyEmptyIndexes, int waitMilliseconds = 0)
diff --git a/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs
index 5a46a37d43..c915013162 100644
--- a/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs
+++ b/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs
@@ -28,10 +28,11 @@ namespace Umbraco.Core.Sync
//
public class DatabaseServerMessenger : ServerMessengerBase, IDatabaseServerMessenger
{
- private readonly IRuntimeState _runtime;
+ private readonly IMainDom _mainDom;
private readonly ManualResetEvent _syncIdle;
private readonly object _locko = new object();
private readonly IProfilingLogger _profilingLogger;
+ private readonly IServerRegistrar _serverRegistrar;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly CacheRefresherCollection _cacheRefreshers;
private readonly ISqlContext _sqlContext;
@@ -46,14 +47,15 @@ namespace Umbraco.Core.Sync
public DatabaseServerMessengerOptions Options { get; }
public DatabaseServerMessenger(
- IRuntimeState runtime, IScopeProvider scopeProvider, ISqlContext sqlContext, IProfilingLogger proflog,
+ IMainDom mainDom, IScopeProvider scopeProvider, ISqlContext sqlContext, IProfilingLogger proflog, IServerRegistrar serverRegistrar,
bool distributedEnabled, DatabaseServerMessengerOptions options, IHostingEnvironment hostingEnvironment, CacheRefresherCollection cacheRefreshers)
: base(distributedEnabled)
{
ScopeProvider = scopeProvider ?? throw new ArgumentNullException(nameof(scopeProvider));
_sqlContext = sqlContext;
- _runtime = runtime;
+ _mainDom = mainDom;
_profilingLogger = proflog ?? throw new ArgumentNullException(nameof(proflog));
+ _serverRegistrar = serverRegistrar;
_hostingEnvironment = hostingEnvironment;
_cacheRefreshers = cacheRefreshers;
Logger = proflog;
@@ -126,7 +128,7 @@ namespace Umbraco.Core.Sync
const int weight = 10;
- var registered = _runtime.MainDom.Register(
+ var registered = _mainDom.Register(
() =>
{
lock (_locko)
@@ -262,7 +264,7 @@ namespace Umbraco.Core.Sync
_lastPruned = _lastSync;
- switch (_runtime.ServerRole)
+ switch (_serverRegistrar.GetCurrentServerRole())
{
case ServerRole.Single:
case ServerRole.Master:
diff --git a/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs b/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs
index 5db79de977..3cfefa77ce 100644
--- a/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs
+++ b/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs
@@ -42,7 +42,7 @@ namespace Umbraco.ModelsBuilder.Embedded
private static readonly string[] OurFiles = { "models.hash", "models.generated.cs", "all.generated.cs", "all.dll.path", "models.err" };
private readonly IModelsBuilderConfig _config;
- private readonly IHostingEnvironment _hostingEnvironment;
+ private readonly IApplicationShutdownRegistry _hostingLifetime;
private readonly IIOHelper _ioHelper;
private readonly ModelsGenerationError _errors;
@@ -51,12 +51,13 @@ namespace Umbraco.ModelsBuilder.Embedded
IProfilingLogger logger,
IModelsBuilderConfig config,
IHostingEnvironment hostingEnvironment,
+ IApplicationShutdownRegistry hostingLifetime,
IIOHelper ioHelper)
{
_umbracoServices = umbracoServices;
_logger = logger;
_config = config;
- _hostingEnvironment = hostingEnvironment;
+ _hostingLifetime = hostingLifetime;
_ioHelper = ioHelper;
_errors = new ModelsGenerationError(config, ioHelper);
_ver = 1; // zero is for when we had no version
@@ -64,7 +65,7 @@ namespace Umbraco.ModelsBuilder.Embedded
RazorBuildProvider.CodeGenerationStarted += RazorBuildProvider_CodeGenerationStarted;
- if (!_hostingEnvironment.IsHosted) return;
+ if (!hostingEnvironment.IsHosted) return;
var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper);
if (!Directory.Exists(modelsDirectory))
@@ -73,7 +74,7 @@ namespace Umbraco.ModelsBuilder.Embedded
// BEWARE! if the watcher is not properly released then for some reason the
// BuildManager will start confusing types - using a 'registered object' here
// though we should probably plug into Umbraco's MainDom - which is internal
- _hostingEnvironment.RegisterObject(this);
+ _hostingLifetime.RegisterObject(this);
_watcher = new FileSystemWatcher(modelsDirectory);
_watcher.Changed += WatcherOnChanged;
_watcher.EnableRaisingEvents = true;
@@ -677,7 +678,7 @@ namespace Umbraco.ModelsBuilder.Embedded
{
_watcher.EnableRaisingEvents = false;
_watcher.Dispose();
- _hostingEnvironment.UnregisterObject(this);
+ _hostingLifetime.UnregisterObject(this);
}
#endregion
diff --git a/src/Umbraco.Tests.Common/TestHelperBase.cs b/src/Umbraco.Tests.Common/TestHelperBase.cs
index 536bebee56..67108833c3 100644
--- a/src/Umbraco.Tests.Common/TestHelperBase.cs
+++ b/src/Umbraco.Tests.Common/TestHelperBase.cs
@@ -12,11 +12,11 @@ using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.PublishedContent;
+using Umbraco.Net;
using Umbraco.Core.Persistence;
using Umbraco.Core.Serialization;
using Umbraco.Core.Strings;
using Umbraco.Core.Sync;
-using Umbraco.Net;
using Umbraco.Web;
using Umbraco.Web.Routing;
@@ -31,7 +31,7 @@ namespace Umbraco.Tests.Common
private UriUtility _uriUtility;
private IIOHelper _ioHelper;
- public TestHelperBase(Assembly entryAssembly)
+ protected TestHelperBase(Assembly entryAssembly)
{
SettingsForTests = new SettingsForTests();
MainDom = new SimpleMainDom();
@@ -52,12 +52,8 @@ namespace Umbraco.Tests.Common
return new RuntimeState(
Mock.Of(),
Mock.Of(),
- new Lazy(),
- new Lazy(),
GetUmbracoVersion(),
- GetHostingEnvironment(),
- GetBackOfficeInfo()
- );
+ GetBackOfficeInfo());
}
public abstract IBackOfficeInfo GetBackOfficeInfo();
@@ -132,6 +128,7 @@ namespace Umbraco.Tests.Common
}
public abstract IHostingEnvironment GetHostingEnvironment();
+ public abstract IApplicationShutdownRegistry GetHostingEnvironmentLifetime();
public abstract IIpResolver GetIpResolver();
diff --git a/src/Umbraco.Tests.Integration/ContainerTests.cs b/src/Umbraco.Tests.Integration/ContainerTests.cs
index d190d1165d..945eeda2f0 100644
--- a/src/Umbraco.Tests.Integration/ContainerTests.cs
+++ b/src/Umbraco.Tests.Integration/ContainerTests.cs
@@ -1,4 +1,5 @@
-using LightInject;
+using System.Threading.Tasks;
+using LightInject;
using LightInject.Microsoft.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
@@ -37,7 +38,7 @@ namespace Umbraco.Tests.Integration
var testHelper = new TestHelper();
var runtimeState = Mock.Of();
var umbracoDatabaseFactory = Mock.Of();
- var dbProviderFactoryCreator = Mock.Of();
+ var dbProviderFactoryCreator = Mock.Of();
var typeLoader = testHelper.GetMockedTypeLoader();
// Register in the container
@@ -45,7 +46,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);
@@ -67,6 +69,46 @@ namespace Umbraco.Tests.Integration
Assertions.AssertContainer(umbracoContainer.Container);
}
+ [Explicit("This test just shows that resolving services from the container before the host is done resolves 2 different instances")]
+ [Test]
+ public async Task BuildServiceProvider_Before_Host_Is_Configured()
+ {
+ // This is a test to show an anti-pattern used in netcore. This should be avoided in all cases if possible.
+ // There's a thread about this here: https://github.com/dotnet/aspnetcore/issues/14587
+ // For some reason we are not being warned about this with our code analysis since we are using it
+ // in a couple of places but we should really try to see if we can avoid it.
+ // The test below shows how it could be possible to resolve an instance and then re-register it as a factory
+ // so that only one singleton instance is every created, but it's hacky and like Fowler says in that article
+ // it means the container won't be disposed, and maybe other services? not sure.
+ // In cases where we use it can we use IConfigureOptions? https://andrewlock.net/access-services-inside-options-and-startup-using-configureoptions/
+
+ var umbracoContainer = RuntimeTests.GetUmbracoContainer(out var serviceProviderFactory);
+
+ IHostApplicationLifetime lifetime1 = null;
+
+ var hostBuilder = new HostBuilder()
+ .UseUmbraco(serviceProviderFactory)
+ .ConfigureServices((hostContext, services) =>
+ {
+ // Resolve a service from the netcore container before the host has finished the ConfigureServices sequence
+ lifetime1 = services.BuildServiceProvider().GetRequiredService();
+
+ // Re-add as a callback, ensures its the same instance all the way through (hack)
+ services.AddSingleton(x => lifetime1);
+ });
+
+ var host = await hostBuilder.StartAsync();
+
+ var lifetime2 = host.Services.GetRequiredService();
+ var lifetime3 = umbracoContainer.GetInstance();
+
+ lifetime1.StopApplication();
+ Assert.IsTrue(lifetime1.ApplicationStopping.IsCancellationRequested);
+ Assert.AreEqual(lifetime1.ApplicationStopping.IsCancellationRequested, lifetime2.ApplicationStopping.IsCancellationRequested);
+ Assert.AreEqual(lifetime1.ApplicationStopping.IsCancellationRequested, lifetime3.ApplicationStopping.IsCancellationRequested);
+
+ }
+
private class Foo
{
public Foo()
diff --git a/src/Umbraco.Tests.Integration/Implementations/HostBuilderExtensions.cs b/src/Umbraco.Tests.Integration/Implementations/HostBuilderExtensions.cs
new file mode 100644
index 0000000000..60cac26349
--- /dev/null
+++ b/src/Umbraco.Tests.Integration/Implementations/HostBuilderExtensions.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Data.Common;
+using System.Data.SqlClient;
+using System.IO;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Hosting;
+using Umbraco.Core;
+using Umbraco.Tests.Integration.Testing;
+
+namespace Umbraco.Tests.Integration.Implementations
+{
+ public static class HostBuilderExtensions
+ {
+
+ public static IHostBuilder UseLocalDb(this IHostBuilder hostBuilder, string dbFilePath)
+ {
+ // Need to register SqlClient manually
+ // TODO: Move this to someplace central
+ DbProviderFactories.RegisterFactory(Constants.DbProviderNames.SqlServer, SqlClientFactory.Instance);
+
+ hostBuilder.ConfigureAppConfiguration(x =>
+ {
+ if (!Directory.Exists(dbFilePath))
+ Directory.CreateDirectory(dbFilePath);
+
+ var dbName = Guid.NewGuid().ToString("N");
+ var instance = TestLocalDb.EnsureLocalDbInstanceAndDatabase(dbName, dbFilePath);
+
+ x.AddInMemoryCollection(new[]
+ {
+ new KeyValuePair($"ConnectionStrings:{Constants.System.UmbracoConnectionName}", instance.GetConnectionString(dbName))
+ });
+ });
+ return hostBuilder;
+ }
+
+
+ }
+
+
+}
diff --git a/src/Umbraco.Tests.Integration/Implementations/TestDbProviderFactoryCreator.cs b/src/Umbraco.Tests.Integration/Implementations/TestDbProviderFactoryCreator.cs
deleted file mode 100644
index 9081c4ccb4..0000000000
--- a/src/Umbraco.Tests.Integration/Implementations/TestDbProviderFactoryCreator.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using System.Data.Common;
-using Umbraco.Core.Persistence;
-using Umbraco.Core.Persistence.SqlSyntax;
-
-namespace Umbraco.Tests.Integration.Implementations
-{
- public class TestDbProviderFactoryCreator : IDbProviderFactoryCreator
- {
- public IBulkSqlInsertProvider CreateBulkSqlInsertProvider(string providerName)
- {
- throw new System.NotImplementedException();
- }
-
- public void CreateDatabase()
- {
- throw new System.NotImplementedException();
- }
-
- public DbProviderFactory CreateFactory()
- {
- throw new System.NotImplementedException();
- }
-
- public DbProviderFactory CreateFactory(string providerName)
- {
- throw new System.NotImplementedException();
- }
-
- public ISqlSyntaxProvider GetSqlSyntaxProvider(string providerName)
- {
- throw new System.NotImplementedException();
- }
- }
-}
diff --git a/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs b/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs
index 5254892b23..4a986fa35a 100644
--- a/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs
+++ b/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs
@@ -3,14 +3,16 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
using Moq;
+using System.Data.Common;
using System.Net;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Diagnostics;
+using Umbraco.Core.Hosting;
using Umbraco.Core.Logging;
+using Umbraco.Net;
using Umbraco.Core.Persistence;
using Umbraco.Core.Runtime;
-using Umbraco.Net;
using Umbraco.Tests.Common;
using Umbraco.Web.BackOffice;
using Umbraco.Web.BackOffice.AspNetCore;
@@ -18,11 +20,11 @@ using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment;
namespace Umbraco.Tests.Integration.Implementations
{
-
public class TestHelper : TestHelperBase
{
private IBackOfficeInfo _backOfficeInfo;
private readonly IHostingEnvironment _hostingEnvironment;
+ private readonly IApplicationShutdownRegistry _hostingLifetime;
private readonly IIpResolver _ipResolver;
private readonly IWebHostEnvironment _hostEnvironment;
private readonly IHttpContextAccessor _httpContextAccessor;
@@ -39,11 +41,12 @@ namespace Umbraco.Tests.Integration.Implementations
&& x.ContentRootPath == CurrentAssemblyDirectory
&& x.WebRootPath == CurrentAssemblyDirectory); // same folder for now?
- _hostingEnvironment = new AspNetCoreHostingEnvironment(
+ _hostingEnvironment = new TestHostingEnvironment(
SettingsForTests.GetDefaultHostingSettings(),
_hostEnvironment,
- _httpContextAccessor,
- Mock.Of());
+ _httpContextAccessor);
+
+ _hostingLifetime = new AspNetCoreApplicationShutdownRegistry(Mock.Of());
Logger = new ProfilingLogger(new ConsoleLogger(new MessageTemplates()), Profiler);
}
@@ -60,7 +63,7 @@ namespace Umbraco.Tests.Integration.Implementations
public IWebHostEnvironment GetWebHostEnvironment() => _hostEnvironment;
- public override IDbProviderFactoryCreator DbProviderFactoryCreator => new TestDbProviderFactoryCreator();
+ public override IDbProviderFactoryCreator DbProviderFactoryCreator => new SqlServerDbProviderFactoryCreator(Constants.DbProviderNames.SqlServer, DbProviderFactories.GetFactory);
public override IBulkSqlInsertProvider BulkSqlInsertProvider => new SqlServerBulkSqlInsertProvider();
@@ -74,7 +77,9 @@ namespace Umbraco.Tests.Integration.Implementations
}
public override IHostingEnvironment GetHostingEnvironment() => _hostingEnvironment;
+ public override IApplicationShutdownRegistry GetHostingEnvironmentLifetime() => _hostingLifetime;
public override IIpResolver GetIpResolver() => _ipResolver;
+
}
}
diff --git a/src/Umbraco.Tests.Integration/Implementations/TestHostingEnvironment.cs b/src/Umbraco.Tests.Integration/Implementations/TestHostingEnvironment.cs
new file mode 100644
index 0000000000..491b7e5480
--- /dev/null
+++ b/src/Umbraco.Tests.Integration/Implementations/TestHostingEnvironment.cs
@@ -0,0 +1,23 @@
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Umbraco.Core.Configuration;
+using Umbraco.Web.BackOffice.AspNetCore;
+
+namespace Umbraco.Tests.Integration.Implementations
+{
+
+ public class TestHostingEnvironment : AspNetCoreHostingEnvironment, Umbraco.Core.Hosting.IHostingEnvironment
+ {
+ public TestHostingEnvironment(IHostingSettings hostingSettings, IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContextAccessor) : base(hostingSettings, webHostEnvironment, httpContextAccessor)
+ {
+ }
+
+ ///
+ /// Override for tests since we are not hosted
+ ///
+ ///
+ /// This is specifically used by IOHelper and we want this to return false so that the root path is manually calcualted which is what we want for tests.
+ ///
+ bool Umbraco.Core.Hosting.IHostingEnvironment.IsHosted { get; } = false;
+ }
+}
diff --git a/src/Umbraco.Tests.Integration/Implementations/TestLifetime.cs b/src/Umbraco.Tests.Integration/Implementations/TestLifetime.cs
new file mode 100644
index 0000000000..a18360eff9
--- /dev/null
+++ b/src/Umbraco.Tests.Integration/Implementations/TestLifetime.cs
@@ -0,0 +1,18 @@
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Hosting;
+
+namespace Umbraco.Tests.Integration.Implementations
+{
+ ///
+ /// Ensures the host lifetime ends as soon as code execution is done
+ ///
+ public class TestLifetime : IHostLifetime
+ {
+ public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
+
+ public Task WaitForStartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
+ }
+
+
+}
diff --git a/src/Umbraco.Tests.Integration/RuntimeTests.cs b/src/Umbraco.Tests.Integration/RuntimeTests.cs
index 24786a1591..0e11a29b95 100644
--- a/src/Umbraco.Tests.Integration/RuntimeTests.cs
+++ b/src/Umbraco.Tests.Integration/RuntimeTests.cs
@@ -7,41 +7,76 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Moq;
using NUnit.Framework;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
using Umbraco.Core;
using Umbraco.Core.Composing;
+using Umbraco.Core.Composing.LightInject;
using Umbraco.Core.Logging;
+using Umbraco.Core.Migrations.Install;
+using Umbraco.Core.Persistence;
using Umbraco.Core.Runtime;
using Umbraco.Tests.Common;
using Umbraco.Tests.Integration.Implementations;
+using Umbraco.Tests.Integration.Testing;
using Umbraco.Web.BackOffice.AspNetCore;
+using static Umbraco.Core.Migrations.Install.DatabaseBuilder;
namespace Umbraco.Tests.Integration
{
+
[TestFixture]
public class RuntimeTests
{
+ [TearDown]
+ public void TearDown()
+ {
+ MyComponent.Reset();
+ MyComposer.Reset();
+ }
+
+ [OneTimeTearDown]
+ public void FixtureTearDown()
+ {
+ TestLocalDb.Cleanup();
+ }
+
+ ///
+ /// Manually configure the containers/dependencies and call Boot on Core runtime
+ ///
[Test]
- public void BootCoreRuntime()
+ public void Boot_Core_Runtime()
{
// LightInject / Umbraco
var container = UmbracoServiceProviderFactory.CreateServiceContainer();
var serviceProviderFactory = new UmbracoServiceProviderFactory(container);
var umbracoContainer = serviceProviderFactory.GetContainer();
- // Create the core runtime
+ // Special case since we are not using the Generic Host, we need to manually add an AspNetCore service to the container
+ umbracoContainer.Register(x => Mock.Of());
+
var testHelper = new TestHelper();
+
+ // Create the core runtime
var coreRuntime = new CoreRuntime(testHelper.GetConfigs(), testHelper.GetUmbracoVersion(),
testHelper.IOHelper, testHelper.Logger, testHelper.Profiler, testHelper.UmbracoBootPermissionChecker,
testHelper.GetHostingEnvironment(), testHelper.GetBackOfficeInfo(), testHelper.DbProviderFactoryCreator,
testHelper.MainDom, testHelper.GetTypeFinder());
- // boot it!
- var factory = coreRuntime.Boot(umbracoContainer);
+ // boot it!
+ var factory = coreRuntime.Configure(umbracoContainer);
Assert.IsTrue(coreRuntime.MainDom.IsMainDom);
Assert.IsNull(coreRuntime.State.BootFailedException);
Assert.AreEqual(RuntimeLevel.Install, coreRuntime.State.Level);
Assert.IsTrue(MyComposer.IsComposed);
+ Assert.IsFalse(MyComponent.IsInit);
+ Assert.IsFalse(MyComponent.IsTerminated);
+
+ coreRuntime.Start();
+
Assert.IsTrue(MyComponent.IsInit);
Assert.IsFalse(MyComponent.IsTerminated);
@@ -52,40 +87,150 @@ namespace Umbraco.Tests.Integration
Assert.IsTrue(MyComponent.IsTerminated);
}
+ ///
+ /// Calling AddUmbracoCore to configure the container
+ ///
[Test]
- public void AddUmbracoCore()
+ public async Task AddUmbracoCore()
{
+ var umbracoContainer = GetUmbracoContainer(out var serviceProviderFactory);
var testHelper = new TestHelper();
- // MSDI
- var services = new ServiceCollection();
- // These services are required
- services.AddSingleton(x => testHelper.GetHttpContextAccessor());
- services.AddSingleton(x => testHelper.GetWebHostEnvironment());
- services.AddSingleton(x => Mock.Of());
+ var hostBuilder = new HostBuilder()
+ .UseUmbraco(serviceProviderFactory)
+ .ConfigureServices((hostContext, services) =>
+ {
+ var webHostEnvironment = testHelper.GetWebHostEnvironment();
+ AddRequiredNetCoreServices(services, testHelper, webHostEnvironment);
- // LightInject / Umbraco
- var container = UmbracoServiceProviderFactory.CreateServiceContainer();
- var serviceProviderFactory = new UmbracoServiceProviderFactory(container);
- var umbracoContainer = serviceProviderFactory.GetContainer();
+ // Add it!
+ services.AddUmbracoConfiguration(hostContext.Configuration);
+ services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly);
+ });
- // Some IConfiguration must exist in the container first
- var configurationBuilder = new ConfigurationBuilder();
- configurationBuilder.AddEnvironmentVariables();
- services.AddSingleton(x => configurationBuilder.Build());
-
- // Add it!
- services.AddUmbracoConfiguration();
- services.AddUmbracoCore(umbracoContainer, GetType().Assembly);
+ var host = await hostBuilder.StartAsync();
+ var app = new ApplicationBuilder(host.Services);
// assert results
- var runtimeState = umbracoContainer.GetInstance();
- var mainDom = umbracoContainer.GetInstance();
+ var runtimeState = app.ApplicationServices.GetRequiredService();
+ var mainDom = app.ApplicationServices.GetRequiredService();
+
+ Assert.IsFalse(mainDom.IsMainDom); // We haven't "Started" the runtime yet
+ Assert.IsNull(runtimeState.BootFailedException);
+ Assert.AreEqual(RuntimeLevel.Install, runtimeState.Level);
+ Assert.IsFalse(MyComponent.IsInit); // We haven't "Started" the runtime yet
+
+ await host.StopAsync();
+
+ Assert.IsFalse(MyComponent.IsTerminated); // we didn't "Start" the runtime so nothing was registered for shutdown
+ }
+
+ ///
+ /// Calling AddUmbracoCore to configure the container and UseUmbracoCore to start the runtime
+ ///
+ ///
+ [Test]
+ public async Task UseUmbracoCore()
+ {
+ var umbracoContainer = GetUmbracoContainer(out var serviceProviderFactory);
+ var testHelper = new TestHelper();
+
+ var hostBuilder = new HostBuilder()
+ .UseUmbraco(serviceProviderFactory)
+ .ConfigureServices((hostContext, services) =>
+ {
+ var webHostEnvironment = testHelper.GetWebHostEnvironment();
+ AddRequiredNetCoreServices(services, testHelper, webHostEnvironment);
+
+ // Add it!
+ services.AddUmbracoConfiguration(hostContext.Configuration);
+ services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly);
+ });
+
+ var host = await hostBuilder.StartAsync();
+ var app = new ApplicationBuilder(host.Services);
+
+ app.UseUmbracoCore();
+
+
+ // assert results
+ var runtimeState = app.ApplicationServices.GetRequiredService();
+ var mainDom = app.ApplicationServices.GetRequiredService();
Assert.IsTrue(mainDom.IsMainDom);
Assert.IsNull(runtimeState.BootFailedException);
Assert.AreEqual(RuntimeLevel.Install, runtimeState.Level);
- Assert.IsTrue(MyComposer.IsComposed);
+ Assert.IsTrue(MyComponent.IsInit);
+
+ await host.StopAsync();
+
+ Assert.IsTrue(MyComponent.IsTerminated);
+ }
+
+ [Test]
+ public async Task Install_Database()
+ {
+ var umbracoContainer = GetUmbracoContainer(out var serviceProviderFactory);
+ var testHelper = new TestHelper();
+
+ var hostBuilder = new HostBuilder()
+ //TODO: Need to have a configured umb version for the runtime state
+ .UseLocalDb(Path.Combine(testHelper.CurrentAssemblyDirectory, "LocalDb"))
+ .UseUmbraco(serviceProviderFactory)
+ .ConfigureServices((hostContext, services) =>
+ {
+ var webHostEnvironment = testHelper.GetWebHostEnvironment();
+ AddRequiredNetCoreServices(services, testHelper, webHostEnvironment);
+
+ // Add it!
+ services.AddUmbracoConfiguration(hostContext.Configuration);
+ services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly);
+ });
+
+ var host = await hostBuilder.StartAsync();
+ var app = new ApplicationBuilder(host.Services);
+
+ app.UseUmbracoCore();
+
+
+ var runtimeState = (RuntimeState)app.ApplicationServices.GetRequiredService();
+ Assert.AreEqual(RuntimeLevel.Install, runtimeState.Level);
+
+ var dbBuilder = app.ApplicationServices.GetRequiredService();
+ Assert.IsNotNull(dbBuilder);
+
+ var canConnect = dbBuilder.CanConnectToDatabase;
+ Assert.IsTrue(canConnect);
+
+ var dbResult = dbBuilder.CreateSchemaAndData();
+ Assert.IsTrue(dbResult.Success);
+
+ // TODO: Get this to work ... but to do that we need to mock or pass in a current umbraco version
+ //var dbFactory = app.ApplicationServices.GetRequiredService();
+ //var profilingLogger = app.ApplicationServices.GetRequiredService();
+ //runtimeState.DetermineRuntimeLevel(dbFactory, profilingLogger);
+ //Assert.AreEqual(RuntimeLevel.Run, runtimeState.Level);
+ }
+
+ internal static LightInjectContainer GetUmbracoContainer(out UmbracoServiceProviderFactory serviceProviderFactory)
+ {
+ var container = UmbracoServiceProviderFactory.CreateServiceContainer();
+ serviceProviderFactory = new UmbracoServiceProviderFactory(container);
+ var umbracoContainer = serviceProviderFactory.GetContainer();
+ return umbracoContainer;
+ }
+
+ ///
+ /// These services need to be manually added because they do not get added by the generic host
+ ///
+ ///
+ ///
+ ///
+ private void AddRequiredNetCoreServices(IServiceCollection services, TestHelper testHelper, IWebHostEnvironment webHostEnvironment)
+ {
+ services.AddSingleton(x => testHelper.GetHttpContextAccessor());
+ // the generic host does add IHostEnvironment but not this one because we are not actually in a web context
+ services.AddSingleton(x => webHostEnvironment);
}
[RuntimeLevel(MinLevel = RuntimeLevel.Install)]
@@ -97,6 +242,11 @@ namespace Umbraco.Tests.Integration
IsComposed = true;
}
+ public static void Reset()
+ {
+ IsComposed = false;
+ }
+
public static bool IsComposed { get; private set; }
}
@@ -121,6 +271,12 @@ namespace Umbraco.Tests.Integration
{
IsTerminated = true;
}
+
+ public static void Reset()
+ {
+ IsTerminated = false;
+ IsInit = false;
+ }
}
}
diff --git a/src/Umbraco.Tests.Integration/Testing/TestLocalDb.cs b/src/Umbraco.Tests.Integration/Testing/TestLocalDb.cs
new file mode 100644
index 0000000000..8ee326783b
--- /dev/null
+++ b/src/Umbraco.Tests.Integration/Testing/TestLocalDb.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Umbraco.Core.Persistence;
+
+namespace Umbraco.Tests.Integration.Testing
+{
+ public static class TestLocalDb
+ {
+ private const string LocalDbInstanceName = "UmbTests";
+
+ private static LocalDb LocalDb { get; } = new LocalDb();
+
+ // TODO: We need to borrow logic from this old branch, this is the latest commit at the old branch where we had LocalDb
+ // working for tests. There's a lot of hoops to jump through to make it work 'fast'. Turns out it didn't actually run as
+ // fast as SqlCe due to the dropping/creating of DB instances since that is faster in SqlCe but this code was all heavily
+ // optimized to go as fast as possible.
+ // see https://github.com/umbraco/Umbraco-CMS/blob/3a8716ac7b1c48b51258724337086cd0712625a1/src/Umbraco.Tests/TestHelpers/LocalDbTestDatabase.cs
+ internal static LocalDb.Instance EnsureLocalDbInstanceAndDatabase(string dbName, string dbFilePath)
+ {
+ if (!LocalDb.InstanceExists(LocalDbInstanceName) && !LocalDb.CreateInstance(LocalDbInstanceName))
+ {
+ throw new InvalidOperationException(
+ $"Failed to create LocalDb instance {LocalDbInstanceName}, assuming LocalDb is not really available.");
+ }
+
+ var instance = LocalDb.GetInstance(LocalDbInstanceName);
+
+ if (instance == null)
+ {
+ throw new InvalidOperationException(
+ $"Failed to get LocalDb instance {LocalDbInstanceName}, assuming LocalDb is not really available.");
+ }
+
+ instance.CreateDatabase(dbName, dbFilePath);
+
+ return instance;
+ }
+
+ public static void Cleanup()
+ {
+ var instance = LocalDb.GetInstance(LocalDbInstanceName);
+ if (instance != null)
+ {
+ instance.DropDatabases();
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj
index 55b3e8cdca..320db33568 100644
--- a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj
+++ b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj
@@ -15,6 +15,7 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs
index 609dcd98b8..bf7cbe40c4 100644
--- a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs
+++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs
@@ -41,6 +41,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
private readonly IEntityXmlSerializer _entitySerializer;
private readonly IVariationContextAccessor _variationContextAccessor;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
+ private readonly IApplicationShutdownRegistry _hostingLifetime;
private readonly IHostingEnvironment _hostingEnvironment;
#region Constructors
@@ -57,6 +58,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
ILogger logger,
IGlobalSettings globalSettings,
IHostingEnvironment hostingEnvironment,
+ IApplicationShutdownRegistry hostingLifetime,
IShortStringHelper shortStringHelper,
ISiteDomainHelper siteDomainHelper,
IEntityXmlSerializer entitySerializer,
@@ -67,7 +69,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor,
documentRepository, mediaRepository, memberRepository,
defaultCultureAccessor,
- logger, globalSettings, hostingEnvironment, shortStringHelper, siteDomainHelper, entitySerializer, null, mainDom, testing, enableRepositoryEvents)
+ logger, globalSettings, hostingEnvironment, hostingLifetime, shortStringHelper, siteDomainHelper, entitySerializer, null, mainDom, testing, enableRepositoryEvents)
{
_umbracoContextAccessor = umbracoContextAccessor;
}
@@ -84,6 +86,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
ILogger logger,
IGlobalSettings globalSettings,
IHostingEnvironment hostingEnvironment,
+ IApplicationShutdownRegistry hostingLifetime,
IShortStringHelper shortStringHelper,
ISiteDomainHelper siteDomainHelper,
IEntityXmlSerializer entitySerializer,
@@ -99,7 +102,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
_xmlStore = new XmlStore(serviceContext.ContentTypeService, serviceContext.ContentService, scopeProvider, _routesCache,
_contentTypeCache, publishedSnapshotAccessor, mainDom, testing, enableRepositoryEvents,
- documentRepository, mediaRepository, memberRepository, globalSettings, entitySerializer, hostingEnvironment, shortStringHelper);
+ documentRepository, mediaRepository, memberRepository, entitySerializer, hostingEnvironment, hostingLifetime, shortStringHelper);
_domainService = serviceContext.DomainService;
_memberService = serviceContext.MemberService;
@@ -113,6 +116,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
_siteDomainHelper = siteDomainHelper;
_entitySerializer = entitySerializer;
_hostingEnvironment = hostingEnvironment;
+ _hostingLifetime = hostingLifetime;
}
public override void Dispose()
diff --git a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs
index 238da68370..dadf8b6824 100644
--- a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs
+++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs
@@ -45,9 +45,8 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
private readonly IDocumentRepository _documentRepository;
private readonly IMediaRepository _mediaRepository;
private readonly IMemberRepository _memberRepository;
- private readonly IGlobalSettings _globalSettings;
private readonly IEntityXmlSerializer _entitySerializer;
- private readonly IHostingEnvironment _hostingEnvironment;
+ private readonly IApplicationShutdownRegistry _hostingLifetime;
private readonly IShortStringHelper _shortStringHelper;
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
private readonly PublishedContentTypeCache _contentTypeCache;
@@ -58,7 +57,6 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
private XmlStoreFilePersister _persisterTask;
private volatile bool _released;
- private bool _withRepositoryEvents;
#region Constructors
@@ -67,8 +65,8 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
///
/// The default constructor will boot the cache, load data from file or database, /// wire events in order to manage changes, etc.
public XmlStore(IContentTypeService contentTypeService, IContentService contentService, IScopeProvider scopeProvider, RoutesCache routesCache, PublishedContentTypeCache contentTypeCache,
- IPublishedSnapshotAccessor publishedSnapshotAccessor, MainDom mainDom, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IGlobalSettings globalSettings, IEntityXmlSerializer entitySerializer, IHostingEnvironment hostingEnvironment, IShortStringHelper shortStringHelper)
- : this(contentTypeService, contentService, scopeProvider, routesCache, contentTypeCache, publishedSnapshotAccessor, mainDom, false, false, documentRepository, mediaRepository, memberRepository, globalSettings, entitySerializer, hostingEnvironment, shortStringHelper)
+ IPublishedSnapshotAccessor publishedSnapshotAccessor, MainDom mainDom, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IEntityXmlSerializer entitySerializer, IHostingEnvironment hostingEnvironment, IApplicationShutdownRegistry hostingLifetime, IShortStringHelper shortStringHelper)
+ : this(contentTypeService, contentService, scopeProvider, routesCache, contentTypeCache, publishedSnapshotAccessor, mainDom, false, false, documentRepository, mediaRepository, memberRepository, entitySerializer, hostingEnvironment, hostingLifetime, shortStringHelper)
{ }
// internal for unit tests
@@ -76,7 +74,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
// TODO: er, we DO have a DB?
internal XmlStore(IContentTypeService contentTypeService, IContentService contentService, IScopeProvider scopeProvider, RoutesCache routesCache, PublishedContentTypeCache contentTypeCache,
IPublishedSnapshotAccessor publishedSnapshotAccessor, MainDom mainDom,
- bool testing, bool enableRepositoryEvents, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IGlobalSettings globalSettings, IEntityXmlSerializer entitySerializer, IHostingEnvironment hostingEnvironment, IShortStringHelper shortStringHelper)
+ bool testing, bool enableRepositoryEvents, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IEntityXmlSerializer entitySerializer, IHostingEnvironment hostingEnvironment, IApplicationShutdownRegistry hostingLifetime, IShortStringHelper shortStringHelper)
{
if (testing == false)
EnsureConfigurationIsValid();
@@ -90,12 +88,11 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
_documentRepository = documentRepository;
_mediaRepository = mediaRepository;
_memberRepository = memberRepository;
- _globalSettings = globalSettings;
_entitySerializer = entitySerializer;
- _hostingEnvironment = hostingEnvironment;
+ _hostingLifetime = hostingLifetime;
_shortStringHelper = shortStringHelper;
- _xmlFileName = TestHelper.IOHelper.MapPath(SystemFiles.GetContentCacheXml(_hostingEnvironment));
+ _xmlFileName = TestHelper.IOHelper.MapPath(SystemFiles.GetContentCacheXml(hostingEnvironment));
if (testing)
{
@@ -150,7 +147,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
LongRunning = true,
KeepAlive = true,
Hosted = false // main domain will take care of stopping the runner (see below)
- }, logger, _hostingEnvironment);
+ }, logger, _hostingLifetime);
// create (and add to runner)
_persisterTask = new XmlStoreFilePersister(runner, this, logger);
@@ -207,7 +204,6 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
MediaTypeService.ScopedRefreshedEntity += OnMediaTypeRefreshedEntity;
MemberTypeService.ScopedRefreshedEntity += OnMemberTypeRefreshedEntity;
- _withRepositoryEvents = true;
}
private void ClearEvents()
@@ -226,7 +222,6 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
MediaTypeService.ScopedRefreshedEntity -= OnMediaTypeRefreshedEntity;
MemberTypeService.ScopedRefreshedEntity -= OnMemberTypeRefreshedEntity;
- _withRepositoryEvents = false;
}
private void LazyInitializeContent()
diff --git a/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs b/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs
index 561a6d945e..f9de3579c2 100644
--- a/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs
+++ b/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs
@@ -32,8 +32,7 @@ namespace Umbraco.Tests.Routing
//create the module
var logger = Mock.Of();
var globalSettings = TestObjects.GetGlobalSettings();
- var runtime = new RuntimeState(logger, globalSettings,
- new Lazy(), new Lazy(), UmbracoVersion, HostingEnvironment, BackOfficeInfo);
+ var runtime = new RuntimeState(logger, globalSettings, UmbracoVersion, BackOfficeInfo);
_module = new UmbracoInjectedModule
(
diff --git a/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs b/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs
index 92ab825ee2..6ccb2c3b35 100644
--- a/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs
+++ b/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs
@@ -104,11 +104,6 @@ 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, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo)
@@ -136,50 +131,14 @@ namespace Umbraco.Tests.Runtimes
return mock.Object;
}
- // FIXME: so how the f* should we do it now?
- /*
- // pretend we have the proper migration
- // else BootFailedException because our mock IUmbracoDatabaseFactory does not provide databases
- protected override bool EnsureUmbracoUpgradeState(IUmbracoDatabaseFactory databaseFactory)
+ public override IFactory Configure(IRegister container)
{
- return true;
- }
- */
+ container.Register(Lifetime.Singleton);
- // because we don't even have the core runtime component,
- // there are a few required stuff that we need to compose
- public override void Compose(Composition composition)
- {
- base.Compose(composition);
-
- var scopeProvider = Mock.Of();
- Mock.Get(scopeProvider)
- .Setup(x => x.CreateScope(
- It.IsAny(),
- It.IsAny(),
- It.IsAny(),
- It.IsAny(),
- It.IsAny(),
- It.IsAny()))
- .Returns(Mock.Of());
-
- composition.RegisterUnique(scopeProvider);
- }
-
- private IMainDom _mainDom;
-
- public override IFactory Boot(IRegister container)
- {
- var factory = base.Boot(container);
- _mainDom = factory.GetInstance();
+ var factory = base.Configure(container);
return factory;
}
- public override void Terminate()
- {
- base.Terminate();
- }
-
// runs with only one single component
// UmbracoCoreComponent will be force-added too
// and that's it
diff --git a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs
index 0cb3f3e2e1..f167aafb89 100644
--- a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs
+++ b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs
@@ -72,7 +72,7 @@ namespace Umbraco.Tests.Runtimes
var mainDom = new SimpleMainDom();
var umbracoVersion = TestHelper.GetUmbracoVersion();
var backOfficeInfo = TestHelper.GetBackOfficeInfo();
- var runtimeState = new RuntimeState(logger, null, new Lazy(() => mainDom), new Lazy(() => factory.GetInstance()), umbracoVersion, hostingEnvironment, backOfficeInfo);
+ var runtimeState = new RuntimeState(logger, null, umbracoVersion, backOfficeInfo);
var configs = TestHelper.GetConfigs();
var variationContextAccessor = TestHelper.VariationContextAccessor;
@@ -80,11 +80,10 @@ 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);
- coreRuntime.Compose(composition);
// determine actual runtime level
runtimeState.DetermineRuntimeLevel(databaseFactory, logger);
@@ -275,11 +274,10 @@ 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);
- coreRuntime.Compose(composition);
// get the components
// all of them?
diff --git a/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests.cs b/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests.cs
index f10b141916..2291584f66 100644
--- a/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests.cs
+++ b/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests.cs
@@ -19,13 +19,13 @@ namespace Umbraco.Tests.Scheduling
public class BackgroundTaskRunnerTests
{
private ILogger _logger;
- private IHostingEnvironment _hostingEnvironment;
+ private IApplicationShutdownRegistry _hostingEnvironment;
[OneTimeSetUp]
public void InitializeFixture()
{
_logger = new ConsoleLogger(new MessageTemplates());
- _hostingEnvironment = TestHelper.GetHostingEnvironment();
+ _hostingEnvironment = TestHelper.GetHostingEnvironmentLifetime();
}
[Test]
@@ -934,7 +934,7 @@ namespace Umbraco.Tests.Scheduling
[Test]
public void SourceTaskTest()
{
- var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, _logger, TestHelper.GetHostingEnvironment());
+ var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, _logger, TestHelper.GetHostingEnvironmentLifetime());
var task = new SourceTask();
runner.Add(task);
diff --git a/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests2.cs b/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests2.cs
index c65c7e3efb..01169abce2 100644
--- a/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests2.cs
+++ b/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests2.cs
@@ -22,7 +22,7 @@ namespace Umbraco.Tests.Scheduling
public async Task ThreadResumeIssue()
{
var logger = new DebugDiagnosticsLogger(new MessageTemplates());
- var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, logger, TestHelper.GetHostingEnvironment());
+ var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, logger, TestHelper.GetHostingEnvironmentLifetime());
var work = new ThreadResumeIssueWorkItem();
runner.Add(work);
@@ -77,7 +77,7 @@ namespace Umbraco.Tests.Scheduling
public async Task DebuggerInterferenceIssue()
{
var logger = new DebugDiagnosticsLogger(new MessageTemplates());
- var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, logger, TestHelper.GetHostingEnvironment());
+ var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, logger, TestHelper.GetHostingEnvironmentLifetime());
var taskCompleted = false;
runner.TaskCompleted += (sender, args) =>
{
diff --git a/src/Umbraco.Tests/TestHelpers/TestHelper.cs b/src/Umbraco.Tests/TestHelpers/TestHelper.cs
index 05d4de6e23..11393e3e6b 100644
--- a/src/Umbraco.Tests/TestHelpers/TestHelper.cs
+++ b/src/Umbraco.Tests/TestHelpers/TestHelper.cs
@@ -21,12 +21,12 @@ using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Models.PublishedContent;
+using Umbraco.Net;
using Umbraco.Core.Persistence;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Serialization;
using Umbraco.Core.Services;
using Umbraco.Core.Strings;
-using Umbraco.Net;
using Umbraco.Tests.Common;
using Umbraco.Web;
using Umbraco.Web.Hosting;
@@ -40,7 +40,7 @@ namespace Umbraco.Tests.TestHelpers
///
public static class TestHelper
{
- private static TestHelperInternal _testHelperInternal = new TestHelperInternal();
+ private static readonly TestHelperInternal _testHelperInternal = new TestHelperInternal();
private class TestHelperInternal : TestHelperBase
{
public TestHelperInternal() : base(typeof(TestHelperInternal).Assembly)
@@ -62,6 +62,9 @@ namespace Umbraco.Tests.TestHelpers
public override IHostingEnvironment GetHostingEnvironment()
=> new AspNetHostingEnvironment(SettingsForTests.GetDefaultHostingSettings());
+ public override IApplicationShutdownRegistry GetHostingEnvironmentLifetime()
+ => new AspNetApplicationShutdownRegistry();
+
public override IIpResolver GetIpResolver()
=> new AspNetIpResolver();
}
@@ -320,6 +323,8 @@ namespace Umbraco.Tests.TestHelpers
public static IHostingEnvironment GetHostingEnvironment() => _testHelperInternal.GetHostingEnvironment();
+ public static IApplicationShutdownRegistry GetHostingEnvironmentLifetime() => _testHelperInternal.GetHostingEnvironmentLifetime();
+
public static IIpResolver GetIpResolver() => _testHelperInternal.GetIpResolver();
public static IRequestCache GetRequestCache() => _testHelperInternal.GetRequestCache();
diff --git a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs
index 5cf2c7b6bd..fbfada118a 100644
--- a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs
+++ b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs
@@ -265,6 +265,7 @@ namespace Umbraco.Tests.TestHelpers
Logger,
Factory.GetInstance(),
HostingEnvironment,
+ HostingLifetime,
ShortStringHelper,
new SiteDomainHelper(),
Factory.GetInstance(),
diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
index ca36a6049e..0345aab2da 100644
--- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
+++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
@@ -51,10 +51,10 @@ using Umbraco.Web.Templates;
using Umbraco.Web.PropertyEditors;
using Umbraco.Core.Dictionary;
using Umbraco.Core.Models;
+using Umbraco.Net;
using Umbraco.Core.Request;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
-using Umbraco.Net;
using Umbraco.Tests.LegacyXmlPublishedCache;
using Umbraco.Web.AspNet;
using Umbraco.Web.Install;
@@ -140,6 +140,7 @@ namespace Umbraco.Tests.Testing
protected virtual IProfilingLogger ProfilingLogger => Factory.GetInstance();
protected IHostingEnvironment HostingEnvironment { get; } = new AspNetHostingEnvironment(TestHelpers.SettingsForTests.GetDefaultHostingSettings());
+ protected IApplicationShutdownRegistry HostingLifetime { get; } = new AspNetApplicationShutdownRegistry();
protected IIpResolver IpResolver => Factory.GetInstance();
protected IBackOfficeInfo BackOfficeInfo => Factory.GetInstance();
protected AppCaches AppCaches => Factory.GetInstance();
diff --git a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs
index 5e5197a28a..c5e9556d05 100644
--- a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs
+++ b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs
@@ -423,6 +423,7 @@ namespace Umbraco.Tests.Web.Mvc
new TestDefaultCultureAccessor(),
Current.Logger, TestObjects.GetGlobalSettings(),
TestHelper.GetHostingEnvironment(),
+ TestHelper.GetHostingEnvironmentLifetime(),
ShortStringHelper,
new SiteDomainHelper(),
Factory.GetInstance(),
diff --git a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreApplicationShutdownRegistry.cs b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreApplicationShutdownRegistry.cs
new file mode 100644
index 0000000000..92af822836
--- /dev/null
+++ b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreApplicationShutdownRegistry.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Concurrent;
+using System.Threading;
+using Microsoft.Extensions.Hosting;
+using Umbraco.Core;
+using Umbraco.Core.Hosting;
+
+namespace Umbraco.Web.BackOffice.AspNetCore
+{
+ public class AspNetCoreApplicationShutdownRegistry : IApplicationShutdownRegistry
+ {
+ private readonly IHostApplicationLifetime _hostApplicationLifetime;
+ private readonly ConcurrentDictionary _registeredObjects =
+ new ConcurrentDictionary();
+
+ public AspNetCoreApplicationShutdownRegistry(IHostApplicationLifetime hostApplicationLifetime)
+ {
+ _hostApplicationLifetime = hostApplicationLifetime;
+ }
+
+ public void RegisterObject(IRegisteredObject registeredObject)
+ {
+ var wrapped = new RegisteredObjectWrapper(registeredObject);
+ if (!_registeredObjects.TryAdd(registeredObject, wrapped))
+ {
+ throw new InvalidOperationException("Could not register object");
+ }
+
+ var cancellationTokenRegistration = _hostApplicationLifetime.ApplicationStopping.Register(() => wrapped.Stop(true));
+ wrapped.CancellationTokenRegistration = cancellationTokenRegistration;
+ }
+
+ public void UnregisterObject(IRegisteredObject registeredObject)
+ {
+ if (_registeredObjects.TryGetValue(registeredObject, out var wrapped))
+ {
+ wrapped.CancellationTokenRegistration.Unregister();
+ }
+ }
+
+
+ private class RegisteredObjectWrapper
+ {
+ private readonly IRegisteredObject _inner;
+
+ public RegisteredObjectWrapper(IRegisteredObject inner)
+ {
+ _inner = inner;
+ }
+
+ public CancellationTokenRegistration CancellationTokenRegistration { get; set; }
+
+ public void Stop(bool immediate)
+ {
+ _inner.Stop(immediate);
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreComposer.cs b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreComposer.cs
new file mode 100644
index 0000000000..fc38e429a0
--- /dev/null
+++ b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreComposer.cs
@@ -0,0 +1,27 @@
+using Microsoft.AspNetCore.Http;
+using Umbraco.Core;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Hosting;
+using Umbraco.Net;
+using Umbraco.Core.Runtime;
+
+namespace Umbraco.Web.BackOffice.AspNetCore
+{
+ ///
+ /// Adds/replaces AspNetCore specific services
+ ///
+ [ComposeBefore(typeof(ICoreComposer))]
+ [ComposeAfter(typeof(CoreInitialComposer))]
+ public class AspNetCoreComposer : IComposer
+ {
+ public void Compose(Composition composition)
+ {
+ // AspNetCore specific services
+ composition.RegisterUnique();
+
+ // Our own netcore implementations
+ composition.RegisterUnique();
+ composition.RegisterUnique();
+ }
+ }
+}
diff --git a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreHostingEnvironment.cs b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreHostingEnvironment.cs
index 00bc894b0d..6f1298918d 100644
--- a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreHostingEnvironment.cs
+++ b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreHostingEnvironment.cs
@@ -1,11 +1,8 @@
using System;
-using System.Collections.Concurrent;
-using System.Diagnostics;
+using System.Globalization;
using System.IO;
-using System.Threading;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Hosting;
using Umbraco.Core;
using Umbraco.Core.Configuration;
@@ -13,30 +10,29 @@ namespace Umbraco.Web.BackOffice.AspNetCore
{
public class AspNetCoreHostingEnvironment : Umbraco.Core.Hosting.IHostingEnvironment
{
- private readonly ConcurrentDictionary _registeredObjects =
- new ConcurrentDictionary();
+
private readonly IHostingSettings _hostingSettings;
private readonly IWebHostEnvironment _webHostEnvironment;
private readonly IHttpContextAccessor _httpContextAccessor;
- private readonly IHostApplicationLifetime _hostApplicationLifetime;
+
private string _localTempPath;
- public AspNetCoreHostingEnvironment(IHostingSettings hostingSettings, IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContextAccessor, IHostApplicationLifetime hostHostApplicationLifetime)
+ public AspNetCoreHostingEnvironment(IHostingSettings hostingSettings, IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContextAccessor)
{
_hostingSettings = hostingSettings ?? throw new ArgumentNullException(nameof(hostingSettings));
_webHostEnvironment = webHostEnvironment;
_httpContextAccessor = httpContextAccessor;
- _hostApplicationLifetime = hostHostApplicationLifetime;
SiteName = webHostEnvironment.ApplicationName;
ApplicationId = AppDomain.CurrentDomain.Id.ToString();
ApplicationPhysicalPath = webHostEnvironment.ContentRootPath;
ApplicationVirtualPath = "/"; //TODO how to find this, This is a server thing, not application thing.
- IISVersion = new Version(0, 0); // TODO not necessary IIS
+ IISVersion = new Version(0, 0); // TODO not necessary IIS
IsDebugMode = _hostingSettings.DebugMode;
}
+
public bool IsHosted { get; } = true;
public string SiteName { get; }
public string ApplicationId { get; }
@@ -56,7 +52,10 @@ namespace Umbraco.Web.BackOffice.AspNetCore
switch (_hostingSettings.LocalTempStorageLocation)
{
case LocalTempStorage.AspNetTemp:
- return _localTempPath = System.IO.Path.Combine(Path.GetTempPath(),ApplicationId, "UmbracoData");
+
+ // 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:
@@ -84,8 +83,11 @@ namespace Umbraco.Web.BackOffice.AspNetCore
}
}
- // TODO: This may need to take into account ~/ paths which means the ApplicationVirtualPath and is this the content root or web root?
- public string MapPath(string path) => Path.Combine(_webHostEnvironment.WebRootPath, path);
+ public string MapPath(string path)
+ {
+ var newPath = path.TrimStart('~', '/').Replace('/', Path.DirectorySeparatorChar);
+ return Path.Combine(_webHostEnvironment.WebRootPath, newPath);
+ }
// TODO: Need to take into account 'root' here
public string ToAbsolute(string virtualPath, string root)
@@ -101,43 +103,7 @@ namespace Umbraco.Web.BackOffice.AspNetCore
return applicationPath.Add(segment).Value;
}
- public void RegisterObject(IRegisteredObject registeredObject)
- {
- var wrapped = new RegisteredObjectWrapper(registeredObject);
- if (!_registeredObjects.TryAdd(registeredObject, wrapped))
- {
- throw new InvalidOperationException("Could not register object");
- }
-
- var cancellationTokenRegistration = _hostApplicationLifetime.ApplicationStopping.Register(() => wrapped.Stop(true));
- wrapped.CancellationTokenRegistration = cancellationTokenRegistration;
- }
-
- public void UnregisterObject(IRegisteredObject registeredObject)
- {
- if (_registeredObjects.TryGetValue(registeredObject, out var wrapped))
- {
- wrapped.CancellationTokenRegistration.Unregister();
- }
- }
-
-
- private class RegisteredObjectWrapper
- {
- private readonly IRegisteredObject _inner;
-
- public RegisteredObjectWrapper(IRegisteredObject inner)
- {
- _inner = inner;
- }
-
- public CancellationTokenRegistration CancellationTokenRegistration { get; set; }
-
- public void Stop(bool immediate)
- {
- _inner.Stop(immediate);
- }
- }
+
}
diff --git a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreMarchal.cs b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreMarchal.cs
index 98e040d338..247666090e 100644
--- a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreMarchal.cs
+++ b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreMarchal.cs
@@ -2,7 +2,7 @@ using System;
using System.Runtime.InteropServices;
using Umbraco.Core.Diagnostics;
-namespace Umbraco.Web.BackOffice
+namespace Umbraco.Web.BackOffice.AspNetCore
{
public class AspNetCoreMarchal : IMarchal
diff --git a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreUmbracoApplicationLifetime.cs b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreUmbracoApplicationLifetime.cs
index 20cfef352d..0dca3edec8 100644
--- a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreUmbracoApplicationLifetime.cs
+++ b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreUmbracoApplicationLifetime.cs
@@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
using Umbraco.Net;
-namespace Umbraco.Web.AspNet
+namespace Umbraco.Web.BackOffice.AspNetCore
{
public class AspNetCoreUmbracoApplicationLifetime : IUmbracoApplicationLifetime
{
diff --git a/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoBackOfficeApplicationBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoBackOfficeApplicationBuilderExtensions.cs
index 1f06a818d6..770f4b883f 100644
--- a/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoBackOfficeApplicationBuilderExtensions.cs
+++ b/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoBackOfficeApplicationBuilderExtensions.cs
@@ -1,5 +1,10 @@
using System;
using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Umbraco.Core;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Hosting;
namespace Umbraco.Web.BackOffice.AspNetCore
{
@@ -7,12 +12,57 @@ 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;
}
+
+ ///
+ /// Start Umbraco
+ ///
+ ///
+ ///
+ public static IApplicationBuilder UseUmbracoCore(this IApplicationBuilder app)
+ {
+ if (app == null) throw new ArgumentNullException(nameof(app));
+
+ // Register a listener for application shutdown in order to terminate the runtime
+ var hostLifetime = app.ApplicationServices.GetRequiredService();
+ var runtime = app.ApplicationServices.GetRequiredService();
+ var runtimeShutdown = new CoreRuntimeShutdown(runtime, hostLifetime);
+ hostLifetime.RegisterObject(runtimeShutdown);
+
+ // Start the runtime!
+ runtime.Start();
+
+ return app;
+ }
+
+ ///
+ /// Ensures the runtime is shutdown when the application is shutting down
+ ///
+ private class CoreRuntimeShutdown : IRegisteredObject
+ {
+ public CoreRuntimeShutdown(IRuntime runtime, IApplicationShutdownRegistry hostLifetime)
+ {
+ _runtime = runtime;
+ _hostLifetime = hostLifetime;
+ }
+
+ private bool _completed = false;
+ private readonly IRuntime _runtime;
+ private readonly IApplicationShutdownRegistry _hostLifetime;
+
+ public void Stop(bool immediate)
+ {
+ if (!_completed)
+ {
+ _completed = true;
+ _runtime.Terminate();
+ _hostLifetime.UnregisterObject(this);
+ }
+
+ }
+ }
}
}
diff --git a/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoBackOfficeServiceCollectionExtensions.cs b/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoCoreServiceCollectionExtensions.cs
similarity index 57%
rename from src/Umbraco.Web.BackOffice/AspNetCore/UmbracoBackOfficeServiceCollectionExtensions.cs
rename to src/Umbraco.Web.BackOffice/AspNetCore/UmbracoCoreServiceCollectionExtensions.cs
index 135ba90b97..d747cb349a 100644
--- a/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoBackOfficeServiceCollectionExtensions.cs
+++ b/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoCoreServiceCollectionExtensions.cs
@@ -6,13 +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.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Logging.Serilog;
@@ -21,17 +19,18 @@ using Umbraco.Core.Runtime;
namespace Umbraco.Web.BackOffice.AspNetCore
{
-
-
- public static class UmbracoBackOfficeServiceCollectionExtensions
+ // TODO: Move to Umbraco.Web.Common
+ public static class UmbracoCoreServiceCollectionExtensions
{
-
- public static IServiceCollection AddUmbracoConfiguration(this IServiceCollection services)
+ ///
+ /// Adds the Umbraco Configuration requirements
+ ///
+ ///
+ ///
+ ///
+ public static IServiceCollection AddUmbracoConfiguration(this IServiceCollection services, IConfiguration configuration)
{
- var serviceProvider = services.BuildServiceProvider();
- var configuration = serviceProvider.GetService();
- if (configuration == null)
- throw new InvalidOperationException($"Could not resolve {typeof(IConfiguration)} from the container");
+ if (configuration == null) throw new ArgumentNullException(nameof(configuration));
var configsFactory = new AspNetCoreConfigsFactory(configuration);
@@ -44,48 +43,59 @@ namespace Umbraco.Web.BackOffice.AspNetCore
///
- /// Adds the Umbraco Back Core requirements
+ /// Adds the Umbraco Back Core requirements
///
///
+ ///
///
- ///
- /// Must be called after all services are added to the application because we are cross-wiring the container (currently)
- ///
- public static IServiceCollection AddUmbracoCore(this IServiceCollection services)
+ public static IServiceCollection AddUmbracoCore(this IServiceCollection services, IWebHostEnvironment webHostEnvironment)
{
if (!UmbracoServiceProviderFactory.IsActive)
throw new InvalidOperationException("Ensure to add UseUmbraco() in your Program.cs after ConfigureWebHostDefaults to enable Umbraco's service provider factory");
var umbContainer = UmbracoServiceProviderFactory.UmbracoContainer;
- return services.AddUmbracoCore(umbContainer, Assembly.GetEntryAssembly());
+ return services.AddUmbracoCore(webHostEnvironment, umbContainer, Assembly.GetEntryAssembly());
}
- public static IServiceCollection AddUmbracoCore(this IServiceCollection services, IRegister umbContainer, Assembly entryAssembly)
+ ///
+ /// Adds the Umbraco Back Core requirements
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IServiceCollection AddUmbracoCore(this IServiceCollection services, IWebHostEnvironment webHostEnvironment, IRegister umbContainer, Assembly entryAssembly)
{
+ if (services is null) throw new ArgumentNullException(nameof(services));
+ if (umbContainer is null) throw new ArgumentNullException(nameof(umbContainer));
+ if (entryAssembly is null) throw new ArgumentNullException(nameof(entryAssembly));
+
+ // Special case! The generic host adds a few default services but we need to manually add this one here NOW because
+ // we resolve it before the host finishes configuring in the call to CreateCompositionRoot
services.AddSingleton();
- CreateCompositionRoot(services);
+ CreateCompositionRoot(services, webHostEnvironment, out var logger, out var configs, out var ioHelper, out var hostingEnvironment, out var backOfficeInfo, out var profiler);
- // TODO: Get rid of this 'Current' requirement
- var globalSettings = Current.Configs.Global();
+ var globalSettings = configs.Global();
var umbracoVersion = new UmbracoVersion(globalSettings);
// TODO: Currently we are not passing in any TypeFinderConfig (with ITypeFinderSettings) which we should do, however
// this is not critical right now and would require loading in some config before boot time so just leaving this as-is for now.
- var typeFinder = new TypeFinder(Current.Logger, new DefaultUmbracoAssemblyProvider(entryAssembly));
+ var typeFinder = new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(entryAssembly));
var coreRuntime = GetCoreRuntime(
- Current.Configs,
+ configs,
umbracoVersion,
- Current.IOHelper,
- Current.Logger,
- Current.Profiler,
- Current.HostingEnvironment,
- Current.BackOfficeInfo,
+ ioHelper,
+ logger,
+ profiler,
+ hostingEnvironment,
+ backOfficeInfo,
typeFinder);
- var factory = coreRuntime.Boot(umbContainer);
+ var factory = coreRuntime.Configure(umbContainer);
return services;
}
@@ -107,7 +117,7 @@ namespace Umbraco.Web.BackOffice.AspNetCore
? (IMainDomLock)new SqlMainDomLock(logger, globalSettings, connStrings, dbProviderFactoryCreator)
: new MainDomSemaphoreLock(logger, hostingEnvironment);
- var mainDom = new MainDom(logger, hostingEnvironment, mainDomLock);
+ var mainDom = new MainDom(logger, mainDomLock);
var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetCoreBootPermissionsChecker(),
hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom, typeFinder);
@@ -115,17 +125,16 @@ namespace Umbraco.Web.BackOffice.AspNetCore
return coreRuntime;
}
- private static void CreateCompositionRoot(IServiceCollection services)
+ private static void CreateCompositionRoot(IServiceCollection services, IWebHostEnvironment webHostEnvironment,
+ 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: We need to avoid this, surely there's a way? See ContainerTests.BuildServiceProvider_Before_Host_Is_Configured
var serviceProvider = services.BuildServiceProvider();
var httpContextAccessor = serviceProvider.GetRequiredService();
- var webHostEnvironment = serviceProvider.GetRequiredService();
- var hostApplicationLifetime = serviceProvider.GetRequiredService();
- var configs = serviceProvider.GetService();
+ configs = serviceProvider.GetService();
if (configs == null)
throw new InvalidOperationException($"Could not resolve type {typeof(Configs)} from the container, ensure {nameof(AddUmbracoConfiguration)} is called before calling {nameof(AddUmbracoCore)}");
@@ -133,18 +142,16 @@ namespace Umbraco.Web.BackOffice.AspNetCore
var coreDebug = configs.CoreDebug();
var globalSettings = configs.Global();
- var hostingEnvironment = new AspNetCoreHostingEnvironment(hostingSettings, webHostEnvironment, httpContextAccessor, hostApplicationLifetime);
- var ioHelper = new IOHelper(hostingEnvironment, globalSettings);
- var logger = SerilogLogger.CreateWithDefaultConfiguration(hostingEnvironment,
+ hostingEnvironment = new AspNetCoreHostingEnvironment(hostingSettings, webHostEnvironment, httpContextAccessor);
+ ioHelper = new IOHelper(hostingEnvironment, globalSettings);
+ logger = SerilogLogger.CreateWithDefaultConfiguration(hostingEnvironment,
new AspNetCoreSessionIdResolver(httpContextAccessor),
- // need to build a new service provider since the one already resolved above doesn't have the IRequestCache yet
+ // TODO: We need to avoid this, surely there's a way? See ContainerTests.BuildServiceProvider_Before_Host_Is_Configured
() => services.BuildServiceProvider().GetService(), coreDebug, ioHelper,
new AspNetCoreMarchal());
- var backOfficeInfo = new AspNetCoreBackOfficeInfo(globalSettings);
- var profiler = new LogProfiler(logger);
-
- Current.Initialize(logger, configs, ioHelper, hostingEnvironment, backOfficeInfo, profiler);
+ backOfficeInfo = new AspNetCoreBackOfficeInfo(globalSettings);
+ profiler = new LogProfiler(logger);
}
private class AspNetCoreBootPermissionsChecker : IUmbracoBootPermissionChecker
@@ -154,5 +161,7 @@ namespace Umbraco.Web.BackOffice.AspNetCore
// nothing to check
}
}
+
+
}
}
diff --git a/src/Umbraco.Web.UI.NetCore/Startup.cs b/src/Umbraco.Web.UI.NetCore/Startup.cs
index ab8c6e021c..2753676452 100644
--- a/src/Umbraco.Web.UI.NetCore/Startup.cs
+++ b/src/Umbraco.Web.UI.NetCore/Startup.cs
@@ -16,13 +16,29 @@ namespace Umbraco.Web.UI.BackOffice
{
public class Startup
{
+ private readonly IWebHostEnvironment _webHostEnvironment;
+ private readonly IConfiguration _config;
+
+ ///
+ /// Constructor
+ ///
+ ///
+ ///
+ ///
+ /// Only a few services are possible to be injected here https://github.com/dotnet/aspnetcore/issues/9337
+ ///
+ public Startup(IWebHostEnvironment webHostEnvironment, IConfiguration config)
+ {
+ _webHostEnvironment = webHostEnvironment ?? throw new ArgumentNullException(nameof(webHostEnvironment));
+ _config = config ?? throw new ArgumentNullException(nameof(config));
+ }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
- services.AddUmbracoConfiguration();
- services.AddUmbracoCore();
+ services.AddUmbracoConfiguration(_config);
+ services.AddUmbracoCore(_webHostEnvironment);
services.AddUmbracoWebsite();
}
diff --git a/src/Umbraco.Web.Website/AspNetCore/UmbracoWebsiteServiceCollectionExtensions.cs b/src/Umbraco.Web.Website/AspNetCore/UmbracoWebsiteServiceCollectionExtensions.cs
index f7a198bc3b..6d2ce5e7e4 100644
--- a/src/Umbraco.Web.Website/AspNetCore/UmbracoWebsiteServiceCollectionExtensions.cs
+++ b/src/Umbraco.Web.Website/AspNetCore/UmbracoWebsiteServiceCollectionExtensions.cs
@@ -19,6 +19,7 @@ namespace Umbraco.Web.Website.AspNetCore
{
public static IServiceCollection AddUmbracoWebsite(this IServiceCollection services)
{
+ // TODO: We need to avoid this, surely there's a way? See ContainerTests.BuildServiceProvider_Before_Host_Is_Configured
var serviceProvider = services.BuildServiceProvider();
var configs = serviceProvider.GetService();
var imagingSettings = configs.Imaging();
diff --git a/src/Umbraco.Web/AspNet/AspNetApplicationShutdownRegistry.cs b/src/Umbraco.Web/AspNet/AspNetApplicationShutdownRegistry.cs
new file mode 100644
index 0000000000..dbd6e9e834
--- /dev/null
+++ b/src/Umbraco.Web/AspNet/AspNetApplicationShutdownRegistry.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Concurrent;
+using System.Web.Hosting;
+using Umbraco.Core.Hosting;
+using IRegisteredObject = Umbraco.Core.IRegisteredObject;
+
+namespace Umbraco.Web.Hosting
+{
+ public class AspNetApplicationShutdownRegistry : IApplicationShutdownRegistry
+ {
+ private readonly ConcurrentDictionary _registeredObjects =
+ new ConcurrentDictionary();
+
+ public void RegisterObject(IRegisteredObject registeredObject)
+ {
+ var wrapped = new RegisteredObjectWrapper(registeredObject);
+ if (!_registeredObjects.TryAdd(registeredObject, wrapped))
+ {
+ throw new InvalidOperationException("Could not register object");
+ }
+ HostingEnvironment.RegisterObject(wrapped);
+ }
+
+ public void UnregisterObject(IRegisteredObject registeredObject)
+ {
+ if (_registeredObjects.TryGetValue(registeredObject, out var wrapped))
+ {
+ HostingEnvironment.UnregisterObject(wrapped);
+ }
+ }
+
+ private class RegisteredObjectWrapper : System.Web.Hosting.IRegisteredObject
+ {
+ private readonly IRegisteredObject _inner;
+
+ public RegisteredObjectWrapper(IRegisteredObject inner)
+ {
+ _inner = inner;
+ }
+
+ public void Stop(bool immediate)
+ {
+ _inner.Stop(immediate);
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Web/AspNet/AspNetHostingEnvironment.cs b/src/Umbraco.Web/AspNet/AspNetHostingEnvironment.cs
index aa07894aa9..a61ad356d5 100644
--- a/src/Umbraco.Web/AspNet/AspNetHostingEnvironment.cs
+++ b/src/Umbraco.Web/AspNet/AspNetHostingEnvironment.cs
@@ -1,21 +1,15 @@
using System;
-using System.Collections;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
using System.Web;
using System.Web.Hosting;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Hosting;
-using Umbraco.Core.IO;
-using IRegisteredObject = Umbraco.Core.IRegisteredObject;
namespace Umbraco.Web.Hosting
{
public class AspNetHostingEnvironment : IHostingEnvironment
{
- private readonly ConcurrentDictionary _registeredObjects =
- new ConcurrentDictionary();
+
private readonly IHostingSettings _hostingSettings;
private string _localTempPath;
@@ -46,23 +40,7 @@ namespace Umbraco.Web.Hosting
}
public string ToAbsolute(string virtualPath, string root) => VirtualPathUtility.ToAbsolute(virtualPath, root);
- public void RegisterObject(IRegisteredObject registeredObject)
- {
- var wrapped = new RegisteredObjectWrapper(registeredObject);
- if (!_registeredObjects.TryAdd(registeredObject, wrapped))
- {
- throw new InvalidOperationException("Could not register object");
- }
- HostingEnvironment.RegisterObject(wrapped);
- }
-
- public void UnregisterObject(IRegisteredObject registeredObject)
- {
- if (_registeredObjects.TryGetValue(registeredObject, out var wrapped))
- {
- HostingEnvironment.UnregisterObject(wrapped);
- }
- }
+
public string LocalTempPath
{
@@ -101,20 +79,7 @@ namespace Umbraco.Web.Hosting
}
}
}
- private class RegisteredObjectWrapper : System.Web.Hosting.IRegisteredObject
- {
- private readonly IRegisteredObject _inner;
-
- public RegisteredObjectWrapper(IRegisteredObject inner)
- {
- _inner = inner;
- }
-
- public void Stop(bool immediate)
- {
- _inner.Stop(immediate);
- }
- }
+
}
diff --git a/src/Umbraco.Web/AspNet/AspNetSessionManager.cs b/src/Umbraco.Web/AspNet/AspNetSessionManager.cs
index bf7b1c05c3..f81daadb0a 100644
--- a/src/Umbraco.Web/AspNet/AspNetSessionManager.cs
+++ b/src/Umbraco.Web/AspNet/AspNetSessionManager.cs
@@ -1,6 +1,6 @@
using System.Web;
-using Umbraco.Core.Session;
using Umbraco.Net;
+using Umbraco.Core.Session;
namespace Umbraco.Web.AspNet
{
diff --git a/src/Umbraco.Web/Compose/AuditEventsComponent.cs b/src/Umbraco.Web/Compose/AuditEventsComponent.cs
index fba6e754c8..bd2520aa90 100644
--- a/src/Umbraco.Web/Compose/AuditEventsComponent.cs
+++ b/src/Umbraco.Web/Compose/AuditEventsComponent.cs
@@ -7,10 +7,10 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
+using Umbraco.Net;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Implement;
-using Umbraco.Net;
using Umbraco.Web.Security;
namespace Umbraco.Core.Compose
diff --git a/src/Umbraco.Web/Composing/Current.cs b/src/Umbraco.Web/Composing/Current.cs
index eec3dcd1e3..70083d47dd 100644
--- a/src/Umbraco.Web/Composing/Current.cs
+++ b/src/Umbraco.Web/Composing/Current.cs
@@ -11,6 +11,7 @@ using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Hosting;
using Umbraco.Core.Mapping;
+using Umbraco.Net;
using Umbraco.Core.PackageActions;
using Umbraco.Core.Packaging;
using Umbraco.Core.PropertyEditors;
@@ -18,7 +19,6 @@ using Umbraco.Core.Scoping;
using Umbraco.Core.Services;
using Umbraco.Core.Strings;
using Umbraco.Core.Sync;
-using Umbraco.Net;
using Umbraco.Web.Actions;
using Umbraco.Web.Cache;
using Umbraco.Web.Editors;
diff --git a/src/Umbraco.Web/Editors/PackageInstallController.cs b/src/Umbraco.Web/Editors/PackageInstallController.cs
index 672b47f1eb..fe552650ea 100644
--- a/src/Umbraco.Web/Editors/PackageInstallController.cs
+++ b/src/Umbraco.Web/Editors/PackageInstallController.cs
@@ -14,11 +14,11 @@ using Umbraco.Core.Logging;
using Umbraco.Core.Mapping;
using Umbraco.Core.Models.Editors;
using Umbraco.Core.Models.Packaging;
+using Umbraco.Net;
using Umbraco.Core.Packaging;
using Umbraco.Core.Persistence;
using Umbraco.Core.Services;
using Umbraco.Core.Strings;
-using Umbraco.Net;
using Umbraco.Web.JavaScript;
using Umbraco.Web.Models;
using Umbraco.Web.Models.ContentEditing;
diff --git a/src/Umbraco.Web/Profiling/WebProfilingController.cs b/src/Umbraco.Web/Profiling/WebProfilingController.cs
index b37a7eefb8..d8f71b5c85 100644
--- a/src/Umbraco.Web/Profiling/WebProfilingController.cs
+++ b/src/Umbraco.Web/Profiling/WebProfilingController.cs
@@ -1,6 +1,7 @@
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
+using Umbraco.Core.Hosting;
using Umbraco.Core.Logging;
using Umbraco.Core.Mapping;
using Umbraco.Core.Persistence;
@@ -18,7 +19,7 @@ namespace Umbraco.Web.Profiling
[UmbracoApplicationAuthorize(Core.Constants.Applications.Settings)]
public class WebProfilingController : UmbracoAuthorizedJsonController
{
- private readonly IRuntimeState _runtimeState;
+ private readonly IHostingEnvironment _hosting;
public WebProfilingController(
IGlobalSettings globalSettings,
@@ -30,17 +31,18 @@ namespace Umbraco.Web.Profiling
IRuntimeState runtimeState,
IShortStringHelper shortStringHelper,
UmbracoMapper umbracoMapper,
- IPublishedUrlProvider publishedUrlProvider)
+ IPublishedUrlProvider publishedUrlProvider,
+ IHostingEnvironment hosting)
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, shortStringHelper, umbracoMapper, publishedUrlProvider)
{
- _runtimeState = runtimeState;
+ _hosting = hosting;
}
public object GetStatus()
{
return new
{
- Enabled = _runtimeState.Debug
+ Enabled = _hosting.IsDebugMode
};
}
}}
diff --git a/src/Umbraco.Web/Runtime/WebInitialComposer.cs b/src/Umbraco.Web/Runtime/WebInitialComposer.cs
index b81cafdb40..2a746ffe4c 100644
--- a/src/Umbraco.Web/Runtime/WebInitialComposer.cs
+++ b/src/Umbraco.Web/Runtime/WebInitialComposer.cs
@@ -18,7 +18,6 @@ using Umbraco.Core.Runtime;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
using Umbraco.Core.Sync;
-using Umbraco.Net;
using Umbraco.Web.Actions;
using Umbraco.Web.Cache;
using Umbraco.Web.Composing.CompositionExtensions;
@@ -46,6 +45,7 @@ using Umbraco.Web.WebApi;
using Umbraco.Web.PropertyEditors;
using Umbraco.Examine;
using Umbraco.Core.Models;
+using Umbraco.Net;
using Umbraco.Core.Request;
using Umbraco.Core.Session;
using Umbraco.Web.AspNet;
@@ -72,8 +72,6 @@ namespace Umbraco.Web.Runtime
composition.Register(Lifetime.Singleton);
- composition.Register();
- composition.Register();
composition.Register(Lifetime.Singleton);
composition.Register();
composition.Register(Lifetime.Singleton);
diff --git a/src/Umbraco.Web/Security/AppBuilderExtensions.cs b/src/Umbraco.Web/Security/AppBuilderExtensions.cs
index 8fab9f4ea8..b3f950433c 100644
--- a/src/Umbraco.Web/Security/AppBuilderExtensions.cs
+++ b/src/Umbraco.Web/Security/AppBuilderExtensions.cs
@@ -17,9 +17,9 @@ using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Core.Mapping;
using Umbraco.Core.Models.Identity;
+using Umbraco.Net;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
-using Umbraco.Net;
using Umbraco.Web.Composing;
using Umbraco.Web.Models.Identity;
using Constants = Umbraco.Core.Constants;
diff --git a/src/Umbraco.Web/Security/BackOfficeUserManager.cs b/src/Umbraco.Web/Security/BackOfficeUserManager.cs
index 354b9c2dde..7de7ba37e5 100644
--- a/src/Umbraco.Web/Security/BackOfficeUserManager.cs
+++ b/src/Umbraco.Web/Security/BackOfficeUserManager.cs
@@ -9,9 +9,9 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Mapping;
using Umbraco.Core.Models.Identity;
+using Umbraco.Net;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
-using Umbraco.Net;
using Umbraco.Web.Models.Identity;
using IPasswordHasher = Microsoft.AspNet.Identity.IPasswordHasher;
diff --git a/src/Umbraco.Web/Security/Providers/UmbracoMembershipProvider.cs b/src/Umbraco.Web/Security/Providers/UmbracoMembershipProvider.cs
index d2eeebaeaf..b099110911 100644
--- a/src/Umbraco.Web/Security/Providers/UmbracoMembershipProvider.cs
+++ b/src/Umbraco.Web/Security/Providers/UmbracoMembershipProvider.cs
@@ -10,10 +10,10 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Hosting;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Membership;
+using Umbraco.Net;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
-using Umbraco.Net;
using Umbraco.Web.Composing;
namespace Umbraco.Web.Security.Providers
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index e8aaecdf4d..4b4f06ad2a 100755
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -134,6 +134,7 @@
+
@@ -585,4 +586,4 @@
-
+
\ No newline at end of file
diff --git a/src/Umbraco.Web/UmbracoApplication.cs b/src/Umbraco.Web/UmbracoApplication.cs
index 9f24da95e3..30d3fe5041 100644
--- a/src/Umbraco.Web/UmbracoApplication.cs
+++ b/src/Umbraco.Web/UmbracoApplication.cs
@@ -32,7 +32,7 @@ namespace Umbraco.Web
? (IMainDomLock)new SqlMainDomLock(logger, globalSettings, connectionStrings, dbProviderFactoryCreator)
: new MainDomSemaphoreLock(logger, hostingEnvironment);
- var mainDom = new MainDom(logger, hostingEnvironment, mainDomLock);
+ var mainDom = new MainDom(logger, mainDomLock);
var requestCache = new HttpRequestAppCache(() => HttpContext.Current?.Items);
var umbracoBootPermissionChecker = new AspNetUmbracoBootPermissionChecker();
diff --git a/src/Umbraco.Web/UmbracoApplicationBase.cs b/src/Umbraco.Web/UmbracoApplicationBase.cs
index ce5f1304cd..0963ad3c07 100644
--- a/src/Umbraco.Web/UmbracoApplicationBase.cs
+++ b/src/Umbraco.Web/UmbracoApplicationBase.cs
@@ -152,7 +152,9 @@ namespace Umbraco.Web
Umbraco.Composing.Current.Profiler,
Umbraco.Composing.Current.HostingEnvironment,
Umbraco.Composing.Current.BackOfficeInfo);
- _factory = Current.Factory = _runtime.Boot(register);
+ _factory = Current.Factory = _runtime.Configure(register);
+
+ _runtime.Start();
}
// called by ASP.NET (auto event wireup) once per app domain
diff --git a/src/Umbraco.Web/UmbracoContext.cs b/src/Umbraco.Web/UmbracoContext.cs
index 6f5fc26f90..9cc651f359 100644
--- a/src/Umbraco.Web/UmbracoContext.cs
+++ b/src/Umbraco.Web/UmbracoContext.cs
@@ -150,7 +150,7 @@ namespace Umbraco.Web
{
var request = GetRequestFromContext();
//NOTE: the request can be null during app startup!
- return Current.RuntimeState.Debug
+ return Current.HostingEnvironment.IsDebugMode
&& request != null
&& (string.IsNullOrEmpty(request["umbdebugshowtrace"]) == false
|| string.IsNullOrEmpty(request["umbdebug"]) == false
diff --git a/src/Umbraco.Web/UmbracoDefaultOwinStartup.cs b/src/Umbraco.Web/UmbracoDefaultOwinStartup.cs
index a69e6c6f8d..a0b7cdd225 100644
--- a/src/Umbraco.Web/UmbracoDefaultOwinStartup.cs
+++ b/src/Umbraco.Web/UmbracoDefaultOwinStartup.cs
@@ -7,8 +7,8 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Core.Mapping;
-using Umbraco.Core.Services;
using Umbraco.Net;
+using Umbraco.Core.Services;
using Umbraco.Web;
using Umbraco.Web.Composing;
using Umbraco.Web.Security;
diff --git a/src/Umbraco.Web/UrlHelperExtensions.cs b/src/Umbraco.Web/UrlHelperExtensions.cs
index a0bf5d3ded..f0ee309630 100644
--- a/src/Umbraco.Web/UrlHelperExtensions.cs
+++ b/src/Umbraco.Web/UrlHelperExtensions.cs
@@ -143,12 +143,12 @@ namespace Umbraco.Web
//in case the user bypasses the installer and just bumps the web.config or client dependency config
//if in debug mode, always burst the cache
- if (Current.RuntimeState.Debug)
+ if (Current.HostingEnvironment.IsDebugMode)
{
return DateTime.Now.Ticks.ToString(CultureInfo.InvariantCulture).GenerateHash();
}
- var version = Current.RuntimeState.SemanticVersion.ToSemanticString();
+ var version = Current.UmbracoVersion.SemanticVersion.ToSemanticString();
return $"{version}.{ClientDependencySettings.Instance.Version}".GenerateHash();
}
}