【问题标题】:SignalR call to specific client from controller ASP.NET Core 2.1SignalR 从控制器 ASP.NET Core 2.1 调用特定客户端
【发布时间】:2023-03-19 15:12:01
【问题描述】:

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

我按照微软的步骤 here 设置了一个 signalR 连接,创建了一个 Hub 类,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)

【问题讨论】:

  • 在您链接的页面上,还有另一个链接解释了Clientsdocs.microsoft.com/en-us/aspnet/core/signalr/…
  • Clients.Caller.SendAsync("ReceiveMessage", message); - 这将只为发起请求的客户端调用客户端函数。
  • 你自己试过了吗?当我使用 _signalHubContext.Clients 时,没有可用的调用方方法。如果我从 Hub 类那里做,但是我需要把业务逻辑放在那里,我想从我通过控制器中的 DI 获得的 hubcontext 做它
  • 这个假设来自:connectionId which is "0" (incrementing by 1 per connection)

标签: c# asp.net-mvc asp.net-core asp.net-core-signalr


【解决方案1】:

这是我在this thread 的答案的启发下提出的最终解决方案

我通过从客户端调用 Hub 类,然后从客户端调用传入 connectionId 的控制器来获取 connectionId。

集线器类:

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);
    }

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

【讨论】:

  • 我无法调用集线器方法,我在该方法中也有业务逻辑。但它似乎只是将消息直接发送给前端用户。哦,我可以使用 _hubContext.Clients.User(userId).SendAsync("method1", message)
【解决方案2】:

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

当从Hub 类外部调用集线器方法时,没有 与调用关联的调用者。因此,无法访问 ConnectionIdCallerOthers 属性。

【讨论】:

  • 是的,谢谢 - 太糟糕了:/。想知道这是技术边界还是他们为什么要这样做,这有点破坏了服务器即时通信的灵活性。然后,我需要在提交表单时从客户端调用 Hub 方法,然后在该方法内部调用控制器操作或另一个存储库方法,从而在集线器类中混合业务逻辑 hmm
  • 只使用 UserId 代替
  • 但是 UserId 会要求站点使用身份验证权限吗?
猜你喜欢
  • 2011-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-06
  • 2013-03-23
  • 2018-08-24
  • 2019-06-17
  • 2019-08-25
相关资源
最近更新 更多