diff --git a/src/Microsoft.AspNet.Hosting.Abstractions/IApplicationLifetime.cs b/src/Microsoft.AspNet.Hosting.Abstractions/IApplicationLifetime.cs
index c229eb6e67..536e24c165 100644
--- a/src/Microsoft.AspNet.Hosting.Abstractions/IApplicationLifetime.cs
+++ b/src/Microsoft.AspNet.Hosting.Abstractions/IApplicationLifetime.cs
@@ -10,6 +10,12 @@ namespace Microsoft.AspNet.Hosting
///
public interface IApplicationLifetime
{
+ ///
+ /// Triggered when the application host has fully started and is about to wait
+ /// for a graceful shutdown.
+ ///
+ CancellationToken ApplicationStarted { get; }
+
///
/// Triggered when the application host is performing a graceful shutdown.
/// Request may still be in flight. Shutdown will block until this event completes.
@@ -25,4 +31,4 @@ namespace Microsoft.AspNet.Hosting
///
CancellationToken ApplicationStopped { get; }
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.AspNet.Hosting/ApplicationLifetime.cs b/src/Microsoft.AspNet.Hosting/ApplicationLifetime.cs
index eb6dc364b9..ced615c889 100644
--- a/src/Microsoft.AspNet.Hosting/ApplicationLifetime.cs
+++ b/src/Microsoft.AspNet.Hosting/ApplicationLifetime.cs
@@ -11,9 +11,19 @@ namespace Microsoft.AspNet.Hosting
///
public class ApplicationLifetime : IApplicationLifetime
{
+ private readonly CancellationTokenSource _startedSource = new CancellationTokenSource();
private readonly CancellationTokenSource _stoppingSource = new CancellationTokenSource();
private readonly CancellationTokenSource _stoppedSource = new CancellationTokenSource();
+ ///
+ /// Triggered when the application host has fully started and is about to wait
+ /// for a graceful shutdown.
+ ///
+ public CancellationToken ApplicationStarted
+ {
+ get { return _startedSource.Token; }
+ }
+
///
/// Triggered when the application host is performing a graceful shutdown.
/// Request may still be in flight. Shutdown will block until this event completes.
@@ -35,6 +45,21 @@ namespace Microsoft.AspNet.Hosting
get { return _stoppedSource.Token; }
}
+ ///
+ /// Signals the ApplicationStarted event and blocks until it completes.
+ ///
+ public void NotifyStarted()
+ {
+ try
+ {
+ _startedSource.Cancel(throwOnFirstException: false);
+ }
+ catch (Exception)
+ {
+ // TODO: LOG
+ }
+ }
+
///
/// Signals the ApplicationStopping event and blocks until it completes.
///
@@ -65,4 +90,4 @@ namespace Microsoft.AspNet.Hosting
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs b/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs
index 56659edc73..48a0069b92 100644
--- a/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs
+++ b/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs
@@ -79,6 +79,8 @@ namespace Microsoft.AspNet.Hosting.Internal
}
});
+ _applicationLifetime.NotifyStarted();
+
return new Disposable(() =>
{
_applicationLifetime.NotifyStopping();
@@ -182,4 +184,4 @@ namespace Microsoft.AspNet.Hosting.Internal
}
}
}
-}
\ No newline at end of file
+}
diff --git a/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs b/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs
index d776c1d481..6c613adcf7 100644
--- a/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs
+++ b/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs
@@ -90,6 +90,21 @@ namespace Microsoft.AspNet.Hosting
Assert.Equal(1, _startInstances[0].DisposeCalls);
}
+ [Fact]
+ public void HostingEngineNotifiesApplicationStarted()
+ {
+ var host = CreateBuilder()
+ .UseServer(this)
+ .Build();
+ var applicationLifetime = host.ApplicationServices.GetRequiredService();
+
+ Assert.False(applicationLifetime.ApplicationStarted.IsCancellationRequested);
+ using (host.Start())
+ {
+ Assert.True(applicationLifetime.ApplicationStarted.IsCancellationRequested);
+ }
+ }
+
[Fact]
public void HostingEngineInjectsHostingEnvironment()
{