Windows Service连接SignalR服务器失败问题求助
问题分析与解决方案
你的代码存在几个关键问题,导致Windows Service中SignalR回调无法正常工作:
重复执行连接初始化与事件订阅
InstallService方法被Timer每5秒调用一次,每次都会重复注册Closed事件、调用StartAsync、订阅InstallService回调。这会导致:- 同一回调被多次订阅,可能引发重复执行或内存泄漏
- 多次调用
StartAsync会在连接已打开时抛出异常,中断连接逻辑 - 重复注册的
Closed事件会导致重连逻辑多次触发,引发混乱
异步操作未等待
OnStart和InstallService中调用connection.StartAsync()时没有等待完成(火并忘),Windows Service的启动线程不会等待异步操作结束,可能导致连接还未建立就被终止,回调自然无法触发。连接状态管理缺失
没有检查连接当前状态就盲目执行启动操作,导致无效重复调用。
修正后的代码实现
public partial class WindowsServiceManager : ServiceBase { private Timer _timer; private HubConnection _connection; private readonly object _connectionLock = new object(); public WindowsServiceManager() { InitializeComponent(); } protected override void OnStart(string[] args) { WriteToFile("Service started at " + DateTime.Now); // 初始化SignalR连接(仅执行一次) InitializeSignalRConnection(); // 启动Timer,仅用于周期性业务逻辑(如果需要),而非重复初始化连接 _timer = new Timer(); _timer.Elapsed += OnElapsedTime; _timer.Interval = 5000; _timer.Enabled = true; } protected override void OnStop() { WriteToFile("Service stopped at " + DateTime.Now); // 停止Timer _timer?.Stop(); _timer?.Dispose(); // 关闭SignalR连接 if (_connection != null) { _connection.DisposeAsync().GetAwaiter().GetResult(); } } private void InitializeSignalRConnection() { lock (_connectionLock) { if (_connection != null && _connection.State == HubConnectionState.Connected) return; // 创建连接 _connection = new HubConnectionBuilder() .WithUrl("https://localhost:7082/InstallService") .Build(); // 注册Closed事件(仅一次),处理重连逻辑 _connection.Closed += async (error) => { WriteToFile($"Connection closed, error: {error?.Message ?? "None"}. Attempting reconnect..."); await Task.Delay(new Random().Next(0, 5) * 1000); try { await _connection.StartAsync(); WriteToFile("Reconnected successfully"); } catch (Exception ex) { WriteToFile($"Reconnect failed: {ex.Message}"); } }; // 订阅服务器回调(仅一次) _connection.On<string, string>("InstallService", (serviceName, serviceURL) => { WriteToFile("Inside SignalR callback"); WriteToFile($"Service URL: {serviceURL}, Service Name: {serviceName}"); }); // 启动连接并等待完成 try { _connection.StartAsync().GetAwaiter().GetResult(); WriteToFile("SignalR connection established successfully"); } catch (Exception ex) { WriteToFile($"Failed to start SignalR connection: {ex.Message}"); } } } private void OnElapsedTime(object source, ElapsedEventArgs e) { WriteToFile("Service recalled at " + DateTime.Now); // 这里仅执行周期性业务逻辑,比如检查连接状态(可选) lock (_connectionLock) { if (_connection == null || _connection.State != HubConnectionState.Connected) { WriteToFile("Connection lost, reinitializing..."); InitializeSignalRConnection(); } } } }
关键修改说明
- 连接初始化仅执行一次:将连接创建、事件订阅、启动逻辑移到
InitializeSignalRConnection方法,通过锁和状态检查避免重复操作。 - 正确等待异步操作:使用
GetAwaiter().GetResult()同步等待StartAsync和DisposeAsync完成,确保连接在服务启动时完全建立,停止时正确关闭。 - 单一的重连逻辑:仅注册一次
Closed事件处理重连,避免重复触发。 - Timer仅处理周期性检查:Timer不再重复初始化连接,只负责周期性检查连接状态(如果需要),或执行其他业务任务。
- 线程安全:使用
lock确保连接操作的线程安全,避免多线程同时修改连接状态。
内容的提问来源于stack exchange,提问作者ardayz
相关产品推荐
相关产品推荐

