我有两种类型的客户端连接我的signalR服务器(ASP.NET Core)。其中一些是发送者,一些是接收者。我需要将消息从发送者路由到接收者,这不是问题,但是当没有接收者时,我需要以某种方式缓冲消息而不丢失它们(最好是单例类中的ConcurrentQueue),但是当在第一个接收者连接时,消息缓冲区需要开始出队。哪个是最好的方法?
我创建了单例类,该类包装了arround ConcurrentQueue集合,并在其中使消息入队和出队。另外,我还有一个单独的单例类,用于持久保存接收者的connectionIDs。我在第二个类中实现了事件,该事件在接收者列表为空之后在第一个接收者连接时触发事件,但这也许不是一个好方法,我不知道如何在Hub中使用id,因为存在多个实例signalR集线器。 第二种方法是将持久性类标记为控制器,并在该类中注入ContextHub和消息缓冲区,然后从该类中出队缓冲区,然后直接将消息发送给接收者。
答案 0 :(得分:0)
如果我很好理解,您想通过在某些IHostedService中使用同步调用之类的方法来延迟SignalR消息的发送。到目前为止,这是我设法实现的目标。
这里是Queues
类:
public class Queues {
public ConcurrentQueue<Action<IHubContext<MyHub, IMyEvents>>> MessagesQueue { get; set; }
}
ConnectionId
,以便以后可以得到呼叫答复。 SendMessage
排队必要的操作委托以对作为参数的集线器实例执行调用。例如,SendMessage
将触发对呼叫者的应答,而BroadcastMessage
将向所有客户端发送一条消息。
使用捕获的集线器实例会导致异常,因为集线器将被快速处置。这就是为什么它将在以后的其他课程中注入的原因。看看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
,但此处未出现)。此类必须作为单例注入。这里是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);
}
}
}
希望有帮助。