ASP.NET Core 2.2 基礎知識(十六) SignalR (未完待續)
阿新 • • 發佈:2019-01-08
我一直覺得學習的最好方法就是先讓程式能夠正常執行,才去學習他的原理,剖析他的細節.
就好像這個圖:
所以,我們先跟著官方文件,建立一個 SignalR 應用: https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/signalr?view=aspnetcore-2.2&tabs=visual-studio
這個例子一共涉及到下面幾個步驟:
- 自定義中心 ChatHub ;
- 在啟動類 Startup 中啟用 SignalR 服務,並新增路由;
- 編寫客戶端JS
- 下載 SignalR 官方JS.
自定義中心 : ChatHub
public class ChatHub : Hub { public async Task SendMessage(string user, string message) { await Clients.All.SendAsync("ReceiveMessage", user, message); } }
"Hub" 一詞,有的地方翻譯成"集線器",有的地方翻譯成"中心",對於我這種非科班出身的人來說,還是"中心"聽起簡單點.
對於基類 Hub ,xml 是這樣說的 : A base class for a SignalR hub. SignalR 中心的基類.
這個很簡單,看這些名字就知道他們是幹嘛用的,具體的描述可以看官方文件.
中心的作用可以這樣簡單的描述:
通過中心,我們能在伺服器的程式碼中定義客戶端可以呼叫的方法(必須是 public);
通過中心,我們能在客戶端的程式碼中定義伺服器可以呼叫的方法.
上述程式碼,我們通過繼承 Hub ,定義了一個自己的中心 : ChatHub (聊天中心) ,在這個類裡面,我們做了下面兩件事:
- 定義了客戶端可以呼叫的方法 : SendMessage(string user, string message)
- 呼叫了所有連線上 Hub 的客戶端的 ReceiveMessage 方法,並將 user,message 兩個字串作為入參傳入該方法.
中心定義好了,肯定需要啟用
在啟動類 Startup 中啟用 SignalR 服務,並新增路由
public void ConfigureServices(IServiceCollection services) { ...... //註冊 SignalR 服務 services.AddSignalR(); }
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { ...... //設定 SignalR 中心路由 app.UseSignalR(routes => { routes.MapHub<ChatHub>("/chatHub"); }); app.UseMvc(); }
編寫客戶端JS
"use strict";//不太明白這句話是什麼意思... //建立一個連線到我們建立的 ChatHub 的 connection. var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build(); //定義客戶端的方法,方法名: ReceiveMessage ,兩個入參. //注意,這個方法就是伺服器要呼叫的方法,伺服器和客戶端的名字一定要一樣. 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().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; //呼叫伺服器的 SendMessage 方法,並傳入兩個入參.這和委託的呼叫太像了. connection.invoke("SendMessage", user, message).catch(function (err) { return console.error(err.toString()); }); event.preventDefault(); });
上面的 ChatHub 類的 SendAsync 方法在呼叫客戶端的方法時,方法名是直接寫的 字串 : "ReceiveMessage"
官方不推薦這樣寫,因為不是強型別,可能出現執行時錯誤,因此建議使用強型別的中心
(順帶附上了一些額外的功能):
//建議使用下面的強型別方式 //方法二 public interface IChatClient { //就算是這種強型別方式,客戶端定義的方法名也必須和這個方法名一樣,包括簽名. Task ReceiveMessage(string user, string message); } public class StronglyTypedChatHub : Hub<IChatClient> { //[HubMethodName("hello")] 可以改名,如果改了名,前端也要跟著改,別忘了. public async Task SendMessage(string user, string message) { //呼叫客戶端定義的 ReceiveMessage 方法. //throw new HubException("哈哈,出錯了!");//可以向客戶端傳送異常.只會向當前呼叫的客戶端傳送,並且只發送 message ,不會發送堆疊資訊. await Clients.All.ReceiveMessage($"{GetHashCode()}" + user, message);//傳遞 hashCode 是為了證明,每次呼叫都是不同的例項.所以官方說不要在"中心"裡面存狀態. } //該方法可以在客戶端連線上後,執行操作 public override async Task OnConnectedAsync() { await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users"); await base.OnConnectedAsync(); } //同理,當客戶端斷開連線時執行的操作 public override async Task OnDisconnectedAsync(Exception exception) { await Groups.RemoveFromGroupAsync(Context.ConnectionId, "SignalR Users"); await base.OnDisconnectedAsync(exception); } }
當然,註冊路由的程式碼也得換了 : app.UseSignalR(routes => { routes.MapHub<StronglyTypedChatHub>("/chatHub"); });
好睏,明天繼續