在实际业务中,当后台数据发生变化,客户端能够实时的收到通知,而不是由用户主动的进行页面刷新才能查看,这将是一个非常人性化的设计。比如数字化大屏,并没有人工的干预,而是自动的刷新数据,那如何才能实现数据的实时刷新呢?本文以一个简单示例,简述如何通过WPF+ASP.NET SignalR实现消息后台通知以及数据的实时刷新,仅供学习分享使用,如有不足之处,还请指正。

通过上一篇文章的学习,了解了如何通过SignalR实现在线聊天功能,在示例中,我们发现每一次的客户端连接都是一个新的实例对象,所以没有办法在中心对象中存储状态信息,所以为了存储用户列表,我们采用了静态变量的方式。并且在线聊天功能是用户发送一条消息(Chat),然后触发中心对象(ChatHub),转发给另一个用户(SendAsync)。那么如果实现数字化大屏,需要服务端持续的往客户端发送消息,而不是客户端主动触发,应该怎么做呢?这就是本文需要分享的内容。
涉及知识点
在本示例中,涉及知识点如下所示:
- 开发工具:Visual Studio 2022 目标框架:.NET6.0
- ASP.NET SignalR,一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信,目前新版已支持.NET6.0及以上版本。在本示例中,作为消息通知的服务端。
- WPF,是微软推出的基于Windows 的用户界面框架,主要用于开发客户端程序。
前提条件
实现服务端持续往客户端发送消息,除了业务上的需求外,还需要满足两个条件:
- 在服务端有一个常驻内存对象,监听数据变化。
- 常驻内存对象,可以访问中心对象(ChatHub),能够获取中心对象的所有连接客户端,并发送消息。
满足以上两个条件,才可以实现想要的功能。
服务端
经过以上分析后,服务端分为两方面,核心对象(ChatHub),处理业务对象(Worker)。下面我们逐一说明:
ChatHub 中心是用于向连接到 SignalR 服务器的客户端发送消息的核心抽象,负责客户端的连接和断开。如下所示:- 1 using Microsoft.AspNetCore.SignalR;
- 2
- 3 namespace SignalRChat.Chat
- 4 {
- 5 public class ChatHub:Hub
- 6 {
- 7 public override Task OnConnectedAsync()
- 8 {
- 9 Console.WriteLine($"ID:{Context.ConnectionId} 已连接");
- 10 return base.OnConnectedAsync();
- 11 }
- 12
- 13 public override Task OnDisconnectedAsync(Exception? exception)
- 14 {
- 15 Console.WriteLine($"ID:{Context.ConnectionId} 已断开");
- 16 return base.OnDisconnectedAsync(exception);
- 17 }
- 18 }
- 19 }
复制代码 Worker实例为一个单例对象,常驻内容,实时监听数据变化,并通过ChatHub上下文(IHubContext)获取连接信息,然后发送消息,如下所示:- 1 using Microsoft.AspNetCore.SignalR;
- 2
- 3 namespace SignalRChat.Chat
- 4 {
- 5 public class Worker
- 6 {
- 7 public static Worker Instance;
- 8
- 9 private static readonly object locker=new object();
- 10
- 11 private IHubContext<ChatHub> context;
- 12
- 13 private System.Timers.Timer timer;
- 14
- 15 public Worker(IHubContext<ChatHub> context) {
- 16 this.context = context;
- 17 timer= new System.Timers.Timer(500);//单位毫秒
- 18 timer.Enabled=true;
- 19 timer.AutoReset=true;//自动重新
- 20 timer.Elapsed += Timer_Elapsed;
- 21 timer.Start();
- 22 }
- 23
- 24 private void Timer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
- 25 {
- 26 //模拟数据,一般情况下,从数据库获取,然后通知到客户端
- 27 Dictionary<string, object> data = new Dictionary<string, object>();
- 28 var online = new Random().Next(0, 100);
- 29 var male = Math.Floor(new Random().NextSingle() * online);
- 30 var female = online - male;
- 31 data["online"]=online;
- 32 data["male"] =male;
- 33 data["female"] = female;
- 34 context.Clients.All.SendAsync("Data",data);
- 35 }
- 36
- 37 public static void Register(IHubContext<ChatHub> context)
- 38 {
- 39 if (Instance == null)
- 40 {
- 41 lock (locker)
- 42 {
- 43 if (Instance == null)
- 44 {
- 45 Instance = new Worker(context);
- 46 }
- 47 }
- 48 }
- 49 }
- 50 }
- 51 }
复制代码 注意:此处发送数据的是Data方法,客户端必须监听Data方法,才能接收数据。
如何创建单例对象呢,中心对象上下文不能自己创建,必须要和ChatHub通过注入方式的上下文是同一个,不然无法获取客户端连接信息。在项目启动时,通过中间件的方式创建,如下所示:- 1 using Microsoft.AspNetCore.SignalR;
- 2 using SignalRChat.Chat;
- 3
- 4 var builder = WebApplication.CreateBuilder(args);
- 5
- 6 // Add services to the container.
- 7
- 8 builder.Services.AddControllers();
- 9 // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
- 10 builder.Services.AddEndpointsApiExplorer();
- 11 builder.Services.AddSwaggerGen();
- 12 //1.添加SignalR服务
- 13 builder.Services.AddSignalR();
- 14 var app = builder.Build();
- 15
- 16 // Configure the HTTP request pipeline.
- 17 if (app.Environment.IsDevelopment())
- 18 {
- 19 app.UseSwagger();
- 20 app.UseSwaggerUI();
- 21 }
- 22 app.UseRouting();
- 23 app.UseHttpsRedirection();
- 24
- 25 app.UseAuthorization();
- 26 //在Use中注册单例实例
- 27 app.Use(async (context, next) =>
- 28 {
- 29 var hubContext = context.RequestServices
- 30 .GetRequiredService<IHubContext<ChatHub>>();
- 31 Worker.Register(hubContext);//调用静态方法注册
- 32
- 33 if (next != null)
- 34 {
- 35 await next.Invoke();
- 36 }
- 37 });
- 38 app.MapControllers();
- 39 //2.映射路由
- 40 app.UseEndpoints(endpoints => {
- 41 endpoints.MapHub<ChatHub>("/chat");
- 42 });
- 43
- 44 app.Run();
复制代码 客户端
客户端主要是连接服务器,然后监听服务端发送数据的方法即可,如下所示:注意:监听Data方法,和服务端发送时保持一致。
运行示例
在示例中,需要同时启动服务端和客户端,所以以多项目方式启动,如下所示:

运行成功后,服务端以ASP.NET Web API的方式呈现,如下所示:

客户端运行如下:

注意:客户端可以有多个,也可以是一个,后台通知消息,会通知到每一个连接的客户端。
源码下载
关注微信公众号,然后发送信息SignalR即可获取下载链接。如下所示:

备注
以上就是WPF+ASP.NET SignalR实现后台实时通知的全部内容,关于SignalR的应用,实际场景有很多,这只是一个简单的入门示例,希望可以抛砖引玉,一起学习,共同进步。学习编程,从关注【老码识途】开始!!!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |