Usar hubs no SignalR para ASP.NET CoreUse hubs in SignalR for ASP.NET Core

Por Rachel appel e Kevin GriffinBy Rachel Appel and Kevin Griffin

Exibir ou baixar o código de exemplo (como baixar)View or download sample code (how to download)

O que é um hub de SignalRWhat is a SignalR hub

A API de hubs de SignalR permite que você chame métodos em clientes conectados do servidor.The SignalR Hubs API enables you to call methods on connected clients from the server. No código do servidor, você define os métodos que são chamados pelo cliente.In the server code, you define methods that are called by client. No código do cliente, você define os métodos que são chamados do servidor.In the client code, you define methods that are called from the server. SignalR cuida de tudo nos bastidores que possibilitam a comunicação de cliente para servidor e servidor para cliente em tempo real possível. takes care of everything behind the scenes that makes real-time client-to-server and server-to-client communications possible.

Configurar hubs de SignalRConfigure SignalR hubs

O middleware SignalR requer alguns serviços, que são configurados chamando services.AddSignalR.The SignalR middleware requires some services, which are configured by calling services.AddSignalR.

services.AddSignalR();

Ao adicionar SignalR funcionalidade a um aplicativo ASP.NET Core, configure SignalR rotas chamando endpoint.MapHub no retorno de chamada Startup.Configure do método app.UseEndpoints.When adding SignalR functionality to an ASP.NET Core app, setup SignalR routes by calling endpoint.MapHub in the Startup.Configure method's app.UseEndpoints callback.

app.UseRouting();
app.UseEndpoints(endpoints =>
{
    endpoints.MapHub<ChatHub>("/chathub");
});

Ao adicionar SignalR funcionalidade a um aplicativo ASP.NET Core, configure SignalR rotas chamando app.UseSignalR no método Startup.Configure.When adding SignalR functionality to an ASP.NET Core app, setup SignalR routes by calling app.UseSignalR in the Startup.Configure method.

app.UseSignalR(route =>
{
    route.MapHub<ChatHub>("/chathub");
});

Criar e usar hubsCreate and use hubs

Crie um hub declarando uma classe que herda de Hube adicione métodos públicos a ela.Create a hub by declaring a class that inherits from Hub, and add public methods to it. Os clientes podem chamar métodos que são definidos como public.Clients can call methods that are defined as public.

public class ChatHub : Hub
{
    public Task SendMessage(string user, string message)
    {
        return Clients.All.SendAsync("ReceiveMessage", user, message);
    }
}

Você pode especificar um tipo de retorno e parâmetros, incluindo tipos complexos e matrizes, como faria em C# qualquer método.You can specify a return type and parameters, including complex types and arrays, as you would in any C# method. SignalR lida com a serialização e desserialização de objetos e matrizes complexos em seus parâmetros e valores de retorno. handles the serialization and deserialization of complex objects and arrays in your parameters and return values.

Observação

Os hubs são transitórios:Hubs are transient:

  • Não armazene o estado em uma propriedade na classe Hub.Don't store state in a property on the hub class. Cada chamada de método de Hub é executada em uma nova instância de Hub.Every hub method call is executed on a new hub instance.
  • Use await ao chamar métodos assíncronos que dependem do Hub permanecendo ativo.Use await when calling asynchronous methods that depend on the hub staying alive. Por exemplo, um método como Clients.All.SendAsync(...) pode falhar se for chamado sem await e o método de Hub for concluído antes de SendAsync ser concluído.For example, a method such as Clients.All.SendAsync(...) can fail if it's called without await and the hub method completes before SendAsync finishes.

O objeto de contextoThe Context object

A classe Hub tem uma propriedade Context que contém as seguintes propriedades com informações sobre a conexão:The Hub class has a Context property that contains the following properties with information about the connection:

propriedadeProperty DescriçãoDescription
ConnectionId Obtém a ID exclusiva da conexão, atribuída por SignalR.Gets the unique ID for the connection, assigned by SignalR. Há uma ID de conexão para cada conexão.There is one connection ID for each connection.
UserIdentifier Obtém o identificador de usuário.Gets the user identifier. Por padrão, SignalR usa o ClaimTypes.NameIdentifier do ClaimsPrincipal associado à conexão como o identificador de usuário.By default, SignalR uses the ClaimTypes.NameIdentifier from the ClaimsPrincipal associated with the connection as the user identifier.
User Obtém o ClaimsPrincipal associado ao usuário atual.Gets the ClaimsPrincipal associated with the current user.
Items Obtém uma coleção de chave/valor que pode ser usada para compartilhar dados dentro do escopo desta conexão.Gets a key/value collection that can be used to share data within the scope of this connection. Os dados podem ser armazenados nessa coleção e serão mantidos para a conexão entre invocações de método de Hub diferentes.Data can be stored in this collection and it will persist for the connection across different hub method invocations.
Features Obtém a coleção de recursos disponíveis na conexão.Gets the collection of features available on the connection. Por enquanto, essa coleção não é necessária na maioria dos cenários, portanto, ela ainda não está documentada em detalhes.For now, this collection isn't needed in most scenarios, so it isn't documented in detail yet.
ConnectionAborted Obtém um CancellationToken que notifica quando a conexão é anulada.Gets a CancellationToken that notifies when the connection is aborted.

o Hub.Context também contém os seguintes métodos:Hub.Context also contains the following methods:

MétodoMethod DescriçãoDescription
GetHttpContext Retorna o HttpContext para a conexão ou null se a conexão não estiver associada a uma solicitação HTTP.Returns the HttpContext for the connection, or null if the connection is not associated with an HTTP request. Para conexões HTTP, você pode usar esse método para obter informações como cabeçalhos HTTP e cadeias de caracteres de consulta.For HTTP connections, you can use this method to get information such as HTTP headers and query strings.
Abort Anula a conexão.Aborts the connection.

O objeto clientsThe Clients object

A classe Hub tem uma propriedade Clients que contém as seguintes propriedades para comunicação entre o servidor e o cliente:The Hub class has a Clients property that contains the following properties for communication between server and client:

propriedadeProperty DescriçãoDescription
All Chama um método em todos os clientes conectadosCalls a method on all connected clients
Caller Chama um método no cliente que invocou o método de HubCalls a method on the client that invoked the hub method
Others Chama um método em todos os clientes conectados, exceto o cliente que invocou o métodoCalls a method on all connected clients except the client that invoked the method

o Hub.Clients também contém os seguintes métodos:Hub.Clients also contains the following methods:

MétodoMethod DescriçãoDescription
AllExcept Chama um método em todos os clientes conectados, exceto para as conexões especificadasCalls a method on all connected clients except for the specified connections
Client Chama um método em um cliente conectado específicoCalls a method on a specific connected client
Clients Chama um método em clientes conectados específicosCalls a method on specific connected clients
Group Chama um método em todas as conexões no grupo especificadoCalls a method on all connections in the specified group
GroupExcept Chama um método em todas as conexões no grupo especificado, exceto as conexões especificadasCalls a method on all connections in the specified group, except the specified connections
Groups Chama um método em vários grupos de conexõesCalls a method on multiple groups of connections
OthersInGroup Chama um método em um grupo de conexões, excluindo o cliente que invocou o método de HubCalls a method on a group of connections, excluding the client that invoked the hub method
User Chama um método em todas as conexões associadas a um usuário específicoCalls a method on all connections associated with a specific user
Users Chama um método em todas as conexões associadas aos usuários especificadosCalls a method on all connections associated with the specified users

Cada propriedade ou método nas tabelas anteriores retorna um objeto com um método SendAsync.Each property or method in the preceding tables returns an object with a SendAsync method. O método SendAsync permite que você forneça o nome e os parâmetros do método de cliente a ser chamado.The SendAsync method allows you to supply the name and parameters of the client method to call.

Enviar mensagens para clientesSend messages to clients

Para fazer chamadas para clientes específicos, use as propriedades do objeto Clients.To make calls to specific clients, use the properties of the Clients object. No exemplo a seguir, há três métodos de Hub:In the following example, there are three Hub methods:

  • SendMessage envia uma mensagem para todos os clientes conectados, usando Clients.All.SendMessage sends a message to all connected clients, using Clients.All.
  • SendMessageToCaller envia uma mensagem de volta ao chamador, usando Clients.Caller.SendMessageToCaller sends a message back to the caller, using Clients.Caller.
  • SendMessageToGroups envia uma mensagem para todos os clientes no grupo de SignalR Users.SendMessageToGroups sends a message to all clients in the SignalR Users group.
public Task SendMessage(string user, string message)
{
    return Clients.All.SendAsync("ReceiveMessage", user, message);
}

public Task SendMessageToCaller(string message)
{
    return Clients.Caller.SendAsync("ReceiveMessage", message);
}

public Task SendMessageToGroup(string message)
{
    return Clients.Group("SignalR Users").SendAsync("ReceiveMessage", message);
}

Hubs com rigidez de tiposStrongly typed hubs

Uma desvantagem de usar SendAsync é que ela se baseia em uma cadeia de caracteres mágica para especificar o método de cliente a ser chamado.A drawback of using SendAsync is that it relies on a magic string to specify the client method to be called. Isso deixa o código aberto para erros de tempo de execução se o nome do método for digitado incorretamente ou ausente no cliente.This leaves code open to runtime errors if the method name is misspelled or missing from the client.

Uma alternativa ao uso de SendAsync é digitar fortemente o Hub com Hub<T>.An alternative to using SendAsync is to strongly type the Hub with Hub<T>. No exemplo a seguir, os métodos de cliente ChatHub foram extraídos em uma interface chamada IChatClient.In the following example, the ChatHub client methods have been extracted out into an interface called IChatClient.

public interface IChatClient
{
    Task ReceiveMessage(string user, string message);
    Task ReceiveMessage(string message);
}

Essa interface pode ser usada para refatorar o exemplo de ChatHub anterior.This interface can be used to refactor the preceding ChatHub example.

public class StronglyTypedChatHub : Hub<IChatClient>
{
    public async Task SendMessage(string user, string message)
    {
        await Clients.All.ReceiveMessage(user, message);
    }

    public Task SendMessageToCaller(string message)
    {
        return Clients.Caller.ReceiveMessage(message);
    }
}

O uso de Hub<IChatClient> permite a verificação de tempo de compilação dos métodos de cliente.Using Hub<IChatClient> enables compile-time checking of the client methods. Isso evita problemas causados pelo uso de cadeias de caracteres mágicas, pois Hub<T> só pode fornecer acesso aos métodos definidos na interface.This prevents issues caused by using magic strings, since Hub<T> can only provide access to the methods defined in the interface.

Usar um Hub<T> fortemente tipado desabilita a capacidade de usar SendAsync.Using a strongly typed Hub<T> disables the ability to use SendAsync. Todos os métodos definidos na interface ainda podem ser definidos como assíncronos.Any methods defined on the interface can still be defined as asynchronous. Na verdade, cada um desses métodos deve retornar um Task.In fact, each of these methods should return a Task. Como é uma interface, não use a palavra-chave async.Since it's an interface, don't use the async keyword. Por exemplo:For example:

public interface IClient
{
    Task ClientMethod();
}

Observação

O sufixo de Async não é removido do nome do método.The Async suffix isn't stripped from the method name. A menos que o método de cliente seja definido com .on('MyMethodAsync'), você não deve usar MyMethodAsync como um nome.Unless your client method is defined with .on('MyMethodAsync'), you shouldn't use MyMethodAsync as a name.

Alterar o nome de um método de HubChange the name of a hub method

Por padrão, um nome de método de Hub de servidor é o nome do método .NET.By default, a server hub method name is the name of the .NET method. No entanto, você pode usar o atributo HubMethodName para alterar esse padrão e especificar manualmente um nome para o método.However, you can use the HubMethodName attribute to change this default and manually specify a name for the method. O cliente deve usar esse nome, em vez do nome do método .NET, ao invocar o método.The client should use this name, instead of the .NET method name, when invoking the method.

[HubMethodName("SendMessageToUser")]
public Task DirectMessage(string user, string message)
{
    return Clients.User(user).SendAsync("ReceiveMessage", message);
}

Manipular eventos para uma conexãoHandle events for a connection

A API de hubs de SignalR fornece o OnConnectedAsync e OnDisconnectedAsync métodos virtuais para gerenciar e controlar as conexões.The SignalR Hubs API provides the OnConnectedAsync and OnDisconnectedAsync virtual methods to manage and track connections. Substitua o método virtual OnConnectedAsync para executar ações quando um cliente se conectar ao Hub, como adicioná-lo a um grupo.Override the OnConnectedAsync virtual method to perform actions when a client connects to the Hub, such as adding it to a group.

public override async Task OnConnectedAsync()
{
    await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
    await base.OnConnectedAsync();
}

Substitua o método virtual OnDisconnectedAsync para executar ações quando um cliente se desconectar.Override the OnDisconnectedAsync virtual method to perform actions when a client disconnects. Se o cliente se desconectar intencionalmente (chamando connection.stop(), por exemplo), o parâmetro exception será null.If the client disconnects intentionally (by calling connection.stop(), for example), the exception parameter will be null. No entanto, se o cliente for desconectado devido a um erro (como uma falha de rede), o parâmetro exception conterá uma exceção que descreve a falha.However, if the client is disconnected due to an error (such as a network failure), the exception parameter will contain an exception describing the failure.

public override async Task OnDisconnectedAsync(Exception exception)
{
    await Groups.RemoveFromGroupAsync(Context.ConnectionId, "SignalR Users");
    await base.OnDisconnectedAsync(exception);
}

Tratar errosHandle errors

As exceções geradas em seus métodos de Hub são enviadas ao cliente que invocou o método.Exceptions thrown in your hub methods are sent to the client that invoked the method. No cliente JavaScript, o método invoke retorna uma promessa de JavaScript.On the JavaScript client, the invoke method returns a JavaScript Promise. Quando o cliente recebe um erro com um manipulador anexado à promessa usando catch, ele é invocado e passado como um objeto JavaScript Error.When the client receives an error with a handler attached to the promise using catch, it's invoked and passed as a JavaScript Error object.

connection.invoke("SendMessage", user, message).catch(err => console.error(err));

Se o Hub lançar uma exceção, as conexões não serão fechadas.If your Hub throws an exception, connections aren't closed. Por padrão, SignalR retorna uma mensagem de erro genérica para o cliente.By default, SignalR returns a generic error message to the client. Por exemplo:For example:

Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'MethodName' on the server.

Exceções inesperadas geralmente contêm informações confidenciais, como o nome de um servidor de banco de dados em uma exceção disparada quando a conexão de banco de dados falha.Unexpected exceptions often contain sensitive information, such as the name of a database server in an exception triggered when the database connection fails. o SignalR não expõe essas mensagens de erro detalhadas por padrão como uma medida de segurança.SignalR doesn't expose these detailed error messages by default as a security measure. Consulte o artigo considerações sobre segurança para obter mais informações sobre por que os detalhes da exceção são suprimidos.See the Security considerations article for more information on why exception details are suppressed.

Se você tiver uma condição excepcional que deseja propagar para o cliente, poderá usar a classe HubException.If you have an exceptional condition you do want to propagate to the client, you can use the HubException class. Se você lançar uma HubException do seu método de Hub, SignalR enviará a mensagem inteira para o cliente, sem modificações.If you throw a HubException from your hub method, SignalR will send the entire message to the client, unmodified.

public Task ThrowException()
{
    throw new HubException("This error will be sent to the client!");
}

Observação

SignalR envia apenas a propriedade Message da exceção para o cliente. only sends the Message property of the exception to the client. O rastreamento de pilha e outras propriedades na exceção não estão disponíveis para o cliente.The stack trace and other properties on the exception aren't available to the client.