SignalR服务端调用带参客户端方法无返回结果问题排查
SignalR服务端调用带参数客户端返回方法时抛出
Client didn't provide a result.异常 环境与场景
- 服务端:.NET7 ASP.NET Core,使用强类型Hub
- 客户端:.NET7 WinForms,依赖
Microsoft.AspNetCore.SignalR.Client7.0.7 - 需求:搭建SignalR服务端与多客户端通信,指定首个连接客户端为主客户端,服务端调用主客户端方法并获取返回结果
问题现象
服务端调用无参数的客户端返回方法(TestBoolean)正常,但调用带参数的客户端返回方法(TestBooleanWithParameters)时,抛出异常:
System.Exception: 'Client didn't provide a result.'
原服务端代码
public interface IStrongServer { Task<bool> TestBoolean(); Task<bool> TestBooleanWithParameters(string toSend); } public class StrongServerHub : Hub<IStrongServer> { private readonly StrongServer _strongServer; public StrongServerHub(StrongServer nStrongServer) { _strongServer = nStrongServer; } public override async Task OnConnectedAsync() { _strongServer.AssignPrimaryConnection(Context.ConnectionId); await base.OnConnectedAsync(); } public override async Task OnDisconnectedAsync(Exception? exception) { _strongServer.DisconnectPrimaryConnection(Context.ConnectionId); await base.OnDisconnectedAsync(exception); } } public class StrongServer : IStrongServer { private string _primaryConnectionId = ""; private bool _primaryConnected = false; private readonly IHubContext<StrongServerHub, IStrongServer> _hub; public StrongServer(IHubContext<StrongServerHub, IStrongServer> hub) { _hub = hub; } public void AssignPrimaryConnection(string connectionId) { if (string.IsNullOrEmpty(_primaryConnectionId)) { _primaryConnectionId = connectionId; _primaryConnected = true; } } public void DisconnectPrimaryConnection(string connectionId) { if (!string.IsNullOrEmpty(_primaryConnectionId) && string.Equals(_primaryConnectionId, connectionId)) { _primaryConnectionId = ""; _primaryConnected = false; } } public async Task<bool> TestBoolean() { return await _hub.Clients.Client(_primaryConnectionId).TestBoolean(); } public async Task<bool> TestBooleanWithParameters(string toSend) { return await _hub.Clients.Client(_primaryConnectionId).TestBooleanWithParameters(toSend); } } public class SignalRHost { public StrongServer Server { get; set; } public void Run() { var builder = WebApplication.CreateBuilder(); builder.Services.AddRazorPages(); builder.Services.AddSignalR(); builder.Services.AddSingleton<StrongServer>(); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.MapRazorPages(); app.MapHub<StrongServerHub>("/strong"); Server = app.Services.GetService<StrongServer>(); app.RunAsync(); } } // Program.cs 调用 SignalRHost host = new SignalRHost(); host.Run(); bool returnedBoolean = await host.Server.TestBoolean(); bool returnedBooleanWithParameters = await host.Server.TestBooleanWithParameters("Hello World!");
原客户端代码
public interface ITestClient { bool TestBoolean(); bool TestBooleanWithParameters(string test); } using System.Diagnostics; public class SignalRClient : ITestClient { HubConnection _testConnection = null; public async void Init() { _testConnection = new HubConnectionBuilder() .WithUrl("http://localhost:5035/strong") .Build(); _testConnection.On(nameof(TestBoolean), TestBoolean); _testConnection.On<string>(nameof(TestBooleanWithParameters), (p1) => TestBooleanWithParameters(p1)); await _testConnection.StartAsync(); } public bool TestBoolean() { return true; } public bool TestBooleanWithParameters(string test) { Debug.WriteLine($"TestBooleanReturn: {test}"); return true; } } internal static class Program { [STAThread] static void Main() { SignalRClient client = new SignalRClient(); client.Init(); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainForm()); } }
问题原因与解决方案
问题根源在于客户端方法的同步返回无法被SignalR正确捕获并回传给服务端,尤其是带参数的场景。SignalR Client Results机制要求客户端方法必须是异步的(返回Task<T>),同时注册方法时要匹配异步委托。
修正步骤:
- 修改客户端接口为异步方法
- 客户端实现类改为异步方法
- 注册客户端方法时使用异步委托
修正后的客户端代码
// 修正接口方法为异步返回Task<bool> public interface ITestClient { Task<bool> TestBoolean(); Task<bool> TestBooleanWithParameters(string test); } using System.Diagnostics; public class SignalRClient : ITestClient { HubConnection _testConnection = null; public async void Init() { _testConnection = new HubConnectionBuilder() .WithUrl("http://localhost:5035/strong") .Build(); // 注册异步方法,使用匹配的委托 _testConnection.On(nameof(TestBoolean), async () => await TestBoolean()); _testConnection.On<string>(nameof(TestBooleanWithParameters), async (p1) => await TestBooleanWithParameters(p1)); await _testConnection.StartAsync(); } // 改为异步方法 public async Task<bool> TestBoolean() { return await Task.FromResult(true); } // 改为异步方法 public async Task<bool> TestBooleanWithParameters(string test) { Debug.WriteLine($"TestBooleanReturn: {test}"); return await Task.FromResult(true); } } internal static class Program { [STAThread] static void Main() { SignalRClient client = new SignalRClient(); client.Init(); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainForm()); } }
额外说明
- SignalR的Client Results功能依赖异步通信,同步方法无法触发结果回传逻辑,即使无参数的场景偶然正常,也属于非预期行为,建议所有需要返回结果的客户端方法都改为异步。
- 服务端代码无需修改,强类型Hub的定义已经符合异步要求。
内容的提问来源于stack exchange,提问作者Merganen
相关产品推荐
相关产品推荐

