使用SignalR隔离特定的浏览器实例

我们正在构建一个应用程序,它将使用SignalR向浏览器发送消息 . 用户可能打开了多个浏览器实例,我们希望将每条消息发送到适当的浏览器 . 我们的理解是ClientId ConnectionId允许我们这样做 . 我们遇到的问题是在代码库中的适当时间访问ClientId ConnectionId或SessionId . 这是我们的场景:

MVC Action执行,并且作为该处理的一部分,进行对Biztalk endpoints 的调用 . Biztalk执行不在进程中(从MVC Action的角度来看)并且在完成时不会返回 . 这是设计的 . 为了通知MVC应用程序已完成,Biztalk通过调用/ myapp / signalr endpoints 向MVC应用程序的SignalR集线器发送消息 . SignalR收到该消息,然后将其路由到相应的浏览器实例 .

由于到SignalR的消息是由Biztalk而不是MVC应用程序发送的,因此与SignalR的连接的ClientId不是标识应该接收消息的浏览器实例的ClientId . 因此,我们试图实现的是类似于返回地址模式的一些东西,它包括在消息中向Biztalk启动Biztalk调用的浏览器实例的ClientId ConnectionId . 当Biztalk将其消息发送到SignalR时,其中一个内容是原始的ClientId ConnectionId值 . 当SignalR处理来自Biztalk的消息时,它可以使用消息中包含的ClientId ConnectionId将该消息路由到适当的浏览器实例 . (是的,我们知道这对此很好 . )

我们面临的问题是,当我们最初从我们的MVC Action向Biztalk发送消息时,我们无法访问ClientId ConnectionId,因为它是's only available in the Hub'的Context . 这是可以理解的,因为MVC Action不知道要查找哪个Hub上下文 .

我们在其中尝试的是通过Biztalk消息传递SessionId并将其返回到SignalR . 这解决了在Biztalk消息中包含浏览器实例标识符并将其返回到SignalR的问题 . 它引入的是当客户端连接到Hub时,我们无法访问Hub的OnConnect方法中的Session(以及SessionId) .

据报道,David Fowler发布了一个要点,该要点显示如何在Hub中访问只读SessionState,但它不起作用 . (https://gist.github.com/davidfowl/4692934)一旦我们将此代码添加到我们的应用程序中,发送到SignalR的消息会导致HTTP 500错误,这是由SignalR引发以下异常引起的 .

[ArgumentNullException: Value cannot be null.Parameter name: s]
System.IO.StringReader..ctor(String s) +10688601
Microsoft.AspNet.SignalR.Json.JsonNetSerializer.Parse(String json, Type targetType) +77
Microsoft.AspNet.SignalR.Json.JsonSerializerExtensions.Parse(IJsonSerializer serializer, String json) +184
Microsoft.AspNet.SignalR.Hubs.HubRequestParser.Parse(String data) +101
Microsoft.AspNet.SignalR.Hubs.HubDispatcher.OnReceived(IRequest request, String connectionId, String data) +143
Microsoft.AspNet.SignalR.<>c__DisplayClassc.<ProcessRequest>b__7() +96
Microsoft.AspNet.SignalR.<>c__DisplayClass3c.<FromMethod>b__3b() +41
Microsoft.AspNet.SignalR.TaskAsyncHelper.FromMethod(Func`1 func) +67

无论我们设置SessionStateBehavior的模式(如David Fowler的要点所示),我们要么在向Hub发送消息时遇到此异常,要么当我们在Hub的OnConnect中时SessionState为null .

那么,在完成所有前导后,我们要问的是在SignalR中使用这种类型的断开连接的消息时,人们如何更新相应的客户端?

回答(1)

2 years ago

如果您希望在对集线器的正常请求之外向客户端发送数据,那么我建议您在集线器上使用静态并发字典来管理用户并将其映射到相应的连接ID .

使用此方法,您可以根据其映射的连接ID在任何位置发送给任何用户 . 因此,当您将数据发送到Biztalk时,您需要做的就是发送您的用户ID(由您创建),然后当数据流回SignalR时,您可以查找给定用户ID的ConnectionId(如果存在) .

最后,您可以通过在OnConnected中将用户添加到并发字典来管理用户映射,仅在OnReconnected中不存在时添加,并在OnDisconnected中删除 .