如何拦截ScaleoutMessage广播:(编辑:如何直接向ServiceBus SignalR Backplane发送消息)

时间:2014-07-09 03:47:17

标签: signalr signalr-backplane

我有以下情况:

  1. 用户对服务器上某些资源的请求,此请求是长时间运行的任务,非常像2~3秒到10秒。我们向用户发出JobTicket,因为我们的用户想要等待。
  2. 在接收请求时,我们将该请求存储在持久性存储中,并向用户发出令牌作为JobTicket(GUID)。
  3. 用户与Hub建立连接以获取有关该GUID的信息。
  4. 背景:

    1. 我们有WAS托管以及Windows服务来执行该请求的某些操作。
    2. 完成后,WAS Hosted / Windows Service将我们的Web应用程序称为已完成作业。
    3. 从那里根据工作票据,我们确定哪个用户及其连接我们让用户知道他们的工作已经完成。
    4. 现在我们有服务器群,我们正在使用Windows Server On Prem ServiceBus 1.1,它工作正常,但我们面临的挑战是我们无法拦截基于ServiceBus的背板消息广播,并且消息将传递给所有客户端。由于我们有农场,用户中间可能有连接并连接到基于负载均衡器的其他服务器,所以我们需要使用Service Bus进行扩展,因为它是无缝集成的,我们也在我们的应用程序中用于我们的内部目的所以我们不希望在复杂的解决方案中使用任何其他组合。

      我已经尝试使用IHubPipelineModule但仍然扩展消息广播没有通过,我试图直接连接SignalR代码并通过它进行调试,但它需要很长时间。我不想在实际代码中弄乱一些任意的东西。我可以看到OnReceive我可以看到消息即将到来,但无法进一步追随。我只需要一个小机制,我可以拦截广播消息,并确保它通过浪费资源和安全问题来到客户端而不是所有客户端。

      请帮助我解决这个问题,它在过去的4天里停滞不前,无法找到任何解决方案,同时我想使用建立模式,并且不想为这种类型分叉任何特殊构建小问题,我相信你们中的一位专家知道如何能够无缝地做到这一点。

      谢谢, Shrenik

1 个答案:

答案 0 :(得分:0)

经过大量的挣扎,没有找到直接的方式,我已经找到了以下的方式,以备将来可能有所帮助。

方案: 1. Web Farm:面向Web页面的主机外部用户 2.后端流程:WebApi,SharePoint,Windows服务等的混合。

来自网页的用户提交一些请求并获得一个唯一ID作为返回。在收到请求的内部,我们使用TopicClient将该请求排队到Service Bus进行处理。

使用SubscriptionClient在服务总线上的消息中观察Windows服务池并处理该消息。完成过程可以在5秒到30秒之间运行,有些情况甚至更多。如果在网页上等待或等待完成通知,我们需要通知客户已完成的工作。

在这个故事中,我们正在使用SignalR将作业完成通知推送给客户。

现在我的早期问题是我如何通过Windows服务向Web应用程序了解作业已完成,因此向提交请求的客户发送通知。

一种方法是我们在Web应用程序内部托管另一个集线器,Windows服务充当客户端并调用Web应用程序托管集线器,并且在该集线器方法中,它将调用面向外部的集线器方法将消息传播到提交请求的特定客户端,我们正在使用单用户组。

由于我们将服务总线注册为背板,它将传播到其他服务器,然后适当的客户端将收到通知。所以这是理想的解决方案,在大多数情况下都应该有效。

在上面的方法中,我们有一个限制,Windows服务如何连接到Web客户端,因为我们没有Windows身份验证,但我们有基于openid的auth与ADFS。现在,在这种情况下,Web应用程序需要特殊代码,其中为Windows服务提供单独的用户标识或密码进行通信,或者也允许Windows服务的服务帐户的该集线器进行Windows身份验证。

我正在尝试并尝试如何消除服务员间沟通和再次管理额外安全性之间的所有希望。

所以我在下面简单地做了,虽然我整晚都在寻找SignalR的内部。但它的确有效:

方法是直接向ServiceBus Backplane发送消息,并且由于所有Web服务器已经与ServiceBus背板连接,因此他们将获得消息。

不幸的是,SignalR没有提供直接向Backplane发送消息的机制。我认为它在pub / sub模型上,所以他们不希望有人破解他们的系统:)。或者它违反了他们的模式,但它有意义,在我的情况下因为不同的角色和安全性,我有简化代码如下:

  1. 在我的代码中创建一个ServiceBusMessageBus实例,方法与下面相同:虽然我已经创建了单独的实例并存储到Windows服务的生命周期,所以我不是每次都创建实例:
  2. ServiceBusMessageBus serviceBusBackplane = new ServiceBusMessageBus(new DefaultDependencyResolver(),new ServiceBusScaleoutConfiguration(connectionString,appName));

    1. 创建ClientHubInvocation对象:这是在基于背板的消息广播时实际在SignalR基础架构中创建的消息:

                      ClientHubInvocation hubData = new ClientHubInvocation
                      {
                          Args = new object[] { msg },
                          Hub = "JobStatusHub",
                          Method = "onJobStatus",
                          State = null,
                      };
      
    2. 创建一个ServiceBusMessageBus.Publish接受的Message对象,是的,所以这是一个实际在基类ScaleoutMessageBus.Publish上调用的方法。该类实际上负责向主题和其他服务器节点上的其他订阅者发送消息。为什么不直接使用它。现在要创建消息对象,您需要以下代码:

    3. 消息backplaneMessage =新消息( 的SourceID, " HG-JobStatusHub&#34。 +名字, new ArraySegment(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(hubData))));

      在上面的第二个参数是有趣的, 如果你想发布到所有客户端,那么语法是" h - ",在我的案例特定组用户中,所以语法是" hg- ..你可以在这里查看代码: https://github.com/SignalR/SignalR/blob/bc9412bcab0f5ef097c7dc919e3ea1b37fc8718c/src/Microsoft.AspNet.SignalR.Core/Infrastructure/PrefixHelper.cs

      1. 直接将消息发布到背板,如下所示:
      2. 等待serviceBusBackplane.Publish(backplaneMessage);

        我希望这个PrefixHelper类已公开。

        请记住:这不是推荐的方式,并且不会对SignalR的未来升级进行隔离,因为它的内部可能会发生变化,因此任何升级都可能带来小的危险,无法更改此代码。但总的来说这是有效的。希望SignalR团队提供一些开箱即用的机制,以便直接向背板发送消息。

        由于