Detatch CancelKeyPress and ProcessExit event handlers when IWebHost.RunAsync is completed. (#6638)
This commit is contained in:
parent
a5658a8c95
commit
0b8e16f10a
|
|
@ -0,0 +1,70 @@
|
||||||
|
// Copyright (c) .NET Foundation. 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.AspNetCore.Hosting.Internal
|
||||||
|
{
|
||||||
|
internal class WebHostLifetime : IDisposable
|
||||||
|
{
|
||||||
|
private readonly CancellationTokenSource _cts;
|
||||||
|
private readonly ManualResetEventSlim _resetEvent;
|
||||||
|
private readonly string _shutdownMessage;
|
||||||
|
|
||||||
|
private bool _disposed = false;
|
||||||
|
|
||||||
|
public WebHostLifetime(CancellationTokenSource cts, ManualResetEventSlim resetEvent, string shutdownMessage)
|
||||||
|
{
|
||||||
|
_cts = cts;
|
||||||
|
_resetEvent = resetEvent;
|
||||||
|
_shutdownMessage = shutdownMessage;
|
||||||
|
|
||||||
|
AppDomain.CurrentDomain.ProcessExit += ProcessExit;
|
||||||
|
Console.CancelKeyPress += CancelKeyPress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
|
AppDomain.CurrentDomain.ProcessExit -= ProcessExit;
|
||||||
|
Console.CancelKeyPress -= CancelKeyPress;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CancelKeyPress(object sender, ConsoleCancelEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
Shutdown();
|
||||||
|
// Don't terminate the process immediately, wait for the Main thread to exit gracefully.
|
||||||
|
eventArgs.Cancel = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessExit(object sender, EventArgs eventArgs)
|
||||||
|
{
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Shutdown()
|
||||||
|
{
|
||||||
|
if (!_cts.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(_shutdownMessage))
|
||||||
|
{
|
||||||
|
Console.WriteLine(_shutdownMessage);
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_cts.Cancel();
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait on the given reset event
|
||||||
|
_resetEvent.Wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -43,15 +43,16 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
var done = new ManualResetEventSlim(false);
|
var done = new ManualResetEventSlim(false);
|
||||||
using (var cts = CancellationTokenSource.CreateLinkedTokenSource(token))
|
using (var cts = CancellationTokenSource.CreateLinkedTokenSource(token))
|
||||||
{
|
{
|
||||||
AttachCtrlcSigtermShutdown(cts, done, shutdownMessage: string.Empty);
|
using (var lifetime = new WebHostLifetime(cts, done, shutdownMessage: string.Empty))
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
await host.WaitForTokenShutdownAsync(cts.Token);
|
try
|
||||||
}
|
{
|
||||||
finally
|
await host.WaitForTokenShutdownAsync(cts.Token);
|
||||||
{
|
}
|
||||||
done.Set();
|
finally
|
||||||
|
{
|
||||||
|
done.Set();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -84,15 +85,16 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
using (var cts = new CancellationTokenSource())
|
using (var cts = new CancellationTokenSource())
|
||||||
{
|
{
|
||||||
var shutdownMessage = host.Services.GetRequiredService<WebHostOptions>().SuppressStatusMessages ? string.Empty : "Application is shutting down...";
|
var shutdownMessage = host.Services.GetRequiredService<WebHostOptions>().SuppressStatusMessages ? string.Empty : "Application is shutting down...";
|
||||||
AttachCtrlcSigtermShutdown(cts, done, shutdownMessage: shutdownMessage);
|
using (var lifetime = new WebHostLifetime(cts, done, shutdownMessage: shutdownMessage))
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
await host.RunAsync(cts.Token, "Application started. Press Ctrl+C to shut down.");
|
try
|
||||||
}
|
{
|
||||||
finally
|
await host.RunAsync(cts.Token, "Application started. Press Ctrl+C to shut down.");
|
||||||
{
|
}
|
||||||
done.Set();
|
finally
|
||||||
|
{
|
||||||
|
done.Set();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -131,36 +133,6 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AttachCtrlcSigtermShutdown(CancellationTokenSource cts, ManualResetEventSlim resetEvent, string shutdownMessage)
|
|
||||||
{
|
|
||||||
void Shutdown()
|
|
||||||
{
|
|
||||||
if (!cts.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(shutdownMessage))
|
|
||||||
{
|
|
||||||
Console.WriteLine(shutdownMessage);
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
cts.Cancel();
|
|
||||||
}
|
|
||||||
catch (ObjectDisposedException) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait on the given reset event
|
|
||||||
resetEvent.Wait();
|
|
||||||
};
|
|
||||||
|
|
||||||
AppDomain.CurrentDomain.ProcessExit += (sender, eventArgs) => Shutdown();
|
|
||||||
Console.CancelKeyPress += (sender, eventArgs) =>
|
|
||||||
{
|
|
||||||
Shutdown();
|
|
||||||
// Don't terminate the process immediately, wait for the Main thread to exit gracefully.
|
|
||||||
eventArgs.Cancel = true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task WaitForTokenShutdownAsync(this IWebHost host, CancellationToken token)
|
private static async Task WaitForTokenShutdownAsync(this IWebHost host, CancellationToken token)
|
||||||
{
|
{
|
||||||
var applicationLifetime = host.Services.GetService<IApplicationLifetime>();
|
var applicationLifetime = host.Services.GetService<IApplicationLifetime>();
|
||||||
|
|
@ -184,4 +156,4 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
await host.StopAsync();
|
await host.StopAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue