一、介紹
SignalR 是一個用於實現實時網站的 Microsoft .NET 庫。它使用多種技術來實現服務器與客戶端間的雙向通信,服務器可以隨時將消息推送到連接的客戶端。
二、新建Core MVC項目並安裝
三、添加 SignalR 客戶端庫
在“解決方案資源管理器” 中,右鍵單擊項目,然后選擇“添加” >“客戶端庫”
在“添加客戶端庫” 對話框中,對於“提供程序” ,選擇“unpkg” 。
對於“庫” ,輸入 @aspnet/signalr@1
,然后選擇不是預覽版的最新版本。
選擇“選擇特定文件” ,展開“dist/browser” 文件夾,然后選擇“signalr.js” 和“signalr.min.js” 。
將“目標位置” 設置為 wwwroot/lib/signalr/ ,然后選擇“安裝” 。
四、創建 SignalR 中心即操作中心。
Hub 消息處理中心
public class TestHub : Hub { public TestHub() { } public async Task SendMessage(string message, string name) { #region Client //this.Context.ConnectionId //每個連接一個connectionId 表示唯一客戶端 //this.Clients.Client().SendAsync(); //指定發送消息 //this.Clients.Clients() #endregion //給多個client發消息 #region Group //this.Clients.Group(); //給某個組發消息 //this.Clients.Groups() //給多個組發消息 //this.Groups.AddToGroupAsync() //將指定連接加入組 //this.Groups.RemoveFromGroupAsync() //將指定連接移除組 #endregion await Clients.All.SendAsync("onMsg", DateTime.Now, message); } //上下線消息 連接、斷開事件 //客戶端連接上 public override Task OnConnectedAsync() { return base.OnConnectedAsync(); } //客戶端斷開 public override Task OnDisconnectedAsync(Exception exception) { string connectionId = this.Context.ConnectionId; return base.OnDisconnectedAsync(exception); } }
以上可以看到SignalR
封裝了很多常用方法(發送指定消息、群發...)
,我們可以很簡單的使用達到目的
創建 Hubs 文件夾 。
在 Hubs 文件夾中,使用以下代碼創建 ChatHub.cs 文件 :
using Microsoft.AspNetCore.SignalR; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; namespace Ban.Hubs { public class ChatHub:Hub { /// <summary> /// /服務端方法 發送消息--發送給所有連接的客戶端 /// </summary> /// <param name="user"></param> /// <param name="message"></param> /// <returns></returns> public async Task SendMessage(string user,string message) { //ReceiveMessage 為客戶端方法,讓所有客戶端調用這個方法 await Clients.All.SendAsync("ReceiveMessage",user,message); } /// <summary> /// 客戶端連接的時候調用 /// </summary> /// <returns></returns> public override Task OnConnectedAsync() { Trace.WriteLine("客戶端連接成功"); return base.OnConnectedAsync(); }//所有鏈接的客戶端都會在這里 /// <summary> /// 連接終止時調用。 /// </summary> /// <returns></returns> public override Task OnDisconnectedAsync(Exception exception) { Trace.WriteLine("連接終止"); return base.OnDisconnectedAsync(exception); } } }
六、配置 SignalR
必須配置 SignalR 服務器,以將 SignalR 請求傳遞到 SignalR。
startup
中ConfigureServices
方法內部添加SignalR
服務services.AddSignalR();
,Configure
中配置具體的Hub
(路由器、中轉):
app.UseSignalR(routes => { routes.MapHub<TestHub>("/testHub"); //可以多個map }); app.UseMvc(); //注意UseSignalR需要在UseMvc()之前
這樣SignalR
服務器端就開發完成了,網頁、Java、.Net客戶端都可以連接的
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using test.Hubs; //3、引用 處理客戶端 - 服務器通信的高級管道 namespace test { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.Configure<CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.AddSignalR();//1、添加服務 } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseCookiePolicy(); app.UseSignalR(routes => //2、引用 { routes.MapHub<ChatHub>("/chatHub"); }); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); } } }
七、添加 SignalR 客戶端代碼(創建index控制器和視圖)
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> </head> <body> <div class="container"> <div class="row"> </div> <div class="row"> <div class="col-6"> </div> <div class="col-6"> User..........<input type="text" id="userInput" /> <br /> Message...<input type="text" id="messageInput" /> <input type="button" id="sendButton" value="Send Message" /> </div> </div> <div class="row"> <div class="col-12"> <hr /> </div> </div> <div class="row"> <div class="col-6"> </div> <div class="col-6"> <ul id="messagesList"></ul> </div> </div> </div> <script src="~/lib/signalr/dist/browser/signalr.js"></script> <script type="text/javascript"> "use strict"; var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build(); //在建立連接之前禁用發送按鈕 document.getElementById("sendButton").disabled = true; //接受消息 connection.on("ReceiveMessage", function (user, message) { var msg = message.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); var encodedMsg = user + " says " + msg; var li = document.createElement("li"); li.textContent = encodedMsg; document.getElementById("messagesList").appendChild(li); }); //開始鏈接 connection.start().then(function () { document.getElementById("sendButton").disabled = false; }).catch(function (err) { return console.error(err.toString()); }); //發送消息 document.getElementById("sendButton").addEventListener("click", function (event) { var user = document.getElementById("userInput").value; var message = document.getElementById("messageInput").value; connection.invoke("SendMessage", user, message).catch(function (err) { return console.error(err.toString()); }); event.preventDefault(); }); </script> </body> </html>
Controller中調用SignalR服務
在構造函數注入IHubContext<>
就可以直接使用了,非常方便:
private readonly IHubContext<TestHub> _hubContext; public HomeController(IHubContext<TestHub> hubContext) { _hubContext = hubContext; } public async Task<IActionResult> Notify() { //拿不到當前Hub的clientId 線程是唯一的 await _hubContext.Clients.All.SendAsync("onMsg", "from controller msg"); return Ok(); }