diff --git a/src/Microsoft.AspNet.Hosting/ApplicationLifetime.cs b/src/Microsoft.AspNet.Hosting/ApplicationLifetime.cs
new file mode 100644
index 0000000000..d1db40def4
--- /dev/null
+++ b/src/Microsoft.AspNet.Hosting/ApplicationLifetime.cs
@@ -0,0 +1,72 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Threading;
+
+namespace Microsoft.AspNet.Hosting
+{
+ ///
+ /// Allows consumers to perform cleanup during a graceful shutdown.
+ ///
+ public class ApplicationLifetime : IApplicationLifetime
+ {
+ private readonly CancellationTokenSource _stoppingSource = new CancellationTokenSource();
+ private readonly CancellationTokenSource _stoppedSource = new CancellationTokenSource();
+
+ public ApplicationLifetime()
+ {
+ }
+
+ ///
+ /// Triggered when the application host is performing a graceful shutdown.
+ /// Request may still be in flight. Shutdown will block until this event completes.
+ ///
+ ///
+ public CancellationToken ApplicationStopping
+ {
+ get { return _stoppingSource.Token; }
+ }
+
+ ///
+ /// Triggered when the application host is performing a graceful shutdown.
+ /// All requests should be complete at this point. Shutdown will block
+ /// until this event completes.
+ ///
+ ///
+ public CancellationToken ApplicationStopped
+ {
+ get { return _stoppedSource.Token; }
+ }
+
+ ///
+ /// Signals the ApplicationStopping event and blocks until it completes.
+ ///
+ public void SignalStopping()
+ {
+ try
+ {
+ _stoppingSource.Cancel(throwOnFirstException: false);
+ }
+ catch (Exception)
+ {
+ // TODO: LOG
+ }
+ }
+
+ ///
+ /// Signals the ApplicationStopped event and blocks until it completes.
+ ///
+ public void SignalStopped()
+ {
+ try
+ {
+ _stoppedSource.Cancel(throwOnFirstException: false);
+ }
+ catch (Exception)
+ {
+ // TODO: LOG
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Hosting/HostingContext.cs b/src/Microsoft.AspNet.Hosting/HostingContext.cs
index ea5685e6bb..7ad428b722 100644
--- a/src/Microsoft.AspNet.Hosting/HostingContext.cs
+++ b/src/Microsoft.AspNet.Hosting/HostingContext.cs
@@ -27,6 +27,7 @@ namespace Microsoft.AspNet.Hosting
{
public IServiceProvider Services { get; set; }
public IConfiguration Configuration { get; set; }
+ public ApplicationLifetime Lifetime { get; set; }
public IBuilder Builder { get; set; }
diff --git a/src/Microsoft.AspNet.Hosting/HostingEngine.cs b/src/Microsoft.AspNet.Hosting/HostingEngine.cs
index b8cecf5752..7458f5713b 100644
--- a/src/Microsoft.AspNet.Hosting/HostingEngine.cs
+++ b/src/Microsoft.AspNet.Hosting/HostingEngine.cs
@@ -21,6 +21,7 @@ using Microsoft.AspNet.Hosting.Builder;
using Microsoft.AspNet.Hosting.Server;
using Microsoft.AspNet.Hosting.Startup;
using Microsoft.Framework.DependencyInjection;
+using Microsoft.Framework.DependencyInjection.Fallback;
namespace Microsoft.AspNet.Hosting
{
@@ -45,6 +46,7 @@ namespace Microsoft.AspNet.Hosting
public IDisposable Start(HostingContext context)
{
+ EnsureLifetime(context);
EnsureBuilder(context);
EnsureServerFactory(context);
InitalizeServerFactory(context);
@@ -55,11 +57,24 @@ namespace Microsoft.AspNet.Hosting
return new Disposable(() =>
{
+ context.Lifetime.SignalStopping();
server.Dispose();
+ context.Lifetime.SignalStopped();
pipeline.Dispose();
});
}
+ private void EnsureLifetime(HostingContext context)
+ {
+ if (context.Lifetime == null)
+ {
+ context.Lifetime = new ApplicationLifetime();
+ }
+ var serviceCollection = new ServiceCollection();
+ serviceCollection.AddInstance(context.Lifetime);
+ context.Services = serviceCollection.BuildServiceProvider(context.Services);
+ }
+
private void EnsureBuilder(HostingContext context)
{
if (context.Builder != null)
diff --git a/src/Microsoft.AspNet.Hosting/IApplicationLifetime.cs b/src/Microsoft.AspNet.Hosting/IApplicationLifetime.cs
new file mode 100644
index 0000000000..df20556da1
--- /dev/null
+++ b/src/Microsoft.AspNet.Hosting/IApplicationLifetime.cs
@@ -0,0 +1,30 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Threading;
+using Microsoft.Framework.Runtime;
+
+namespace Microsoft.AspNet.Hosting
+{
+ ///
+ /// Allows consumers to perform cleanup during a graceful shutdown.
+ ///
+ [AssemblyNeutral]
+ public interface IApplicationLifetime
+ {
+ ///
+ /// Triggered when the application host is performing a graceful shutdown.
+ /// Request may still be in flight. Shutdown will block until this event completes.
+ ///
+ ///
+ CancellationToken ApplicationStopping { get; }
+
+ ///
+ /// Triggered when the application host is performing a graceful shutdown.
+ /// All requests should be complete at this point. Shutdown will block
+ /// until this event completes.
+ ///
+ ///
+ CancellationToken ApplicationStopped { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Hosting/Microsoft.AspNet.Hosting.kproj b/src/Microsoft.AspNet.Hosting/Microsoft.AspNet.Hosting.kproj
index 60f6546eb4..c58f27a50a 100644
--- a/src/Microsoft.AspNet.Hosting/Microsoft.AspNet.Hosting.kproj
+++ b/src/Microsoft.AspNet.Hosting/Microsoft.AspNet.Hosting.kproj
@@ -20,6 +20,7 @@
+
@@ -27,6 +28,7 @@
+
@@ -45,4 +47,4 @@
-
+
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Hosting/Program.cs b/src/Microsoft.AspNet.Hosting/Program.cs
index 00b4a6af5c..8599267216 100644
--- a/src/Microsoft.AspNet.Hosting/Program.cs
+++ b/src/Microsoft.AspNet.Hosting/Program.cs
@@ -17,6 +17,8 @@
using System;
using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.DependencyInjection.Fallback;
@@ -67,11 +69,29 @@ namespace Microsoft.AspNet.Hosting
throw new Exception("TODO: IHostingEngine service not available exception");
}
- using (engine.Start(context))
+ var appShutdownService = _serviceProvider.GetService();
+ if (appShutdownService == null)
+ {
+ throw new Exception("TODO: IApplicationShutdown service not available");
+ }
+ var shutdownHandle = new ManualResetEvent(false);
+
+ var serverShutdown = engine.Start(context);
+
+ appShutdownService.ShutdownRequested.Register(() =>
+ {
+ serverShutdown.Dispose();
+ shutdownHandle.Set();
+ });
+
+ Task ignored = Task.Run(() =>
{
Console.WriteLine("Started");
Console.ReadLine();
- }
+ appShutdownService.RequestShutdown();
+ });
+
+ shutdownHandle.WaitOne();
}
}
}