SignalR是為了提供更方便的web交互響應式到推送式的解決方案。有了它之後可以實現客戶端直接調用服務端的方法並且獲得返回值 (客戶端可以是各種平臺,目前SignalR支持的語言版本有C#、java、javaScript、nodejs等),服務端也是可以調用客戶端的方法,通過這樣的方式實現了由原來 ...
SignalR是為了提供更方便的web交互響應式到推送式的解決方案。有了它之後可以實現客戶端直接調用服務端的方法並且獲得返回值 (客戶端可以是各種平臺,目前SignalR支持的語言版本有C#、java、javaScript、nodejs等),服務端也是可以調用客戶端的方法,通過這樣的方式實現了由原來的單通變成雙通的目的。
在SignalR中有個非常重要的概念就是Hub,這個Hub如果拿到以前的MVC架構中所對應的就是控制器,他們的區別就是我們需要自己去註冊這個Hub的路由,而控制器是可以基於約定的。
首先創建一個Hub
public class NewsPushHub:Hub { }
這是一個新聞推送的Hub,它必須要繼承至Hub這個基類,Hub這個基類還可以接收一個泛型的實現,這個泛型可以用來規範客戶端的方法
public class NewsPushHub : Hub<IClientFuncs> { /// <summary> /// 可以被客戶端調用的方法 /// </summary> /// <param name="msg"></param> /// <returns></returns> public async Task DepartmentNotice(string msg) { //這裡發送只能是介面中約束的方法 await Clients.All.SendMsg( msg); } } /// <summary> /// 定義客戶端所監聽的方法名稱 /// </summary> public interface IClientFuncs { Task SendMsg(string msg); }
這裡面寫的兩個方法是可以被客戶端直接調用的,但是在被調用之前首先要註冊,在Core3.0之前 我們是用app.UseSignalR(hub=>hub.MapHub<NewsPushHub>("/SignalRNews"))來註冊SignalR的訪問路由,現在改成全部統一在app.UseEndpoints()這個擴展方法中去註冊,現在在Startup類的代碼就像這樣了
public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddSignalR(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapHub<NewsPushHub>("/SignalRNews"); endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}"); }); }
在這個裡面我配置了包含MVC的中間件和依賴註入,在3.0中MVC的中間件和依賴註入都變了 變得更加具體,路由設置也變得統一在UseEndpoints()這個方法裡面,它裡面的委托是一個IEndpointRouteBuilder的參數,我們通過這個參數可以映射各種路由配置,有非常多的map,在這裡配置MVC的目的是為了和SignalR交互的。下麵是客戶端的js代碼首先需要安裝aspnet-signalr
//創建一個匹配 http:localhost:5000/SignalRNews路由的連接 const connection = new signalR.HubConnectionBuilder() .withUrl("/SignalRNews") .configureLogging(signalR.LogLevel.Information) .build(); // 開始連接,這個時候會發送一個101狀態為pending的連接 connection.start().then(function () { console.log("connected"); }); // 監聽服務端調用的客戶端方法 connection.on("sendMsg", (msg) => { $(".dispaly-message").append(`<p>${msg}</p>`); }); $("#submit").click(e => { const msg = $("#msg").val(); // 調用服務端的DepartmentNotice方法 connection.invoke("DepartmentNotice", msg).then(() => { console.log("消息發送完成"); }); })
上面是最終的結果 可以看出實現了不同客戶端之間的消息互通
其實Signalr還可以有依賴註入的用法例如在控制器裡面註入 然後直接在MVC中隨意推送消息
public class HomeController:Controller { private readonly IHubContext<NewsPushHub> _hub; public HomeController(IHubContext<NewsPushHub> hub) { this._hub = hub; } public IActionResult Index() { _hub.Clients.All.SendAsync("Temp", "test"); return View(); } }
從上面代碼中看的出在Home控制器中註入了NewsPushHub這個Hub 只要有一個客戶端訪問Index界面就會通知所有的客戶端
總結:SignalR把原來複雜低效率的雙通編程變得簡單,Siganlr只要是支持3中模式進行客戶端和服務端的連接(1、長輪詢模式 2、伺服器發送事件 3、websocket)最高效的當然是websocket 但是某一些瀏覽器是不支持的;