我有一个按钮,单击该按钮将/应该通知服务器。然后,服务器会将值保存到数据库。如果一切顺利,则应返回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完全陌生
答案 0 :(得分:1)
希望我没问题:您想在控制器中设置isSuccess并将其发送到特定客户端,但是不从集线器外部访问特定客户端吗?
关于“如何”:
您应该找到一种识别客户的方法,即实施某种身份验证。这里的更多信息:Authentication in .net core当客户端连接到SignalR时,它们将获得一个连接ID。您可以将连接ID映射到真实的客户端身份。此处更多信息:Mapping clients to connections
比您的服务器方法还多:
从您的代码中可以看到,您可能正在从事一些个人使用/探索性项目,并且可能对实现身份验证不感兴趣/不关心安全性。通过$.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。