2

I am trying to disable the automatically enabled "Ctrl+C" shutdown for an API Host created in an ASP.NET Core Web Application. The same question was asked previously here, but it doesn't work for me using the code below -- the "Press Ctrl+C" message is still shown on startup and, indeed, pressing Ctrl+C stops the application.

How can I turn off this behavior?

Adding Console.CancelKeyPress handler to trap the Ctrl-C doesn't work -- setting 'Cancel = True' doesn't stop the ASP.NET host from seeing the Ctrl-C and halting.

Here's the code:

public static void Main(string[] args) {
    var tokenSource = new CancellationTokenSource();
    var task = CreateHostBuilder(args).Build().RunAsync(tokenSource.Token);
    while (!task.IsCompleted) {
        // TODO: Other stuff...
        Thread.Sleep(1000);
    };
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder => {
            webBuilder.UseStartup<Startup>();
        });

And here's the output on application start (note that the "Press Ctrl+C..." message is still there):

info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: <path>
BoCoKeith
  • 817
  • 10
  • 21
  • Solutions in the alleged question revolves around `Console.CancelKeyPress`. But it isn't enough to intercept the exit event before ASP.NET Core does. – abdusco Jul 26 '21 at 17:48
  • The solution is to implement a custom `IHostLifetime` and replace the default `ConsoleLifetime`. I would have added an answer with the implementation, but I'll have to wait until the question is reopened, if at all. – abdusco Jul 26 '21 at 18:10
  • Just register it as singleton: `services.AddSingleton()` – abdusco Jul 26 '21 at 19:09

1 Answers1

4

ASP.NET Core has a concept of host lifetime to manage the lifetime of an application.

There are a couple of implementations, such as

  • ConsoleLifetime, which listens for Ctrl+C or SIGTERM and initiates shutdown.
  • SystemdLifetime, which notifies systemd of service start & stops
  • WindowsServiceLifetime, which integrates with Windows services

We'll plug in our own implementation, which will listen to Ctrl+C key, and cancel it to prevent it from stopping the application:

public class NoopConsoleLifetime : IHostLifetime, IDisposable
{
    private readonly ILogger<NoopConsoleLifetime> _logger;

    public NoopConsoleLifetime(ILogger<NoopConsoleLifetime> logger)
    {
        _logger = logger;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }

    public Task WaitForStartAsync(CancellationToken cancellationToken)
    {
        Console.CancelKeyPress += OnCancelKeyPressed;
        return Task.CompletedTask;
    }

    private void OnCancelKeyPressed(object? sender, ConsoleCancelEventArgs e)
    {
        _logger.LogInformation("Ctrl+C has been pressed, ignoring.");
        e.Cancel = true;
    }

    public void Dispose()
    {
        Console.CancelKeyPress -= OnCancelKeyPressed;
    }
}

then register this with DI:

services.AddSingleton<IHostLifetime, NoopConsoleLifetime>();

When you start the application, you will not be able to stop it with Ctrl+C:

info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://localhost:5000
info: Demo.NoopConsoleLifetime[0]
      Ctrl+C has been pressed, ignoring.
info: Demo.NoopConsoleLifetime[0]
      Ctrl+C has been pressed, ignoring.

References

abdusco
  • 9,700
  • 2
  • 27
  • 44