[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 傳來的使用者唯一識別碼

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

1
2
3
4
5
6
7
8
9
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裡面註冊即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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 的程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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