diff --git a/src/Umbraco.Core/Notifications/UmbracoApplicationStartedNotification.cs b/src/Umbraco.Core/Notifications/UmbracoApplicationStartedNotification.cs
new file mode 100644
index 0000000000..a3d38720d7
--- /dev/null
+++ b/src/Umbraco.Core/Notifications/UmbracoApplicationStartedNotification.cs
@@ -0,0 +1,9 @@
+namespace Umbraco.Cms.Core.Notifications
+{
+ ///
+ /// Notification that occurs when Umbraco has completely booted up and the request processing pipeline is configured.
+ ///
+ ///
+ public class UmbracoApplicationStartedNotification : INotification
+ { }
+}
diff --git a/src/Umbraco.Core/Notifications/UmbracoApplicationStartingNotification.cs b/src/Umbraco.Core/Notifications/UmbracoApplicationStartingNotification.cs
index 4cbf0a55c6..dd60f9431c 100644
--- a/src/Umbraco.Core/Notifications/UmbracoApplicationStartingNotification.cs
+++ b/src/Umbraco.Core/Notifications/UmbracoApplicationStartingNotification.cs
@@ -1,23 +1,23 @@
-// Copyright (c) Umbraco.
-// See LICENSE for more details.
-
namespace Umbraco.Cms.Core.Notifications
{
///
- /// Notification that occurs at the very end of the Umbraco boot
- /// process and after all initialize.
+ /// Notification that occurs at the very end of the Umbraco boot process (after all s are initialized).
///
+ ///
public class UmbracoApplicationStartingNotification : INotification
{
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
/// The runtime level
public UmbracoApplicationStartingNotification(RuntimeLevel runtimeLevel) => RuntimeLevel = runtimeLevel;
///
- /// Gets the runtime level of execution.
+ /// Gets the runtime level.
///
+ ///
+ /// The runtime level.
+ ///
public RuntimeLevel RuntimeLevel { get; }
}
}
diff --git a/src/Umbraco.Core/Notifications/UmbracoApplicationStoppedNotification.cs b/src/Umbraco.Core/Notifications/UmbracoApplicationStoppedNotification.cs
new file mode 100644
index 0000000000..be4c6ccfd4
--- /dev/null
+++ b/src/Umbraco.Core/Notifications/UmbracoApplicationStoppedNotification.cs
@@ -0,0 +1,9 @@
+namespace Umbraco.Cms.Core.Notifications
+{
+ ///
+ /// Notification that occurs when Umbraco has completely shutdown.
+ ///
+ ///
+ public class UmbracoApplicationStoppedNotification : INotification
+ { }
+}
diff --git a/src/Umbraco.Core/Notifications/UmbracoApplicationStoppingNotification.cs b/src/Umbraco.Core/Notifications/UmbracoApplicationStoppingNotification.cs
index db86a1e614..6d5234bbcc 100644
--- a/src/Umbraco.Core/Notifications/UmbracoApplicationStoppingNotification.cs
+++ b/src/Umbraco.Core/Notifications/UmbracoApplicationStoppingNotification.cs
@@ -1,4 +1,9 @@
namespace Umbraco.Cms.Core.Notifications
{
- public class UmbracoApplicationStoppingNotification : INotification { }
+ ///
+ /// Notification that occurs when Umbraco is shutting down (after all s are terminated).
+ ///
+ ///
+ public class UmbracoApplicationStoppingNotification : INotification
+ { }
}
diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
index 175bceb9e0..5dbe78c2f5 100644
--- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
+++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
@@ -2,6 +2,8 @@ using System;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration;
@@ -16,12 +18,13 @@ using Umbraco.Cms.Infrastructure.Persistence;
using Umbraco.Cms.Web.Common.DependencyInjection;
using Umbraco.Extensions;
using ComponentCollection = Umbraco.Cms.Core.Composing.ComponentCollection;
+using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment;
namespace Umbraco.Cms.Infrastructure.Runtime
{
+ ///
public class CoreRuntime : IRuntime
{
- private readonly ILogger _logger;
private readonly ILoggerFactory _loggerFactory;
private readonly ComponentCollection _components;
private readonly IApplicationShutdownRegistry _applicationShutdownRegistry;
@@ -32,14 +35,16 @@ namespace Umbraco.Cms.Infrastructure.Runtime
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IUmbracoVersion _umbracoVersion;
private readonly IServiceProvider _serviceProvider;
+ private readonly IHostApplicationLifetime _hostApplicationLifetime;
+ private readonly ILogger _logger;
private CancellationToken _cancellationToken;
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
public CoreRuntime(
- ILoggerFactory loggerFactory,
IRuntimeState state,
+ ILoggerFactory loggerFactory,
ComponentCollection components,
IApplicationShutdownRegistry applicationShutdownRegistry,
IProfilingLogger profilingLogger,
@@ -48,9 +53,11 @@ namespace Umbraco.Cms.Infrastructure.Runtime
IEventAggregator eventAggregator,
IHostingEnvironment hostingEnvironment,
IUmbracoVersion umbracoVersion,
- IServiceProvider serviceProvider)
+ IServiceProvider serviceProvider,
+ IHostApplicationLifetime hostApplicationLifetime)
{
State = state;
+
_loggerFactory = loggerFactory;
_components = components;
_applicationShutdownRegistry = applicationShutdownRegistry;
@@ -61,6 +68,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime
_hostingEnvironment = hostingEnvironment;
_umbracoVersion = umbracoVersion;
_serviceProvider = serviceProvider;
+ _hostApplicationLifetime = hostApplicationLifetime;
_logger = _loggerFactory.CreateLogger();
}
@@ -76,23 +84,49 @@ namespace Umbraco.Cms.Infrastructure.Runtime
IUmbracoDatabaseFactory databaseFactory,
IEventAggregator eventAggregator,
IHostingEnvironment hostingEnvironment,
- IUmbracoVersion umbracoVersion
- ):this(
- loggerFactory,
- state,
- components,
- applicationShutdownRegistry,
- profilingLogger,
- mainDom,
- databaseFactory,
- eventAggregator,
- hostingEnvironment,
- umbracoVersion,
- null
- )
- {
+ IUmbracoVersion umbracoVersion,
+ IServiceProvider serviceProvider)
+ : this(
+ state,
+ loggerFactory,
+ components,
+ applicationShutdownRegistry,
+ profilingLogger,
+ mainDom,
+ databaseFactory,
+ eventAggregator,
+ hostingEnvironment,
+ umbracoVersion,
+ serviceProvider,
+ serviceProvider?.GetRequiredService())
+ { }
- }
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ [Obsolete]
+ public CoreRuntime(
+ ILoggerFactory loggerFactory,
+ IRuntimeState state,
+ ComponentCollection components,
+ IApplicationShutdownRegistry applicationShutdownRegistry,
+ IProfilingLogger profilingLogger,
+ IMainDom mainDom,
+ IUmbracoDatabaseFactory databaseFactory,
+ IEventAggregator eventAggregator,
+ IHostingEnvironment hostingEnvironment,
+ IUmbracoVersion umbracoVersion)
+ : this(
+ loggerFactory,
+ state,
+ components,
+ applicationShutdownRegistry,
+ profilingLogger,
+ mainDom,
+ databaseFactory,
+ eventAggregator,
+ hostingEnvironment,
+ umbracoVersion,
+ null)
+ { }
///
/// Gets the state of the Umbraco runtime.
@@ -103,13 +137,17 @@ namespace Umbraco.Cms.Infrastructure.Runtime
public async Task RestartAsync()
{
await StopAsync(_cancellationToken);
+ await _eventAggregator.PublishAsync(new UmbracoApplicationStoppedNotification(), _cancellationToken);
await StartAsync(_cancellationToken);
+ await _eventAggregator.PublishAsync(new UmbracoApplicationStartedNotification(), _cancellationToken);
}
///
public async Task StartAsync(CancellationToken cancellationToken)
{
+ // Store token, so we can re-use this during restart
_cancellationToken = cancellationToken;
+
StaticApplicationLogging.Initialize(_loggerFactory);
StaticServiceProvider.Instance = _serviceProvider;
@@ -130,6 +168,13 @@ namespace Umbraco.Cms.Infrastructure.Runtime
_logger.LogError(exception, msg);
};
+ // Add application started and stopped notifications (only on initial startup, not restarts)
+ if (_hostApplicationLifetime.ApplicationStarted.IsCancellationRequested == false)
+ {
+ _hostApplicationLifetime.ApplicationStarted.Register(() => _eventAggregator.Publish(new UmbracoApplicationStartedNotification()));
+ _hostApplicationLifetime.ApplicationStopped.Register(() => _eventAggregator.Publish(new UmbracoApplicationStoppedNotification()));
+ }
+
// acquire the main domain - if this fails then anything that should be registered with MainDom will not operate
AcquireMainDom();
@@ -137,7 +182,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime
await _eventAggregator.PublishAsync(new UmbracoApplicationMainDomAcquiredNotification(), cancellationToken);
// notify for unattended install
- await _eventAggregator.PublishAsync(new RuntimeUnattendedInstallNotification());
+ await _eventAggregator.PublishAsync(new RuntimeUnattendedInstallNotification(), cancellationToken);
DetermineRuntimeLevel();
if (!State.UmbracoCanBoot())
@@ -153,7 +198,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime
// if level is Run and reason is UpgradeMigrations, that means we need to perform an unattended upgrade
var unattendedUpgradeNotification = new RuntimeUnattendedUpgradeNotification();
- await _eventAggregator.PublishAsync(unattendedUpgradeNotification);
+ await _eventAggregator.PublishAsync(unattendedUpgradeNotification, cancellationToken);
switch (unattendedUpgradeNotification.UnattendedUpgradeResult)
{
case RuntimeUnattendedUpgradeNotification.UpgradeResult.HasErrors:
@@ -161,6 +206,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime
{
throw new InvalidOperationException($"Unattended upgrade result was {RuntimeUnattendedUpgradeNotification.UpgradeResult.HasErrors} but no {nameof(BootFailedException)} was registered");
}
+
// we cannot continue here, the exception will be rethrown by BootFailedMiddelware
return;
case RuntimeUnattendedUpgradeNotification.UpgradeResult.CoreUpgradeComplete: