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

时间:2013-04-11 15:41:50

标签: signalr signalr-hub

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

执行MVC操作,并且作为该处理的一部分,进行对Biztalk端点的调用。 Biztalk执行不在进程中(从MVC Action的角度来看)并且在完成时不会返回。这是设计的。为了通知MVC应用程序已完成,Biztalk通过调用/ myapp / signalr端点向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,因为它仅在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 个答案:

答案 0 :(得分:0)

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

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

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