You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何捕获.NET Core控制台应用关闭事件?实现前端通知方案

.NET Core控制台API关闭时通知React前端的实现方案

一、能不能捕获.NET Core控制台的关闭事件?

完全可以。.NET Core提供了多种方式捕获控制台应用的关闭信号,覆盖正常退出、Ctrl+C中断、进程被终止等常见场景。

二、捕获关闭事件的具体实现

1. 基于Generic Host的监听(推荐)

现在大多数.NET Core控制台API都会基于Generic Host构建,这种方式可以通过注入IHostApplicationLifetime监听应用的关闭阶段:

public class ShutdownNotificationService : BackgroundService
{
    private readonly IHostApplicationLifetime _appLifetime;
    private readonly ILogger<ShutdownNotificationService> _logger;

    public ShutdownNotificationService(IHostApplicationLifetime appLifetime, ILogger<ShutdownNotificationService> logger)
    {
        _appLifetime = appLifetime;
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // 注册应用即将关闭的回调
        _appLifetime.ApplicationStopping.Register(() =>
        {
            _logger.LogInformation("服务器即将关闭,准备通知前端");
            // 调用通知前端的逻辑
            NotifyReactClients().Wait();
        });

        // 保持服务运行
        await Task.Delay(Timeout.Infinite, stoppingToken);
    }

    private async Task NotifyReactClients()
    {
        // 这里写通知前端的具体代码
    }
}

在Program.cs中注册这个后台服务:

var builder = Host.CreateDefaultBuilder(args);
builder.ConfigureServices(services =>
{
    services.AddHostedService<ShutdownNotificationService>();
    // 注册你的API服务,比如AddControllers()等
});

var host = builder.Build();
await host.RunAsync();

2. 直接注册底层事件

如果项目没用到Generic Host,可以直接注册进程级别的事件:

class Program
{
    static void Main(string[] args)
    {
        // 捕获Ctrl+C、Ctrl+Break这类中断信号
        Console.CancelKeyPress += (sender, e) =>
        {
            e.Cancel = true; // 先阻止立即退出,执行自定义逻辑
            NotifyReactClients().Wait();
            Environment.Exit(0);
        };

        // 捕获进程正常退出的事件
        AppDomain.CurrentDomain.ProcessExit += (sender, e) =>
        {
            NotifyReactClients().Wait();
        };

        // 启动你的API服务,比如用WebHost
        var host = WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .Build();
        host.Run();
    }

    private static async Task NotifyReactClients()
    {
        // 通知前端逻辑
    }
}

三、通知React前端的可行方案

1. WebSocket实时推送(最可靠)

WebSocket支持双向通信,API可以主动给前端发通知,是实时通知的最佳选择:

  • .NET Core端:配置WebSocket中间件,维护所有连接的客户端列表,关闭事件触发时批量发送通知。
  • React端:建立WebSocket连接,监听消息,收到关闭信号后执行操作。

.NET Core端简化代码:

// 在Program.cs中配置WebSocket
app.UseWebSockets();
app.Map("/ws", async context =>
{
    if (!context.WebSockets.IsWebSocketRequest)
    {
        context.Response.StatusCode = 400;
        return;
    }

    using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
    // 把连接加入全局集合,方便后续通知
    WebSocketManager.AddConnection(webSocket);

    // 监听客户端消息(可选)
    var buffer = new byte[4096];
    var receiveResult = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
    while (!receiveResult.CloseStatus.HasValue)
    {
        receiveResult = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
    }
    await webSocket.CloseAsync(receiveResult.CloseStatus.Value, receiveResult.CloseStatusDescription, CancellationToken.None);
    WebSocketManager.RemoveConnection(webSocket);
});

// 通知逻辑
private static async Task NotifyReactClients()
{
    var shutdownMessage = Encoding.UTF8.GetBytes("server_shutdown_imminent");
    foreach (var socket in WebSocketManager.GetConnections())
    {
        if (socket.State == WebSocketState.Open)
        {
            await socket.SendAsync(new ArraySegment<byte>(shutdownMessage), WebSocketMessageType.Text, true, CancellationToken.None);
        }
    }
}

// 简单的WebSocket连接管理器
public static class WebSocketManager
{
    private static readonly HashSet<WebSocket> _connections = new();
    public static void AddConnection(WebSocket socket) => _connections.Add(socket);
    public static void RemoveConnection(WebSocket socket) => _connections.Remove(socket);
    public static IEnumerable<WebSocket> GetConnections() => _connections;
}

React端代码示例:

import { useEffect } from 'react';

function App() {
    useEffect(() => {
        const socket = new WebSocket('ws://your-api-domain/ws');
        
        socket.onmessage = (event) => {
            if (event.data === 'server_shutdown_imminent') {
                // 执行前端操作:提示用户、保存数据、跳转页面等
                alert('服务器即将关闭,请保存当前工作');
                // 比如清理用户状态或跳转到离线提示页
            }
        };

        // 组件卸载时关闭连接
        return () => {
            socket.close();
        };
    }, []);

    return <div>你的应用内容</div>;
}

export default App;

2. 心跳检测(降级方案)

如果WebSocket无法使用,可以用前端定时心跳的方式:

  • React端每隔3-5秒向API发送一个简单的GET请求(比如/api/health)。
  • 当API关闭时,请求会超时或返回4xx/5xx状态码,前端连续检测到几次失败后,判定服务器已关闭,执行相应操作。
  • 缺点是有延迟,但实现简单,适合对实时性要求不高的场景。

3. 服务器发送事件(SSE)

SSE是单向的服务器推送,适合不需要双向通信的场景:

  • .NET Core端配置SSE端点,在关闭事件触发时向所有客户端发送事件。
  • React端通过EventSource监听SSE流,收到关闭通知后执行操作。

注意事项

  • 如果部署在容器或云服务中,部分平台会给进程发送SIGTERM信号后强制杀死进程,所以通知逻辑要尽量轻量化,避免耗时操作。
  • 确保WebSocket连接有重连机制,防止网络波动导致连接断开后收不到通知。

内容的提问来源于stack exchange,提问作者Avanish Srivastava

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 06:32:13