【问题标题】:SignalR call works but doesn't return to clientSignalR 调用有效但不返回给客户端
【发布时间】:2020-05-13 20:33:33
【问题描述】:

我正在使用 Blazor 构建一个 Web 应用程序,通过 SignalR 同步团队(我的域模型)。 (Blazor RC1 WebApp,core31 WebApi)

我的客户有一个调用,触发服务器将当前团队列表发送给客户。这个方法只有两行:

var currentTeams = await teamService.GetAllTeams().ConfigureAwait(false);
await SendTeamsToClient(currentTeams).ConfigureAwait(false);

这些工作 - SendTeamsToClient 获取列表并在客户端上调用另一个 SignalR 方法 - 成功。对象被发送到客户端并在那里正确处理。

唯一的问题是:客户端调用永远不会返回。客户端方法只有一行:

await connection.InvokeAsync(nameof(ServerHub.SubscribeToAndReceiveTeamsAsync));

而那个人永远不会回来。知道为什么吗?

我有一个解决方法,我将该方法称为“即发即弃”,但这确实不是一个长期可行的解决方案。

我还尝试让服务器将SendTeamsToClient 称为即发即弃,以防万一发生干扰。尽管如此,团队还是会被发送,但最初调用的 hub 方法会在服务器上返回,但不会在客户端上返回。

更新(MCVE 有效,我的项目无效):

所以我试图重现这个问题,但我失败了。此 MCVE 完美运行:

MCVE 前端,数字表示成功进入控制台:

public async Task Ping()
{
    Console.WriteLine("Sending ping..."); // 1
    await c.InvokeAsync("Ping");
    Console.WriteLine("ping returned."); // 4
}

public Task Pong(string p)
{
    Console.WriteLine("Received pong: "+p); // 2+3
    Pongs.Add(p);
    StateHasChanged();
    return Task.CompletedTask;
}

MCVE 后端:

public async Task Ping()
{
    var pongs = new string[]
    {
        "Pong1",
        "Pong2"
    };
    await SendPongs(pongs).ConfigureAwait(false);
}

public async Task SendPongs(IEnumerable<string> pongs)
{
    foreach (var pong in pongs)
    {
        await Clients.Caller.Pong(pong).ConfigureAwait(false);
    }
}

实际项目前端:

public async Task SubscribeToAndReceiveTeamsAsync()
{
    Console.WriteLine("Frontend Hub triggering teams"); // This arrives
    await connection.InvokeAsync(nameof(ServerHub.SubscribeToAndReceiveTeamsAsync));
    Console.WriteLine("Frontend hub done triggering teams."); // This doesn't
}

public Task ReceiveTeam(Team team) // Works completely (teams arrive in view)
{
    Console.WriteLine("Frontend hub receiving team "+team.Name);
    Console.WriteLine($"Invoking event with {OnNewTeam?.GetInvocationList().Length} listener(s).");
    OnNewTeam?.Invoke(team);
    return Task.CompletedTask;
}

实际项目后端:

public async Task SubscribeToAndReceiveTeamsAsync()
{
    var currentTeams = await teamService.GetAllTeams().ConfigureAwait(false);
    Log(currentTeams.Count()); // This arrives with "2"
    await SendTeamsToClient(currentTeams).ConfigureAwait(false);
    Log("Server done"); // This arrives, therefore this method returns?
}

private async Task SendTeamsToClient(IEnumerable<Team> teams)
{
    foreach (var team in teams)
    {
        await Clients.Caller.ReceiveTeam(team).ConfigureAwait(false);
    }
}

不知道为什么一个可以工作而另一个不能。

快速更新:不管我是使用 IIS 还是自托管。都不行。

更新 2

MCVE 和实际项目都使用 DI:

前端:

builder.Services.AddSingleton<HubConnection>(sp => new HubConnectionBuilder().WithUrl($"{builder.HostEnvironment.BaseAddress}signalr").WithAutomaticReconnect().Build());

后端:

app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages(); // <- Not in actual project
            endpoints.MapControllers();
            endpoints.MapFallbackToFile("index.html"); // <- Not in actual project
            endpoints.MapHub<MyHub>("/signalr");
        });

我确实添加了一个新方法,但它也有同样的问题:

前端事件调用await connection.InvokeAsync(nameof(ServerHub.SendChatMessage), message);

后端将其发送给其他客户端:

public Task SendChatMessage(string message)
{
    Clients.Others.ReceiveMessage(message).ConfigureAwait(false);
    return Task.CompletedTask;
} // Debugger says this returns successfully

其他人成功收到消息。

调用者前端调用永远不会返回。

【问题讨论】:

  • 您是否在客户端进一步阻塞调用堆栈?
  • 没有任何阻塞,除了这个调用。在这个调用之前和之后有一个Console.WriteLine,当我awaitInvokeAsync 时没有调用之后的那个。再往上基本就是调用这一个和多个Console.WriteLines,从OnInitializedAsync开始。
  • 我的意思是像 .Wait().Result anywhere 那样阻塞调用堆栈。
  • 啊不,我在任何地方都没有阻塞呼叫。 await 从上到下。
  • 你能发布一个最小的复制吗?

标签: c# signalr blazor


【解决方案1】:

所以我将我的项目升级到 .NET 5,它现在可以完美运行。不知道是关于框架还是 SignalR 更新,但我猜是点击了什么?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-31
    • 1970-01-01
    • 1970-01-01
    • 2019-05-22
    相关资源
    最近更新 更多