【问题标题】:Pass a parameter value to the client将参数值传递给客户端
【发布时间】:2019-03-16 17:08:00
【问题描述】:

我有一个按钮,单击该按钮将/应该通知服务器。然后服务器将值保存到数据库中。如果一切顺利,它应该返回true,否则返回false。

我在我的视图中实例化了一个集线器

var signalRhub = $.connection.hubSignalR;    

开始连接:

    $.connection.hub.start().done(function () {
        $("#submitBut").click(function () {
             signalRhub.server.cardAdded();
        });            
    });

定义服务器用来返回布尔值的函数:

signalRhub.client.cardAddedRes = function (isSuccess) {
     alert("From server: " + isSuccss);
}

我的 Hub 类:

public class HubSignalR : Hub
{
    public bool isSuccess = false; <-- Will be set from controller

    public void CardAdded() 
    {
        Clients.Caller.CardAddedRes(isSuccess);  <-- Notice the isSuccess
    }
}

我的问题是 isSuccess 值来自我的控制器,它与模型/数据库交互。 所以我得到了错误:

Using a Hub instance not created by the HubPipeline is unsupported.

我尝试使用:GlobalHost.ConnectionManager.GetHubContext&lt;HubSignalR&gt;() 但我不能让它工作。

这是我控制器中的相关代码:

private HubSignalR signalR = new HubSignalR(); <-- Field variable

 [HttpPost]
 public ActionResult AttachCard(Card model, int MemberID)
 {
  var hub = GlobalHost.ConnectionManager.GetHubContext<HubSignalR>();
  ...
  //We saved to the database, so we call the client function with bool = true   
  hub.Clients.All.CardAdded(true);  <-- Actually I want to send to one client, NOT ALL
  //Something like hub.Clients.Caller.CardAdded();
  }

我不得不在 HubSignalR 类中创建 isSuccess 字段,因为我需要将其作为参数从我的控制器返回。但是当按钮被点击时,这个值还没有被设置(我认为)。

我可以从调试器中看到,我确实达到了:signalRhub.server.cardAdded(); 但是服务器从不响应,所以我没有达到这个功能:

    signalRhub.client.cardAddedRes = function (isSuccess) {
     alert("From server: " + isSuccss);
}

我并没有真正从我的控制器调用CardAdded() 方法,就像GlobalHost.ConnectionManager.GetHubContext 一样。但是你可以看到

如果您有比我尝试做的更好的解决方案,请告诉我。我对 SignalR 很陌生,对 ASP.net MVC 很陌生

【问题讨论】:

    标签: c# asp.net-mvc-4 asp.net-mvc-5 signalr


    【解决方案1】:

    希望我的问题是正确的:您想在控制器中设置 isSuccess 并将其发送到特定客户端,但不要从集线器外部到达特定客户端?

    至于“如何”:

    您应该找到一种方法来识别您的客户,即实施某种身份验证。更多信息在这里:Authentication in .net core 当客户端连接到 SignalR 时,他们会获得一个连接 ID。您可以将连接 ID 映射到真实的客户端身份。更多信息在这里:Mapping clients to connections

    比你的服务器方法:

    • 获取经过身份验证的客户端身份
    • 获取 signalR 集线器上下文
    • 将客户端身份映射到现有的 signalR 连接 ID
    • 向该 signalR 连接发送消息

    正如我从您的代码中看到的那样,您可能正在从事一些个人用途/探索性项目,并且可能对实施身份验证不感兴趣/不关心安全性。通过$.connection.hub.id 连接后,您可以在客户端中获取signalR 连接ID。您可以将此 ID 作为参数或标头发送到服务器方法。这绝不应该在生产环境中使用,因为您会相信客户是谁,并传递您的方法并不严格需要的参数。

    至于“为什么”:

    事实上,我认为您的用例不需要 signalR。您调用服务器方法,它会保存到数据库并返回 OK 或不 OK,客户端很高兴。无需通过signalR。

    你确实需要 signalR 例如什么时候: - 同一个客户端在多台设备上登录并希望在其中一台设备上进行更改时获取更新 - 客户处理某事,另一人更改相同的数据。您想通知第一个客户。 - 通知您的客户一个不是由他触发的事件(新通知)

    在所有这些情况下,您都有某种身份验证,并且向正确的客户端发送 signalR 消息不是问题。

    在下方回复评论

    我对 ajax 几乎没有经验,我想它可能会起作用。如果您想避免身份验证,另一个想法是使用 SignalR 的订阅模型。 你必须找出你有哪些特定的资源,比如说你的“游戏”,它们有 ID。比对特定资源感兴趣的客户应该订阅更改。

    特定纸牌游戏实例的所有参与者都应调用如下定义的集线器方法:

    public async Task SubscribeToGameChanges(long id)
    {
        await this.Groups.AddToGroupAsync(this.Context.ConnectionId, Helper.GetGameGroupName(id));
    }
    

    公共静态类助手 { 公共静态字符串 GetGameGroupName(long id) { 返回 $"Game_{id}"; } }

    比从客户端调用它。注意AddToGroupAsync。 SignalR 应创建一个具有给定名称的组并向其添加客户端。如果组存在,它只会添加另一个客户端。因此,每个游戏实例都有一个组,其中包含感兴趣的客户(玩家)列表。

    现在,当游戏发生变化时,您可以通过在集线器上下文中调用控制器来通知所有客户端:

    await hubContext.Clients.Groups(Helper.GetGameGroupName(id)).SendAsync("myNotifyMethod", myParameters);
    

    您可以将所有更改打包到参数中,或者只是通知客户端游戏(或任何其他资源)的状态已更改,客户端应通过正常的 API 调用重新查询状态。

    我还注意到您在代码中使用了 GlobalHost。我的代码示例适用于 .net core SignalR 版本,在您的情况下可能略有不同。请参阅 here 了解 .net 核心和完整 .net SignalR 之间的差异。

    【讨论】:

    • 我明白你的意思@Maxim 那么你会用什么来从服务器到客户端获取信息?我以前使用过 Ajax 来完成类似的任务。在我的情况下,也许这仍然是要走的路
    • 我在答案中添加了更多信息。
    猜你喜欢
    • 1970-01-01
    • 2023-03-29
    • 2016-06-16
    • 1970-01-01
    • 1970-01-01
    • 2016-01-10
    • 1970-01-01
    • 1970-01-01
    • 2019-04-15
    相关资源
    最近更新 更多