標題起得有點厲害,漢字夾雜着E文,不符合教育部公佈的「向社會推薦使用的外語詞中文譯名」規範。不過他管不着我。寫本篇的原由,是重構一個現有的WinForms程序,將Server端的部分邏輯從raw socket通信的方式,改成調用WebAPI。重構則是由於原先代碼有嚴重的性能問題,而組裏並無可以寫好socket通信的同窗。javascript
WebAPI的編寫相對就簡單多了,但原先從Server端push消息到Client的功能就須要找到替代的解決方案。因此有了本篇對於SignalR的介紹。html
「ASP.NET Core SignalR 是一個開源代碼庫,它簡化了嚮應用添加實時 Web 功能的過程。 實時 Web 功能使服務器端代碼可以即時將內容推送到客戶端。」看不懂不能怪我,MSDN上的原話。簡單能夠理解爲SignalR是一個基於WebSocket的庫,可以幫助咱們避免直接使用socket,而寫出一些性能誇張的代碼……java
SignalR的基本push流程是這樣的,首先Server端有一個Hub類,Hub類中會定義一個方法,該方法會在某個時機被觸發,而在該方法內部,會有一個Clients.All.SendAsync之類的操做。而後經過該SendAsync方法,來將消息內容傳遞給事先定義好的Client端的方法。git
public class TestCaseHub : Hub { public async Task SayHello() { await Clients.All.SendAsync("AreYouOK"); } }
上述代碼中(TestSignalRServer工程的Hubs\TestCaseHub.cs),TestCaseHub中的SayHello方法執行時,會調用client端的AreYouOK方法。爲了簡單起見,這個方法沒有參數。github
SignalR客戶端的結構也很簡單,打開TestSignalRClient工程的program.cs文件,僅有的Main方法以下:api
static void Main(string[] args) { HubConnection connection = new HubConnectionBuilder().WithUrl("https://localhost:44306/TestCaseHub").Build(); connection.On("AreYouOK", () => { Console.WriteLine("Fine, thank you. And you?"); }); connection.StartAsync(); Console.WriteLine("Start connect"); Console.ReadKey(); }
首先經過Hub的url build出HubConnection對象。再經過HubConnection的On方法,向Server端註冊AreYouOK方法。這個方法會在Server端經過SendAsync來被調用。服務器
可能有新同窗會問Hub的url是什麼,這是由於SignalR是基於ASP.Net Core工程的,因此TestSignalRServer工程實際是一個Visual Studio裏建立的Web Application,咱們打開Startup類,能夠看到註冊了SignalR的service和TestCaseHub類的route映射。(TestSignalRServer的代碼是.NET Core 2.2的,後面咱們還會建立.NET Core 3.1的,經過WebApi調用觸發的SignalR通知,代碼會有細微的差異)app
public void ConfigureServices(IServiceCollection services) { services.AddSignalR(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseFileServer(); app.UseSignalR(routes => { routes.MapHub<TestCaseHub>("/testcasehub"); }); }
在TestSignalRServer這個Web Application中,最終是經過html頁面上的button,執行javascript來觸發SayHello方法,最終將通知發送到Console Client。而咱們實際的需求,是須要一個WebApi來觸發SignalR通知。還記得開頭提到的WinForms程序嗎?由WinForms程序調用WebApi,傳遞要push給Console Client的參數,再經過包含SignalR Hub的WebApi完成push。框架
首先咱們建立一個空的ASP.NET Core Web Application。模板類型選擇API。socket
默認的API模板會包含一個WeatherForecastController,此時按下F5運行,能夠測試下環境是否配置正確。
接下來咱們建立NotificationHub。啥也不用寫,空的就好了。
public class NotificationHub: Hub { }
而後照着WeatherForecastController抄襲一個NotificationController。NotificatoinHub空着的緣由在於咱們將SendAsync寫在這裏了。具體能夠參考「Send messages from outside a hub」。ASP.NET Core能夠經過自帶的依賴注入框架,在Controller裏獲取IHubContext對象。
[Route("api/[controller]")] [ApiController] public class NotificationController : ControllerBase { private readonly IHubContext<NotificationHub> _hubContext; public NotificationController(IHubContext<NotificationHub> hubContext) { _hubContext = hubContext; } [HttpGet] public async Task<IActionResult> Notify() { await _hubContext.Clients.All.SendAsync("Notify", $"It's time: {DateTime.Now}"); return Ok(); } }
在Startup裏添加上對SignalR的service使用和endpoint設置,Server端的編寫就結束了。
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddSignalR(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); endpoints.MapHub<NotificationHub>("/notificationHub"); }); }
Client的代碼和以前.NET Core 2.2的例子基本沒有區別,惟一不一樣此次帶了一個string參數。強類型的參數SignalR也是支持的,會自動完成序列化和反序列化的操做。
var connection = new HubConnectionBuilder() .WithUrl("https://localhost:44354/NotificationHub") .Build(); await connection.StartAsync(); connection.On<string>("Notify", (a) => { Console.WriteLine($"Notify: {a}"); });
若是發現找不到HubConnectionBuilder,記得去NuGet安裝Microsoft.AspNetCore.SignalR.Client。
將包含NotificationConroller的Web Applicatin和Console Client分別啓動後。咱們只須要訪問https://localhost:xxxx/api/notification這個地址,便可觸發SignalR通知。從下圖看這是一個簡單的報時通知。
本篇介紹瞭如何建立ASP.NET Core的WebApi,實現從Server端push消息到Client。同時將觸發通知的操做放到WebApi的Controller裏,從而避免了html和javascript的編寫,緩解了傳統桌面開發人員的不適,延長了部分壽命。
Sample工程:
SignalRTest基於.NET Core 2.2,在抄襲了官方sample的基礎上,實現點擊html頁面的button推送小文件給Client的功能。
https://github.com/manupstairs/SignalRTest
SignalRTest1一看名字就很隨性,基於.NET Core 3.1,寫成WebApi的形式,做爲專門的Notification Service。