Merge pull request #7840 from umbraco/netcore/feature/booting-netcore-db

Netcore - Runtime booting and shutting down (and more)
This commit is contained in:
Shannon Deminick
2020-03-26 15:40:18 +11:00
committed by GitHub
81 changed files with 924 additions and 534 deletions
+1
View File
@@ -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/*
+7 -7
View File
@@ -33,13 +33,13 @@ namespace Umbraco.Core.Composing
/// <param name="ioHelper">An IOHelper</param>
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
@@ -18,6 +18,7 @@ namespace Umbraco.Core.Composing
{
"Umbraco.Core",
"Umbraco.Web",
"Umbraco.Web.BackOffice",
"Umbraco.Infrastructure",
"Umbraco.PublishedCache.NuCache",
"Umbraco.ModelsBuilder.Embedded",
@@ -0,0 +1,8 @@
namespace Umbraco.Core.Hosting
{
public interface IApplicationShutdownRegistry
{
void RegisterObject(IRegisteredObject registeredObject);
void UnregisterObject(IRegisteredObject registeredObject);
}
}
@@ -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);
}
}
@@ -1,5 +1,6 @@
namespace Umbraco.Net
{
// TODO: This shouldn't be in this namespace?
public interface IUmbracoApplicationLifetime
{
/// <summary>
+9 -1
View File
@@ -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.
/// </summary>
/// <remarks>
/// 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
/// </remarks>
bool IsMainDom { get; }
/// <summary>
/// Tries to acquire the MainDom, returns true if successful else false
/// </summary>
/// <param name="hostingEnvironment"></param>
/// <returns></returns>
bool Acquire(IApplicationShutdownRegistry hostingEnvironment);
/// <summary>
/// Registers a resource that requires the current AppDomain to be the main domain to function.
/// </summary>
+16 -9
View File
@@ -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();
});
}
/// <summary>
/// Registers a resource that requires the current AppDomain to be the main domain to function.
/// </summary>
@@ -180,10 +188,9 @@ namespace Umbraco.Core.Runtime
/// Gets a value indicating whether the current domain is the main domain.
/// </summary>
/// <remarks>
/// 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
/// </remarks>
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
+10 -6
View File
@@ -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<RecurringTaskBase> 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<bool> PerformRunAsync(CancellationToken token)
{
// not on replicas nor unknown role servers
switch (_runtime.ServerRole)
switch (_serverRegistrar.GetCurrentServerRole())
{
case ServerRole.Replica:
_logger.Debug<KeepAlive>("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<KeepAlive>("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<KeepAlive>("No umbracoApplicationUrl for service (yet), skip.");
@@ -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<RecurringTaskBase> runner, int delayMilliseconds, int periodMilliseconds,
IEnumerable<DirectoryInfo> 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<TempFileCleanup>("Does not run if not MainDom.");
return false; // do NOT repeat, going down
+3 -1
View File
@@ -13,13 +13,15 @@ namespace Umbraco.Core
/// </summary>
/// <param name="register">The application register.</param>
/// <returns>The application factory.</returns>
IFactory Boot(IRegister register);
IFactory Configure(IRegister register);
/// <summary>
/// Gets the runtime state.
/// </summary>
IRuntimeState State { get; }
void Start();
/// <summary>
/// Terminates the runtime.
/// </summary>
@@ -25,33 +25,12 @@ namespace Umbraco.Core
/// </summary>
SemVersion SemanticVersion { get; }
/// <summary>
/// Gets a value indicating whether the application is running in debug mode.
/// </summary>
bool Debug { get; }
/// <summary>
/// Gets a value indicating whether the runtime is the current main domain.
/// </summary>
bool IsMainDom { get; }
/// <summary>
/// Get the server's current role.
/// </summary>
ServerRole ServerRole { get; }
/// <summary>
/// Gets the Umbraco application url.
/// </summary>
/// <remarks>This is eg "http://www.example.com".</remarks>
Uri ApplicationUrl { get; }
/// <summary>
/// Gets the Umbraco application virtual path.
/// </summary>
/// <remarks>This is either "/" or eg "/virtual".</remarks>
string ApplicationVirtualPath { get; }
/// <summary>
/// Gets the runtime level of execution.
/// </summary>
@@ -77,6 +56,5 @@ namespace Umbraco.Core
/// </summary>
BootFailedException BootFailedException { get; }
IMainDom MainDom { get; }
}
}
+4
View File
@@ -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
/// <inheritdoc />
public bool IsMainDom { get; private set; } = true;
// always acquire
public bool Acquire(IApplicationShutdownRegistry hostingEnvironment) => true;
/// <inheritdoc />
public bool Register(Action release, int weight = 100)
=> Register(null, release, weight);
@@ -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;
@@ -91,7 +91,6 @@ namespace Umbraco.Web.Compose
private readonly BackgroundTaskRunner<IBackgroundTask> _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
@@ -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;
@@ -13,8 +13,9 @@ namespace Umbraco.Core.Composing
/// <param name="builder"></param>
/// <returns></returns>
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);
}
}
@@ -1,6 +1,7 @@
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
@@ -15,6 +16,9 @@ namespace Umbraco.Core
/// <summary>
/// Registers essential services.
/// </summary>
/// <remarks>
/// These services are all either created by the runtime or used to construct the runtime
/// </remarks>
public static void RegisterEssentials(this Composition composition,
ILogger logger, IProfiler profiler, IProfilingLogger profilingLogger,
IMainDom mainDom,
@@ -25,8 +29,10 @@ namespace Umbraco.Core
ITypeFinder typeFinder,
IIOHelper ioHelper,
IUmbracoVersion umbracoVersion,
IDbProviderFactoryCreator dbProviderFactoryCreator)
{
IDbProviderFactoryCreator dbProviderFactoryCreator,
IHostingEnvironment hostingEnvironment,
IBackOfficeInfo backOfficeInfo)
{
composition.RegisterUnique(logger);
composition.RegisterUnique(profiler);
composition.RegisterUnique(profilingLogger);
@@ -42,6 +48,8 @@ namespace Umbraco.Core
composition.RegisterUnique(umbracoVersion);
composition.RegisterUnique(dbProviderFactoryCreator);
composition.RegisterUnique(factory => factory.GetInstance<IUmbracoDatabaseFactory>().BulkSqlInsertProvider);
composition.RegisterUnique(hostingEnvironment);
composition.RegisterUnique(backOfficeInfo);
}
}
}
@@ -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
@@ -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
@@ -46,7 +46,7 @@ namespace Umbraco.Core.Migrations.Install
IIOHelper ioHelper,
IUmbracoVersion umbracoVersion,
IDbProviderFactoryCreator dbProviderFactoryCreator,
IConfigManipulator configManipulator)
IConfigManipulator configManipulator)
{
_scopeProvider = scopeProvider;
_globalSettings = globalSettings;
@@ -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<IServerMessenger>(factory
=> new DatabaseServerMessenger(
factory.GetInstance<IRuntimeState>(),
factory.GetInstance<IMainDom>(),
factory.GetInstance<IScopeProvider>(),
factory.GetInstance<ISqlContext>(),
factory.GetInstance<IProfilingLogger>(),
factory.GetInstance<IServerRegistrar>(),
true, new DatabaseServerMessengerOptions(),
factory.GetInstance<IHostingEnvironment>(),
factory.GetInstance<CacheRefresherCollection>()
@@ -176,6 +177,8 @@ namespace Umbraco.Core.Runtime
// Grid config is not a real config file as we know them
composition.RegisterUnique<IGridConfig, GridConfig>();
// Config manipulator
composition.RegisterUnique<IConfigManipulator, JsonConfigManipulator>();
}
}
}
@@ -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<T>()' and NOT '_factory.GetInstance<T>'
// as the second one captures the current value (null) and therefore fails
_state = new RuntimeState(Logger,
Configs.Global(),
new Lazy<IMainDom>(() => mainDom),
new Lazy<IServerRegistrar>(() => _factory.GetInstance<IServerRegistrar>()),
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; }
/// <summary>
/// Gets the profiler.
/// </summary>
protected IProfiler Profiler { get; set; }
protected IProfiler Profiler { get; }
/// <summary>
/// Gets the profiling logger.
@@ -110,11 +103,13 @@ namespace Umbraco.Core.Runtime
/// <inheritdoc />
public IRuntimeState State => _state;
public IMainDom MainDom { get; private set; }
public IMainDom MainDom { get; }
/// <inheritdoc/>
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;
}
/// <summary>
/// Boots the runtime within a timer.
/// Configure the runtime within a timer.
/// </summary>
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<T>()' and NOT '_factory.GetInstance<T>'
// as the second one captures the current value (null) and therefore fails
_state = new RuntimeState(Logger,
Configs.Global(),
new Lazy<IMainDom>(() => _factory.GetInstance<IMainDom>()),
new Lazy<IServerRegistrar>(() => _factory.GetInstance<IServerRegistrar>()),
UmbracoVersion, HostingEnvironment, BackOfficeInfo)
{
Level = RuntimeLevel.Boot
};
// create the composition
composition = new Composition(register, typeLoader, ProfilingLogger, _state, Configs, IOHelper, appCaches);
composition.RegisterEssentials(Logger, Profiler, ProfilingLogger, MainDom, appCaches, databaseFactory, typeLoader, _state, TypeFinder, IOHelper, UmbracoVersion, DbProviderFactoryCreator);
composition.RegisterEssentials(Logger, Profiler, ProfilingLogger, MainDom, appCaches, databaseFactory, typeLoader, _state, TypeFinder, IOHelper, UmbracoVersion, DbProviderFactoryCreator, HostingEnvironment, BackOfficeInfo);
// run handlers
RuntimeOptions.DoRuntimeEssentials(composition, appCaches, typeLoader, databaseFactory);
// 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<IRuntime>(_ => 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<ComponentCollection>();
_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<IApplicationShutdownRegistry>();
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<IApplicationShutdownRegistry>());
// create & initialize the components
_components = _factory.GetInstance<ComponentCollection>();
_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<CoreRuntime>("Acquiring MainDom.", "Acquired."))
{
try
{
return mainDom.IsMainDom;
return mainDom.Acquire(applicationShutdownRegistry);
}
catch
{
@@ -346,12 +337,6 @@ namespace Umbraco.Core.Runtime
_components?.Terminate();
}
/// <summary>
/// Composes the runtime.
/// </summary>
public virtual void Compose(Composition composition)
{
}
#region Getters
@@ -392,5 +377,6 @@ namespace Umbraco.Core.Runtime
#endregion
}
}
@@ -40,7 +40,7 @@ namespace Umbraco.Web.Runtime
}
/// <inheritdoc/>
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<CoreRuntime>("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
+5 -5
View File
@@ -16,7 +16,7 @@ namespace Umbraco.Core
public static class RuntimeOptions
{
private static List<Action<IProfilingLogger>> _onBoot;
private static List<Action<Composition, AppCaches, TypeLoader, IUmbracoDatabaseFactory>> _onEssentials;
private static List<Action<IFactory>> _onEssentials;
/// <summary>
/// Executes the RuntimeBoot handlers.
@@ -33,13 +33,13 @@ namespace Umbraco.Core
/// <summary>
/// Executes the RuntimeEssentials handlers.
/// </summary>
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);
}
/// <summary>
@@ -64,10 +64,10 @@ namespace Umbraco.Core
/// essential things (AppCaches, a TypeLoader, and a database factory) but
/// before anything else.</para>
/// </remarks>
public static void OnRuntimeEssentials(Action<Composition, AppCaches, TypeLoader, IUmbracoDatabaseFactory> action)
public static void OnRuntimeEssentials(Action<IFactory> action)
{
if (_onEssentials == null)
_onEssentials = new List<Action<Composition, AppCaches, TypeLoader, IUmbracoDatabaseFactory>>();
_onEssentials = new List<Action<IFactory>>();
_onEssentials.Add(action);
}
}
+4 -40
View File
@@ -22,46 +22,22 @@ namespace Umbraco.Core
private readonly ILogger _logger;
private readonly IGlobalSettings _globalSettings;
private readonly ConcurrentHashSet<string> _applicationUrls = new ConcurrentHashSet<string>();
private readonly Lazy<IMainDom> _mainDom;
private readonly Lazy<IServerRegistrar> _serverRegistrar;
private readonly IUmbracoVersion _umbracoVersion;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IBackOfficeInfo _backOfficeInfo;
/// <summary>
/// Initializes a new instance of the <see cref="RuntimeState"/> class.
/// </summary>
public RuntimeState(ILogger logger, IGlobalSettings globalSettings,
Lazy<IMainDom> mainDom, Lazy<IServerRegistrar> 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;
}
/// <summary>
/// Gets the server registrar.
/// </summary>
/// <remarks>
/// <para>This is NOT exposed in the interface.</para>
/// </remarks>
private IServerRegistrar ServerRegistrar => _serverRegistrar.Value;
/// <summary>
/// Gets the application MainDom.
/// </summary>
/// <remarks>
/// <para>This is NOT exposed in the interface as MainDom is internal.</para>
/// </remarks>
public IMainDom MainDom => _mainDom.Value;
/// <inheritdoc />
public Version Version => _umbracoVersion.Current;
@@ -72,26 +48,14 @@ namespace Umbraco.Core
/// <inheritdoc />
public SemVersion SemanticVersion => _umbracoVersion.SemanticVersion;
/// <inheritdoc />
public bool Debug => _hostingEnvironment.IsDebugMode;
/// <inheritdoc />
public bool IsMainDom => MainDom.IsMainDom;
/// <inheritdoc />
public ServerRole ServerRole => ServerRegistrar.GetCurrentServerRole();
/// <inheritdoc />
public Uri ApplicationUrl { get; private set; }
/// <inheritdoc />
public string ApplicationVirtualPath { get; }
public string CurrentMigrationState { get; private set; }
/// <inheritdoc />
public string CurrentMigrationState { get; internal set; }
/// <inheritdoc />
public string FinalMigrationState { get; internal set; }
public string FinalMigrationState { get; private set; }
/// <inheritdoc />
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;
@@ -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<T> _tasks = new BufferBlock<T>(new DataflowBlockOptions());
@@ -105,7 +105,7 @@ namespace Umbraco.Web.Scheduling
/// <param name="logger">A logger.</param>
/// <param name="hostingEnvironment">The hosting environment</param>
/// <param name="hook">An optional main domain hook.</param>
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
/// <param name="logger">A logger.</param>
/// <param name="hostingEnvironment">The hosting environment</param>
/// <param name="hook">An optional main domain hook.</param>
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
/// <param name="logger">A logger.</param>
/// <param name="hostingEnvironment">The hosting environment</param>
/// <param name="hook">An optional main domain hook.</param>
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
/// <param name="logger">A logger.</param>
/// <param name="hostingEnvironment">The hosting environment</param>
/// <param name="hook">An optional main domain hook.</param>
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));
@@ -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<RecurringTaskBase> 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<bool> 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<HealthCheckNotifier>("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<HealthCheckNotifier>("Does not run if not MainDom.");
return false; // do NOT repeat, going down
@@ -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<RecurringTaskBase> 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<LogScrubber>("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<LogScrubber>("Does not run if not MainDom.");
return false; // do NOT repeat, going down
@@ -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<RecurringTaskBase> 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<ScheduledPublishing>("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<ScheduledPublishing>("Does not run if not MainDom.");
return false; // do NOT repeat, going down
@@ -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<IBackgroundTask> _keepAliveRunner;
private BackgroundTaskRunner<IBackgroundTask> _publishingRunner;
private BackgroundTaskRunner<IBackgroundTask> _tasksRunner;
private BackgroundTaskRunner<IBackgroundTask> _scrubberRunner;
private BackgroundTaskRunner<IBackgroundTask> _fileCleanupRunner;
private BackgroundTaskRunner<IBackgroundTask> _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<IBackgroundTask>("KeepAlive", _logger, _hostingEnvironment);
_publishingRunner = new BackgroundTaskRunner<IBackgroundTask>("ScheduledPublishing", _logger, _hostingEnvironment);
_tasksRunner = new BackgroundTaskRunner<IBackgroundTask>("ScheduledTasks", _logger, _hostingEnvironment);
_scrubberRunner = new BackgroundTaskRunner<IBackgroundTask>("LogScrubber", _logger, _hostingEnvironment);
_fileCleanupRunner = new BackgroundTaskRunner<IBackgroundTask>("TempFileCleanup", _logger, _hostingEnvironment);
_healthCheckRunner = new BackgroundTaskRunner<IBackgroundTask>("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;
}
@@ -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<IBackgroundTask> _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
/// <summary>
/// Called to rebuild empty indexes on startup
/// </summary>
/// <param name="indexRebuilder"></param>
/// <param name="logger"></param>
/// <param name="onlyEmptyIndexes"></param>
/// <param name="waitMilliseconds"></param>
public void RebuildIndexes(bool onlyEmptyIndexes, int waitMilliseconds = 0)
@@ -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:
@@ -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
+4 -7
View File
@@ -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<ILogger>(),
Mock.Of<IGlobalSettings>(),
new Lazy<IMainDom>(),
new Lazy<IServerRegistrar>(),
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();
@@ -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<IRuntimeState>();
var umbracoDatabaseFactory = Mock.Of<IUmbracoDatabaseFactory>();
var dbProviderFactoryCreator = Mock.Of<IDbProviderFactoryCreator>();
var dbProviderFactoryCreator = Mock.Of<IDbProviderFactoryCreator>();
var typeLoader = testHelper.GetMockedTypeLoader();
// Register in the container
@@ -45,7 +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<IHostApplicationLifetime>();
// Re-add as a callback, ensures its the same instance all the way through (hack)
services.AddSingleton<IHostApplicationLifetime>(x => lifetime1);
});
var host = await hostBuilder.StartAsync();
var lifetime2 = host.Services.GetRequiredService<IHostApplicationLifetime>();
var lifetime3 = umbracoContainer.GetInstance<IHostApplicationLifetime>();
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()
@@ -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<string, string>($"ConnectionStrings:{Constants.System.UmbracoConnectionName}", instance.GetConnectionString(dbName))
});
});
return hostBuilder;
}
}
}
@@ -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();
}
}
}
@@ -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<IHostApplicationLifetime>());
_httpContextAccessor);
_hostingLifetime = new AspNetCoreApplicationShutdownRegistry(Mock.Of<IHostApplicationLifetime>());
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;
}
}
@@ -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)
{
}
/// <summary>
/// Override for tests since we are not hosted
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
bool Umbraco.Core.Hosting.IHostingEnvironment.IsHosted { get; } = false;
}
}
@@ -0,0 +1,18 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
namespace Umbraco.Tests.Integration.Implementations
{
/// <summary>
/// Ensures the host lifetime ends as soon as code execution is done
/// </summary>
public class TestLifetime : IHostLifetime
{
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public Task WaitForStartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
}
+182 -26
View File
@@ -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();
}
/// <summary>
/// Manually configure the containers/dependencies and call Boot on Core runtime
/// </summary>
[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<IHostApplicationLifetime>());
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);
}
/// <summary>
/// Calling AddUmbracoCore to configure the container
/// </summary>
[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<IHttpContextAccessor>(x => testHelper.GetHttpContextAccessor());
services.AddSingleton<IWebHostEnvironment>(x => testHelper.GetWebHostEnvironment());
services.AddSingleton<IHostApplicationLifetime>(x => Mock.Of<IHostApplicationLifetime>());
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<IConfiguration>(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<IRuntimeState>();
var mainDom = umbracoContainer.GetInstance<IMainDom>();
var runtimeState = app.ApplicationServices.GetRequiredService<IRuntimeState>();
var mainDom = app.ApplicationServices.GetRequiredService<IMainDom>();
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
}
/// <summary>
/// Calling AddUmbracoCore to configure the container and UseUmbracoCore to start the runtime
/// </summary>
/// <returns></returns>
[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<IRuntimeState>();
var mainDom = app.ApplicationServices.GetRequiredService<IMainDom>();
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<IRuntimeState>();
Assert.AreEqual(RuntimeLevel.Install, runtimeState.Level);
var dbBuilder = app.ApplicationServices.GetRequiredService<DatabaseBuilder>();
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<IUmbracoDatabaseFactory>();
//var profilingLogger = app.ApplicationServices.GetRequiredService<IProfilingLogger>();
//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;
}
/// <summary>
/// These services need to be manually added because they do not get added by the generic host
/// </summary>
/// <param name="services"></param>
/// <param name="testHelper"></param>
/// <param name="webHostEnvironment"></param>
private void AddRequiredNetCoreServices(IServiceCollection services, TestHelper testHelper, IWebHostEnvironment webHostEnvironment)
{
services.AddSingleton<IHttpContextAccessor>(x => testHelper.GetHttpContextAccessor());
// the generic host does add IHostEnvironment but not this one because we are not actually in a web context
services.AddSingleton<IWebHostEnvironment>(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;
}
}
}
@@ -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();
}
}
}
}
@@ -15,6 +15,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Data.SqlClient" Version="4.8.1" />
</ItemGroup>
<ItemGroup>
@@ -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()
@@ -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
/// </summary>
/// <remarks>The default constructor will boot the cache, load data from file or database, /// wire events in order to manage changes, etc.</remarks>
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()
@@ -32,8 +32,7 @@ namespace Umbraco.Tests.Routing
//create the module
var logger = Mock.Of<ILogger>();
var globalSettings = TestObjects.GetGlobalSettings();
var runtime = new RuntimeState(logger, globalSettings,
new Lazy<IMainDom>(), new Lazy<IServerRegistrar>(), UmbracoVersion, HostingEnvironment, BackOfficeInfo);
var runtime = new RuntimeState(logger, globalSettings, UmbracoVersion, BackOfficeInfo);
_module = new UmbracoInjectedModule
(
+3 -44
View File
@@ -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<IApplicationShutdownRegistry, AspNetApplicationShutdownRegistry>(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<IScopeProvider>();
Mock.Get(scopeProvider)
.Setup(x => x.CreateScope(
It.IsAny<IsolationLevel>(),
It.IsAny<RepositoryCacheMode>(),
It.IsAny<IEventDispatcher>(),
It.IsAny<bool?>(),
It.IsAny<bool>(),
It.IsAny<bool>()))
.Returns(Mock.Of<IScope>());
composition.RegisterUnique(scopeProvider);
}
private IMainDom _mainDom;
public override IFactory Boot(IRegister container)
{
var factory = base.Boot(container);
_mainDom = factory.GetInstance<IMainDom>();
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
@@ -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<IMainDom>(() => mainDom), new Lazy<IServerRegistrar>(() => factory.GetInstance<IServerRegistrar>()), 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?
@@ -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<IBackgroundTask>(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, _logger, TestHelper.GetHostingEnvironment());
var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, _logger, TestHelper.GetHostingEnvironmentLifetime());
var task = new SourceTask();
runner.Add(task);
@@ -22,7 +22,7 @@ namespace Umbraco.Tests.Scheduling
public async Task ThreadResumeIssue()
{
var logger = new DebugDiagnosticsLogger(new MessageTemplates());
var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, logger, TestHelper.GetHostingEnvironment());
var runner = new BackgroundTaskRunner<IBackgroundTask>(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<IBackgroundTask>(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, logger, TestHelper.GetHostingEnvironment());
var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, logger, TestHelper.GetHostingEnvironmentLifetime());
var taskCompleted = false;
runner.TaskCompleted += (sender, args) =>
{
+7 -2
View File
@@ -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
/// </summary>
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();
@@ -265,6 +265,7 @@ namespace Umbraco.Tests.TestHelpers
Logger,
Factory.GetInstance<IGlobalSettings>(),
HostingEnvironment,
HostingLifetime,
ShortStringHelper,
new SiteDomainHelper(),
Factory.GetInstance<IEntityXmlSerializer>(),
+2 -1
View File
@@ -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<IProfilingLogger>();
protected IHostingEnvironment HostingEnvironment { get; } = new AspNetHostingEnvironment(TestHelpers.SettingsForTests.GetDefaultHostingSettings());
protected IApplicationShutdownRegistry HostingLifetime { get; } = new AspNetApplicationShutdownRegistry();
protected IIpResolver IpResolver => Factory.GetInstance<IIpResolver>();
protected IBackOfficeInfo BackOfficeInfo => Factory.GetInstance<IBackOfficeInfo>();
protected AppCaches AppCaches => Factory.GetInstance<AppCaches>();
@@ -423,6 +423,7 @@ namespace Umbraco.Tests.Web.Mvc
new TestDefaultCultureAccessor(),
Current.Logger, TestObjects.GetGlobalSettings(),
TestHelper.GetHostingEnvironment(),
TestHelper.GetHostingEnvironmentLifetime(),
ShortStringHelper,
new SiteDomainHelper(),
Factory.GetInstance<IEntityXmlSerializer>(),
@@ -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<IRegisteredObject, RegisteredObjectWrapper> _registeredObjects =
new ConcurrentDictionary<IRegisteredObject, RegisteredObjectWrapper>();
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);
}
}
}
}
@@ -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
{
/// <summary>
/// Adds/replaces AspNetCore specific services
/// </summary>
[ComposeBefore(typeof(ICoreComposer))]
[ComposeAfter(typeof(CoreInitialComposer))]
public class AspNetCoreComposer : IComposer
{
public void Compose(Composition composition)
{
// AspNetCore specific services
composition.RegisterUnique<IHttpContextAccessor, HttpContextAccessor>();
// Our own netcore implementations
composition.RegisterUnique<IUmbracoApplicationLifetime, AspNetCoreUmbracoApplicationLifetime>();
composition.RegisterUnique<IApplicationShutdownRegistry, AspNetCoreApplicationShutdownRegistry>();
}
}
}
@@ -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<IRegisteredObject, RegisteredObjectWrapper> _registeredObjects =
new ConcurrentDictionary<IRegisteredObject, RegisteredObjectWrapper>();
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);
}
}
}
@@ -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
@@ -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
{
@@ -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;
}
/// <summary>
/// Start Umbraco
/// </summary>
/// <param name="app"></param>
/// <returns></returns>
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<IApplicationShutdownRegistry>();
var runtime = app.ApplicationServices.GetRequiredService<IRuntime>();
var runtimeShutdown = new CoreRuntimeShutdown(runtime, hostLifetime);
hostLifetime.RegisterObject(runtimeShutdown);
// Start the runtime!
runtime.Start();
return app;
}
/// <summary>
/// Ensures the runtime is shutdown when the application is shutting down
/// </summary>
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);
}
}
}
}
}
@@ -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)
/// <summary>
/// Adds the Umbraco Configuration requirements
/// </summary>
/// <param name="services"></param>
/// <param name="configuration"></param>
/// <returns></returns>
public static IServiceCollection AddUmbracoConfiguration(this IServiceCollection services, IConfiguration configuration)
{
var serviceProvider = services.BuildServiceProvider();
var configuration = serviceProvider.GetService<IConfiguration>();
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
/// <summary>
/// Adds the Umbraco Back Core requirements
/// Adds the Umbraco Back Core requirements
/// </summary>
/// <param name="services"></param>
/// <param name="webHostEnvironment"></param>
/// <returns></returns>
/// <remarks>
/// Must be called after all services are added to the application because we are cross-wiring the container (currently)
/// </remarks>
public static IServiceCollection AddUmbracoCore(this IServiceCollection services)
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)
/// <summary>
/// Adds the Umbraco Back Core requirements
/// </summary>
/// <param name="services"></param>
/// <param name="webHostEnvironment"></param>
/// <param name="umbContainer"></param>
/// <param name="entryAssembly"></param>
/// <returns></returns>
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<IHttpContextAccessor, HttpContextAccessor>();
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<IHttpContextAccessor>();
var webHostEnvironment = serviceProvider.GetRequiredService<IWebHostEnvironment>();
var hostApplicationLifetime = serviceProvider.GetRequiredService<IHostApplicationLifetime>();
var configs = serviceProvider.GetService<Configs>();
configs = serviceProvider.GetService<Configs>();
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<IRequestCache>(), 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
}
}
}
}
+18 -2
View File
@@ -16,13 +16,29 @@ namespace Umbraco.Web.UI.BackOffice
{
public class Startup
{
private readonly IWebHostEnvironment _webHostEnvironment;
private readonly IConfiguration _config;
/// <summary>
/// Constructor
/// </summary>
/// <param name="webHostEnvironment"></param>
/// <param name="config"></param>
/// <remarks>
/// Only a few services are possible to be injected here https://github.com/dotnet/aspnetcore/issues/9337
/// </remarks>
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();
}
@@ -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<Configs>();
var imagingSettings = configs.Imaging();
@@ -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<IRegisteredObject, RegisteredObjectWrapper> _registeredObjects =
new ConcurrentDictionary<IRegisteredObject, RegisteredObjectWrapper>();
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);
}
}
}
}
@@ -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<IRegisteredObject, RegisteredObjectWrapper> _registeredObjects =
new ConcurrentDictionary<IRegisteredObject, RegisteredObjectWrapper>();
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);
}
}
}
@@ -1,6 +1,6 @@
using System.Web;
using Umbraco.Core.Session;
using Umbraco.Net;
using Umbraco.Core.Session;
namespace Umbraco.Web.AspNet
{
@@ -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
+1 -1
View File
@@ -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;
@@ -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;
@@ -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
};
}
}}
@@ -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<IRequestAccessor, AspNetRequestAccessor>(Lifetime.Singleton);
composition.Register<IHostingEnvironment, AspNetHostingEnvironment>();
composition.Register<IBackOfficeInfo, AspNetBackOfficeInfo>();
composition.Register<IUmbracoApplicationLifetime, AspNetUmbracoApplicationLifetime>(Lifetime.Singleton);
composition.Register<IPasswordHasher, AspNetPasswordHasher>();
composition.Register<IFilePermissionHelper, FilePermissionHelper>(Lifetime.Singleton);
@@ -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;
@@ -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;
@@ -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
+2 -1
View File
@@ -134,6 +134,7 @@
<Compile Include="AppBuilderExtensions.cs" />
<Compile Include="AreaRegistrationContextExtensions.cs" />
<Compile Include="AspNet\AspNetHostingEnvironment.cs" />
<Compile Include="AspNet\AspNetApplicationShutdownRegistry.cs" />
<Compile Include="AspNet\AspNetRequestAccessor.cs" />
<Compile Include="AspNet\AspNetSessionManager.cs" />
<Compile Include="AspNet\AspNetUserAgentProvider.cs" />
@@ -585,4 +586,4 @@
</None>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
</Project>
+1 -1
View File
@@ -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();
+3 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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;
+2 -2
View File
@@ -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();
}
}