在實際業務中,當后臺資料發生變化,客戶端能夠實時的收到通知,而不是由用戶主動的進行頁面重繪才能查看,這將是一個非常人性化的設計,比如數字化大屏,并沒有人工的干預,而是自動的重繪資料,那如何才能實作資料的實時重繪呢?本文以一個簡單示例,簡述如何通過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<ChatHub>)獲取連接資訊,然后發送訊息,如下所示:
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 = https://www.cnblogs.com/hsiang/archive/2022/09/14/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();
客戶端
客戶端主要是連接服務器,然后監聽服務端發送資料的方法即可,如下所示:
1 namespace SignalRClient 2 { 3 public class ShowDataViewModel : ObservableObject 4 { 5 #region 屬性及建構式 6 7 private int online; 8 9 public int Online 10 { 11 get { return online; } 12 set { SetProperty(ref online, value); } 13 } 14 15 private int male; 16 17 public int Male 18 { 19 get { return male; } 20 set { SetProperty(ref male, value); } 21 } 22 23 24 private int female; 25 26 public int Female 27 { 28 get { return female; } 29 set { SetProperty(ref female, value); } 30 } 31 32 private HubConnection hubConnection; 33 34 public ShowDataViewModel() 35 { 36 37 } 38 39 #endregion 40 41 #region 命令 42 43 private ICommand loadedCommand; 44 45 public ICommand LoadedCommand 46 { 47 get 48 { 49 if (loadedCommand == null) 50 { 51 loadedCommand = new RelayCommand<object>(Loaded); 52 } 53 return loadedCommand; 54 } 55 } 56 57 private void Loaded(object obj) 58 { 59 //1.初始化 60 InitInfo(); 61 //2.監聽 62 Listen(); 63 //3.連接 64 Link(); 65 } 66 67 #endregion 68 69 /// <summary> 70 /// 初始化Connection物件 71 /// </summary> 72 private void InitInfo() 73 { 74 hubConnection = new HubConnectionBuilder().WithUrl("https://localhost:7149/chat").WithAutomaticReconnect().Build(); 75 hubConnection.KeepAliveInterval = TimeSpan.FromSeconds(5); 76 } 77 78 /// <summary> 79 /// 監聽 80 /// </summary> 81 private void Listen() 82 { 83 hubConnection.On<Dictionary<string,object>>("Data", ReceiveInfos); 84 } 85 86 /// <summary> 87 /// 連接 88 /// </summary> 89 private async void Link() 90 { 91 try 92 { 93 await hubConnection.StartAsync(); 94 } 95 catch (Exception ex) 96 { 97 MessageBox.Show(ex.Message); 98 } 99 } 100 101 private void ReceiveInfos(Dictionary<string, object> data) 102 { 103 if (data =https://www.cnblogs.com/hsiang/archive/2022/09/14/= null || data.Count < 1) 104 { 105 return; 106 } 107 int.TryParse(data["online"]?.ToString(),out int online); 108 int.TryParse(data["male"]?.ToString(),out int male); 109 int.TryParse(data["female"]?.ToString(),out int female); 110 this.Online=online; 111 this.Male = male; 112 this.Female=female; 113 } 114 } 115 }
注意:監聽Data方法,和服務端發送時保持一致,
運行示例
在示例中,需要同時啟動服務端和客戶端,所以以多專案方式啟動,如下所示:

運行成功后,服務端以ASP.NET Web API的方式呈現,如下所示:

客戶端運行如下:
注意:客戶端可以有多個,也可以是一個,后臺通知訊息,會通知到每一個連接的客戶端,
原始碼下載
關注微信公眾號,然后發送資訊SignalR即可獲取下載鏈接,如下所示:

備注
以上就是WPF+ASP.NET SignalR實作后臺實時通知的全部內容,關于SignalR的應用,實際場景有很多,這只是一個簡單的入門示例,希望可以拋磚引玉,一起學習,共同進步,學習編程,從關注【老碼識途】開始!!!
作者:小六公子
出處:http://www.cnblogs.com/hsiang/
本文著作權歸作者和博客園共有,寫文不易,支持原創,歡迎轉載【點贊】,轉載請保留此段宣告,且在文章頁面明顯位置給出原文連接,謝謝,
關注個人公眾號,定時同步更新技術及職場文章
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/507087.html
標籤:.NET技术
上一篇:【Shashlik.EventBus】.NET 事件總線,分布式事務最終一致性
下一篇:限制JavaScript運行X次
