グループ、ユーザーと接続管理
グループを管理し、特定のユーザーや接続を対象にして、接続・切断のライフサイクルイベントを処理します。
「グループ、ユーザーと接続管理」はCoddyKit上の無料C# Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC# Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C# Academyコースには全4レッスンが含まれています。
グループとユーザーを使用する理由
実際のアプリケーションで、すべてのクライアントにブロードキャストしたい場面はほとんどありません。SignalR のグループを使用すると接続の一部(チャットルームなど)を対象にでき、ユーザーを使用すると特定の認証済みユーザーに属するすべての接続にアドレス指定できます。
接続をグループに追加する
接続 ID とグループ名を指定して Groups.AddToGroupAsync() を呼び出します。1 つの接続を同時に複数のグループに所属させることができます。
public class ChatHub : Hub
{
public async Task JoinRoom(string roomName)
{
await Groups.AddToGroupAsync(Context.ConnectionId, roomName);
await Clients.Group(roomName)
.SendAsync("UserJoined", Context.User!.Identity!.Name);
}
public async Task LeaveRoom(string roomName)
{
await Groups.RemoveFromGroupAsync(Context.ConnectionId, roomName);
await Clients.Group(roomName)
.SendAsync("UserLeft", Context.User!.Identity!.Name);
}
}グループに送信する
Clients.Group(name) を使用して、グループ内のすべての接続に送信します。その他の対象指定オプションには、GroupExcept と Groups(一度に複数のグループ)が含まれます。
public async Task SendToRoom(string roomName, string message)
{
var sender = Context.User!.Identity!.Name;
// Everyone in the room
await Clients.Group(roomName)
.SendAsync("ReceiveMessage", sender, message);
// Everyone in the room except the sender
await Clients.GroupExcept(roomName, Context.ConnectionId)
.SendAsync("ReceiveMessage", sender, message);
}ユーザーベースの対象指定
ユーザーが複数のブラウザタブやデバイスを開いている場合、そのユーザーには複数の接続があります。Clients.User(userId) を使用すると、そのユーザーのすべての接続に同時に送信できます。
// Send to all connections of user with ID "user-123"
await Clients.User("user-123")
.SendAsync("Notification", "Your order has shipped!");
// SignalR uses the NameIdentifier claim by default.
// Context.UserIdentifier returns the current user's ID.
var myId = Context.UserIdentifier;
await Clients.User(myId!).SendAsync("Ack", "Server received your message");カスタムユーザー ID プロバイダー
SignalR は既定で NameIdentifier クレームをユーザー ID として使用します。別のクレームやカスタムロジックを使用するには、IUserIdProvider を実装します。
public class EmailUserIdProvider : IUserIdProvider
{
public string? GetUserId(HubConnectionContext connection)
{
return connection.User?.FindFirst(ClaimTypes.Email)?.Value;
}
}
// Register:
builder.Services.AddSingleton<IUserIdProvider, EmailUserIdProvider>();接続状態を追跡する
SignalR は切断後も接続状態を保持しません。ユーザー ID と接続 ID のマッピングを、スレッドセーフなディクショナリ(単一サーバー)または Redis(複数サーバー)で独自に追跡してください。
public class ConnectionTracker
{
private readonly ConcurrentDictionary<string, HashSet<string>> _userConnections
= new();
public void AddConnection(string userId, string connectionId)
=> _userConnections.GetOrAdd(userId, _ => new()).Add(connectionId);
public void RemoveConnection(string userId, string connectionId)
{
if (_userConnections.TryGetValue(userId, out var conns))
{
conns.Remove(connectionId);
if (conns.Count == 0) _userConnections.TryRemove(userId, out _);
}
}
public IEnumerable<string> GetConnections(string userId)
=> _userConnections.TryGetValue(userId, out var c) ? c : Enumerable.Empty<string>();
}OnConnected/OnDisconnected でグループを自動管理する
一般的なパターンとして、OnConnectedAsync で認証済みユーザーを個人用グループに自動的に追加します。これにより、カスタムの追跡処理を行わずにグループ名でユーザーを対象にできます。
public override async Task OnConnectedAsync()
{
// Add to a personal group named by user ID
var userId = Context.UserIdentifier;
if (userId is not null)
await Groups.AddToGroupAsync(Context.ConnectionId, userId);
await base.OnConnectedAsync();
}
// Now send to a user by their personal group:
await _hub.Clients.Group(userId)
.SendAsync("Update", payload);グループを使用してバックグラウンドサービスから送信する
IHubContext を使用すると、バックグラウンドサービスからグループやユーザーを対象にできます。システム内のイベントをきっかけにした非同期通知に最適です。
public class OrderShippedHandler : INotificationHandler<OrderShipped>
{
private readonly IHubContext<OrderHub> _hub;
public OrderShippedHandler(IHubContext<OrderHub> hub) => _hub = hub;
public async Task Handle(OrderShipped notification, CancellationToken ct)
{
// Push to the customer's personal group
await _hub.Clients.Group(notification.CustomerId.ToString())
.SendAsync("OrderShipped",
new { notification.OrderId, notification.TrackingNumber },
ct);
}
}グループメンバーシップの永続化
グループメンバーシップは永続化されません。サーバーが再起動したり、Redis バックプレーンの状態が失われたりすると、グループは空になります。クライアントの onreconnected イベントを使用して、再接続時にグループへ再参加させてください。
// JavaScript client: re-join groups after reconnect
connection.onreconnected(async connectionId => {
console.log(`Reconnected as ${connectionId}`);
// Re-join previously joined rooms
for (const room of joinedRooms) {
await connection.invoke("JoinRoom", room);
}
});プレゼンス:オンライン/オフラインの検出
OnConnected/OnDisconnected でユーザーごとの接続数を数え、関連するグループにプレゼンスイベントをブロードキャストすることで、オンライン状態を追跡します。
public override async Task OnConnectedAsync()
{
var userId = Context.UserIdentifier!;
var count = _tracker.AddConnection(userId, Context.ConnectionId);
if (count == 1) // first connection for this user
await Clients.Others.SendAsync("UserOnline", userId);
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception? ex)
{
var userId = Context.UserIdentifier!;
var count = _tracker.RemoveConnection(userId, Context.ConnectionId);
if (count == 0) // no more connections
await Clients.Others.SendAsync("UserOffline", userId);
await base.OnDisconnectedAsync(ex);
}確認問題
ユーザーがブラウザーのタブを3つ開いている場合、Clients.User(userId) は何を行いますか?
まとめ:グループ、ユーザー、接続管理
主なポイント:
Groups.AddToGroupAsync/RemoveFromGroupAsync:グループメンバーシップを管理しますClients.Group(name):接続の一部にメッセージを送信しますClients.User(userId):ユーザーのすべての接続にメッセージを送信します- カスタムユーザー ID クレームには
IUserIdProviderを実装します - グループは永続化されないため、再接続時に再参加させます
- プレゼンス検出のため、ConcurrentDictionary で接続数を追跡します
よくある質問
「グループ、ユーザーと接続管理」レッスンは無料ですか?
はい。「グループ、ユーザーと接続管理」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C# Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C# Academyコースには全4レッスンが含まれています。
「グループ、ユーザーと接続管理」で何を学びますか?
グループを管理し、特定のユーザーや接続を対象にして、接続・切断のライフサイクルイベントを処理します。 ブラウザで直接実行するハンズオンコードでC# Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C# Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC# Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「グループ、ユーザーと接続管理」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC# Academyレッスンでコードを書いて実行できますか?
はい。すべてのC# Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- SignalR Hubと接続
- グループ、ユーザーと接続管理
- 型付きHub
- Redis Backplaneによるスケーリング