Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Por Rachel Appel e Kevin Griffin
A SignalR API de Hubs permite que clientes conectados chamem métodos no servidor, facilitando a comunicação em tempo real. O servidor define métodos que são chamados pelo cliente e o cliente define métodos que são chamados pelo servidor. SignalR também permite a SignalR comunicação indireta cliente-a-cliente, sempre mediada pelo Hub, permitindo que mensagens sejam enviadas entre clientes individuais, grupos ou para todos os clientes conectados. SignalR Cuida de tudo o que é necessário para tornar possível a comunicação cliente-servidor e servidor-cliente em tempo real.
Configuração de SignalR hubs
Para registar os serviços requeridos pelos SignalR hubs, ligue para AddSignalR em Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
Para configurar os SignalR endpoints, ligue para MapHub, também em Program.cs:
app.MapRazorPages();
app.MapHub<ChatHub>("/Chat");
app.Run();
Note
As assemblies do lado do servidor do ASP.NET Core SignalR agora são instaladas com o SDK do .NET Core. Consulte SignalR conjuntos na estrutura comum para mais informações.
Criar e usar hubs
Crie um hub declarando uma classe que herda do Hub. Adicione public métodos à classe para torná-los chamáveis pelos clientes.
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
}
Note
Os hubs são transitórios:
- Não armazene o estado numa propriedade da classe Hub. Cada chamada de método de hub é executada em uma nova instância de hub.
- Não instancie um hub diretamente por meio de injeção de dependência. Para enviar mensagens para um cliente de outro lugar na sua aplicação, use um
IHubContext. - Use
awaitao chamar métodos assíncronos que dependem de o hub permanecer ativo. Por exemplo, um método comoClients.All.SendAsync(...)pode falhar se for chamado semawaite o método da hub for concluído antes deSendAsyncterminar.
O objeto Context
A Hub classe inclui uma Context propriedade que contém as seguintes propriedades com informações sobre a conexão:
| Property | Description |
|---|---|
| ConnectionId | Obtém a ID exclusiva para a conexão, atribuída por SignalR. Há um ID de conexão para cada conexão. |
| UserIdentifier | Obtém o identificador de usuário. Por padrão, SignalR utiliza o ClaimTypes.NameIdentifier da ClaimsPrincipal associada à conexão como identificador de usuário. |
| User | Obtém o ClaimsPrincipal associado com o usuário atual. |
| Items | Obtém uma coleção de chave/valor que pode ser usada para compartilhar dados dentro do escopo dessa conexão. Os dados podem ser armazenados nessa coleção e persistirão no âmbito da conexão entre diferentes invocações de método de hub. |
| Features | Obtém a coleção de recursos disponíveis na conexão. Por enquanto, essa coleção não é necessária na maioria dos cenários, portanto, ainda não está documentada em detalhes. |
| ConnectionAborted | Obtém um CancellationToken que avisa quando a conexão é interrompida. |
Hub.Context também contém os seguintes métodos:
| Method | Description |
|---|---|
| GetHttpContext | Retorna o HttpContext para a conexão ou null se a conexão não estiver associada a uma solicitação HTTP. Para conexões HTTP, use esse método para obter informações como cabeçalhos HTTP e cadeias de caracteres de consulta. |
| Abort | Anula a ligação. |
O objeto Clients
A Hub classe inclui uma Clients propriedade que contém as seguintes propriedades para comunicação entre servidor e cliente:
| Property | Description |
|---|---|
| All | Chama um método em todos os clientes conectados |
| Caller | Chama um método no cliente que invocou o método hub |
| Others | Chama um método em todos os clientes conectados, exceto o cliente que invocou o método |
Hub.Clients também contém os seguintes métodos:
| Method | Description |
|---|---|
| AllExcept | Chama um método em todos os clientes conectados, exceto para as conexões especificadas |
| Client | Chama um método em um cliente conectado específico |
| Clients | Chama um método em clientes conectados específicos |
| Group | Chama um método em todas as conexões no grupo especificado |
| GroupExcept | Chama um método em todas as conexões no grupo especificado, exceto as conexões especificadas |
| Groups | Chama um método em vários grupos de conexões |
| OthersInGroup | Chama um método em um grupo de conexões, excluindo o cliente que invocou o método hub |
| User | Chama um método em todas as conexões associadas a um usuário específico |
| Users | Chama um método em todas as conexões associadas aos usuários especificados |
Cada propriedade ou método nas tabelas anteriores retorna um objeto com um SendAsync método. O método SendAsync recebe o nome do método do cliente a chamar e quaisquer parâmetros.
O objeto retornado pelos Client métodos e Caller também contém um InvokeAsync método, que pode ser usado para aguardar um resultado do cliente.
Enviar mensagens aos clientes
Para fazer chamadas para clientes específicos, use as Clients propriedades do objeto. No exemplo a seguir, há três métodos de hub:
-
SendMessageenvia uma mensagem para todos os clientes ligados, usandoClients.All. -
SendMessageToCallerenvia uma mensagem de volta para o chamador, usandoClients.Caller. -
SendMessageToGroupEnvia uma mensagem para todos os clientes doSignalR Usersgrupo.
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
Hubs fortemente tipados
Uma desvantagem do uso SendAsync é que ele depende de uma cadeia de caracteres para especificar o método de cliente a ser chamado. Isso deixa o código aberto para erros de tempo de execução se o nome do método estiver escrito incorretamente ou ausente do cliente.
Uma alternativa ao uso SendAsync é digitar fortemente a Hub classe com Hub<T>. No exemplo a seguir, o método cliente ChatHub foi extraído para uma interface chamada IChatClient:
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
}
Esta interface pode ser usada para refatorar o exemplo anterior ChatHub para ser fortemente tipado:
public class StronglyTypedChatHub : Hub<IChatClient>
{
public async Task SendMessage(string user, string message)
=> await Clients.All.ReceiveMessage(user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.ReceiveMessage(user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").ReceiveMessage(user, message);
}
O uso Hub<IChatClient> permite a verificação em tempo de compilação dos métodos do cliente. Isso evita problemas causados pelo uso de cadeias de caracteres, uma vez que Hub<T> só pode fornecer acesso aos métodos definidos na interface. Usar um tipo fortemente definido Hub<T> desativa a capacidade de usar SendAsync.
Note
O Async sufixo não é removido dos nomes dos métodos. A menos que um método de cliente seja definido com .on('MyMethodAsync'), não use MyMethodAsync como o nome.
Resultados do cliente
Além de fazer chamadas para clientes, o servidor pode solicitar um resultado de um cliente. Isso requer que o servidor use ISingleClientProxy.InvokeAsync e o cliente retorne um resultado de seu manipulador de .On.
Há duas maneiras de usar a API no servidor, a primeira é chamar Client(...) ou Caller na Clients propriedade em um método Hub:
public class ChatHub : Hub
{
public async Task<string> WaitForMessage(string connectionId)
{
var message = await Clients.Client(connectionId).InvokeAsync<string>(
"GetMessage");
return message;
}
}
A segunda maneira é invocar Client(...) numa instância de IHubContext<T>:
async Task SomeMethod(IHubContext<MyHub> context)
{
string result = await context.Clients.Client(connectionID).InvokeAsync<string>(
"GetMessage");
}
Hubs fortemente tipados também podem retornar valores de métodos de interface:
public interface IClient
{
Task<string> GetMessage();
}
public class ChatHub : Hub<IClient>
{
public async Task<string> WaitForMessage(string connectionId)
{
string message = await Clients.Client(connectionId).GetMessage();
return message;
}
}
Os clientes retornam resultados em seus .On(...) manipuladores, conforme mostrado abaixo:
Cliente .NET
hubConnection.On("GetMessage", async () =>
{
Console.WriteLine("Enter message:");
var message = await Console.In.ReadLineAsync();
return message;
});
Cliente Typescript
hubConnection.on("GetMessage", async () => {
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("message");
}, 100);
});
return promise;
});
Cliente Java
hubConnection.onWithResult("GetMessage", () -> {
return Single.just("message");
});
Alterar o nome de um método de hub
Por padrão, um nome de método de hub de servidor é o nome do método .NET. Para alterar esse comportamento padrão para um método específico, use o atributo HubMethodName . O cliente deve usar esse nome em vez do nome do método .NET ao invocar o método:
[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
=> await Clients.User(user).SendAsync("ReceiveMessage", user, message);
Injetar serviços em um hub
Os construtores de hub podem aceitar serviços de DI como parâmetros, que podem ser armazenados em propriedades na classe para uso em um método de hub.
Ao injetar vários serviços para diferentes métodos de hub ou como uma maneira alternativa de escrever código, os métodos de hub também podem aceitar serviços de DI. Por padrão, os parâmetros do método hub são inspecionados e resolvidos a partir da DI, se possível.
services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();
// ...
public class ChatHub : Hub
{
public Task SendMessage(string user, string message, IDatabaseService dbService)
{
var userName = dbService.GetUserName(user);
return Clients.All.SendAsync("ReceiveMessage", userName, message);
}
}
Se a resolução implícita de parâmetros de serviços não for desejada, desative-a com DisableImplicitFromServicesParameters.
Para especificar explicitamente quais parâmetros são resolvidos a partir de DI em métodos de hub, use a opção DisableImplicitFromServicesParameters e aplique o atributo [FromServices] ou um atributo personalizado que implemente IFromServiceMetadata nos parâmetros do método de hub que devem ser resolvidos a partir de DI.
services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();
services.AddSignalR(options =>
{
options.DisableImplicitFromServicesParameters = true;
});
// ...
public class ChatHub : Hub
{
public Task SendMessage(string user, string message,
[FromServices] IDatabaseService dbService)
{
var userName = dbService.GetUserName(user);
return Clients.All.SendAsync("ReceiveMessage", userName, message);
}
}
Note
Este recurso faz uso do IServiceProviderIsService, que é opcionalmente implementado por implementações DI. Se o contêiner DI do aplicativo não oferecer suporte a esse recurso, não há suporte para injetar serviços em métodos de hub.
Suporte para serviços chaveados na injeção de dependências
Serviços identificados por chaves refere-se a um mecanismo para registar e recuperar serviços de injeção de dependência (DI) usando chaves. Um serviço é associado a uma chave chamando AddKeyedSingleton (ou AddKeyedScoped ou AddKeyedTransient) para registrá-lo. Acesse um serviço registrado especificando a chave com o atributo [FromKeyedServices]. O código a seguir mostra como usar serviços com chave:
using Microsoft.AspNetCore.SignalR;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddKeyedSingleton<ICache, BigCache>("big");
builder.Services.AddKeyedSingleton<ICache, SmallCache>("small");
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
var app = builder.Build();
app.MapRazorPages();
app.MapHub<MyHub>("/myHub");
app.Run();
public interface ICache
{
object Get(string key);
}
public class BigCache : ICache
{
public object Get(string key) => $"Resolving {key} from big cache.";
}
public class SmallCache : ICache
{
public object Get(string key) => $"Resolving {key} from small cache.";
}
public class MyHub : Hub
{
public void SmallCacheMethod([FromKeyedServices("small")] ICache cache)
{
Console.WriteLine(cache.Get("signalr"));
}
public void BigCacheMethod([FromKeyedServices("big")] ICache cache)
{
Console.WriteLine(cache.Get("signalr"));
}
}
Gerir eventos para uma conexão
A SignalR API de Hubs fornece os OnConnectedAsync métodos virtuais OnDisconnectedAsync para gerir e monitorizar conexões. Substitua o OnConnectedAsync método virtual para executar ações quando um cliente se conecta ao hub, como adicioná-lo a um grupo:
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 desligar. Se o cliente se desconectar intencionalmente, como chamando connection.stop(), o exception parâmetro será definido como null. No entanto, se o cliente se desconectar devido a um erro, como uma falha de rede, o exception parâmetro contém uma exceção que descreve a falha:
public override async Task OnDisconnectedAsync(Exception? exception)
{
await base.OnDisconnectedAsync(exception);
}
RemoveFromGroupAsync não precisa ser chamado em OnDisconnectedAsync, é tratado automaticamente.
Lidar com erros
As exceções geradas nos métodos do hub são enviadas para o cliente que invocou o método. No cliente JavaScript, o invoke método retorna um JavaScript Promise. Os clientes podem anexar um catch manipulador à promessa retornada ou usar try/catch com async/await para lidar com exceções:
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
As conexões não são fechadas quando um hub lança uma exceção. Por padrão, SignalR retorna uma mensagem de erro genérica para o cliente, conforme mostrado no exemplo a seguir:
Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'SendMessage' 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 acionada quando a conexão de banco de dados falha. SignalR não expõe essas mensagens de erro detalhadas por padrão como medida de segurança. Para obter mais informações sobre por que os detalhes da exceção são suprimidos, consulte Considerações de segurança no ASP.NET Core SignalR.
Se uma condição excecional deve ser propagada para o cliente, use a HubException classe. Se um HubException for lançado em um método de hub, SignalRenviará toda a mensagem de exceção para o cliente, sem modificações:
public Task ThrowException()
=> throw new HubException("This error will be sent to the client!");
Note
SignalR apenas envia a Message propriedade da exceção para o cliente. O rastreamento de pilha e outras propriedades da exceção não estão disponíveis para o cliente.
Recursos adicionais
Por Rachel Appel e Kevin Griffin
A SignalR API de Hubs permite que clientes conectados chamem métodos no servidor, facilitando a comunicação em tempo real. O servidor define métodos que são chamados pelo cliente e o cliente define métodos que são chamados pelo servidor. SignalR também permite a SignalR comunicação indireta cliente-a-cliente, sempre mediada pelo Hub, permitindo que mensagens sejam enviadas entre clientes individuais, grupos ou para todos os clientes conectados. SignalR Cuida de tudo o que é necessário para tornar possível a comunicação cliente-servidor e servidor-cliente em tempo real.
Configuração de SignalR hubs
Para registar os serviços requeridos pelos SignalR hubs, ligue para AddSignalR em Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
Para configurar os SignalR endpoints, ligue para MapHub, também em Program.cs:
app.MapRazorPages();
app.MapHub<ChatHub>("/Chat");
app.Run();
Note
As assemblies do lado do servidor do ASP.NET Core SignalR agora são instaladas com o SDK do .NET Core. Consulte SignalR conjuntos na estrutura comum para mais informações.
Criar e usar hubs
Crie um hub declarando uma classe que herda do Hub. Adicione public métodos à classe para torná-los chamáveis pelos clientes.
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
}
Note
Os hubs são transitórios:
- Não armazene o estado numa propriedade da classe Hub. Cada chamada de método de hub é executada em uma nova instância de hub.
- Não instancie um hub diretamente por meio de injeção de dependência. Para enviar mensagens para um cliente de outro lugar na sua aplicação, use um
IHubContext. - Use
awaitao chamar métodos assíncronos que dependem de o hub permanecer ativo. Por exemplo, um método comoClients.All.SendAsync(...)pode falhar se for chamado semawaite o método da hub for concluído antes deSendAsyncterminar.
O objeto Context
A Hub classe inclui uma Context propriedade que contém as seguintes propriedades com informações sobre a conexão:
| Property | Description |
|---|---|
| ConnectionId | Obtém a ID exclusiva para a conexão, atribuída por SignalR. Há um ID de conexão para cada conexão. |
| UserIdentifier | Obtém o identificador de usuário. Por padrão, SignalR utiliza o ClaimTypes.NameIdentifier da ClaimsPrincipal associada à conexão como identificador de usuário. |
| User | Obtém o ClaimsPrincipal associado com o usuário atual. |
| Items | Obtém uma coleção de chave/valor que pode ser usada para compartilhar dados dentro do escopo dessa conexão. Os dados podem ser armazenados nessa coleção e persistirão no âmbito da conexão entre diferentes invocações de método de hub. |
| Features | Obtém a coleção de recursos disponíveis na conexão. Por enquanto, essa coleção não é necessária na maioria dos cenários, portanto, ainda não está documentada em detalhes. |
| ConnectionAborted | Obtém um CancellationToken que avisa quando a conexão é interrompida. |
Hub.Context também contém os seguintes métodos:
| Method | Description |
|---|---|
| GetHttpContext | Retorna o HttpContext para a conexão ou null se a conexão não estiver associada a uma solicitação HTTP. Para conexões HTTP, use esse método para obter informações como cabeçalhos HTTP e cadeias de caracteres de consulta. |
| Abort | Anula a ligação. |
O objeto Clients
A Hub classe inclui uma Clients propriedade que contém as seguintes propriedades para comunicação entre servidor e cliente:
| Property | Description |
|---|---|
| All | Chama um método em todos os clientes conectados |
| Caller | Chama um método no cliente que invocou o método hub |
| Others | Chama um método em todos os clientes conectados, exceto o cliente que invocou o método |
Hub.Clients também contém os seguintes métodos:
| Method | Description |
|---|---|
| AllExcept | Chama um método em todos os clientes conectados, exceto para as conexões especificadas |
| Client | Chama um método em um cliente conectado específico |
| Clients | Chama um método em clientes conectados específicos |
| Group | Chama um método em todas as conexões no grupo especificado |
| GroupExcept | Chama um método em todas as conexões no grupo especificado, exceto as conexões especificadas |
| Groups | Chama um método em vários grupos de conexões |
| OthersInGroup | Chama um método em um grupo de conexões, excluindo o cliente que invocou o método hub |
| User | Chama um método em todas as conexões associadas a um usuário específico |
| Users | Chama um método em todas as conexões associadas aos usuários especificados |
Cada propriedade ou método nas tabelas anteriores retorna um objeto com um SendAsync método. O método SendAsync recebe o nome do método do cliente a chamar e quaisquer parâmetros.
O objeto retornado pelos Client métodos e Caller também contém um InvokeAsync método, que pode ser usado para aguardar um resultado do cliente.
Enviar mensagens aos clientes
Para fazer chamadas para clientes específicos, use as Clients propriedades do objeto. No exemplo a seguir, há três métodos de hub:
-
SendMessageenvia uma mensagem para todos os clientes ligados, usandoClients.All. -
SendMessageToCallerenvia uma mensagem de volta para o chamador, usandoClients.Caller. -
SendMessageToGroupEnvia uma mensagem para todos os clientes doSignalR Usersgrupo.
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
Hubs fortemente tipados
Uma desvantagem do uso SendAsync é que ele depende de uma cadeia de caracteres para especificar o método de cliente a ser chamado. Isso deixa o código aberto para erros de tempo de execução se o nome do método estiver escrito incorretamente ou ausente do cliente.
Uma alternativa ao uso SendAsync é digitar fortemente a Hub classe com Hub<T>. No exemplo a seguir, o método cliente ChatHub foi extraído para uma interface chamada IChatClient:
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
}
Esta interface pode ser usada para refatorar o exemplo anterior ChatHub para ser fortemente tipado:
public class StronglyTypedChatHub : Hub<IChatClient>
{
public async Task SendMessage(string user, string message)
=> await Clients.All.ReceiveMessage(user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.ReceiveMessage(user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").ReceiveMessage(user, message);
}
O uso Hub<IChatClient> permite a verificação em tempo de compilação dos métodos do cliente. Isso evita problemas causados pelo uso de cadeias de caracteres, uma vez que Hub<T> só pode fornecer acesso aos métodos definidos na interface. Usar um tipo fortemente definido Hub<T> desativa a capacidade de usar SendAsync.
Note
O Async sufixo não é removido dos nomes dos métodos. A menos que um método de cliente seja definido com .on('MyMethodAsync'), não use MyMethodAsync como o nome.
Resultados do cliente
Além de fazer chamadas para clientes, o servidor pode solicitar um resultado de um cliente. Isso requer que o servidor use ISingleClientProxy.InvokeAsync e o cliente retorne um resultado de seu manipulador de .On.
Há duas maneiras de usar a API no servidor, a primeira é chamar Client(...) ou Caller na Clients propriedade em um método Hub:
public class ChatHub : Hub
{
public async Task<string> WaitForMessage(string connectionId)
{
var message = await Clients.Client(connectionId).InvokeAsync<string>(
"GetMessage");
return message;
}
}
A segunda maneira é invocar Client(...) numa instância de IHubContext<T>:
async Task SomeMethod(IHubContext<MyHub> context)
{
string result = await context.Clients.Client(connectionID).InvokeAsync<string>(
"GetMessage");
}
Hubs fortemente tipados também podem retornar valores de métodos de interface:
public interface IClient
{
Task<string> GetMessage();
}
public class ChatHub : Hub<IClient>
{
public async Task<string> WaitForMessage(string connectionId)
{
string message = await Clients.Client(connectionId).GetMessage();
return message;
}
}
Os clientes retornam resultados em seus .On(...) manipuladores, conforme mostrado abaixo:
Cliente .NET
hubConnection.On("GetMessage", async () =>
{
Console.WriteLine("Enter message:");
var message = await Console.In.ReadLineAsync();
return message;
});
Cliente Typescript
hubConnection.on("GetMessage", async () => {
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("message");
}, 100);
});
return promise;
});
Cliente Java
hubConnection.onWithResult("GetMessage", () -> {
return Single.just("message");
});
Alterar o nome de um método de hub
Por padrão, um nome de método de hub de servidor é o nome do método .NET. Para alterar esse comportamento padrão para um método específico, use o atributo HubMethodName . O cliente deve usar esse nome em vez do nome do método .NET ao invocar o método:
[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
=> await Clients.User(user).SendAsync("ReceiveMessage", user, message);
Injetar serviços em um hub
Os construtores de hub podem aceitar serviços de DI como parâmetros, que podem ser armazenados em propriedades na classe para uso em um método de hub.
Ao injetar vários serviços para diferentes métodos de hub ou como uma maneira alternativa de escrever código, os métodos de hub também podem aceitar serviços de DI. Por padrão, os parâmetros do método hub são inspecionados e resolvidos a partir da DI, se possível.
services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();
// ...
public class ChatHub : Hub
{
public Task SendMessage(string user, string message, IDatabaseService dbService)
{
var userName = dbService.GetUserName(user);
return Clients.All.SendAsync("ReceiveMessage", userName, message);
}
}
Se a resolução implícita de parâmetros de serviços não for desejada, desative-a com DisableImplicitFromServicesParameters.
Para especificar explicitamente quais parâmetros são resolvidos a partir de DI em métodos de hub, use a opção DisableImplicitFromServicesParameters e aplique o atributo [FromServices] ou um atributo personalizado que implemente IFromServiceMetadata nos parâmetros do método de hub que devem ser resolvidos a partir de DI.
services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();
services.AddSignalR(options =>
{
options.DisableImplicitFromServicesParameters = true;
});
// ...
public class ChatHub : Hub
{
public Task SendMessage(string user, string message,
[FromServices] IDatabaseService dbService)
{
var userName = dbService.GetUserName(user);
return Clients.All.SendAsync("ReceiveMessage", userName, message);
}
}
Note
Este recurso faz uso do IServiceProviderIsService, que é opcionalmente implementado por implementações DI. Se o contêiner DI do aplicativo não oferecer suporte a esse recurso, não há suporte para injetar serviços em métodos de hub.
Gerir eventos para uma conexão
A SignalR API de Hubs fornece os OnConnectedAsync métodos virtuais OnDisconnectedAsync para gerir e monitorizar conexões. Substitua o OnConnectedAsync método virtual para executar ações quando um cliente se conecta ao hub, como adicioná-lo a um grupo:
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 desligar. Se o cliente se desconectar intencionalmente, como chamando connection.stop(), o exception parâmetro será definido como null. No entanto, se o cliente se desconectar devido a um erro, como uma falha de rede, o exception parâmetro contém uma exceção que descreve a falha:
public override async Task OnDisconnectedAsync(Exception? exception)
{
await base.OnDisconnectedAsync(exception);
}
RemoveFromGroupAsync não precisa ser chamado em OnDisconnectedAsync, é tratado automaticamente por si.
Lidar com erros
As exceções geradas nos métodos do hub são enviadas para o cliente que invocou o método. No cliente JavaScript, o invoke método retorna um JavaScript Promise. Os clientes podem anexar um catch manipulador à promessa retornada ou usar try/catch com async/await para lidar com exceções:
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
As conexões não são fechadas quando um hub lança uma exceção. Por padrão, SignalR retorna uma mensagem de erro genérica para o cliente, conforme mostrado no exemplo a seguir:
Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'SendMessage' 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 acionada quando a conexão de banco de dados falha. SignalR não expõe essas mensagens de erro detalhadas por padrão como medida de segurança. Para obter mais informações sobre por que os detalhes da exceção são suprimidos, consulte Considerações de segurança no ASP.NET Core SignalR.
Se uma condição excecional deve ser propagada para o cliente, use a HubException classe. Se um HubException for lançado em um método de hub, SignalRenviará toda a mensagem de exceção para o cliente, sem modificações:
public Task ThrowException()
=> throw new HubException("This error will be sent to the client!");
Note
SignalR apenas envia a Message propriedade da exceção para o cliente. O rastreamento de pilha e outras propriedades da exceção não estão disponíveis para o cliente.
Recursos adicionais
Por Rachel Appel e Kevin Griffin
A SignalR API de Hubs permite que clientes conectados chamem métodos no servidor, facilitando a comunicação em tempo real. O servidor define métodos que são chamados pelo cliente e o cliente define métodos que são chamados pelo servidor. SignalR também permite a SignalR comunicação indireta cliente-a-cliente, sempre mediada pelo Hub, permitindo que mensagens sejam enviadas entre clientes individuais, grupos ou para todos os clientes conectados. SignalR Cuida de tudo o que é necessário para tornar possível a comunicação cliente-servidor e servidor-cliente em tempo real.
Configuração de SignalR hubs
Para registar os serviços requeridos pelos SignalR hubs, ligue para AddSignalR em Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
Para configurar os SignalR endpoints, ligue para MapHub, também em Program.cs:
app.MapRazorPages();
app.MapHub<ChatHub>("/Chat");
app.Run();
Note
As assemblies do lado do servidor do ASP.NET Core SignalR agora são instaladas com o SDK do .NET Core. Consulte SignalR conjuntos na estrutura comum para mais informações.
Criar e usar hubs
Crie um hub declarando uma classe que herda do Hub. Adicione public métodos à classe para torná-los chamáveis pelos clientes.
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
}
Note
Os hubs são transitórios:
- Não armazene o estado numa propriedade da classe Hub. Cada chamada de método de hub é executada em uma nova instância de hub.
- Não instancie um hub diretamente por meio de injeção de dependência. Para enviar mensagens para um cliente de outro lugar na sua aplicação, use um
IHubContext. - Use
awaitao chamar métodos assíncronos que dependem de o hub permanecer ativo. Por exemplo, um método comoClients.All.SendAsync(...)pode falhar se for chamado semawaite o método da hub for concluído antes deSendAsyncterminar.
O objeto Context
A Hub classe inclui uma Context propriedade que contém as seguintes propriedades com informações sobre a conexão:
| Property | Description |
|---|---|
| ConnectionId | Obtém a ID exclusiva para a conexão, atribuída por SignalR. Há um ID de conexão para cada conexão. |
| UserIdentifier | Obtém o identificador de usuário. Por padrão, SignalR utiliza o ClaimTypes.NameIdentifier da ClaimsPrincipal associada à conexão como identificador de usuário. |
| User | Obtém o ClaimsPrincipal associado com o usuário atual. |
| Items | Obtém uma coleção de chave/valor que pode ser usada para compartilhar dados dentro do escopo dessa conexão. Os dados podem ser armazenados nessa coleção e persistirão no âmbito da conexão entre diferentes invocações de método de hub. |
| Features | Obtém a coleção de recursos disponíveis na conexão. Por enquanto, essa coleção não é necessária na maioria dos cenários, portanto, ainda não está documentada em detalhes. |
| ConnectionAborted | Obtém um CancellationToken que avisa quando a conexão é interrompida. |
Hub.Context também contém os seguintes métodos:
| Method | Description |
|---|---|
| GetHttpContext | Retorna o HttpContext para a conexão ou null se a conexão não estiver associada a uma solicitação HTTP. Para conexões HTTP, use esse método para obter informações como cabeçalhos HTTP e cadeias de caracteres de consulta. |
| Abort | Anula a ligação. |
O objeto Clients
A Hub classe inclui uma Clients propriedade que contém as seguintes propriedades para comunicação entre servidor e cliente:
| Property | Description |
|---|---|
| All | Chama um método em todos os clientes conectados |
| Caller | Chama um método no cliente que invocou o método hub |
| Others | Chama um método em todos os clientes conectados, exceto o cliente que invocou o método |
Hub.Clients também contém os seguintes métodos:
| Method | Description |
|---|---|
| AllExcept | Chama um método em todos os clientes conectados, exceto para as conexões especificadas |
| Client | Chama um método em um cliente conectado específico |
| Clients | Chama um método em clientes conectados específicos |
| Group | Chama um método em todas as conexões no grupo especificado |
| GroupExcept | Chama um método em todas as conexões no grupo especificado, exceto as conexões especificadas |
| Groups | Chama um método em vários grupos de conexões |
| OthersInGroup | Chama um método em um grupo de conexões, excluindo o cliente que invocou o método hub |
| User | Chama um método em todas as conexões associadas a um usuário específico |
| Users | Chama um método em todas as conexões associadas aos usuários especificados |
Cada propriedade ou método nas tabelas anteriores retorna um objeto com um SendAsync método. O método SendAsync recebe o nome do método do cliente a chamar e quaisquer parâmetros.
Enviar mensagens aos clientes
Para fazer chamadas para clientes específicos, use as Clients propriedades do objeto. No exemplo a seguir, há três métodos de hub:
-
SendMessageenvia uma mensagem para todos os clientes ligados, usandoClients.All. -
SendMessageToCallerenvia uma mensagem de volta para o chamador, usandoClients.Caller. -
SendMessageToGroupEnvia uma mensagem para todos os clientes doSignalR Usersgrupo.
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
Hubs fortemente tipados
Uma desvantagem do uso SendAsync é que ele depende de uma cadeia de caracteres para especificar o método de cliente a ser chamado. Isso deixa o código aberto para erros de tempo de execução se o nome do método estiver escrito incorretamente ou ausente do cliente.
Uma alternativa ao uso SendAsync é digitar fortemente a Hub classe com Hub<T>. No exemplo a seguir, o método cliente ChatHub foi extraído para uma interface chamada IChatClient:
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
}
Esta interface pode ser usada para refatorar o exemplo anterior ChatHub para ser fortemente tipado:
public class StronglyTypedChatHub : Hub<IChatClient>
{
public async Task SendMessage(string user, string message)
=> await Clients.All.ReceiveMessage(user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.ReceiveMessage(user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").ReceiveMessage(user, message);
}
O uso Hub<IChatClient> permite a verificação em tempo de compilação dos métodos do cliente. Isso evita problemas causados pelo uso de cadeias de caracteres, uma vez que Hub<T> só pode fornecer acesso aos métodos definidos na interface. Usar um tipo fortemente definido Hub<T> desativa a capacidade de usar SendAsync.
Note
O Async sufixo não é removido dos nomes dos métodos. A menos que um método de cliente seja definido com .on('MyMethodAsync'), não use MyMethodAsync como o nome.
Alterar o nome de um método de hub
Por padrão, um nome de método de hub de servidor é o nome do método .NET. Para alterar esse comportamento padrão para um método específico, use o atributo HubMethodName . O cliente deve usar esse nome em vez do nome do método .NET ao invocar o método:
[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
=> await Clients.User(user).SendAsync("ReceiveMessage", user, message);
Gerir eventos para uma conexão
A SignalR API de Hubs fornece os OnConnectedAsync métodos virtuais OnDisconnectedAsync para gerir e monitorizar conexões. Substitua o OnConnectedAsync método virtual para executar ações quando um cliente se conecta ao hub, como adicioná-lo a um grupo:
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 desligar. Se o cliente se desconectar intencionalmente, como chamando connection.stop(), o exception parâmetro será definido como null. No entanto, se o cliente se desconectar devido a um erro, como uma falha de rede, o exception parâmetro contém uma exceção que descreve a falha:
public override async Task OnDisconnectedAsync(Exception? exception)
{
await base.OnDisconnectedAsync(exception);
}
RemoveFromGroupAsync não precisa ser chamado em OnDisconnectedAsync, é tratado automaticamente por si.
Lidar com erros
As exceções geradas nos métodos do hub são enviadas para o cliente que invocou o método. No cliente JavaScript, o invoke método retorna um JavaScript Promise. Os clientes podem anexar um catch manipulador à promessa retornada ou usar try/catch com async/await para lidar com exceções:
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
As conexões não são fechadas quando um hub lança uma exceção. Por padrão, SignalR retorna uma mensagem de erro genérica para o cliente, conforme mostrado no exemplo a seguir:
Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'SendMessage' 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 acionada quando a conexão de banco de dados falha. SignalR não expõe essas mensagens de erro detalhadas por padrão como medida de segurança. Para obter mais informações sobre por que os detalhes da exceção são suprimidos, consulte Considerações de segurança no ASP.NET Core SignalR.
Se uma condição excecional deve ser propagada para o cliente, use a HubException classe. Se um HubException for lançado em um método de hub, SignalRenviará toda a mensagem de exceção para o cliente, sem modificações:
public Task ThrowException()
=> throw new HubException("This error will be sent to the client!");
Note
SignalR apenas envia a Message propriedade da exceção para o cliente. O rastreamento de pilha e outras propriedades da exceção não estão disponíveis para o cliente.
Recursos adicionais
Por Rachel Appel e Kevin Griffin
Ver ou baixar código de exemplo(como baixar)
O que é um SignalR hub
A SignalR API de Hubs permite que clientes conectados chamem métodos no servidor, facilitando a comunicação em tempo real. O servidor define métodos que são chamados pelo cliente e o cliente define métodos que são chamados pelo servidor. SignalR também permite a SignalR comunicação indireta cliente-a-cliente, sempre mediada pelo Hub, permitindo que mensagens sejam enviadas entre clientes individuais, grupos ou para todos os clientes conectados. SignalR Cuida de tudo o que é necessário para tornar possível a comunicação cliente-servidor e servidor-cliente em tempo real.
Configuração de SignalR hubs
O SignalR middleware requer alguns serviços, que são configurados chamando AddSignalR:
services.AddSignalR();
Ao adicionar SignalR funcionalidade a uma aplicação ASP.NET Core, configure as rotas SignalR chamando MapHub no retorno de chamada Startup.Configure do método UseEndpoints:
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<ChatHub>("/chathub");
});
Note
As assemblies do lado do servidor do ASP.NET Core SignalR agora são instaladas com o SDK do .NET Core. Consulte SignalR conjuntos na estrutura comum para mais informações.
Criar e usar hubs
Crie um hub declarando uma classe que herda do Hube adicione métodos públicos a ele. Os clientes podem chamar métodos definidos como 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 e matrizes complexos, como faria em qualquer método C#. SignalR lida com a serialização e desserialização de objetos complexos e matrizes em seus parâmetros e valores de retorno.
Note
Os hubs são transitórios:
- Não armazene o estado em uma propriedade na classe do hub. Cada chamada de método de hub é executada em uma nova instância de hub.
- Não instancie um hub diretamente por meio de injeção de dependência. Para enviar mensagens para um cliente de outro lugar na sua aplicação, use um
IHubContext. - Use
awaitao chamar métodos assíncronos que dependem de o hub permanecer ativo. Por exemplo, um método comoClients.All.SendAsync(...)pode falhar se for chamado semawaite o método da hub for concluído antes deSendAsyncterminar.
O objeto Context
A Hub classe tem uma Context propriedade que contém as seguintes propriedades com informações sobre a conexão:
| Property | Description |
|---|---|
| ConnectionId | Obtém a ID exclusiva para a conexão, atribuída por SignalR. Há um ID de conexão para cada conexão. |
| UserIdentifier | Obtém o identificador de usuário. Por padrão, SignalR utiliza o ClaimTypes.NameIdentifier da ClaimsPrincipal associada à conexão como identificador de usuário. |
| User | Obtém o ClaimsPrincipal associado com o usuário atual. |
| Items | Obtém uma coleção de chave/valor que pode ser usada para compartilhar dados dentro do escopo dessa conexão. Os dados podem ser armazenados nessa coleção e persistirão no âmbito da conexão entre diferentes invocações de método de hub. |
| Features | Obtém a coleção de recursos disponíveis na conexão. Por enquanto, essa coleção não é necessária na maioria dos cenários, portanto, ainda não está documentada em detalhes. |
| ConnectionAborted | Obtém um CancellationToken que avisa quando a conexão é interrompida. |
Hub.Context também contém os seguintes métodos:
| Method | Description |
|---|---|
| GetHttpContext | Retorna o HttpContext para a conexão ou null se a conexão não estiver associada a uma solicitação HTTP. Para conexões HTTP, você pode usar esse método para obter informações como cabeçalhos HTTP e cadeias de caracteres de consulta. |
| Abort | Anula a ligação. |
O objeto Clients
A Hub classe tem uma Clients propriedade que contém as seguintes propriedades para comunicação entre servidor e cliente:
| Property | Description |
|---|---|
| All | Chama um método em todos os clientes conectados |
| Caller | Chama um método no cliente que invocou o método hub |
| Others | Chama um método em todos os clientes conectados, exceto o cliente que invocou o método |
Hub.Clients também contém os seguintes métodos:
| Method | Description |
|---|---|
| AllExcept | Chama um método em todos os clientes conectados, exceto para as conexões especificadas |
| Client | Chama um método em um cliente conectado específico |
| Clients | Chama um método em clientes conectados específicos |
| Group | Chama um método em todas as conexões no grupo especificado |
| GroupExcept | Chama um método em todas as conexões no grupo especificado, exceto as conexões especificadas |
| Groups | Chama um método em vários grupos de conexões |
| OthersInGroup | Chama um método em um grupo de conexões, excluindo o cliente que invocou o método hub |
| User | Chama um método em todas as conexões associadas a um usuário específico |
| Users | Chama um método em todas as conexões associadas aos usuários especificados |
Cada propriedade ou método nas tabelas anteriores retorna um objeto com um SendAsync método. O SendAsync método permite que você forneça o nome e os parâmetros do método cliente para chamar.
Enviar mensagens aos clientes
Para fazer chamadas para clientes específicos, use as Clients propriedades do objeto. No exemplo a seguir, há três métodos Hub:
-
SendMessageenvia uma mensagem para todos os clientes ligados, usandoClients.All. -
SendMessageToCallerenvia uma mensagem de volta para o chamador, usandoClients.Caller. -
SendMessageToGroupEnvia uma mensagem para todos os clientes doSignalR Usersgrupo.
public Task SendMessage(string user, string message)
{
return Clients.All.SendAsync("ReceiveMessage", user, message);
}
public Task SendMessageToCaller(string user, string message)
{
return Clients.Caller.SendAsync("ReceiveMessage", user, message);
}
public Task SendMessageToGroup(string user, string message)
{
return Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
}
Hubs fortemente tipados
Uma desvantagem do uso SendAsync é que ele depende de uma cadeia de caracteres mágica para especificar o método de cliente a ser chamado. Isso deixa o código aberto para erros de tempo de execução se o nome do método estiver escrito incorretamente ou ausente do cliente.
Uma alternativa ao uso SendAsync é digitar fortemente o Hub com Hub<T>. No exemplo a seguir, os métodos do cliente foram extraídos para uma interface chamada ChatHub.
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
}
Esta interface pode ser usada para refatorar o exemplo anterior ChatHub :
public class StronglyTypedChatHub : Hub<IChatClient>
{
public async Task SendMessage(string user, string message)
{
await Clients.All.ReceiveMessage(user, message);
}
public Task SendMessageToCaller(string user, string message)
{
return Clients.Caller.ReceiveMessage(user, message);
}
}
O uso Hub<IChatClient> permite a verificação em tempo de compilação dos métodos do cliente. Isso evita problemas causados pelo uso de strings mágicas, uma vez que Hub<T> só pode fornecer acesso aos métodos definidos na interface.
Usar um tipo fortemente definido Hub<T> desativa a capacidade de usar SendAsync. Todos os métodos definidos na interface ainda podem ser definidos como assíncronos. Na verdade, cada um desses métodos deve retornar um Task. Como é uma interface, não use a async palavra-chave. Por exemplo:
public interface IClient
{
Task ClientMethod();
}
Note
O Async sufixo não é removido do nome do método. A menos que seu método de cliente seja definido com .on('MyMethodAsync'), você não deve usar MyMethodAsync como um nome.
Alterar o nome de um método de hub
Por padrão, um nome de método de hub de servidor é o nome do método .NET. No entanto, você pode usar o atributo HubMethodName para alterar esse padrão e especificar manualmente um nome para o método. O cliente deve usar esse nome, em vez do nome do método .NET, ao invocar o método:
[HubMethodName("SendMessageToUser")]
public Task DirectMessage(string user, string message)
{
return Clients.User(user).SendAsync("ReceiveMessage", user, message);
}
Gerir eventos para uma conexão
A SignalR API de Hubs fornece os OnConnectedAsync métodos virtuais OnDisconnectedAsync para gerir e monitorizar conexões. Substitua o OnConnectedAsync método virtual para executar ações quando um cliente se conecta ao Hub, como adicioná-lo a um grupo:
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 desligar. Se o cliente se desconectar intencionalmente (chamando connection.stop(), por exemplo), o exception parâmetro será null. No entanto, se o cliente for desconectado devido a um erro (como uma falha de rede), o exception parâmetro conterá uma exceção descrevendo a falha:
public override async Task OnDisconnectedAsync(Exception exception)
{
await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", "I", "disconnect");
await base.OnDisconnectedAsync(exception);
}
RemoveFromGroupAsync não precisa ser chamado em OnDisconnectedAsync, é tratado automaticamente por si.
Warning
Aviso de segurança: Expor ConnectionId pode resultar em falsificação maliciosa se a versão do SignalR servidor ou cliente for ASP.NET Core 2.2 ou versões anteriores.
Lidar com erros
As exceções lançadas nos métodos do seu hub são enviadas para o cliente que invocou o método. No cliente JavaScript, o invoke método retorna um JavaScript Promise. Quando o cliente recebe um erro com um manipulador anexado à promessa utilizando catch, ele é invocado e passado como um objeto JavaScript Error:
connection.invoke("SendMessage", user, message).catch(err => console.error(err));
Se o Hub gerar uma exceção, as conexões não serão fechadas. Por padrão, SignalR retorna uma mensagem de erro genérica para o cliente. Por exemplo:
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 acionada quando a conexão de banco de dados falha. SignalR não expõe essas mensagens de erro detalhadas por padrão como medida de segurança. Para obter mais informações sobre por que os detalhes da exceção são suprimidos, consulte Considerações de segurança no ASP.NET Core SignalR.
Se você tiver uma condição excecional que deseja propagar para o cliente, poderá usar a HubException classe. Se você lançar um HubException do seu método de hub, SignalRenviará a mensagem inteira para o cliente, sem modificações:
public Task ThrowException()
{
throw new HubException("This error will be sent to the client!");
}
Note
SignalR apenas envia a Message propriedade da exceção para o cliente. O rastreamento de pilha e outras propriedades da exceção não estão disponíveis para o cliente.
Recursos adicionais
Por Rachel Appel e Kevin Griffin
Ver ou baixar código de exemplo(como baixar)
O que é um SignalR hub
A SignalR API de Hubs permite que clientes conectados chamem métodos no servidor, facilitando a comunicação em tempo real. O servidor define métodos que são chamados pelo cliente e o cliente define métodos que são chamados pelo servidor. SignalR também permite a SignalR comunicação indireta cliente-a-cliente, sempre mediada pelo Hub, permitindo que mensagens sejam enviadas entre clientes individuais, grupos ou para todos os clientes conectados. SignalR Cuida de tudo o que é necessário para tornar possível a comunicação cliente-servidor e servidor-cliente em tempo real.
Configuração de SignalR hubs
O SignalR middleware requer alguns serviços, que são configurados chamando AddSignalR:
services.AddSignalR();
Ao adicionar SignalR funcionalidade a um aplicativo ASP.NET Core, configure SignalR rotas chamando UseSignalR no método Startup.Configure.
app.UseSignalR(route =>
{
route.MapHub<ChatHub>("/chathub");
});
Criar e usar hubs
Crie um hub declarando uma classe que herda do Hube adicione métodos públicos a ele. Os clientes podem chamar métodos definidos como 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 e matrizes complexos, como faria em qualquer método C#. SignalR lida com a serialização e desserialização de objetos complexos e matrizes em seus parâmetros e valores de retorno.
Note
Os hubs são transitórios:
- Não armazene o estado em uma propriedade na classe do hub. Cada chamada de método de hub é executada em uma nova instância de hub.
- Não instancie um hub diretamente por meio de injeção de dependência. Para enviar mensagens para um cliente de outro lugar na sua aplicação, use um
IHubContext. - Use
awaitao chamar métodos assíncronos que dependem de o hub permanecer ativo. Por exemplo, um método comoClients.All.SendAsync(...)pode falhar se for chamado semawaite o método da hub for concluído antes deSendAsyncterminar.
O objeto Context
A Hub classe tem uma Context propriedade que contém as seguintes propriedades com informações sobre a conexão:
| Property | Description |
|---|---|
| ConnectionId | Obtém a ID exclusiva para a conexão, atribuída por SignalR. Há um ID de conexão para cada conexão. |
| UserIdentifier | Obtém o identificador de usuário. Por padrão, SignalR utiliza o ClaimTypes.NameIdentifier da ClaimsPrincipal associada à conexão como identificador de usuário. |
| User | Obtém o ClaimsPrincipal associado com o usuário atual. |
| Items | Obtém uma coleção de chave/valor que pode ser usada para compartilhar dados dentro do escopo dessa conexão. Os dados podem ser armazenados nessa coleção e persistirão no âmbito da conexão entre diferentes invocações de método de hub. |
| Features | Obtém a coleção de recursos disponíveis na conexão. Por enquanto, essa coleção não é necessária na maioria dos cenários, portanto, ainda não está documentada em detalhes. |
| ConnectionAborted | Obtém um CancellationToken que avisa quando a conexão é interrompida. |
Hub.Context também contém os seguintes métodos:
| Method | Description |
|---|---|
| GetHttpContext | Retorna o HttpContext para a conexão ou null se a conexão não estiver associada a uma solicitação HTTP. Para conexões HTTP, você pode usar esse método para obter informações como cabeçalhos HTTP e cadeias de caracteres de consulta. |
| Abort | Anula a ligação. |
O objeto Clients
A Hub classe tem uma Clients propriedade que contém as seguintes propriedades para comunicação entre servidor e cliente:
| Property | Description |
|---|---|
| All | Chama um método em todos os clientes conectados |
| Caller | Chama um método no cliente que invocou o método hub |
| Others | Chama um método em todos os clientes conectados, exceto o cliente que invocou o método |
Hub.Clients também contém os seguintes métodos:
| Method | Description |
|---|---|
| AllExcept | Chama um método em todos os clientes conectados, exceto para as conexões especificadas |
| Client | Chama um método em um cliente conectado específico |
| Clients | Chama um método em clientes conectados específicos |
| Group | Chama um método em todas as conexões no grupo especificado |
| GroupExcept | Chama um método em todas as conexões no grupo especificado, exceto as conexões especificadas |
| Groups | Chama um método em vários grupos de conexões |
| OthersInGroup | Chama um método em um grupo de conexões, excluindo o cliente que invocou o método hub |
| User | Chama um método em todas as conexões associadas a um usuário específico |
| Users | Chama um método em todas as conexões associadas aos usuários especificados |
Cada propriedade ou método nas tabelas anteriores retorna um objeto com um SendAsync método. O SendAsync método permite que você forneça o nome e os parâmetros do método cliente para chamar.
Enviar mensagens aos clientes
Para fazer chamadas para clientes específicos, use as Clients propriedades do objeto. No exemplo a seguir, há três métodos Hub:
-
SendMessageenvia uma mensagem para todos os clientes ligados, usandoClients.All. -
SendMessageToCallerenvia uma mensagem de volta para o chamador, usandoClients.Caller. -
SendMessageToGroupEnvia uma mensagem para todos os clientes doSignalR Usersgrupo.
public Task SendMessage(string user, string message)
{
return Clients.All.SendAsync("ReceiveMessage", user, message);
}
public Task SendMessageToCaller(string user, string message)
{
return Clients.Caller.SendAsync("ReceiveMessage", user, message);
}
public Task SendMessageToGroup(string user, string message)
{
return Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
}
Hubs fortemente tipados
Uma desvantagem do uso SendAsync é que ele depende de uma cadeia de caracteres mágica para especificar o método de cliente a ser chamado. Isso deixa o código aberto para erros de tempo de execução se o nome do método estiver escrito incorretamente ou ausente do cliente.
Uma alternativa ao uso SendAsync é digitar fortemente o Hub com Hub<T>. No exemplo a seguir, os métodos do cliente foram extraídos para uma interface chamada ChatHub.
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
}
Esta interface pode ser usada para refatorar o exemplo anterior ChatHub :
public class StronglyTypedChatHub : Hub<IChatClient>
{
public async Task SendMessage(string user, string message)
{
await Clients.All.ReceiveMessage(user, message);
}
public Task SendMessageToCaller(string user, string message)
{
return Clients.Caller.ReceiveMessage(user, message);
}
}
O uso Hub<IChatClient> permite a verificação em tempo de compilação dos métodos do cliente. Isso evita problemas causados pelo uso de strings mágicas, uma vez que Hub<T> só pode fornecer acesso aos métodos definidos na interface.
Usar um tipo fortemente definido Hub<T> desativa a capacidade de usar SendAsync. Todos os métodos definidos na interface ainda podem ser definidos como assíncronos. Na verdade, cada um desses métodos deve retornar um Task. Como é uma interface, não use a async palavra-chave. Por exemplo:
public interface IClient
{
Task ClientMethod();
}
Note
O Async sufixo não é removido do nome do método. A menos que seu método de cliente seja definido com .on('MyMethodAsync'), você não deve usar MyMethodAsync como um nome.
Alterar o nome de um método de hub
Por padrão, um nome de método de hub de servidor é o nome do método .NET. No entanto, você pode usar o atributo HubMethodName para alterar esse padrão e especificar manualmente um nome para o método. O cliente deve usar esse nome, em vez do nome do método .NET, ao invocar o método:
[HubMethodName("SendMessageToUser")]
public Task DirectMessage(string user, string message)
{
return Clients.User(user).SendAsync("ReceiveMessage", user, message);
}
Gerir eventos para uma conexão
A SignalR API de Hubs fornece os OnConnectedAsync métodos virtuais OnDisconnectedAsync para gerir e monitorizar conexões. Substitua o OnConnectedAsync método virtual para executar ações quando um cliente se conecta ao Hub, como adicioná-lo a um grupo:
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 desligar. Se o cliente se desconectar intencionalmente (chamando connection.stop(), por exemplo), o exception parâmetro será null. No entanto, se o cliente for desconectado devido a um erro (como uma falha de rede), o exception parâmetro conterá uma exceção descrevendo a falha:
public override async Task OnDisconnectedAsync(Exception exception)
{
await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", "I", "disconnect");
await base.OnDisconnectedAsync(exception);
}
RemoveFromGroupAsync não precisa ser chamado em OnDisconnectedAsync, é tratado automaticamente por si.
Warning
Aviso de segurança: Expor ConnectionId pode resultar em falsificação maliciosa se a versão do SignalR servidor ou cliente for ASP.NET Core 2.2 ou versões anteriores.
Lidar com erros
As exceções lançadas nos métodos do seu hub são enviadas para o cliente que invocou o método. No cliente JavaScript, o invoke método retorna um JavaScript Promise. Quando o cliente recebe um erro com um manipulador anexado à promessa utilizando catch, ele é invocado e passado como um objeto JavaScript Error:
connection.invoke("SendMessage", user, message).catch(err => console.error(err));
Se o Hub gerar uma exceção, as conexões não serão fechadas. Por padrão, SignalR retorna uma mensagem de erro genérica para o cliente. Por exemplo:
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 acionada quando a conexão de banco de dados falha. SignalR não expõe essas mensagens de erro detalhadas por padrão como medida de segurança. Para obter mais informações sobre por que os detalhes da exceção são suprimidos, consulte Considerações de segurança no ASP.NET Core SignalR.
Se você tiver uma condição excecional que deseja propagar para o cliente, poderá usar a HubException classe. Se você lançar um HubException do seu método de hub, SignalRenviará a mensagem inteira para o cliente, sem modificações:
public Task ThrowException()
{
throw new HubException("This error will be sent to the client!");
}
Note
SignalR apenas envia a Message propriedade da exceção para o cliente. O rastreamento de pilha e outras propriedades da exceção não estão disponíveis para o cliente.