1

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

执行 MVC 操作,并且作为该处理的一部分,调用 Biztalk 端点。Biztalk 执行不在进程中(从 MVC 操作的角度来看),完成后不会返回。这是设计使然。为了通知 MVC 应用程序它已完成,Biztalk 通过调用 /myapp/signalr 端点向 MVC 应用程序的 SignalR 集线器发送一条消息。消息由 SignalR 接收,然后应路由到适当的浏览器实例。

由于发送给 SignalR 的消息是由 Biztalk 而不是 MVC 应用程序发送的,因此与 SignalR 的连接的 ClientId 不是标识应该接收消息的浏览器实例的那个。因此,我们试图通过在发送给 Biztalk 的消息中包含启动 Biztalk 调用的浏览器实例的ClientId ConnectionId 来实现类似于返回地址模式的东西。当 Biztalk 将其消息发送到 SignalR 时,其中一个内容是原始ClientId ConnectionId 值。当 SignalR 处理来自 Biztalk 的消息时,它可以使用ClientIdConnectionId 包含在消息中,用于将该消息路由到适当的浏览器实例。(是的,我们知道如果浏览器已关闭并重新打开,这将不起作用,我们对此很好。)

我们面临的问题是,当最初从我们的 MVC Action 向 Biztalk 发送消息时,我们无法访问ClientId ConnectionId,因为它仅在 Hub 的上下文中可用。这是可以理解的,因为 MVC 操作不知道要查找哪个 Hub 上下文。

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

据报道,David Fowler 发布了一个要点,该要点显示了如何使只读 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 中使用这种类型的断开连接的消息传递时如何更新适当的客户端?

4

1 回答 1

0

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

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

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

于 2013-04-15T17:11:28.950 回答