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

SignalR服务端调用带参客户端方法无返回结果问题排查

SignalR服务端调用带参数客户端返回方法时抛出Client didn't provide a result.异常

环境与场景

  • 服务端:.NET7 ASP.NET Core,使用强类型Hub
  • 客户端:.NET7 WinForms,依赖Microsoft.AspNetCore.SignalR.Client 7.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>),同时注册方法时要匹配异步委托。

修正步骤:

  1. 修改客户端接口为异步方法
  2. 客户端实现类改为异步方法
  3. 注册客户端方法时使用异步委托

修正后的客户端代码

// 修正接口方法为异步返回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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 16:24:54