กลุ่ม ผู้ใช้ และการจัดการการเชื่อมต่อ
จัดการกลุ่ม กำหนดเป้าหมายผู้ใช้หรือการเชื่อมต่อเฉพาะราย และจัดการเหตุการณ์ตลอดอายุการใช้งานเมื่อเชื่อมต่อหรือยกเลิกการเชื่อมต่อ
กลุ่ม ผู้ใช้ และการจัดการการเชื่อมต่อ เป็นบทเรียน C# Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C# Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดจึงต้องใช้กลุ่มและผู้ใช้
ในแอปพลิเคชันจริง คุณแทบไม่ต้องการกระจายข้อความไปยังไคลเอ็นต์ ALL ราย SignalR มี กลุ่มสำหรับระบุชุดย่อยของการเชื่อมต่อ (เช่น ห้องสนทนา) และมี ผู้ใช้สำหรับส่งข้อความไปยังการเชื่อมต่อทั้งหมดของผู้ใช้ที่ผ่านการยืนยันตัวตนรายใดรายหนึ่ง
การเพิ่มการเชื่อมต่อเข้ากลุ่ม
เรียก Groups.AddToGroupAsync() พร้อมรหัสการเชื่อมต่อและชื่อกลุ่ม การเชื่อมต่อหนึ่งรายการสามารถอยู่ในหลายกลุ่มพร้อมกันได้
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) จะส่งไปยังการเชื่อมต่อ ALL รายของผู้ใช้นั้นพร้อมกัน
// 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");ผู้ให้บริการรหัสผู้ใช้แบบกำหนดเอง
โดยค่าเริ่มต้น SignalR จะใช้เคลม NameIdentifier เป็นรหัสผู้ใช้ ให้เขียน IUserIdProvider เพื่อใช้เคลมอื่นหรือตรรกะแบบกำหนดเอง
public class EmailUserIdProvider : IUserIdProvider
{
public string? GetUserId(HubConnectionContext connection)
{
return connection.User?.FindFirst(ClaimTypes.Email)?.Value;
}
}
// Register:
builder.Services.AddSingleton<IUserIdProvider, EmailUserIdProvider>();การติดตามสถานะการเชื่อมต่อ
SignalR ไม่เก็บสถานะการเชื่อมต่อไว้ระหว่างการขาดการเชื่อมต่อ ให้จัดเก็บการจับคู่ระหว่างรหัสผู้ใช้กับรหัสการเชื่อมต่อของคุณเองในพจนานุกรมที่ปลอดภัยต่อเธรด (สำหรับเซิร์ฟเวอร์เดียว) หรือ 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 ช่วยให้คุณระบุเป้าหมายเป็นกลุ่มและผู้ใช้จากบริการเบื้องหลังได้ เหมาะอย่างยิ่งสำหรับการแจ้งเตือนแบบ async ที่เกิดจากเหตุการณ์ในระบบ
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);
}ตรวจสอบความเข้าใจ
เมื่อผู้ใช้เปิดแท็บเบราว์เซอร์ไว้สามแท็บ Clients.User(userId) จะทำอะไร
ทบทวน: กลุ่ม ผู้ใช้ และการจัดการการเชื่อมต่อ
ประเด็นสำคัญ:
Groups.AddToGroupAsync/RemoveFromGroupAsync: จัดการการเป็นสมาชิกกลุ่มClients.Group(name): ส่งข้อความไปยังกลุ่มย่อยของการเชื่อมต่อClients.User(userId): ส่งข้อความไปยังการเชื่อมต่อทั้งหมดของผู้ใช้รายหนึ่ง- ใช้
IUserIdProviderเพื่อกำหนดเคลมรหัสผู้ใช้แบบกำหนดเอง - กลุ่มจะไม่ถูกคงไว้ — ให้เข้าร่วมกลุ่มอีกครั้งเมื่อเชื่อมต่อใหม่
- ติดตามจำนวนการเชื่อมต่อใน ConcurrentDictionary เพื่อตรวจจับสถานะการออนไลน์
คำถามที่พบบ่อย
บทเรียน “กลุ่ม ผู้ใช้ และการจัดการการเชื่อมต่อ” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “กลุ่ม ผู้ใช้ และการจัดการการเชื่อมต่อ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C# Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “กลุ่ม ผู้ใช้ และการจัดการการเชื่อมต่อ”
จัดการกลุ่ม กำหนดเป้าหมายผู้ใช้หรือการเชื่อมต่อเฉพาะราย และจัดการเหตุการณ์ตลอดอายุการใช้งานเมื่อเชื่อมต่อหรือยกเลิกการเชื่อมต่อ คุณปฏิบัติ C# Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C# Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน C# Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “กลุ่ม ผู้ใช้ และการจัดการการเชื่อมต่อ” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน C# Academy นี้ได้ไหม
ได้ บทเรียน C# Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ฮับและการเชื่อมต่อ SignalR
- กลุ่ม ผู้ใช้ และการจัดการการเชื่อมต่อ
- ฮับแบบระบุชนิดอย่างเคร่งครัด
- การปรับขนาดด้วย Redis Backplane