.Net Core SignalR 初體驗
前言
Asp.Net SignalR已經出來很久了,但是一直沒有靜下心來好好看看。昨天花了幾個小時的時間看了下。首先借鑑了官方文件,如何搭建一個SignalR的Demo。
所以為了快速搭建和體驗.Net Core版本的SignalR,我選擇了下載官方的Demo和參考官方給的教程。所以具體的搭建過程我就不再本文中寫了。
體驗效果
官網給出的DEMO執行如下圖:
點選connect,檢視一下network。可以發現,它在當前瀏覽器支援三種方式。
而且和.NET Framework版本不同的是,新版SignalR中的Hub型別也是蠻豐富的。Demo中給出了 普通Hub,DynamicHub,Hub<T> 三種類型。我們去看看其中的區別吧。
普通Hub
檢視定義,可以看到普通Hub中的Clients型別是 IHubCallerClients
namespace Microsoft.AspNetCore.SignalR { // // 摘要: // A base class for a SignalR hub. public abstract class Hub : IDisposable { protected Hub(); // // 摘要: // Gets or sets an object that can be used to invoke methods on the clients connected // to this hub. public IHubCallerClients Clients { get; set; } // // 摘要: // Gets or sets the hub caller context. public HubCallerContext Context { get; set; } // // 摘要: // Gets or sets the group manager. public IGroupManager Groups { get; set; } // public void Dispose(); // // 摘要: // Called when a new connection is established with the hub. // // 返回結果: // A System.Threading.Tasks.Task that represents the asynchronous connect. public virtual Task OnConnectedAsync(); // // 摘要: // Called when a connection with the hub is terminated. // // 返回結果: // A System.Threading.Tasks.Task that represents the asynchronous disconnect. public virtual Task OnDisconnectedAsync(Exception exception); // // 摘要: // Releases all resources currently used by this Microsoft.AspNetCore.SignalR.Hub // instance. // // 引數: // disposing: // true if this method is being invoked by the Microsoft.AspNetCore.SignalR.Hub.Dispose // method, otherwise false. protected virtual void Dispose(bool disposing); } }
IHubCallerClients 定義如下:
public interface IHubCallerClients : IHubCallerClients<IClientProxy>, IHubClients<IClientProxy> { }
而框架又給IClientProxy增加了擴充套件方法:SendAsync
所以在普通Hub中,定義客戶端方法的時候,需要把方法名當作引數傳入SendAsync方法中。例如如下程式碼:
public Task Send(string message) { return Clients.All.SendAsync("Receive", $"{Context.ConnectionId}: {message}"); }
DynamicHub
DynamicHub我是比較喜歡的,因為他和 Framework版的是一樣(或者說看起來是一樣的)的。動態Hub我們就可以不必拘泥於只能呼叫SendAsync方法了。例如:
public Task SendToOthers(string message) { return Clients.Others.ThisIsMyReceiveMethod($"{Context.ConnectionId}: {message}"); }
DynamicHub的Clients型別為:DynamicHubClients ,它的內部變數全都是dynamic型別的。
Hub<T>
泛型Hub就把規約交給開發者制定。在Demo中 Hub<IChatClient> 中的IChatClient介面定義了Receive方法,因此Clients中的物件可以呼叫Receive方法。同理,我們可以根據業務需要定義自己的方法。至少從程式碼上看會顯得更加通俗易懂一些。比如:
public interface IChatClient { Task Receive(string message); Task LoginSuccess(long userId); }
public Task Login(long userId) { return Clients.Caller.LoginSuccess(userId); }
其實從程式碼上來看的話,他們都是Hub,只不過是不同的擴充套件實現而已。而泛型Hub不過是使用者自定義泛型介面,而預設Hub中的預設泛型介面為:IClientProxy.所以看到這裡,如果我就想使用原生的Hub而又想自定義方法怎麼辦呢?很簡單,加擴充套件就可以了。
為什麼自己加就可以呢,其實 SendAsync 就是擴充套件方法,它內部也是呼叫了SendCoreAsync方法。於是乎,寫下自己的擴充套件方法,那這樣子就很靈活了。我們把method引數去掉,直接寫死試試:
public static Task LoginAsync(this IClientProxy clientProxy, string message, CancellationToken cancellationToken = default(CancellationToken)) { return clientProxy.SendCoreAsync("LoginSuccess", new object[] { message}, cancellationToken); }
其實說白了,這個擴充套件方法還是需要傳入method引數的,只不過封裝了一層(似乎感覺這麼做有意義嗎?哈哈,還是老老實實用泛型吧),那麼我們在去看Hub中的方法,修改Send方法如下:
public Task Send(string message) { return Clients.All.LoginAsync($"{Context.ConnectionId}: {message}"); }
是不是這樣子就實現了自己自定義方法了呢?個人覺得這麼寫還繞了一圈,不如用泛型或者Dynamic了。
執行一下,看看效果:
其實我也是抱著試試的態度,沒想到還真是這樣,和新方法就是SendCoreAsync,而其他方法只不過是上層封裝使得程式碼更加通俗易懂。
使用Redis
Demo中的其他例子就不再演示了。廣播,一對一,一對多,加入組,退出組等基本和之前一樣。這裡在演示一下使用Redis做不同例項之間的通訊效果。
首先程式集是不能少的:Microsoft.AspNetCore.SignalR.Redis,然後在Startup中補充程式碼:
開啟Redis客戶端,使用MONITOR命令監聽一下,從程式啟動,到連線,在傳送一條廣播訊息:hello redis。 redis 監聽結果如下:
所以,PUB/SUB還是立了大功呢。
這裡用CMD運行了兩個例項,埠分別為 8881,8882來模擬兩個站點。
演示效果如下:
沒問題的哦,其實仔細想想,雖然運行了兩個網站例項,但是連線資訊都儲存在同一個Redis上,那肯定通訊是木的問題的啦。
總結
只是簡單的運行了一下DEMO,大致瞭解了一下 .Net Core SignalR的表層,至少跑Demo是跑起來了,並且使用Redis也是沒有問題的。不過好像會出現執行一旦時間,程式自動停掉的問題,不知道是不是我電腦的問題。。今天就到這裡吧,希望大家能有所收穫。