0Pricing
C# Academy · Aula

Grupos, usuários e gerenciamento de conexões

Gerencie grupos, direcione mensagens a usuários ou conexões específicos e trate eventos do ciclo de vida de conexão e desconexão.

Grupos, usuários e gerenciamento de conexões é uma aula grátis de C# Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C# Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C# Academy inclui 4 aulas no total.

Por que grupos e usuários

Em aplicações reais, raramente você deseja transmitir para ALL os clientes. Os grupos do SignalR permitem direcionar mensagens a subconjuntos de conexões (por exemplo, uma sala de conversa), e os usuários permitem endereçar todas as conexões pertencentes a um usuário autenticado específico.

Adicionando conexões a grupos

Chame Groups.AddToGroupAsync() com o ID da conexão e o nome de um grupo. Uma conexão pode pertencer a vários grupos simultaneamente.

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);
    }
}

Enviando para grupos

Use Clients.Group(name) para enviar mensagens a todas as conexões de um grupo. Outras opções de direcionamento incluem GroupExcept e Groups (vários grupos ao mesmo tempo).

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);
}

Direcionamento baseado em usuário

Quando um usuário tem várias abas do navegador ou dispositivos abertos, ele possui várias conexões. Clients.User(userId) envia mensagens para ALL as conexões desse usuário simultaneamente.

// 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");

Provedor de ID de usuário personalizado

Por padrão, o SignalR usa a declaração NameIdentifier como ID do usuário. Implemente IUserIdProvider para usar outra declaração ou uma lógica personalizada.

public class EmailUserIdProvider : IUserIdProvider
{
    public string? GetUserId(HubConnectionContext connection)
    {
        return connection.User?.FindFirst(ClaimTypes.Email)?.Value;
    }
}

// Register:
builder.Services.AddSingleton<IUserIdProvider, EmailUserIdProvider>();

Acompanhando o estado das conexões

O SignalR não persiste o estado das conexões entre desconexões. Mantenha seu próprio mapeamento de IDs de usuário para IDs de conexão em um dicionário seguro para threads (servidor único) ou no Redis (vários servidores).

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>();
}

Gerenciando grupos automaticamente em OnConnected/OnDisconnected

Um padrão comum é adicionar automaticamente usuários autenticados ao grupo pessoal deles em OnConnectedAsync, para que você possa direcioná-los pelo nome do grupo sem precisar de um acompanhamento personalizado.

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);

Enviando de serviços em segundo plano com grupos

Usando IHubContext, você pode direcionar mensagens a grupos e usuários a partir de serviços em segundo plano — perfeito para notificações assíncronas acionadas por eventos no sistema.

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);
    }
}

Persistência da associação a grupos

A associação a grupos não é persistida — se o servidor for reiniciado ou o barramento intermediário do Redis perder o estado, os grupos ficarão vazios. Associe-se novamente aos grupos ao reconectar usando o evento onreconnected do cliente.

// 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);
    }
});

Presença: detecção de usuários conectados/desconectados

Acompanhe o status online contando as conexões de cada usuário em OnConnected/OnDisconnected e transmitindo eventos de presença aos grupos relevantes.

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);
}

Verificação rápida

Quando um usuário tem três abas do navegador abertas, o que Clients.User(userId) faz?

Recapitulação: grupos, usuários e gerenciamento de conexões

Principais conclusões:

  • Groups.AddToGroupAsync/RemoveFromGroupAsync: gerenciam a associação a grupos
  • Clients.Group(name): envia para um subconjunto de conexões
  • Clients.User(userId): envia para todas as conexões de um usuário
  • Implemente IUserIdProvider para declarações de ID de usuário personalizadas
  • Os grupos não são persistidos — associe-se novamente ao reconectar
  • Acompanhe as contagens de conexões em ConcurrentDictionary para detectar a presença

Perguntas Frequentes

A aula “Grupos, usuários e gerenciamento de conexões” é grátis?

Sim — o texto completo de “Grupos, usuários e gerenciamento de conexões” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C# Academy, atualize para CoddyKit PRO. O curso de C# Academy inclui 4 aulas no total.

O que vou aprender em “Grupos, usuários e gerenciamento de conexões”?

Gerencie grupos, direcione mensagens a usuários ou conexões específicos e trate eventos do ciclo de vida de conexão e desconexão. Você pratica C# Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar C# Academy?

Nenhuma experiência prévia é necessária. C# Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Grupos, usuários e gerenciamento de conexões”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de C# Academy?

Sim. Cada aula de C# Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Hubs e conexões do SignalR
  2. Grupos, usuários e gerenciamento de conexões
  3. Hubs fortemente tipados
  4. Escalonamento com Redis Backplane
← Voltar para C# Academy