如何捕获.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
相关产品推荐
相关产品推荐

