[SignalR] 04 - IUserIdProvider


這次利用官網介紹的IUserId Provider來替換掉單一使用者群組

當初為了向某位多開視窗的使用者也可以正確發送、接收訊息,採用了單一使用者群組的方式實作,但是這樣子會發現程式碼需要在 OnConnected 的時候做一些事情,而且是每一個 Hub 都要這樣做,所以今天改用 IUserIdProvider 的方式處理

Ref:將 SignalR 使用者對應至連線


原先 Hub 推訊息的部分Clients.Group(userId).Received($"{msg} at {DateTime.Now:f}");,是依據我們給的 UserId 去找到該 Group,然後傳送給這個 Group 裡面所有的 Client;現在我們改用Clients.User(userId).Received(msg);,直接將訊息送給使用者,但是要用Clients.Usre(userId)之前,我們還必須要先告訴 SignalR,怎麼樣取得使用者 ID

自訂 UserIdProvider

依照文件,繼承IUserIdProvider,實作介面方法,裡面撰寫如何取得使用者 ID 的邏輯,此處依照先前作法,仍舊是從 QueryString 取得 client 傳來的使用者唯一識別碼

需要注意的是使用者識別碼有區分大小寫

    public class CustomUserIdProvider : IUserIdProvider
    {
        public string GetUserId(IRequest request)
        {
            // 從QueryString中取得ID作為使用者的識別名稱
            var id = request.QueryString["id"];
            return string.IsNullOrWhiteSpace(id) ? string.Empty : id;
        }
    }

註冊自訂的 Provider

直接在startup.cs裡面註冊即可

    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // 註冊自訂的使用者ID Provider規則
            var idProvider = new CustomUserIdProvider();
            GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider), () => idProvider);

            app.Map("/signalr", map =>
            {
                map.UseCors(CorsOptions.AllowAll);
                var hubConfiguration = new HubConfiguration { };
                map.RunSignalR(hubConfiguration);
            });
        }
    }

順便列出 Hub 的程式碼

 public abstract class BaseHub : Hub<IClient>
    {
        /// <summary>
        /// 傳遞訊息給某人
        /// </summary>
        /// <param name="userId">要傳遞的對象</param>
        /// <param name="msg">訊息內容</param>
        public void SendPrivateMsg(string userId, string msg)
        {
            //透過使用者ID來針對該使用者相關聯的連接發送訊息
            //此處Clients.User()必須要先註冊自訂的IUserIdProvider,讓SignalR知道怎麼取得使用者Id
            Clients.User(userId).Received($"{msg} at {DateTime.Now:f} By User");
        }

        /// <summary>
        /// 傳送訊息給Hub的所有人
        /// </summary>
        /// <param name="msg">The MSG.</param>
        public void Send(string msg)
        {
            Clients.All.Received($"{msg} at {DateTime.Now:f} By All");
        }
    }

    [HubName("v4hub")]
    public class V4Hub : BaseHub
    {
    }

嗯,沒錯,v4 測試版本的 Hub 程式碼直接就是繼承就好了,東西都在父類別,而且也不用再去 override,如果有多個 Hub,就直接繼承。因為我上一個版本也沒有重構…現在也懶得回頭重構了

細節有需要的請直接參考 GitHub