如何在正确的客户端出现时在信号集线器上缓冲消息并发送消息? [英] How to buffer messages on signal hub and send them when the right client appears?

查看:74
本文介绍了如何在正确的客户端出现时在信号集线器上缓冲消息并发送消息?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两种类型的客户端连接我的signalR服务器(ASP.NET Core).其中一些是发送者,一些是接收者.我需要将消息从发送者路由到接收者,这不是问题,但是当没有接收者时,我需要以某种方式缓冲消息而不丢失它们(最好是单例类中的ConcurrentQueue),但是当在第一个接收者连接时,消息缓冲区需要开始出队.哪个是最好的方法?

I hawe two type of clients connecting my signalR server (ASP.NET Core). Some of them are senders, and some of them are receivers. I need to route messages from senders to the receivers, which is not a problem, but when there is no receivers, I need to somehow buffer messages and not lose them (probably the best is ConcurrentQueue in some kind of a singleton class) but when the first receiver connect, the message buffer needs to start dequeue. Which is the best approach for this?

我创建了单例类,该类包装了arround ConcurrentQueue集合,并在其中使消息入队和出队.另外,我还有一个单独的单例类,用于持久保存接收者的connectionIDs集合.我在第二个类中实现了事件,该事件在接收者列表为空之后在第一个接收者连接时触发事件,但这也许不是一个好方法,我不知道如何在Hub中使用id,因为存在多个实例signalR集线器. 第二种方法是将持久性类标记为控制器,并在该类中注入ContextHub和消息缓冲区,然后从该类中出队缓冲区,然后直接将消息发送给接收者.

I created singleton class that wraps arround ConcurrentQueue collection and I enqueue and dequeue messages there. Also I have a separate singleton class which persist collection of the receivers connectionIDs. And I implemented event in this second class that fires event when first receiver connects after the list of receivers was empty but maybe this is not a good approach, I don't know how to use id in Hub, because there is more than one instance of a signalR hub. Second approach is to mark persistance class as controller and inject the ContextHub and message buffer in this class and dequeue buffer from there and directly send messages to the receivers???

推荐答案

如果我很好理解,您想通过在某些IHostedService中使用诸如同步调用之类的方法来推迟SignalR消息的发送.到目前为止,这是我设法实现的目标.

If I understood well, you want to defer SignalR message sending by using something like a synchronized call in some IHostedService. Here is what I managed to achieve so far.

  • 您的方法是使用一个ConcurrentQueue包含正确的方法,该ConcurrentQueue包含可调用的Action委托来处理并发的中心调用.如您所述,它必须作为单例注入.

这里是Queues类:

public class Queues {
    public ConcurrentQueue<Action<IHubContext<MyHub, IMyEvents>>> MessagesQueue { get; set; }
}

  • 现在,我们需要捕获呼叫者的ConnectionId,这样呼叫才能稍后获得答案. SendMessage将必要的操作委托放入队列,以对作为参数的集线器实例执行调用.
    • Now we need to capture the ConnectionId of the caller so a call can get an answer later. SendMessage enqueue the necessary action delegate to perform a call against a hub instance as a parameter.
    • 作为示例,SendMessage将触发对呼叫者的应答,而BroadcastMessage将向所有客户端发送一条消息.

      As an example SendMessage will trigger an answer back to the caller, and BroadcastMessage will send a message to all clients.

      使用捕获的集线器实例会导致异常,因为集线器将被快速处置.这就是为什么它将在以后的其他课程中注入的原因.看看SendMessage_BAD

      这是MyHub类和相应的IMyEvents接口:

      public interface IMyEvents {
          void ReceiveMessage(string myMessage);
      }
      
      public class MyHub : Hub<IMyEvents> {
          Queues queues;
      
          public MyHub(Queues queues) {
              this.queues = queues;
          }
      
          public void SendMessage(string message) {
              var callerId = Context.ConnectionId;
              queues.MessagesQueue.Enqueue(hub => hub.Clients.Client(callerId).ReceiveMessage(message));
          }
      
          // This will crash
          public void SendMessage_BAD(string message) {
              this.callerId = Context.ConnectionId;
              queues.MessagesQueue.Enqueue(_ => this.Clients.Client(callerId).ReceiveMessage(message));
          }
      
          public void BroadcastMessage(string message) {
              queues.MessagesQueue.Enqueue(hub => hub.Clients.All.ReceiveMessage(message));
          }
      }
      

      • 现在,使用幼稚的方法,此代码将触发消息以延迟方式发送. (在工作中,计时器确保常规节奏,并且该类为IHostedService,但此处未出现).此类必须作为单例注入.
        • Now, using a naive approach, this code will trigger the message sending a deferred way. (At work, a timer ensure a regular cadence, and the class is an IHostedService but it is does not appear here). This class has to be injected as a singleton.
        • 这是DeferredMessageSender类:

          public class DeferredMessageSender {
              Queues queues;
              IHubContext<MyHub, IMyEvents> hub;
          
              public DeferredMessageSender(Queues queues, IHubContext<MyHub, IMyEvents> hub) {
                  this.queues = queues;
                  this.hub = hub;
              }
          
              public void GlobalSend() {
                  while(queues.MessagesQueue.TryDequeue(out var evt)) {
                      evt.Invoke(hub);
                  }
              }
          }
          

          希望有帮助.

          这篇关于如何在正确的客户端出现时在信号集线器上缓冲消息并发送消息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆