Eventos
Junte-se a nós na FabCon Vegas
31 de mar., 23 - 2 de abr., 23
O melhor evento liderado pela comunidade Microsoft Fabric, Power BI, SQL e AI. 31 de março a 2 de abril de 2025.
Registre-se hoje mesmoNão há mais suporte para esse navegador.
Atualize o Microsoft Edge para aproveitar os recursos, o suporte técnico e as atualizações de segurança mais recentes.
Observação
Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 9 deste artigo.
Aviso
Esta versão do ASP.NET Core não tem mais suporte. Para obter mais informações, consulte a Política de Suporte do .NET e do .NET Core. Para a versão atual, consulte a versão .NET 9 deste artigo.
Importante
Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.
Para a versão atual, consulte a versão .NET 9 deste artigo.
Este artigo explica como começar a usar o WebSockets no ASP.NET Core. WebSocket (RFC 6455) é um protocolo que permite canais de comunicação persistentes bidirecionais em conexões TCP. Ele é usado em aplicativos que se beneficiam de comunicação rápida e em tempo real, como chat, painel e aplicativos de jogos.
Exibir ou fazer download do código de exemplo (como fazer download, como executar).
O uso de WebSockets por HTTP/2 aproveita novos recursos, como:
Esses recursos com suporte estão disponíveis no Kestrel em todas as plataformas habilitadas para HTTP/2. A negociação de versão é automática em navegadores e no Kestrel, ou seja, nenhuma nova API é necessária.
O .NET 7 introduziu o suporte do WebSockets por HTTP/2 a Kestrel, cliente JavaScript SignalR e SignalR com Blazor WebAssembly.
Observação
WebSockets HTTP/2 usam solicitações CONNECT em vez de GET, portanto, suas próprias rotas e controladores podem precisar de atualização. Para obter mais informações, consulte Adicionar suporte a WebSockets HTTP/2 para controladores existentes neste artigo.
O Chrome e o Edge têm WebSockets HTTP/2 habilitados por padrão e você pode habilitá-los no FireFox na página about:config
com o sinalizador network.http.spdy.websockets
.
WebSockets foram originalmente projetados para HTTP/1.1, mas desde então foram adaptados para funcionar via HTTP/2. (RFC 8441)
ASP.NET Core SignalR é uma biblioteca que simplifica a adição da funcionalidade da Web em tempo real aos aplicativos. Ele usa WebSockets sempre que possível.
Para a maioria dos aplicativos, recomendamos o SignalR ao invés de WebSockets brutos. SignalR:
Há suporte para WebSockets via HTTP/2 para:
Para alguns aplicativos, o gRPC no .NET fornece uma alternativa para WebSockets.
Adicione o middleware de WebSockets em Program.cs
:
app.UseWebSockets();
As seguintes configurações podem ser definidas:
var webSocketOptions = new WebSocketOptions
{
KeepAliveInterval = TimeSpan.FromMinutes(2)
};
app.UseWebSockets(webSocketOptions);
Futuramente no ciclo de vida da solicitação (mais tarde em Program.cs
ou em um método de ação, por exemplo), verifique se é uma solicitação do WebSocket e aceite-a.
O exemplo a seguir é de uma fase posterior em Program.cs
:
app.Use(async (context, next) =>
{
if (context.Request.Path == "/ws")
{
if (context.WebSockets.IsWebSocketRequest)
{
using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
await Echo(webSocket);
}
else
{
context.Response.StatusCode = StatusCodes.Status400BadRequest;
}
}
else
{
await next(context);
}
});
Uma solicitação do WebSocket pode entrar em qualquer URL, mas esse código de exemplo aceita apenas solicitações de /ws
.
Uma abordagem semelhante pode ser adotada em um método de controlador:
public class WebSocketController : ControllerBase
{
[Route("/ws")]
public async Task Get()
{
if (HttpContext.WebSockets.IsWebSocketRequest)
{
using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
await Echo(webSocket);
}
else
{
HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
}
}
Ao usar um WebSocket, você deve manter o pipeline de middleware em execução durante a conexão. Se tentar enviar ou receber uma mensagem do WebSocket após o término do pipeline de middleware, você poderá receber uma exceção semelhante à seguinte:
System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake. ---> System.ObjectDisposedException: Cannot write to the response body, the response has completed.
Object name: 'HttpResponseStream'.
Se você estiver usando um serviço em segundo plano para gravar dados em um WebSocket, mantenha o pipeline do middleware em execução. Faça isso usando um TaskCompletionSource<TResult>. Passe o TaskCompletionSource
ao seu serviço em segundo plano e faça-o chamar TrySetResult quando terminar com o WebSocket. Em seguida await
a propriedade Task durante a solicitação, conforme é mostrado no exemplo a seguir:
app.Run(async (context) =>
{
using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
var socketFinishedTcs = new TaskCompletionSource<object>();
BackgroundSocketProcessor.AddSocket(webSocket, socketFinishedTcs);
await socketFinishedTcs.Task;
});
A exceção fechada do WebSocket também poderá ocorrer ao retornar muito rapidamente de um método de ação. Ao aceitar um soquete de um método de ação, aguarde até que o código que usa o soquete seja concluído antes de retornar do método de ação.
Nunca use Task.Wait
, Task.Result
ou chamadas de bloqueio semelhantes para aguardar a conclusão do soquete, pois isso pode causar sérios problemas de threading. Sempre use await
.
O .NET 7 introduziu o suporte do WebSockets por HTTP/2 a Kestrel, cliente JavaScript SignalR e SignalR com Blazor WebAssembly. WebSockets HTTP/2 usam solicitações CONNECT em vez de GET. Se você usou [HttpGet("/path")]
anteriormente em seu método de ação do controlador para solicitações Websocket, atualize-o para usar [Route("/path")]
em vez disso.
public class WebSocketController : ControllerBase
{
[Route("/ws")]
public async Task Get()
{
if (HttpContext.WebSockets.IsWebSocketRequest)
{
using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
await Echo(webSocket);
}
else
{
HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
}
}
Aviso
Habilitar a compactação em conexões criptografadas pode tornar um aplicativo sujeito a ataques CRIME/BREACH.
Se estiver enviando informações confidenciais, evite habilitar a compactação ou use WebSocketMessageFlags.DisableCompression
ao chamar WebSocket.SendAsync
.
Isso se aplica a ambos os lados do WebSocket. Observe que a API dos WebSockets no navegador não tem configuração para desabilitar a compactação por envio.
Caso deseje fazer a compactação de mensagens por WebSockets, o código de aceitação deverá especificar que ele permite a compactação da seguinte maneira:
using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(
new WebSocketAcceptContext { DangerousEnableCompression = true }))
{
}
WebSocketAcceptContext.ServerMaxWindowBits
e WebSocketAcceptContext.DisableServerContextTakeover
são opções avançadas que controlam como a compactação funciona.
A compactação é negociada entre o cliente e o servidor ao estabelecer uma conexão pela primeira vez. Você pode ler mais sobre a negociação em Extensões de Compactação para WebSocket RFC.
Observação
Se a negociação de compactação não for aceita pelo servidor ou pelo cliente, a conexão ainda será estabelecida. No entanto, a conexão não usa compactação ao enviar e receber mensagens.
O método AcceptWebSocketAsync
atualiza a conexão TCP para uma conexão WebSocket e fornece um objeto WebSocket. Use o objeto WebSocket
para enviar e receber mensagens.
O código mostrado anteriormente que aceita a solicitação do WebSocket passa o objeto WebSocket
para um método Echo
. O código recebe uma mensagem e envia de volta imediatamente a mesma mensagem. As mensagens são enviadas e recebidas em um loop até que o cliente feche a conexão:
private static async Task Echo(WebSocket webSocket)
{
var buffer = new byte[1024 * 4];
var receiveResult = await webSocket.ReceiveAsync(
new ArraySegment<byte>(buffer), CancellationToken.None);
while (!receiveResult.CloseStatus.HasValue)
{
await webSocket.SendAsync(
new ArraySegment<byte>(buffer, 0, receiveResult.Count),
receiveResult.MessageType,
receiveResult.EndOfMessage,
CancellationToken.None);
receiveResult = await webSocket.ReceiveAsync(
new ArraySegment<byte>(buffer), CancellationToken.None);
}
await webSocket.CloseAsync(
receiveResult.CloseStatus.Value,
receiveResult.CloseStatusDescription,
CancellationToken.None);
}
Ao aceitar a conexão WebSocket antes de iniciar o loop, o pipeline de middleware é encerrado. Ao fechar o soquete, o pipeline é desenrolado. Ou seja, a solicitação deixa de avançar no pipeline quando o WebSocket é aceito. Quando o loop é concluído e o soquete é fechado, a solicitação continua a avançar no pipeline.
O servidor não é informado automaticamente quando o cliente se desconecta devido à perda de conectividade. O servidor recebe uma mensagem de desconexão apenas quando o cliente a envia, e isso é possível somente quando há conexão com a Internet. Se quiser tomar alguma medida quando isso ocorrer, defina um tempo limite, caso não receba nada do cliente após uma determinada janela de tempo.
Se o cliente não envia mensagens com frequência, e você não deseja atingir um tempo limite apenas porque a conexão fica ociosa, peça ao cliente para usar um temporizador a fim de enviar uma mensagem de ping a cada X segundos. No servidor, se uma mensagem não chegar dentro de 2*X segundos após a mensagem anterior, encerre a conexão e informe que o cliente se desconectou. Aguarde o dobro do intervalo de tempo esperado a fim de deixar um tempo extra para atrasos na rede, que possam atrasar a mensagem de ping.
As proteções fornecidas pelo CORS não se aplicam ao WebSockets. Navegadores não:
Access-Control
ao fazer solicitações de WebSocket.No entanto, os navegadores enviam o cabeçalho Origin
ao emitir solicitações de WebSocket. Os aplicativos devem ser configurados para validar esses cabeçalhos e garantir que apenas WebSockets provenientes de origens esperadas sejam permitidos.
Se você estiver hospedando o servidor em "https://server.com" e hospedando seu cliente em "https://client.com", adicione "https://client.com" à lista AllowedOrigins para que seja feita a verificação pelos WebSockets.
var webSocketOptions = new WebSocketOptions
{
KeepAliveInterval = TimeSpan.FromMinutes(2)
};
webSocketOptions.AllowedOrigins.Add("https://client.com");
webSocketOptions.AllowedOrigins.Add("https://www.client.com");
app.UseWebSockets(webSocketOptions);
Observação
O cabeçalho Origin
é controlado pelo cliente e, como o cabeçalho Referer
, pode ser falsificado. Não use esses cabeçalhos como um mecanismo de autenticação.
O Windows Server 2012 ou posterior e o Windows 8 ou posterior com o IIS/IIS Express 8 ou posterior são compatíveis com o protocolo WebSocket, mas não para WebSockets via HTTP/2.
Observação
WebSockets estão sempre habilitados ao usar o IIS Express.
Para habilitar o suporte para o protocolo WebSocket no Windows Server 2012 ou posterior:
Observação
Estas etapas não são necessárias ao usar o IIS Express
Para habilitar o suporte para o protocolo WebSocket no Windows 8 ou posterior:
Observação
Estas etapas não são necessárias ao usar o IIS Express
Se estiver usando o suporte para WebSocket em socket.io no Node.js, desabilite o módulo WebSocket do IIS padrão usando o elemento webSocket
em web.config ou applicationHost.config. Caso contrário, o módulo WebSocket do IIS tentará lidar com a comunicação do WebSocket em vez do Node.js e do aplicativo.
<system.webServer>
<webSocket enabled="false" />
</system.webServer>
O aplicativo de exemplo que acompanha este artigo é um aplicativo de eco. Ele tem uma página da Web que faz conexões do WebSocket e o servidor reenvia para o cliente todas as mensagens recebidas. O aplicativo de amostra dá suporte a WebSockets via HTTP/2 ao usar uma estrutura de destino do .NET 7 ou posterior.
Executar o aplicativo:
dotnet run
e navegue em um navegador até http://localhost:<port>
.A página da Web mostra o status de conexão:
Selecione Conectar para enviar uma solicitação WebSocket para a URL exibida. Insira uma mensagem de teste e selecione Enviar. Quando terminar, selecione Fechar Soquete. A seção Log de Comunicação relata cada ação de abertura, envio e fechamento conforme ela ocorre.
Este artigo explica como começar a usar o WebSockets no ASP.NET Core. WebSocket (RFC 6455) é um protocolo que permite canais de comunicação persistentes bidirecionais em conexões TCP. Ele é usado em aplicativos que se beneficiam de comunicação rápida e em tempo real, como chat, painel e aplicativos de jogos.
Exibir ou fazer download do código de exemplo (como fazer download, como executar).
O uso de WebSockets por HTTP/2 aproveita novos recursos, como:
Esses recursos com suporte estão disponíveis no Kestrel em todas as plataformas habilitadas para HTTP/2. A negociação de versão é automática em navegadores e no Kestrel, ou seja, nenhuma nova API é necessária.
O .NET 7 introduziu o suporte do WebSockets por HTTP/2 a Kestrel, cliente JavaScript SignalR e SignalR com Blazor WebAssembly.
Observação
WebSockets HTTP/2 usam solicitações CONNECT em vez de GET, portanto, suas próprias rotas e controladores podem precisar de atualização. Para obter mais informações, consulte Adicionar suporte a WebSockets HTTP/2 para controladores existentes neste artigo.
O Chrome e o Edge têm WebSockets HTTP/2 habilitados por padrão e você pode habilitá-los no FireFox na página about:config
com o sinalizador network.http.spdy.websockets
.
WebSockets foram originalmente projetados para HTTP/1.1, mas desde então foram adaptados para funcionar via HTTP/2. (RFC 8441)
ASP.NET Core SignalR é uma biblioteca que simplifica a adição da funcionalidade da Web em tempo real aos aplicativos. Ele usa WebSockets sempre que possível.
Para a maioria dos aplicativos, recomendamos o SignalR ao invés de WebSockets brutos. SignalR:
Há suporte para WebSockets via HTTP/2 para:
Para alguns aplicativos, o gRPC no .NET fornece uma alternativa para WebSockets.
Adicione o middleware de WebSockets em Program.cs
:
app.UseWebSockets();
As seguintes configurações podem ser definidas:
var webSocketOptions = new WebSocketOptions
{
KeepAliveInterval = TimeSpan.FromMinutes(2)
};
app.UseWebSockets(webSocketOptions);
Futuramente no ciclo de vida da solicitação (mais tarde em Program.cs
ou em um método de ação, por exemplo), verifique se é uma solicitação do WebSocket e aceite-a.
O exemplo a seguir é de uma fase posterior em Program.cs
:
app.Use(async (context, next) =>
{
if (context.Request.Path == "/ws")
{
if (context.WebSockets.IsWebSocketRequest)
{
using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
await Echo(webSocket);
}
else
{
context.Response.StatusCode = StatusCodes.Status400BadRequest;
}
}
else
{
await next(context);
}
});
Uma solicitação do WebSocket pode entrar em qualquer URL, mas esse código de exemplo aceita apenas solicitações de /ws
.
Uma abordagem semelhante pode ser adotada em um método de controlador:
public class WebSocketController : ControllerBase
{
[Route("/ws")]
public async Task Get()
{
if (HttpContext.WebSockets.IsWebSocketRequest)
{
using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
await Echo(webSocket);
}
else
{
HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
}
}
Ao usar um WebSocket, você deve manter o pipeline de middleware em execução durante a conexão. Se tentar enviar ou receber uma mensagem do WebSocket após o término do pipeline de middleware, você poderá receber uma exceção semelhante à seguinte:
System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake. ---> System.ObjectDisposedException: Cannot write to the response body, the response has completed.
Object name: 'HttpResponseStream'.
Se você estiver usando um serviço em segundo plano para gravar dados em um WebSocket, mantenha o pipeline do middleware em execução. Faça isso usando um TaskCompletionSource<TResult>. Passe o TaskCompletionSource
ao seu serviço em segundo plano e faça-o chamar TrySetResult quando terminar com o WebSocket. Em seguida await
a propriedade Task durante a solicitação, conforme é mostrado no exemplo a seguir:
app.Run(async (context) =>
{
using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
var socketFinishedTcs = new TaskCompletionSource<object>();
BackgroundSocketProcessor.AddSocket(webSocket, socketFinishedTcs);
await socketFinishedTcs.Task;
});
A exceção fechada do WebSocket também poderá ocorrer ao retornar muito rapidamente de um método de ação. Ao aceitar um soquete de um método de ação, aguarde até que o código que usa o soquete seja concluído antes de retornar do método de ação.
Nunca use Task.Wait
, Task.Result
ou chamadas de bloqueio semelhantes para aguardar a conclusão do soquete, pois isso pode causar sérios problemas de threading. Sempre use await
.
O .NET 7 introduziu o suporte do WebSockets por HTTP/2 a Kestrel, cliente JavaScript SignalR e SignalR com Blazor WebAssembly. WebSockets HTTP/2 usam solicitações CONNECT em vez de GET. Se você usou [HttpGet("/path")]
anteriormente em seu método de ação do controlador para solicitações Websocket, atualize-o para usar [Route("/path")]
em vez disso.
public class WebSocketController : ControllerBase
{
[Route("/ws")]
public async Task Get()
{
if (HttpContext.WebSockets.IsWebSocketRequest)
{
using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
await Echo(webSocket);
}
else
{
HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
}
}
Aviso
Habilitar a compactação em conexões criptografadas pode tornar um aplicativo sujeito a ataques CRIME/BREACH.
Se estiver enviando informações confidenciais, evite habilitar a compactação ou use WebSocketMessageFlags.DisableCompression
ao chamar WebSocket.SendAsync
.
Isso se aplica a ambos os lados do WebSocket. Observe que a API dos WebSockets no navegador não tem configuração para desabilitar a compactação por envio.
Caso deseje fazer a compactação de mensagens por WebSockets, o código de aceitação deverá especificar que ele permite a compactação da seguinte maneira:
using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(
new WebSocketAcceptContext { DangerousEnableCompression = true }))
{
}
WebSocketAcceptContext.ServerMaxWindowBits
e WebSocketAcceptContext.DisableServerContextTakeover
são opções avançadas que controlam como a compactação funciona.
A compactação é negociada entre o cliente e o servidor ao estabelecer uma conexão pela primeira vez. Você pode ler mais sobre a negociação em Extensões de Compactação para WebSocket RFC.
Observação
Se a negociação de compactação não for aceita pelo servidor ou pelo cliente, a conexão ainda será estabelecida. No entanto, a conexão não usa compactação ao enviar e receber mensagens.
O método AcceptWebSocketAsync
atualiza a conexão TCP para uma conexão WebSocket e fornece um objeto WebSocket. Use o objeto WebSocket
para enviar e receber mensagens.
O código mostrado anteriormente que aceita a solicitação do WebSocket passa o objeto WebSocket
para um método Echo
. O código recebe uma mensagem e envia de volta imediatamente a mesma mensagem. As mensagens são enviadas e recebidas em um loop até que o cliente feche a conexão:
private static async Task Echo(WebSocket webSocket)
{
var buffer = new byte[1024 * 4];
var receiveResult = await webSocket.ReceiveAsync(
new ArraySegment<byte>(buffer), CancellationToken.None);
while (!receiveResult.CloseStatus.HasValue)
{
await webSocket.SendAsync(
new ArraySegment<byte>(buffer, 0, receiveResult.Count),
receiveResult.MessageType,
receiveResult.EndOfMessage,
CancellationToken.None);
receiveResult = await webSocket.ReceiveAsync(
new ArraySegment<byte>(buffer), CancellationToken.None);
}
await webSocket.CloseAsync(
receiveResult.CloseStatus.Value,
receiveResult.CloseStatusDescription,
CancellationToken.None);
}
Ao aceitar a conexão WebSocket antes de iniciar o loop, o pipeline de middleware é encerrado. Ao fechar o soquete, o pipeline é desenrolado. Ou seja, a solicitação deixa de avançar no pipeline quando o WebSocket é aceito. Quando o loop é concluído e o soquete é fechado, a solicitação continua a avançar no pipeline.
O servidor não é informado automaticamente quando o cliente se desconecta devido à perda de conectividade. O servidor recebe uma mensagem de desconexão apenas quando o cliente a envia, e isso é possível somente quando há conexão com a Internet. Se quiser tomar alguma medida quando isso ocorrer, defina um tempo limite, caso não receba nada do cliente após uma determinada janela de tempo.
Se o cliente não envia mensagens com frequência, e você não deseja atingir um tempo limite apenas porque a conexão fica ociosa, peça ao cliente para usar um temporizador a fim de enviar uma mensagem de ping a cada X segundos. No servidor, se uma mensagem não chegar dentro de 2*X segundos após a mensagem anterior, encerre a conexão e informe que o cliente se desconectou. Aguarde o dobro do intervalo de tempo esperado a fim de deixar um tempo extra para atrasos na rede, que possam atrasar a mensagem de ping.
As proteções fornecidas pelo CORS não se aplicam ao WebSockets. Navegadores não:
Access-Control
ao fazer solicitações de WebSocket.No entanto, os navegadores enviam o cabeçalho Origin
ao emitir solicitações de WebSocket. Os aplicativos devem ser configurados para validar esses cabeçalhos e garantir que apenas WebSockets provenientes de origens esperadas sejam permitidos.
Se você estiver hospedando o servidor em "https://server.com" e hospedando seu cliente em "https://client.com", adicione "https://client.com" à lista AllowedOrigins para que seja feita a verificação pelos WebSockets.
var webSocketOptions = new WebSocketOptions
{
KeepAliveInterval = TimeSpan.FromMinutes(2)
};
webSocketOptions.AllowedOrigins.Add("https://client.com");
webSocketOptions.AllowedOrigins.Add("https://www.client.com");
app.UseWebSockets(webSocketOptions);
Observação
O cabeçalho Origin
é controlado pelo cliente e, como o cabeçalho Referer
, pode ser falsificado. Não use esses cabeçalhos como um mecanismo de autenticação.
O Windows Server 2012 ou posterior e o Windows 8 ou posterior com o IIS/IIS Express 8 ou posterior são compatíveis com o protocolo WebSocket, mas não para WebSockets via HTTP/2.
Observação
WebSockets estão sempre habilitados ao usar o IIS Express.
Para habilitar o suporte para o protocolo WebSocket no Windows Server 2012 ou posterior:
Observação
Estas etapas não são necessárias ao usar o IIS Express
Para habilitar o suporte para o protocolo WebSocket no Windows 8 ou posterior:
Observação
Estas etapas não são necessárias ao usar o IIS Express
Se estiver usando o suporte para WebSocket em socket.io no Node.js, desabilite o módulo WebSocket do IIS padrão usando o elemento webSocket
em web.config ou applicationHost.config. Caso contrário, o módulo WebSocket do IIS tentará lidar com a comunicação do WebSocket em vez do Node.js e do aplicativo.
<system.webServer>
<webSocket enabled="false" />
</system.webServer>
O aplicativo de exemplo que acompanha este artigo é um aplicativo de eco. Ele tem uma página da Web que faz conexões do WebSocket e o servidor reenvia para o cliente todas as mensagens recebidas. O aplicativo de amostra dá suporte a WebSockets via HTTP/2 ao usar uma estrutura de destino do .NET 7 ou posterior.
Executar o aplicativo:
dotnet run
e navegue em um navegador até http://localhost:<port>
.A página da Web mostra o status de conexão:
Selecione Conectar para enviar uma solicitação WebSocket para a URL exibida. Insira uma mensagem de teste e selecione Enviar. Quando terminar, selecione Fechar Soquete. A seção Log de Comunicação relata cada ação de abertura, envio e fechamento conforme ela ocorre.
Este artigo explica como começar a usar o WebSockets no ASP.NET Core. WebSocket (RFC 6455) é um protocolo que permite canais de comunicação persistentes bidirecionais em conexões TCP. Ele é usado em aplicativos que se beneficiam de comunicação rápida e em tempo real, como chat, painel e aplicativos de jogos.
Exibir ou fazer download do código de exemplo (como fazer download, como executar).
ASP.NET Core SignalR é uma biblioteca que simplifica a adição da funcionalidade da Web em tempo real aos aplicativos. Ele usa WebSockets sempre que possível.
Para a maioria dos aplicativos, recomendamos o SignalR ao invés de WebSockets brutos. SignalR fornece o fallback de transporte para os ambientes em que os WebSockets não estão disponíveis. Fornece também um modelo de aplicativo de chamada de procedimento remoto básico. E, na maioria dos cenários, SignalR não tem nenhuma desvantagem de desempenho significativa em comparação ao uso de WebSockets brutos.
Para alguns aplicativos, o gRPC no .NET fornece uma alternativa para WebSockets.
Adicione o middleware de WebSockets em Program.cs
:
app.UseWebSockets();
As seguintes configurações podem ser definidas:
var webSocketOptions = new WebSocketOptions
{
KeepAliveInterval = TimeSpan.FromMinutes(2)
};
app.UseWebSockets(webSocketOptions);
Futuramente no ciclo de vida da solicitação (mais tarde em Program.cs
ou em um método de ação, por exemplo), verifique se é uma solicitação do WebSocket e aceite-a.
O exemplo a seguir é de uma fase posterior em Program.cs
:
app.Use(async (context, next) =>
{
if (context.Request.Path == "/ws")
{
if (context.WebSockets.IsWebSocketRequest)
{
using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
await Echo(webSocket);
}
else
{
context.Response.StatusCode = StatusCodes.Status400BadRequest;
}
}
else
{
await next(context);
}
});
Uma solicitação do WebSocket pode entrar em qualquer URL, mas esse código de exemplo aceita apenas solicitações de /ws
.
Uma abordagem semelhante pode ser adotada em um método de controlador:
public class WebSocketController : ControllerBase
{
[HttpGet("/ws")]
public async Task Get()
{
if (HttpContext.WebSockets.IsWebSocketRequest)
{
using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
await Echo(webSocket);
}
else
{
HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
}
}
Ao usar um WebSocket, você deve manter o pipeline de middleware em execução durante a conexão. Se tentar enviar ou receber uma mensagem do WebSocket após o término do pipeline de middleware, você poderá receber uma exceção semelhante à seguinte:
System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake. ---> System.ObjectDisposedException: Cannot write to the response body, the response has completed.
Object name: 'HttpResponseStream'.
Se você estiver usando um serviço em segundo plano para gravar dados em um WebSocket, mantenha o pipeline do middleware em execução. Faça isso usando um TaskCompletionSource<TResult>. Passe o TaskCompletionSource
ao seu serviço em segundo plano e faça-o chamar TrySetResult quando terminar com o WebSocket. Em seguida await
a propriedade Task durante a solicitação, conforme é mostrado no exemplo a seguir:
app.Run(async (context) =>
{
using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
var socketFinishedTcs = new TaskCompletionSource<object>();
BackgroundSocketProcessor.AddSocket(webSocket, socketFinishedTcs);
await socketFinishedTcs.Task;
});
A exceção fechada do WebSocket também poderá ocorrer ao retornar muito rapidamente de um método de ação. Ao aceitar um soquete de um método de ação, aguarde até que o código que usa o soquete seja concluído antes de retornar do método de ação.
Nunca use Task.Wait
, Task.Result
ou chamadas de bloqueio semelhantes para aguardar a conclusão do soquete, pois isso pode causar sérios problemas de threading. Sempre use await
.
Aviso
Habilitar a compactação em conexões criptografadas pode tornar um aplicativo sujeito a ataques CRIME/BREACH.
Se estiver enviando informações confidenciais, evite habilitar a compactação ou use WebSocketMessageFlags.DisableCompression
ao chamar WebSocket.SendAsync
.
Isso se aplica a ambos os lados do WebSocket. Observe que a API dos WebSockets no navegador não tem configuração para desabilitar a compactação por envio.
Caso deseje fazer a compactação de mensagens por WebSockets, o código de aceitação deverá especificar que ele permite a compactação da seguinte maneira:
using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(
new WebSocketAcceptContext { DangerousEnableCompression = true }))
{
}
WebSocketAcceptContext.ServerMaxWindowBits
e WebSocketAcceptContext.DisableServerContextTakeover
são opções avançadas que controlam como a compactação funciona.
A compactação é negociada entre o cliente e o servidor ao estabelecer uma conexão pela primeira vez. Você pode ler mais sobre a negociação em Extensões de Compactação para WebSocket RFC.
Observação
Se a negociação de compactação não for aceita pelo servidor ou pelo cliente, a conexão ainda será estabelecida. No entanto, a conexão não usa compactação ao enviar e receber mensagens.
O método AcceptWebSocketAsync
atualiza a conexão TCP para uma conexão WebSocket e fornece um objeto WebSocket. Use o objeto WebSocket
para enviar e receber mensagens.
O código mostrado anteriormente que aceita a solicitação do WebSocket passa o objeto WebSocket
para um método Echo
. O código recebe uma mensagem e envia de volta imediatamente a mesma mensagem. As mensagens são enviadas e recebidas em um loop até que o cliente feche a conexão:
private static async Task Echo(WebSocket webSocket)
{
var buffer = new byte[1024 * 4];
var receiveResult = await webSocket.ReceiveAsync(
new ArraySegment<byte>(buffer), CancellationToken.None);
while (!receiveResult.CloseStatus.HasValue)
{
await webSocket.SendAsync(
new ArraySegment<byte>(buffer, 0, receiveResult.Count),
receiveResult.MessageType,
receiveResult.EndOfMessage,
CancellationToken.None);
receiveResult = await webSocket.ReceiveAsync(
new ArraySegment<byte>(buffer), CancellationToken.None);
}
await webSocket.CloseAsync(
receiveResult.CloseStatus.Value,
receiveResult.CloseStatusDescription,
CancellationToken.None);
}
Ao aceitar a conexão WebSocket antes de iniciar o loop, o pipeline de middleware é encerrado. Ao fechar o soquete, o pipeline é desenrolado. Ou seja, a solicitação deixa de avançar no pipeline quando o WebSocket é aceito. Quando o loop é concluído e o soquete é fechado, a solicitação continua a avançar no pipeline.
O servidor não é informado automaticamente quando o cliente se desconecta devido à perda de conectividade. O servidor recebe uma mensagem de desconexão apenas quando o cliente a envia, e isso é possível somente quando há conexão com a Internet. Se quiser tomar alguma medida quando isso ocorrer, defina um tempo limite, caso não receba nada do cliente após uma determinada janela de tempo.
Se o cliente não envia mensagens com frequência, e você não deseja atingir um tempo limite apenas porque a conexão fica ociosa, peça ao cliente para usar um temporizador a fim de enviar uma mensagem de ping a cada X segundos. No servidor, se uma mensagem não chegar dentro de 2*X segundos após a mensagem anterior, encerre a conexão e informe que o cliente se desconectou. Aguarde o dobro do intervalo de tempo esperado a fim de deixar um tempo extra para atrasos na rede, que possam atrasar a mensagem de ping.
As proteções fornecidas pelo CORS não se aplicam ao WebSockets. Navegadores não:
Access-Control
ao fazer solicitações de WebSocket.No entanto, os navegadores enviam o cabeçalho Origin
ao emitir solicitações de WebSocket. Os aplicativos devem ser configurados para validar esses cabeçalhos e garantir que apenas WebSockets provenientes de origens esperadas sejam permitidos.
Se você estiver hospedando o servidor em "https://server.com" e hospedando seu cliente em "https://client.com", adicione "https://client.com" à lista AllowedOrigins para que seja feita a verificação pelos WebSockets.
var webSocketOptions = new WebSocketOptions
{
KeepAliveInterval = TimeSpan.FromMinutes(2)
};
webSocketOptions.AllowedOrigins.Add("https://client.com");
webSocketOptions.AllowedOrigins.Add("https://www.client.com");
app.UseWebSockets(webSocketOptions);
Observação
O cabeçalho Origin
é controlado pelo cliente e, como o cabeçalho Referer
, pode ser falsificado. Não use esses cabeçalhos como um mecanismo de autenticação.
O Windows Server 2012 ou posterior e o Windows 8 ou posterior com o IIS/IIS Express 8 ou posterior são compatíveis com o protocolo WebSocket.
Observação
WebSockets estão sempre habilitados ao usar o IIS Express.
Para habilitar o suporte para o protocolo WebSocket no Windows Server 2012 ou posterior:
Observação
Estas etapas não são necessárias ao usar o IIS Express
Para habilitar o suporte para o protocolo WebSocket no Windows 8 ou posterior:
Observação
Estas etapas não são necessárias ao usar o IIS Express
Se estiver usando o suporte para WebSocket em socket.io no Node.js, desabilite o módulo WebSocket do IIS padrão usando o elemento webSocket
em web.config ou applicationHost.config. Caso contrário, o módulo WebSocket do IIS tentará lidar com a comunicação do WebSocket em vez do Node.js e do aplicativo.
<system.webServer>
<webSocket enabled="false" />
</system.webServer>
O aplicativo de exemplo que acompanha este artigo é um aplicativo de eco. Ele tem uma página da Web que faz conexões do WebSocket e o servidor reenvia para o cliente todas as mensagens recebidas. O aplicativo de amostra não está configurado para ser executado no Visual Studio com IIS Express, portanto, execute o aplicativo em um shell de comando com dotnet run
e navegue em um navegador até http://localhost:<port>
. A página da Web mostra o status de conexão:
Selecione Conectar para enviar uma solicitação WebSocket para a URL exibida. Insira uma mensagem de teste e selecione Enviar. Quando terminar, selecione Fechar Soquete. A seção Log de Comunicação relata cada ação de abertura, envio e fechamento conforme ela ocorre.
Este artigo explica como começar a usar o WebSockets no ASP.NET Core. WebSocket (RFC 6455) é um protocolo que permite canais de comunicação persistentes bidirecionais em conexões TCP. Ele é usado em aplicativos que se beneficiam de comunicação rápida e em tempo real, como chat, painel e aplicativos de jogos.
Exibir ou baixar um código de exemplo (como baixar). Como executar.
ASP.NET Core SignalR é uma biblioteca que simplifica a adição da funcionalidade da Web em tempo real aos aplicativos. Ele usa WebSockets sempre que possível.
Para a maioria dos aplicativos, recomendamos o SignalR ao invés de WebSockets brutos. SignalR fornece o fallback de transporte para os ambientes em que os WebSockets não estão disponíveis. Fornece também um modelo de aplicativo de chamada de procedimento remoto básico. E, na maioria dos cenários, SignalR não tem nenhuma desvantagem de desempenho significativa em comparação ao uso de WebSockets brutos.
Para alguns aplicativos, o gRPC no .NET fornece uma alternativa para WebSockets.
Adicione o middleware do WebSockets no método Configure
da classe Startup
:
app.UseWebSockets();
Observação
Se você quiser aceitar solicitações de WebSocket em um controlador, a chamada para app.UseWebSockets
deverá ocorrer antes de app.UseEndpoints
.
As seguintes configurações podem ser definidas:
var webSocketOptions = new WebSocketOptions()
{
KeepAliveInterval = TimeSpan.FromSeconds(120),
};
app.UseWebSockets(webSocketOptions);
Futuramente no ciclo de vida da solicitação (mais tarde no método Configure
ou em um método de ação, por exemplo), verifique se é uma solicitação do WebSocket e aceite-a.
O exemplo a seguir é de uma fase posterior do método Configure
:
app.Use(async (context, next) =>
{
if (context.Request.Path == "/ws")
{
if (context.WebSockets.IsWebSocketRequest)
{
using (WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync())
{
await Echo(context, webSocket);
}
}
else
{
context.Response.StatusCode = (int) HttpStatusCode.BadRequest;
}
}
else
{
await next();
}
});
Uma solicitação do WebSocket pode entrar em qualquer URL, mas esse código de exemplo aceita apenas solicitações de /ws
.
Uma abordagem semelhante pode ser adotada em um método de controlador:
public class WebSocketController : ControllerBase
{
[HttpGet("/ws")]
public async Task Get()
{
if (HttpContext.WebSockets.IsWebSocketRequest)
{
using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
await Echo(webSocket);
}
else
{
HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
}
}
Ao usar um WebSocket, você deve manter o pipeline de middleware em execução durante a conexão. Se tentar enviar ou receber uma mensagem do WebSocket após o término do pipeline de middleware, você poderá receber uma exceção semelhante à seguinte:
System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake. ---> System.ObjectDisposedException: Cannot write to the response body, the response has completed.
Object name: 'HttpResponseStream'.
Se você estiver usando um serviço em segundo plano para gravar dados em um WebSocket, mantenha o pipeline do middleware em execução. Faça isso usando um TaskCompletionSource<TResult>. Passe o TaskCompletionSource
ao seu serviço em segundo plano e faça-o chamar TrySetResult quando terminar com o WebSocket. Em seguida await
a propriedade Task durante a solicitação, conforme é mostrado no exemplo a seguir:
app.Use(async (context, next) =>
{
using (WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync())
{
var socketFinishedTcs = new TaskCompletionSource<object>();
BackgroundSocketProcessor.AddSocket(webSocket, socketFinishedTcs);
await socketFinishedTcs.Task;
}
});
A exceção fechada do WebSocket também poderá ocorrer ao retornar muito rapidamente de um método de ação. Ao aceitar um soquete de um método de ação, aguarde até que o código que usa o soquete seja concluído antes de retornar do método de ação.
Nunca use Task.Wait
, Task.Result
ou chamadas de bloqueio semelhantes para aguardar a conclusão do soquete, pois isso pode causar sérios problemas de threading. Sempre use await
.
O método AcceptWebSocketAsync
atualiza a conexão TCP para uma conexão WebSocket e fornece um objeto WebSocket. Use o objeto WebSocket
para enviar e receber mensagens.
O código mostrado anteriormente que aceita a solicitação do WebSocket passa o objeto WebSocket
para um método Echo
. O código recebe uma mensagem e envia de volta imediatamente a mesma mensagem. As mensagens são enviadas e recebidas em um loop até que o cliente feche a conexão:
private async Task Echo(HttpContext context, WebSocket webSocket)
{
var buffer = new byte[1024 * 4];
WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
while (!result.CloseStatus.HasValue)
{
await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
}
await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
}
Ao aceitar a conexão WebSocket antes de iniciar o loop, o pipeline de middleware é encerrado. Ao fechar o soquete, o pipeline é desenrolado. Ou seja, a solicitação deixa de avançar no pipeline quando o WebSocket é aceito. Quando o loop é concluído e o soquete é fechado, a solicitação continua a avançar no pipeline.
O servidor não é informado automaticamente quando o cliente se desconecta devido à perda de conectividade. O servidor recebe uma mensagem de desconexão apenas quando o cliente a envia, e isso é possível somente quando há conexão com a Internet. Se quiser tomar alguma medida quando isso ocorrer, defina um tempo limite, caso não receba nada do cliente após uma determinada janela de tempo.
Se o cliente não envia mensagens com frequência, e você não deseja atingir um tempo limite apenas porque a conexão fica ociosa, peça ao cliente para usar um temporizador a fim de enviar uma mensagem de ping a cada X segundos. No servidor, se uma mensagem não chegar dentro de 2*X segundos após a mensagem anterior, encerre a conexão e informe que o cliente se desconectou. Aguarde o dobro do intervalo de tempo esperado a fim de deixar um tempo extra para atrasos na rede, que possam atrasar a mensagem de ping.
Observação
O interno ManagedWebSocket
manipula os quadros ping/pong implicitamente para manter a conexão ativa se a opção KeepAliveInterval
for maior que zero, o que significa 30 segundos (TimeSpan.FromSeconds(30)
).
As proteções fornecidas pelo CORS não se aplicam ao WebSockets. Navegadores não:
Access-Control
ao fazer solicitações de WebSocket.No entanto, os navegadores enviam o cabeçalho Origin
ao emitir solicitações de WebSocket. Os aplicativos devem ser configurados para validar esses cabeçalhos e garantir que apenas WebSockets provenientes de origens esperadas sejam permitidos.
Se você estiver hospedando o servidor em "https://server.com" e hospedando seu cliente em "https://client.com", adicione "https://client.com" à lista AllowedOrigins para que seja feita a verificação pelos WebSockets.
var webSocketOptions = new WebSocketOptions()
{
KeepAliveInterval = TimeSpan.FromSeconds(120),
};
webSocketOptions.AllowedOrigins.Add("https://client.com");
webSocketOptions.AllowedOrigins.Add("https://www.client.com");
app.UseWebSockets(webSocketOptions);
Observação
O cabeçalho Origin
é controlado pelo cliente e, como o cabeçalho Referer
, pode ser falsificado. Não use esses cabeçalhos como um mecanismo de autenticação.
O Windows Server 2012 ou posterior e o Windows 8 ou posterior com o IIS/IIS Express 8 ou posterior são compatíveis com o protocolo WebSocket.
Observação
WebSockets estão sempre habilitados ao usar o IIS Express.
Para habilitar o suporte para o protocolo WebSocket no Windows Server 2012 ou posterior:
Observação
Estas etapas não são necessárias ao usar o IIS Express
Para habilitar o suporte para o protocolo WebSocket no Windows 8 ou posterior:
Observação
Estas etapas não são necessárias ao usar o IIS Express
Se estiver usando o suporte para WebSocket em socket.io no Node.js, desabilite o módulo WebSocket do IIS padrão usando o elemento webSocket
em web.config ou applicationHost.config. Caso contrário, o módulo WebSocket do IIS tentará lidar com a comunicação do WebSocket em vez do Node.js e do aplicativo.
<system.webServer>
<webSocket enabled="false" />
</system.webServer>
O aplicativo de exemplo que acompanha este artigo é um aplicativo de eco. Ele tem uma página da Web que faz conexões do WebSocket e o servidor reenvia para o cliente todas as mensagens recebidas. O aplicativo de amostra não está configurado para ser executado no Visual Studio com IIS Express, portanto, execute o aplicativo em um shell de comando com dotnet run
e navegue em um navegador até http://localhost:5000
. A página da Web mostra o status de conexão:
Selecione Conectar para enviar uma solicitação WebSocket para a URL exibida. Insira uma mensagem de teste e selecione Enviar. Quando terminar, selecione Fechar Soquete. A seção Log de Comunicação relata cada ação de abertura, envio e fechamento conforme ela ocorre.
Comentários do ASP.NET Core
O ASP.NET Core é um projeto código aberto. Selecione um link para fornecer comentários:
Eventos
Junte-se a nós na FabCon Vegas
31 de mar., 23 - 2 de abr., 23
O melhor evento liderado pela comunidade Microsoft Fabric, Power BI, SQL e AI. 31 de março a 2 de abril de 2025.
Registre-se hoje mesmo