当服务端进行数据处理时(数据可能来源于非人工操作,比如各种控制器和信号源),需要将处理结果推送给客户端,进行实时数据显示。
在上一篇文章中我们创建过服务端,代码吗如下
using Microsoft.AspNetCore.SignalR;
namespace Demo_WarningMonitor.Api.SignalRHubs
{
///
/// 报警广播
///
public class WarningBroadcastHub : Hub
{
private ILogger logger;
public WarningBroadcastHub(ILogger logger, IConfiguration configuration)
{
this.logger = logger;
}
public async Task SendMessage(string user, string message)
{
try
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
catch (Exception ex)
{
logger.LogError(ex,"发送消息出现异常");
}
}
}
}
我想这直接在数据处理服务中i性能调用SendMessage方法就能实现发送消息了,
但是事与愿违,因为这里涉及到一个对象声明周期的问题,在调用Clients.All的时候会提示调用了一个已经释放的资源对象,具体错误如下:System.ObjectDisposedException:"Cannot access a disposed object.
https://learn.microsoft.com/zh-cn/aspnet/core/signalr/hubcontext?view=aspnetcore-6.0
我这里使用了MessageBus的一个中间件,这样就实现了解耦,Messagebus的nuget包
using Demo_WarningMonitor.Api.Models;
using iml6yu.MessageBus;
using iml6yu.MessageBus.Constand;
using Microsoft.AspNetCore.SignalR;
namespace Demo_WarningMonitor.Api.SignalRHubs
{
public class WarningBroadcast
{
private ISubscriber warningSubscriber;
private ISubscriber realtimeDataSubscriber;
private IConfiguration configuration;
private string warningChannel;
private ILogger logger;
private IHubContext hubContext;//
public WarningBroadcast(IConfiguration configuration, IHubContext context, ILogger logger)//
{
hubContext = context;
this.logger = logger;
this.configuration = configuration;
warningChannel = configuration.GetSection("WarningChannel").Get();
warningSubscriber = MessageBuses.Subscrib(warningChannel);
warningSubscriber.OnNoticed += Subscriber_OnNoticed;
realtimeDataSubscriber = MessageBuses.Subscrib(configuration.GetSection("RealtimeDataChannel").Get());
realtimeDataSubscriber.OnNoticed += RealtimeDataSubscriber_OnNoticed;
}
private async void RealtimeDataSubscriber_OnNoticed(MessageChannel channel, MessageBusArges message)
{
try
{
await hubContext.Clients.All.SendAsync("ReceiveMessage", "HubServiceCenter", message.Data);
}
catch (Exception ex)
{
logger.LogError(ex, "WarningBroadcast发送消息出现异常");
}
}
///
/// 接收到消息的通知后进行分发处理
///
///
///
///
private async void Subscriber_OnNoticed(MessageChannel channel, MessageBusArges message)
{
try
{
Console.ForegroundColor = ConsoleColor.Red;
var msg = System.Text.Json.JsonSerializer.Serialize(message.Data);
await hubContext.Clients.All.SendAsync("WarningMessage", "HubServiceCenter", msg);
Console.WriteLine("发送一次报警信息\r\n" + msg);
Console.ForegroundColor = ConsoleColor.White;
}
catch (Exception ex)
{
logger.LogError(ex, "WarningBroadcast发送消息出现异常");
}
}
}
}
这里的重点就是构造函数
这里涉及到如何获取IHubContext
实例,可以查看文章
https://learn.microsoft.com/zh-cn/aspnet/core/signalr/hubcontext?view=aspnetcore-6.0
var hubContext = app.Services.GetService>();
if (hubContext != null)
{
new WarningBroadcast(app.Services.GetService(), hubContext,app.Services.GetService>());
}
对此我新建了一个扩展类,完整代码如下
using Microsoft.AspNetCore.SignalR;
namespace Demo_WarningMonitor.Api.SignalRHubs
{
///
/// 扩展类
///
public static class WarningBroadcastExt
{
public static WebApplication UseWarningBroadcast(this WebApplication app)
{
var hubContext = app.Services.GetService>();
if (hubContext != null)
{
new WarningBroadcast(app.Services.GetService(), hubContext,app.Services.GetService>());
}
return app;
}
}
}
在main函数中使用
app.UseWarningBroadcast();
在需要发送给客户端消息的时候使用
MessageBuses.Publish 推送一个消息,订阅者直接收到消息后就会调用await hubContext.Clients.All.SendAsync(“WarningMessage”, “HubServiceCenter”, msg); 给客户端发送消息了
MessageBuses.Publish(new MyClass1());
ISubscriber subscriber;
subscriber = MessageBuses.Subscrib("newWin");
subscriber.OnNoticed += (channel,e)=>{
Debug.WriteLine(e.Data.ToString())
};