0Pricing
C# Academy · บทเรียน

กลุ่ม ผู้ใช้ และการจัดการการเชื่อมต่อ

จัดการกลุ่ม กำหนดเป้าหมายผู้ใช้หรือการเชื่อมต่อเฉพาะราย และจัดการเหตุการณ์ตลอดอายุการใช้งานเมื่อเชื่อมต่อหรือยกเลิกการเชื่อมต่อ

กลุ่ม ผู้ใช้ และการจัดการการเชื่อมต่อ เป็นบทเรียน 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. ฮับและการเชื่อมต่อ SignalR
  2. กลุ่ม ผู้ใช้ และการจัดการการเชื่อมต่อ
  3. ฮับแบบระบุชนิดอย่างเคร่งครัด
  4. การปรับขนาดด้วย Redis Backplane
← กลับไปที่ C# Academy