在以前的 Asp.NETCore 輕鬆學系列中,曾經介紹過一個輕量級服務主機 IHostedService ,利用 IHostedService 能夠輕鬆的實現一個系統級別的後臺服務,該服務跟隨系統啓動和中止;同時,其使用異步加載和兼容注入的特性,能夠很好的實現業務的擴展和隔離。javascript
IHostedService 有一個默認的實現基類 Microsoft.Extensions.Hosting.BackgroundService,咱們僅須要繼承 BackgroundService 便可實現後臺主機。html
本文主要目的在於實現一個後臺心跳廣播包,全部鏈接到 SignalR 的客戶端,經過訂閱心跳包廣播頻道,可以自動收到服務器發送的心跳廣播java
public interface IHeartbeat { Task HeartbeatAsync(int data); }
上面定義 了一個接口 IHeartbeat,該接口有一個異步的方法 HeartbeatAsync,主要就是心跳的定義,先無論它怎麼使用,咱們繼續往下git
public class WeChatHub : Hub<IHeartbeat> { public void Send(ChatMessage body) { Clients.All.RecvAsync(body); } public override Task OnConnectedAsync() { Console.WriteLine("遊客[{0}]進入了聊天室", this.Context.ConnectionId); return base.OnConnectedAsync(); } public override Task OnDisconnectedAsync(Exception exception) { Console.WriteLine("遊客[{0}]離開了聊天室", this.Context.ConnectionId); return base.OnDisconnectedAsync(exception); } }
上面定義了一個SignalR通訊管理對象 WeChatHub ,其繼承字泛型的 Hub
上面的這段話比較繞口,其實我也以爲不太好理解,簡單來講就是客戶端要偵聽一個和 SignalR 服務端定義的相同的頻道,才能夠收到廣播。服務器
在定義好 SignalR 的通訊協議後,接下來要作的就是實現一個後臺服務主機,也就是 IHostedService 的實現。根據 Asp.Net Core 輕鬆學-基於微服務的後臺任務調度管理器 中的提示,咱們不須要實現這個接口,只須要繼承 Microsoft.Extensions.Hosting.BackgroundService 便可app
public class WeChatHubWorker : BackgroundService { private readonly IHubContext<WeChatHub, IHeartbeat> heartbeat; public WeChatHubWorker(IHubContext<WeChatHub, IHeartbeat> heartbeat) { this.heartbeat = heartbeat; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { await this.heartbeat.Clients.All.HeartbeatAsync(0); await Task.Delay(3000); Console.WriteLine("heartbeat"); } } }
上面的代碼比較簡單,首先定義了 IHubContext<WeChatHub, IHeartbeat> 對象 heartbeat,而後在構造函數中經過注入的方式將其實例化,緊接着在 ExecuteAsync(CancellationToken stoppingToken) 方法中,執行了一個無限循環的操做,每 3000 毫秒給全部 SignalR 客戶端發送一個內容爲 0 的心跳包。異步
實現了後臺主機後,須要將其注入到 Asp.NETCore 的管道中async
// 添加服務主機隨主機啓動 public void ConfigureServices(IServiceCollection services) { services.AddSignalR(); services.AddHostedService<WeChatHubWorker>(); ... } // 配置 SignalR 偵聽的 Uri 地址 public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseSignalR(routes => { routes.MapHub<WeChatHub>("/wechatHub"); }); ... }
經過服務注入,咱們就完成了服務端的實現,下面看看 JavaScript 的實現。ide
var connection = new signalR.HubConnectionBuilder() .withUrl("/wechatHub") .build(); connection.on("RecvAsync", function (data) { var li = document.createElement("li"); li = $(li).text(data.userName + ":" + data.content); $("#msgList").append(li); }); connection.on("HeartbeatAsync", (data) => { console.log(data); }); connection.start() .then(function () { console.log("客戶端已鏈接"); }).catch(function (err) { console.log(err); });
上面的代碼,若是有看過前兩章的同窗,應該是很是熟悉的,這裏就很少解釋了;可是,因爲本次 SignalR 服務端的 Hub 實現不太同樣,因此,這裏仍是要解釋一下。
上面的代碼分別偵聽了兩個通道 connection.on("RecvAsync",...) 和 connection.on("HeartbeatAsync",...) ,這兩個通道對應服務端的 IHeartbeat 的定義的成員名稱,而後在 Callback 中的參數,也須要和 IHeartbeat 定義的同樣,保證能夠完整接收服務端推送的消息。
紅圈處就是心跳廣播的內容:0。
紅圈處就是聊天消息。
若是須要開通多個通道的話怎麼辦呢,聰明的你必定想到了,就是增長 IHeartbeat 的定義,而後在客戶端訂閱該頻道便可。
https://github.com/lianggx/Examples/tree/master/SignalR/Ron.SignalRLesson3