使用控制台或客户端操作优雅地停止 .NET Core 服务器

Gracefully stop .NET Core server with console or client action

我正在将一些服务器应用程序从 .NET Framework+WCF 移植到 .NET Core,但我在管理服务器出口时遇到了问题。在我们当前的 WCF 服务器上,我们允许从 WCF 请求和控制台输入中退出:

    static void Main()
    {
        hExit = new ManualResetEvent(false);
        StartServer();

        Console.WriteLine("Server started. Press [Enter] to quit.");
        char key;
        while((key=WaitForKeyOrEvent(hExit)) != '[=10=]' && key != '\r') { }
        Console.WriteLine();

        StopServer();
    }

    private static char WaitForKeyOrEvent(System.Threading.WaitHandle hEvent)
    {
        const int Timeout = 500;
        bool dueToEvent = false;
        while(!Console.KeyAvailable)
        {
            if(hEvent.WaitOne(Timeout, false))
            {
                dueToEvent = true;
                break;
            }
        }
        char ret = '[=10=]';
        if(!dueToEvent)
        {
            ret = Console.ReadKey().KeyChar;
            if(ret == '[=10=]')
                ret = char.MaxValue;
        }
        return ret;
    }

    ...

    class ServerObj : IMyWcfInterface
    {
        void IMyWcfInterface.ExitServer() { hExit.Set(); }
    }

这种方法是否也适用于 .NET Core? (当然使用 WCF 以外的其他技术,因为它已被废弃)我依稀记得听说 KeyAvailable/ReadKey 可能不适用于 Docker 容器中的应用程序,而容器的使用是“结束”之一迁移到 .NET Core 的目标”...

通常,当 运行 在容器中时,您通常无法访问输入设备(想想键盘)。因此该选项在容器化应用程序中不可靠。

侦听某种网络请求(例如 HTTP、grpc、protobuf)可能有效,但您必须确保请求的来源有效并且不是攻击您的应用程序的恶意实体,并且强制关闭。

容器环境(例如 Kubernetes,Docker)中的惯用方法是容器引擎向您的应用程序发送 Linux 信号,例如 SIGTERMdocker stop 会这样做,Kubernetes 在停止 pods 时也会这样做。然后您的应用程序应该处理该问题并正确关闭。

根据您是否使用 ASP.NET 核心,实现会有所不同。

在 ASP.NET Core 中,您可以使用 IApplicationLifetime.ApplicationStopping 注册一些在应用程序停止时调用的代码。

这是涵盖实施方面的 Whosebug 答案:

如果您没有使用 ASP.NET 核心,您可以处理 AppDomain.ProcessExit 以注册一个在应用程序停止时调用的处理程序。