Added overload of Run that triggers shutdown on a cancellation token

- Added test
- Changed NotifyStopped() after all work has been done
This commit is contained in:
David Fowler 2016-01-15 11:20:57 +00:00
parent 7a44cf4da9
commit 0673acedc4
3 changed files with 67 additions and 9 deletions

View File

@ -233,8 +233,8 @@ namespace Microsoft.AspNet.Hosting.Internal
_logger?.Shutdown(); _logger?.Shutdown();
_applicationLifetime.StopApplication(); _applicationLifetime.StopApplication();
Server?.Dispose(); Server?.Dispose();
_applicationLifetime.NotifyStopped();
(_applicationServices as IDisposable)?.Dispose(); (_applicationServices as IDisposable)?.Dispose();
_applicationLifetime.NotifyStopped();
} }
private class Disposable : IDisposable private class Disposable : IDisposable

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Threading;
using Microsoft.AspNet.Hosting.Server; using Microsoft.AspNet.Hosting.Server;
using Microsoft.AspNet.Server.Features; using Microsoft.AspNet.Server.Features;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
@ -105,6 +106,32 @@ namespace Microsoft.AspNet.Hosting
/// </summary> /// </summary>
/// <param name="application"></param> /// <param name="application"></param>
public static void Run(this IWebApplication application) public static void Run(this IWebApplication application)
{
using (var cts = new CancellationTokenSource())
{
Console.CancelKeyPress += (sender, eventArgs) =>
{
cts.Cancel();
// Don't terminate the process immediately, wait for the Main thread to exit gracefully.
eventArgs.Cancel = true;
};
application.Run(cts.Token, "Application started. Press Ctrl+C to shut down.");
}
}
/// <summary>
/// Runs a web application and block the calling thread until token is triggered or shutdown is triggered
/// </summary>
/// <param name="application"></param>
/// <param name="token">The token to trigger shutdown</param>
public static void Run(this IWebApplication application, CancellationToken token)
{
application.Run(token, shutdownMessage: null);
}
private static void Run(this IWebApplication application, CancellationToken token, string shutdownMessage)
{ {
using (application) using (application)
{ {
@ -124,15 +151,16 @@ namespace Microsoft.AspNet.Hosting
} }
} }
Console.WriteLine("Application started. Press Ctrl+C to shut down."); if (!string.IsNullOrEmpty(shutdownMessage))
Console.CancelKeyPress += (sender, eventArgs) =>
{ {
applicationLifetime.StopApplication(); Console.WriteLine(shutdownMessage);
}
// Don't terminate the process immediately, wait for the Main thread to exit gracefully. token.Register(state =>
eventArgs.Cancel = true; {
}; ((IApplicationLifetime)state).StopApplication();
},
applicationLifetime);
applicationLifetime.ApplicationStopping.WaitHandle.WaitOne(); applicationLifetime.ApplicationStopping.WaitHandle.WaitOne();
} }

View File

@ -6,6 +6,7 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Builder; using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting.Fakes; using Microsoft.AspNet.Hosting.Fakes;
@ -30,7 +31,8 @@ namespace Microsoft.AspNet.Hosting
private IFeatureCollection _featuresSupportedByThisHost = NewFeatureCollection(); private IFeatureCollection _featuresSupportedByThisHost = NewFeatureCollection();
private IFeatureCollection _instanceFeaturesSupportedByThisHost; private IFeatureCollection _instanceFeaturesSupportedByThisHost;
public IFeatureCollection Features { public IFeatureCollection Features
{
get get
{ {
var features = new FeatureCollection(); var features = new FeatureCollection();
@ -158,6 +160,34 @@ namespace Microsoft.AspNet.Hosting
Assert.Equal(1, _startInstances[0].DisposeCalls); Assert.Equal(1, _startInstances[0].DisposeCalls);
} }
[Fact]
public void WebApplicationShutsDownWhenTokenTriggers()
{
var app = CreateBuilder()
.UseServer((IServerFactory)this)
.UseStartup("Microsoft.AspNet.Hosting.Tests")
.Build();
var lifetime = app.Services.GetRequiredService<IApplicationLifetime>();
var cts = new CancellationTokenSource();
Task.Run(() => app.Run(cts.Token));
// Wait on the app to be started
lifetime.ApplicationStarted.WaitHandle.WaitOne();
Assert.Equal(1, _startInstances.Count);
Assert.Equal(0, _startInstances[0].DisposeCalls);
cts.Cancel();
// Wait on the app to shutdown
lifetime.ApplicationStopped.WaitHandle.WaitOne();
Assert.Equal(1, _startInstances[0].DisposeCalls);
}
[Fact] [Fact]
public void WebApplicationDisposesServiceProvider() public void WebApplicationDisposesServiceProvider()
{ {