SignalR 从控制器 ASP.NET Core 2.1 调用特定客户端

SignalR call to specific client from controller ASP.NET Core 2.1

用户在浏览器中提交表单后,我需要从服务器向客户端发送即时消息。

我按照 Microsoft 的步骤 here 设置了 signalR 连接,创建了集线器 class、signalr.js 等

问题是我只能向所有客户端调用消息,但我需要向发起请求的特定调用者调用消息(否则每个人都会收到消息)。

这是我在 HomeController.cs 中的 POST 操作:

[HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Submit(string signalRconnectionId, Dictionary<string, string> inputs)
    {
        //Invoke signal to all clients sending a message to initSignal WORKS FINE
        await _signalHubContext.Clients.All.SendAsync("initSignal", "This is a message from the server!");

        //Invoke signal to specified client where signalRConnectionId = connection.id DOES NOT WORK
        await _signalHubContext.Clients.Client(signalRconnectionId).SendAsync("initSignal", "This is a message from server to this client: " + signalRconnectionId);

        return RedirectToAction("Success", inputs);
    }

我的客户javascript 文件:

    //Create connection and start it
const connection = new signalR.HubConnectionBuilder()
    .withUrl("/signalHub")
    .configureLogging(signalR.LogLevel.Information)
    .build();
connection.start().catch(err => console.error(err.toString()));

console.log("connectionID: " + connection.id);
$("#signalRconnectionId").attr("value", connection.id);

//Signal method invoked from server
connection.on("initSignal", (message) => {

    console.log("We got signal! and the message is: " + message);


});

我已经尝试调试操作方法,我正确地传入了“0”的 connectionId(每个连接递增 1)

根据 Microsoft 的说法,您无法从集线器外部访问 ConnectionId 和 Caller https://docs.microsoft.com/en-us/aspnet/core/signalr/hubcontext?view=aspnetcore-2.1

When hub methods are called from outside of the Hub class, there's no caller associated with the invocation. Therefore, there's no access to the ConnectionId, Caller, and Others properties.

这是我根据

的答案得出的最终解决方案

我通过从客户端调用 Hub class 获得了 connectionId,然后从客户端调用传入 connectionId 的控制器。

中心 class:

public class SignalHub : Hub
{
    

    public string GetConnectionId()
    {
        return Context.ConnectionId;
    }
}

客户端javascript启动时执行的代码:

connection.start().catch(err => console.error(err.toString())).then(function(){
connection.invoke('getConnectionId')
    .then(function (connectionId) {
        // Send the connectionId to controller
        console.log("connectionID: " + connectionId);
        $("#signalRconnectionId").attr("value", connectionId);
    });
});

HomeController.cs:

public async Task<IActionResult> Submit(string signalRconnectionId, Dictionary<string, string> inputs)
    {
        
        //Invoke signal to specified client WORKS NOW
        await _signalHubContext.Clients.Client(signalRconnectionId).SendAsync("initSignal", "This is a message from server to this client: " + signalRconnectionId);

        return RedirectToAction("Success", inputs);
    }

它工作正常,但仍然感觉有点像往返,如果我们不必通过枢纽 class 来实现它会更容易。也许只是从客户端开始使用 connectionId,但也许有一个很好的设计理由:)