.NET 4.8客户端用AspNetCore.SignalR.Client连Windows Service SignalR失败
我已在Windows Service中成功创建SignalR连接且运行正常,但在.NET 4.8桌面应用中使用Microsoft.AspDotNet.SignalR.Client连接时,启动连接环节一直卡住无法完成。
服务端基于.NET 4.8,代码如下:
Windows Service启动代码:
var _ServiceSignalR = WebApp.Start<Startup>("http://localhost:8585"); var ServiceHubContext = GlobalHost.ConnectionManager.GetHubContext<ServiceHub>();
Startup.cs:
public class Startup { public void Configuration(IAppBuilder app) { app.UseCors(CorsOptions.AllowAll); app.MapSignalR(new HubConfiguration { EnableDetailedErrors = true}); } }
ServiceHub.cs:
[HubName("ServiceHub")] public class ServiceHub : Hub { public override Task OnConnected() { // 应该能进入这里 return base.OnConnected(); } }
客户端同样基于.NET 4.8,使用AspNetCore.SignalR.Client的代码:
var serviceHubConnectionx = new HubConnectionBuilder() .WithUrl("http://localhost:8585/signalr") .Build(); await serviceHubConnectionx.StartAsync(); // 这里一直卡住!
我尝试使用AspNet.SignalR.Client创建Hub代理,连接可立即成功,但该客户端无AspNetCore版本的特性(如程序关闭时触发OnDisconnected、客户端方法返回值等),因此希望使用AspNetCore.SignalR.Client。请问在此场景下是否有可行方案?
核心问题是传统ASP.NET SignalR(Microsoft.AspNet.SignalR)和ASP.NET Core SignalR是完全不兼容的两个框架:
- 服务端用的是传统SignalR,它的路由规则、通信协议和ASP.NET Core SignalR完全不同
- 用ASP.NET Core SignalR Client连接传统SignalR服务端时,两者无法协商出可用的通信方式,导致连接卡住
方案1:将服务端升级为ASP.NET Core SignalR(兼容.NET Framework 4.8)
.NET Framework 4.8支持运行ASP.NET Core应用,把Windows Service中的SignalR服务替换为ASP.NET Core版本后,就能和ASP.NET Core SignalR Client正常通信,步骤如下:
- 移除服务端原有的
Microsoft.AspNet.SignalR相关NuGet包,安装Microsoft.AspNetCore.SignalR和Microsoft.AspNetCore.Owin - 修改Windows Service的SignalR启动代码:
// 替换原WebApp.Start方式,使用ASP.NET Core WebHost托管 var host = WebHost.CreateDefaultBuilder() .UseUrls("http://localhost:8585") .ConfigureServices(services => { // 配置Cors services.AddCors(options => { options.AddPolicy("AllowAll", builder => { builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials(); }); }); // 注册SignalR服务 services.AddSignalR(); }) .Configure(app => { app.UseCors("AllowAll"); app.UseRouting(); app.UseEndpoints(endpoints => { // 配置Hub的路由 endpoints.MapHub<ServiceHub>("/serviceHub"); }); }) .Build(); host.Start(); // 获取HubContext的方式更新为ASP.NET Core的依赖注入方式 var serviceHubContext = host.Services.GetRequiredService<IHubContext<ServiceHub>>();
- 修改ServiceHub代码(ASP.NET Core SignalR不再需要
[HubName]特性,默认使用类名):
public class ServiceHub : Hub { public override Task OnConnectedAsync() { // 连接建立时触发 return base.OnConnectedAsync(); } public override Task OnDisconnectedAsync(Exception exception) { // 连接断开时触发(包括程序关闭场景) return base.OnDisconnectedAsync(exception); } }
- 客户端连接代码调整路由:
var serviceHubConnectionx = new HubConnectionBuilder() .WithUrl("http://localhost:8585/serviceHub") .Build(); await serviceHubConnectionx.StartAsync(); // 现在可以正常完成连接
方案2:保留传统SignalR服务端,手动实现所需特性
如果无法升级服务端,只能继续使用传统SignalR Client,但可以手动模拟你需要的ASP.NET Core SignalR特性:
1. 程序关闭时触发断开事件
在桌面应用的退出逻辑中手动调用连接停止方法,同时订阅客户端的Closed事件处理断开场景:
var hubConnection = new HubConnection("http://localhost:8585/signalr"); var hubProxy = hubConnection.CreateHubProxy("ServiceHub"); // 订阅连接断开事件 hubConnection.Closed += async () => { // 这里处理断开后的逻辑,比如记录日志或尝试重连 await Task.Delay(1000); // 可选:自动重连 await hubConnection.Start(); }; await hubConnection.Start(); // 在程序退出时(比如FormClosing事件中)主动停止连接 private void Form_FormClosing(object sender, FormClosingEventArgs e) { hubConnection.Stop().Wait(); }
2. 客户端方法返回值
传统SignalR支持客户端调用服务端方法获取返回值,若需要服务端调用客户端方法时获取返回值,可以通过回调方式实现:
// 服务端代码 public async Task RequestClientData(string callbackId) { // 通知客户端需要返回数据,并传入回调ID await Clients.Caller.SendAsync("ProvideData", callbackId); } // 服务端接收客户端返回结果的方法 public void ReceiveClientResult(string callbackId, string result) { // 处理客户端返回的数据 } // 客户端代码 hubProxy.On<string>("ProvideData", async callbackId => { var clientData = "客户端生成的数据"; // 调用服务端方法返回结果 await hubProxy.InvokeAsync("ReceiveClientResult", callbackId, clientData); });
内容的提问来源于stack exchange,提问作者GameHackerPM

