将参数值传递给客户端

时间:2018-10-11 14:51:05

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

我有一个按钮,单击该按钮将/应该通知服务器。然后,服务器会将值保存到数据库。如果一切顺利,则应返回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<HubSignalR>() 但我无法使其正常工作。

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

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

我不得不在我的isSuccess类中创建HubSignalR字段,因为我需要从控制器返回该字段作为参数。但是,当单击按钮时,此值尚未设置(我认为)。

我从调试器中看到确实可以达到:signalRhub.server.cardAdded(); 但是服务器从不响应,因此我无法实现此功能:

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

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

如果您有比我想要的解决方案更好的解决方案,请告知。我对SignalR完全陌生,而对ASP.net MVC完全陌生

1 个答案:

答案 0 :(得分:1)

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

关于“如何”:

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

比您的服务器方法还多:

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

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

关于“为什么”:

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

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

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

在下面发表评论

我对ajax经验很少,我想它可能有用。如果您想避免进行身份验证,则另一个想法是使用SignalR的订阅模型。 您必须找出自己拥有哪些特定资源,比如说“游戏”,其中包含ID。对特定资源感兴趣的客户应订阅更改。

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

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

公共静态类帮助器 {     公共静态字符串GetGameGroupName(长ID)     {         返回$“ Game_ {id}”;     } }

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

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

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

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

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