Dela via


WebSockets-stöd i ASP.NET Core

Anmärkning

Det här är inte den senaste versionen av den här artikeln. För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .

Varning

Den här versionen av ASP.NET Core stöds inte längre. Mer information finns i supportpolicyn för .NET och .NET Core. För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .

Viktigt!

Den här informationen gäller en förhandsversionsprodukt som kan ändras avsevärt innan den släpps kommersiellt. Microsoft lämnar inga garantier, uttryckliga eller underförstådda, med avseende på den information som tillhandahålls här.

För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .

Den här artikeln beskriver hur du kommer igång med WebSockets i ASP.NET Core. WebSocket (RFC 6455) är ett protokoll som möjliggör dubbelriktade beständiga kommunikationskanaler via TCP-anslutningar. Den används i appar som drar nytta av snabb kommunikation i realtid, till exempel chatt, instrumentpanel och spelappar.

Visa eller ladda ned exempelkod (ladda ned, hur du kör).

Stöd för Http/2 WebSockets

Användning av WebSockets via HTTP/2 drar nytta av nya funktioner som:

  • Rubrikkomprimering.
  • Multiplexering, vilket minskar den tid och de resurser som behövs när du gör flera begäranden till servern.

Dessa funktioner som stöds är tillgängliga i Kestrel på alla HTTP/2-aktiverade plattformar. Versionsförhandlingen sker automatiskt i webbläsare och Kestrel, så inga nya API:er behövs.

.NET 7 introducerade WebSockets via HTTP/2-stöd för Kestrel, SignalR JavaScript-klienten och SignalR med Blazor WebAssembly.

Anmärkning

HTTP/2 WebSockets använder CONNECT-begäranden i stället för GET, så dina egna vägar och kontrollanter kan behöva uppdateras. Mer information finns i Lägga till HTTP/2 WebSockets-stöd för befintliga kontrollanter i den här artikeln.

Chrome och Edge har HTTP/2 WebSockets aktiverat som standard, och du kan aktivera det i FireFox på about:config sidan med network.http.spdy.websockets flaggan.

WebSockets utformades ursprungligen för HTTP/1.1 men har sedan dess anpassats för att fungera via HTTP/2. (RFC 8441)

SignalR

ASP.NET Core SignalR är ett bibliotek som gör det enklare att lägga till webbfunktioner i realtid i appar. Den använder WebSockets när det är möjligt.

För de flesta applikationer rekommenderar vi SignalR istället för råa websockets. SignalR:

  • Tillhandahåller transportåterställning för miljöer där WebSockets inte är tillgängligt.
  • Tillhandahåller en grundläggande appmodell för fjärrproceduranrop.
  • Har ingen betydande prestandanackdel jämfört med att använda råa WebSockets i de flesta scenarier.

WebSockets via HTTP/2 stöds för:

  • ASP.NET Core SignalR JavaScript-klient
  • ASP.NET Core SignalR med Blazor WebAssembly

För vissa appar är gRPC på .NET ett alternativ till WebSockets.

Förutsättningar

  • Alla operativsystem som stöder ASP.NET Core:
    • Windows 7/Windows Server 2008 eller senare
    • Linux
    • macOS
  • Om appen körs i Windows med IIS:
  • Om appen körs på HTTP.sys:
    • Windows 8/Windows Server 2012 eller senare
  • För webbläsare som stöds, se Kan jag använda.

Konfigurera mellanprogrammet

Lägg till WebSockets-mellanprogrammet i Program.cs:

app.UseWebSockets();

Följande inställningar kan konfigureras:

  • KeepAliveInterval – Hur ofta du skickar "ping"-ramar till klienten för att säkerställa att proxyservrarna håller anslutningen öppen. Standardvärdet är två minuter.
  • AllowedOrigins – En lista över tillåtna ursprungshuvudvärden för WebSocket-begäranden. Som standard tillåts alla ursprung. Mer information finns i Ursprungsbegränsning för WebSocket i den här artikeln.
var webSocketOptions = new WebSocketOptions
{
    KeepAliveInterval = TimeSpan.FromMinutes(2)
};

app.UseWebSockets(webSocketOptions);

Acceptera WebSocket-förfrågningar

Någonstans senare i livscykeln för begäran (senare i Program.cs eller i en åtgärdsmetod, till exempel) kontrollerar du om det är en WebSocket-begäran och godkänner WebSocket-begäran.

Följande exempel är från senare i 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);
    }

});

En WebSocket-begäran kan komma in på valfri URL, men den här exempelkoden accepterar endast begäranden för /ws.

En liknande metod kan användas i en kontrollantmetod:

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

När du använder en WebSocket måste du hålla pipelinen för mellanprogram igång under hela anslutningen. Om du försöker skicka eller ta emot ett WebSocket-meddelande när pipelinen för mellanprogram har upphört kan du få ett undantag som liknar följande:

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'.

Om du använder en bakgrundstjänst för att skriva data till en WebSocket, ska du se till att pipelinen för mellanprogramvara körs. Gör detta med hjälp av en TaskCompletionSource<TResult>. Skicka TaskCompletionSource till din bakgrundstjänst och låt den anropa TrySetResult när du är klar med WebSocket. Sedan await egenskapen Task under begäran, som visas i följande exempel:

app.Run(async (context) =>
{
    using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
    var socketFinishedTcs = new TaskCompletionSource<object>();

    BackgroundSocketProcessor.AddSocket(webSocket, socketFinishedTcs);

    await socketFinishedTcs.Task;
});

Det stängda WebSocket-undantaget kan också inträffa när du returnerar för tidigt från en åtgärdsmetod. När du accepterar en socket i en åtgärdsmetod väntar du på att koden som använder socketen ska slutföras innan du återvänder från åtgärdsmetoden.

Använd aldrig Task.Wait, Task.Result eller liknande blockeringsanrop för att vänta tills socketen har slutförts, eftersom det kan orsaka allvarliga trådproblem. Använd awaitalltid .

Lägga till HTTP/2 WebSockets-stöd för befintliga kontrollanter

.NET 7 introducerade WebSockets via HTTP/2-stöd för Kestrel, SignalR JavaScript-klienten och SignalR med Blazor WebAssembly. HTTP/2 WebSockets använder CONNECT-begäranden i stället för GET. Om du tidigare använde [HttpGet("/path")] på din kontrollers åtgärdsmetod för Websocket-begäranden, uppdatera den till att använda [Route("/path")] i stället.

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

Komprimering

Varning

Om du aktiverar komprimering över krypterade anslutningar kan en app utsättas för CRIME/BREACH attacker. Om du skickar känslig information bör du undvika att aktivera komprimering eller användning WebSocketMessageFlags.DisableCompression när du anropar WebSocket.SendAsync. Detta gäller för båda sidor av WebSocket. Observera att WebSockets-API:et i webbläsaren inte har någon konfiguration för inaktivering av komprimering per sändning.

Om komprimering av meddelanden via WebSockets önskas måste acceptkoden ange att den tillåter komprimering på följande sätt:

using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(
    new WebSocketAcceptContext { DangerousEnableCompression = true }))
{

}

WebSocketAcceptContext.ServerMaxWindowBits och WebSocketAcceptContext.DisableServerContextTakeover är avancerade alternativ som styr hur komprimering fungerar.

Komprimering förhandlas mellan klienten och servern när du först upprättar en anslutning. Du kan läsa mer om förhandlingen i Komprimeringstillägg för WebSocket RFC.

Anmärkning

Om komprimeringsförhandlingen inte godkänns av servern eller klienten upprättas anslutningen fortfarande. Anslutningen använder dock inte komprimering när meddelanden skickas och tas emot.

Skicka och ta emot meddelanden

Metoden AcceptWebSocketAsync uppgraderar TCP-anslutningen till en WebSocket-anslutning och tillhandahåller ett WebSocket objekt. Använd objektet WebSocket för att skicka och ta emot meddelanden.

Koden som visades tidigare och som accepterar WebSocket-begäran skickar WebSocket objektet till en Echo metod. Koden tar emot ett meddelande och skickar omedelbart tillbaka samma meddelande. Meddelanden skickas och tas emot i en loop tills klienten stänger anslutningen:

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

När du godkänner WebSocket-anslutningen innan du påbörjar loopen avslutas pipelinen för mellanprogram. När du stänger socketen spolas pipelinen av. Begäran slutar alltså att gå framåt i pipelinen när WebSocket godkänns. När loopen är klar och socketen stängs fortsätter begäran att gå tillbaka genom pipelinen.

Hantera frånkopplingar av klienten

Servern informeras inte automatiskt när klienten kopplas från på grund av förlust av anslutning. Servern tar endast emot ett frånkopplingsmeddelande om klienten skickar det, vilket inte kan göras om Internetanslutningen går förlorad. Om du vill vidta en åtgärd när det händer anger du en tidsgräns efter att inget har tagits emot från klienten inom en viss tidsperiod.

Om klienten inte alltid skickar meddelanden och du inte vill överskrida tidsgränsen bara för att anslutningen går inaktiv ska klienten använda en timer för att skicka ett pingmeddelande var X:e sekund. Om ett meddelande inte har kommit inom 2*X sekunder efter föregående meddelande på servern avslutar du anslutningen och rapporterar att klienten har kopplats från. Vänta två gånger det förväntade tidsintervallet för att lämna extra tid på grund av nätverksfördröjningar som kan fördröja pingmeddelandet.

Ursprungsbegränsning för WebSocket

De skydd som tillhandahålls av CORS gäller inte för WebSockets. Webbläsare gör inte:

  • Utför CORS-begäranden före flygning.
  • Respektera de begränsningar som anges i Access-Control rubriker när du gör WebSocket-begäranden.

Webbläsare skickar dock Origin-huvudet när de utfärdar WebSocket-begäranden. Program bör konfigureras för att verifiera dessa huvuden för att säkerställa att endast WebSockets som kommer från det förväntade ursprunget tillåts.

Om du har din server på "https://server.com"" och din klient på "https://client.com"", lägg till "https://client.com"" till listan AllowedOrigins för verifiering av 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);

Anmärkning

Origin-huvudet styrs av klienten och, precis som Referer-huvudet, kan förfalskas. Använd inte dessa huvuden som en autentiseringsmekanism.

Expresssupport för IIS/IIS

Windows Server 2012 eller senare och Windows 8 eller senare med IIS/IIS Express 8 eller senare har stöd för WebSocket-protokollet, men inte för WebSockets via HTTP/2.

Anmärkning

WebSockets aktiveras alltid när du använder IIS Express.

Aktivera WebSockets på IIS

Så här aktiverar du stöd för WebSocket-protokollet på Windows Server 2012 eller senare:

Anmärkning

De här stegen krävs inte när du använder IIS Express

  1. Använd guiden Lägg till roller och funktioner från menyn Hantera eller länken i Serverhanteraren.
  2. Välj Rollbaserad eller Funktionsbaserad installation. Välj Nästa.
  3. Välj lämplig server (den lokala servern är markerad som standard). Välj Nästa.
  4. Expandera Webbserver (IIS) i trädet Roller , expandera Webbserver och expandera sedan Programutveckling.
  5. Välj WebSocket Protocol. Välj Nästa.
  6. Om ytterligare funktioner inte behövs väljer du Nästa.
  7. Välj Installera.
  8. När installationen är klar klickar du på Stäng för att avsluta guiden.

Så här aktiverar du stöd för WebSocket-protokollet i Windows 8 eller senare:

Anmärkning

De här stegen krävs inte när du använder IIS Express

  1. Gå till Kontrollpanelen>Program>program och funktioner>Aktivera eller inaktivera Windows-funktioner (till vänster på skärmen).
  2. Öppna följande noder: Internet Information Services>World Wide Web Services>Application Development Features.
  3. Välj funktionen WebSocket Protocol. Välj OK.

Inaktivera WebSocket när du använder socket.io på Node.js

Om du använder WebSocket-stöd i socket.ioNode.jsinaktiverar du IIS WebSocket-standardmodulen med elementet webSocket i web.config eller applicationHost.config. Om det här steget inte utförs försöker IIS WebSocket-modulen hantera WebSocket-kommunikationen i stället för Node.js och appen.

<system.webServer>
  <webSocket enabled="false" />
</system.webServer>

Exempelapp

Exempelappen som medföljer den här artikeln är en ekoapp. Den har en webbsida som gör WebSocket-anslutningar, och servern skickar alla meddelanden som den tar emot tillbaka till klienten. Exempelappen stöder WebSockets via HTTP/2 när du använder ett målramverk med .NET 7 eller senare.

Kör appen:

  • Så här kör du appen i Visual Studio: Öppna exempelprojektet i Visual Studio och tryck på Ctrl+F5 för att köra utan felsökningsprogrammet.
  • Så här kör du appen i ett kommandogränssnitt: Kör kommandot dotnet run och navigera i en webbläsare till http://localhost:<port>.

Webbsidan visar anslutningsstatus:

Starttillstånd för webbsidan före WebSockets-anslutning

Välj Anslut för att skicka en WebSocket-begäran till den URL som visas. Ange ett testmeddelande och välj Skicka. När du är klar väljer du Stäng socket. Avsnittet Kommunikationslogg rapporterar varje åtgärd för att öppna, skicka och stänga när det händer.

Sluttillstånd för webbsidan efter att WebSockets-anslutning och testmeddelanden har skickats och tagits emot

Den här artikeln beskriver hur du kommer igång med WebSockets i ASP.NET Core. WebSocket (RFC 6455) är ett protokoll som möjliggör dubbelriktade beständiga kommunikationskanaler via TCP-anslutningar. Den används i appar som drar nytta av snabb kommunikation i realtid, till exempel chatt, instrumentpanel och spelappar.

Visa eller ladda ned exempelkod (ladda ned, hur du kör).

Stöd för Http/2 WebSockets

Användning av WebSockets via HTTP/2 drar nytta av nya funktioner som:

  • Rubrikkomprimering.
  • Multiplexering, vilket minskar den tid och de resurser som behövs när du gör flera begäranden till servern.

Dessa funktioner som stöds är tillgängliga i Kestrel på alla HTTP/2-aktiverade plattformar. Versionsförhandlingen sker automatiskt i webbläsare och Kestrel, så inga nya API:er behövs.

.NET 7 introducerade WebSockets via HTTP/2-stöd för Kestrel, SignalR JavaScript-klienten och SignalR med Blazor WebAssembly.

Anmärkning

HTTP/2 WebSockets använder CONNECT-begäranden i stället för GET, så dina egna vägar och kontrollanter kan behöva uppdateras. Mer information finns i Lägga till HTTP/2 WebSockets-stöd för befintliga kontrollanter i den här artikeln.

Chrome och Edge har HTTP/2 WebSockets aktiverat som standard, och du kan aktivera det i FireFox på about:config sidan med network.http.spdy.websockets flaggan.

WebSockets utformades ursprungligen för HTTP/1.1 men har sedan dess anpassats för att fungera via HTTP/2. (RFC 8441)

SignalR

ASP.NET Core SignalR är ett bibliotek som gör det enklare att lägga till webbfunktioner i realtid i appar. Den använder WebSockets när det är möjligt.

För de flesta applikationer rekommenderar vi SignalR istället för råa websockets. SignalR:

  • Tillhandahåller transportåterställning för miljöer där WebSockets inte är tillgängligt.
  • Tillhandahåller en grundläggande appmodell för fjärrproceduranrop.
  • Har ingen betydande prestandanackdel jämfört med att använda råa WebSockets i de flesta scenarier.

WebSockets via HTTP/2 stöds för:

  • ASP.NET Core SignalR JavaScript-klient
  • ASP.NET Core SignalR med Blazor WebAssembly

För vissa appar är gRPC på .NET ett alternativ till WebSockets.

Förutsättningar

  • Alla operativsystem som stöder ASP.NET Core:
    • Windows 7/Windows Server 2008 eller senare
    • Linux
    • macOS
  • Om appen körs i Windows med IIS:
  • Om appen körs på HTTP.sys:
    • Windows 8/Windows Server 2012 eller senare
  • För webbläsare som stöds, se Kan jag använda.

Konfigurera mellanprogrammet

Lägg till WebSockets-mellanprogrammet i Program.cs:

app.UseWebSockets();

Följande inställningar kan konfigureras:

  • KeepAliveInterval – Hur ofta du skickar "ping"-ramar till klienten för att säkerställa att proxyservrarna håller anslutningen öppen. Standardvärdet är två minuter.
  • AllowedOrigins – En lista över tillåtna ursprungshuvudvärden för WebSocket-begäranden. Som standard tillåts alla ursprung. Mer information finns i Ursprungsbegränsning för WebSocket i den här artikeln.
var webSocketOptions = new WebSocketOptions
{
    KeepAliveInterval = TimeSpan.FromMinutes(2)
};

app.UseWebSockets(webSocketOptions);

Acceptera WebSocket-förfrågningar

Någonstans senare i livscykeln för begäran (senare i Program.cs eller i en åtgärdsmetod, till exempel) kontrollerar du om det är en WebSocket-begäran och godkänner WebSocket-begäran.

Följande exempel är från senare i 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);
    }

});

En WebSocket-begäran kan komma in på valfri URL, men den här exempelkoden accepterar endast begäranden för /ws.

En liknande metod kan användas i en kontrollantmetod:

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

När du använder en WebSocket måste du hålla pipelinen för mellanprogram igång under hela anslutningen. Om du försöker skicka eller ta emot ett WebSocket-meddelande när pipelinen för mellanprogram har upphört kan du få ett undantag som liknar följande:

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'.

Om du använder en bakgrundstjänst för att skriva data till en WebSocket, ska du se till att pipelinen för mellanprogramvara körs. Gör detta med hjälp av en TaskCompletionSource<TResult>. Skicka TaskCompletionSource till din bakgrundstjänst och låt den anropa TrySetResult när du är klar med WebSocket. Sedan await egenskapen Task under begäran, som visas i följande exempel:

app.Run(async (context) =>
{
    using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
    var socketFinishedTcs = new TaskCompletionSource<object>();

    BackgroundSocketProcessor.AddSocket(webSocket, socketFinishedTcs);

    await socketFinishedTcs.Task;
});

Det stängda WebSocket-undantaget kan också inträffa när du returnerar för tidigt från en åtgärdsmetod. När du accepterar en socket i en åtgärdsmetod väntar du på att koden som använder socketen ska slutföras innan du återvänder från åtgärdsmetoden.

Använd aldrig Task.Wait, Task.Result eller liknande blockeringsanrop för att vänta tills socketen har slutförts, eftersom det kan orsaka allvarliga trådproblem. Använd awaitalltid .

Lägga till HTTP/2 WebSockets-stöd för befintliga kontrollanter

.NET 7 introducerade WebSockets via HTTP/2-stöd för Kestrel, SignalR JavaScript-klienten och SignalR med Blazor WebAssembly. HTTP/2 WebSockets använder CONNECT-begäranden i stället för GET. Om du tidigare använde [HttpGet("/path")] på din kontrollers åtgärdsmetod för Websocket-begäranden, uppdatera den till att använda [Route("/path")] i stället.

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

Komprimering

Varning

Om du aktiverar komprimering över krypterade anslutningar kan en app utsättas för CRIME/BREACH attacker. Om du skickar känslig information bör du undvika att aktivera komprimering eller användning WebSocketMessageFlags.DisableCompression när du anropar WebSocket.SendAsync. Detta gäller för båda sidor av WebSocket. Observera att WebSockets-API:et i webbläsaren inte har någon konfiguration för inaktivering av komprimering per sändning.

Om komprimering av meddelanden via WebSockets önskas måste acceptkoden ange att den tillåter komprimering på följande sätt:

using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(
    new WebSocketAcceptContext { DangerousEnableCompression = true }))
{

}

WebSocketAcceptContext.ServerMaxWindowBits och WebSocketAcceptContext.DisableServerContextTakeover är avancerade alternativ som styr hur komprimering fungerar.

Komprimering förhandlas mellan klienten och servern när du först upprättar en anslutning. Du kan läsa mer om förhandlingen i Komprimeringstillägg för WebSocket RFC.

Anmärkning

Om komprimeringsförhandlingen inte godkänns av servern eller klienten upprättas anslutningen fortfarande. Anslutningen använder dock inte komprimering när meddelanden skickas och tas emot.

Skicka och ta emot meddelanden

Metoden AcceptWebSocketAsync uppgraderar TCP-anslutningen till en WebSocket-anslutning och tillhandahåller ett WebSocket objekt. Använd objektet WebSocket för att skicka och ta emot meddelanden.

Koden som visades tidigare och som accepterar WebSocket-begäran skickar WebSocket objektet till en Echo metod. Koden tar emot ett meddelande och skickar omedelbart tillbaka samma meddelande. Meddelanden skickas och tas emot i en loop tills klienten stänger anslutningen:

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

När du godkänner WebSocket-anslutningen innan du påbörjar loopen avslutas pipelinen för mellanprogram. När du stänger socketen spolas pipelinen av. Begäran slutar alltså att gå framåt i pipelinen när WebSocket godkänns. När loopen är klar och socketen stängs fortsätter begäran att gå tillbaka genom pipelinen.

Hantera frånkopplingar av klienten

Servern informeras inte automatiskt när klienten kopplas från på grund av förlust av anslutning. Servern tar endast emot ett frånkopplingsmeddelande om klienten skickar det, vilket inte kan göras om Internetanslutningen går förlorad. Om du vill vidta en åtgärd när det händer anger du en tidsgräns efter att inget har tagits emot från klienten inom en viss tidsperiod.

Om klienten inte alltid skickar meddelanden och du inte vill överskrida tidsgränsen bara för att anslutningen går inaktiv ska klienten använda en timer för att skicka ett pingmeddelande var X:e sekund. Om ett meddelande inte har kommit inom 2*X sekunder efter föregående meddelande på servern avslutar du anslutningen och rapporterar att klienten har kopplats från. Vänta två gånger det förväntade tidsintervallet för att lämna extra tid på grund av nätverksfördröjningar som kan fördröja pingmeddelandet.

Ursprungsbegränsning för WebSocket

De skydd som tillhandahålls av CORS gäller inte för WebSockets. Webbläsare gör inte:

  • Utför CORS-begäranden före flygning.
  • Respektera de begränsningar som anges i Access-Control rubriker när du gör WebSocket-begäranden.

Webbläsare skickar dock Origin-huvudet när de utfärdar WebSocket-begäranden. Program bör konfigureras för att verifiera dessa huvuden för att säkerställa att endast WebSockets som kommer från det förväntade ursprunget tillåts.

Om du har din server på "https://server.com"" och din klient på "https://client.com"", lägg till "https://client.com"" till listan AllowedOrigins för verifiering av 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);

Anmärkning

Origin-huvudet styrs av klienten och, precis som Referer-huvudet, kan förfalskas. Använd inte dessa huvuden som en autentiseringsmekanism.

Expresssupport för IIS/IIS

Windows Server 2012 eller senare och Windows 8 eller senare med IIS/IIS Express 8 eller senare har stöd för WebSocket-protokollet, men inte för WebSockets via HTTP/2.

Anmärkning

WebSockets aktiveras alltid när du använder IIS Express.

Aktivera WebSockets på IIS

Så här aktiverar du stöd för WebSocket-protokollet på Windows Server 2012 eller senare:

Anmärkning

De här stegen krävs inte när du använder IIS Express

  1. Använd guiden Lägg till roller och funktioner från menyn Hantera eller länken i Serverhanteraren.
  2. Välj Rollbaserad eller Funktionsbaserad installation. Välj Nästa.
  3. Välj lämplig server (den lokala servern är markerad som standard). Välj Nästa.
  4. Expandera Webbserver (IIS) i trädet Roller , expandera Webbserver och expandera sedan Programutveckling.
  5. Välj WebSocket Protocol. Välj Nästa.
  6. Om ytterligare funktioner inte behövs väljer du Nästa.
  7. Välj Installera.
  8. När installationen är klar klickar du på Stäng för att avsluta guiden.

Så här aktiverar du stöd för WebSocket-protokollet i Windows 8 eller senare:

Anmärkning

De här stegen krävs inte när du använder IIS Express

  1. Gå till Kontrollpanelen>Program>program och funktioner>Aktivera eller inaktivera Windows-funktioner (till vänster på skärmen).
  2. Öppna följande noder: Internet Information Services>World Wide Web Services>Application Development Features.
  3. Välj funktionen WebSocket Protocol. Välj OK.

Inaktivera WebSocket när du använder socket.io på Node.js

Om du använder WebSocket-stöd i socket.ioNode.jsinaktiverar du IIS WebSocket-standardmodulen med elementet webSocket i web.config eller applicationHost.config. Om det här steget inte utförs försöker IIS WebSocket-modulen hantera WebSocket-kommunikationen i stället för Node.js och appen.

<system.webServer>
  <webSocket enabled="false" />
</system.webServer>

Exempelapp

Exempelappen som medföljer den här artikeln är en ekoapp. Den har en webbsida som gör WebSocket-anslutningar, och servern skickar alla meddelanden som den tar emot tillbaka till klienten. Exempelappen stöder WebSockets via HTTP/2 när du använder ett målramverk med .NET 7 eller senare.

Kör appen:

  • Så här kör du appen i Visual Studio: Öppna exempelprojektet i Visual Studio och tryck på Ctrl+F5 för att köra utan felsökningsprogrammet.
  • Så här kör du appen i ett kommandogränssnitt: Kör kommandot dotnet run och navigera i en webbläsare till http://localhost:<port>.

Webbsidan visar anslutningsstatus:

Starttillstånd för webbsidan före WebSockets-anslutning

Välj Anslut för att skicka en WebSocket-begäran till den URL som visas. Ange ett testmeddelande och välj Skicka. När du är klar väljer du Stäng socket. Avsnittet Kommunikationslogg rapporterar varje åtgärd för att öppna, skicka och stänga när det händer.

Sluttillstånd för webbsidan efter att WebSockets-anslutning och testmeddelanden har skickats och tagits emot

Den här artikeln beskriver hur du kommer igång med WebSockets i ASP.NET Core. WebSocket (RFC 6455) är ett protokoll som möjliggör dubbelriktade beständiga kommunikationskanaler via TCP-anslutningar. Den används i appar som drar nytta av snabb kommunikation i realtid, till exempel chatt, instrumentpanel och spelappar.

Visa eller ladda ned exempelkod (ladda ned, hur du kör).

Stöd för Http/2 WebSockets

Användning av WebSockets via HTTP/2 drar nytta av nya funktioner som:

  • Rubrikkomprimering.
  • Multiplexering, vilket minskar den tid och de resurser som behövs när du gör flera begäranden till servern.

Dessa funktioner som stöds är tillgängliga i Kestrel på alla HTTP/2-aktiverade plattformar. Versionsförhandlingen sker automatiskt i webbläsare och Kestrel, så inga nya API:er behövs.

.NET 7 introducerade WebSockets via HTTP/2-stöd för Kestrel, SignalR JavaScript-klienten och SignalR med Blazor WebAssembly.

Anmärkning

HTTP/2 WebSockets använder CONNECT-begäranden i stället för GET, så dina egna vägar och kontrollanter kan behöva uppdateras. Mer information finns i Lägga till HTTP/2 WebSockets-stöd för befintliga kontrollanter i den här artikeln.

Chrome och Edge har HTTP/2 WebSockets aktiverat som standard, och du kan aktivera det i FireFox på about:config sidan med network.http.spdy.websockets flaggan.

WebSockets utformades ursprungligen för HTTP/1.1 men har sedan dess anpassats för att fungera via HTTP/2. (RFC 8441)

SignalR

ASP.NET Core SignalR är ett bibliotek som gör det enklare att lägga till webbfunktioner i realtid i appar. Den använder WebSockets när det är möjligt.

För de flesta applikationer rekommenderar vi SignalR istället för råa websockets. SignalR:

  • Tillhandahåller transportåterställning för miljöer där WebSockets inte är tillgängligt.
  • Tillhandahåller en grundläggande appmodell för fjärrproceduranrop.
  • Har ingen betydande prestandanackdel jämfört med att använda råa WebSockets i de flesta scenarier.

WebSockets via HTTP/2 stöds för:

  • ASP.NET Core SignalR JavaScript-klient
  • ASP.NET Core SignalR med Blazor WebAssembly

För vissa appar är gRPC på .NET ett alternativ till WebSockets.

Förutsättningar

  • Alla operativsystem som stöder ASP.NET Core:
    • Windows 7/Windows Server 2008 eller senare
    • Linux
    • macOS
  • Om appen körs i Windows med IIS:
  • Om appen körs på HTTP.sys:
    • Windows 8/Windows Server 2012 eller senare
  • För webbläsare som stöds, se Kan jag använda.

Konfigurera mellanprogrammet

Lägg till WebSockets-mellanprogrammet i Program.cs:

app.UseWebSockets();

Följande inställningar kan konfigureras:

  • KeepAliveInterval – Hur ofta du skickar "ping"-ramar till klienten för att säkerställa att proxyservrarna håller anslutningen öppen. Standardvärdet är två minuter.
  • AllowedOrigins – En lista över tillåtna ursprungshuvudvärden för WebSocket-begäranden. Som standard tillåts alla ursprung. Mer information finns i Ursprungsbegränsning för WebSocket i den här artikeln.
var webSocketOptions = new WebSocketOptions
{
    KeepAliveInterval = TimeSpan.FromMinutes(2)
};

app.UseWebSockets(webSocketOptions);

Acceptera WebSocket-förfrågningar

Någonstans senare i livscykeln för begäran (senare i Program.cs eller i en åtgärdsmetod, till exempel) kontrollerar du om det är en WebSocket-begäran och godkänner WebSocket-begäran.

Följande exempel är från senare i 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);
    }

});

En WebSocket-begäran kan komma in på valfri URL, men den här exempelkoden accepterar endast begäranden för /ws.

En liknande metod kan användas i en kontrollantmetod:

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

När du använder en WebSocket måste du hålla pipelinen för mellanprogram igång under hela anslutningen. Om du försöker skicka eller ta emot ett WebSocket-meddelande när pipelinen för mellanprogram har upphört kan du få ett undantag som liknar följande:

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'.

Om du använder en bakgrundstjänst för att skriva data till en WebSocket, ska du se till att pipelinen för mellanprogramvara körs. Gör detta med hjälp av en TaskCompletionSource<TResult>. Skicka TaskCompletionSource till din bakgrundstjänst och låt den anropa TrySetResult när du är klar med WebSocket. Sedan await egenskapen Task under begäran, som visas i följande exempel:

app.Run(async (context) =>
{
    using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
    var socketFinishedTcs = new TaskCompletionSource<object>();

    BackgroundSocketProcessor.AddSocket(webSocket, socketFinishedTcs);

    await socketFinishedTcs.Task;
});

Det stängda WebSocket-undantaget kan också inträffa när du returnerar för tidigt från en åtgärdsmetod. När du accepterar en socket i en åtgärdsmetod väntar du på att koden som använder socketen ska slutföras innan du återvänder från åtgärdsmetoden.

Använd aldrig Task.Wait, Task.Result eller liknande blockeringsanrop för att vänta tills socketen har slutförts, eftersom det kan orsaka allvarliga trådproblem. Använd awaitalltid .

Lägga till HTTP/2 WebSockets-stöd för befintliga kontrollanter

.NET 7 introducerade WebSockets via HTTP/2-stöd för Kestrel, SignalR JavaScript-klienten och SignalR med Blazor WebAssembly. HTTP/2 WebSockets använder CONNECT-begäranden i stället för GET. Om du tidigare använde [HttpGet("/path")] på din kontrollers åtgärdsmetod för Websocket-begäranden, uppdatera den till att använda [Route("/path")] i stället.

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

Komprimering

Varning

Om du aktiverar komprimering över krypterade anslutningar kan en app utsättas för CRIME/BREACH attacker. Om du skickar känslig information bör du undvika att aktivera komprimering eller användning WebSocketMessageFlags.DisableCompression när du anropar WebSocket.SendAsync. Detta gäller för båda sidor av WebSocket. Observera att WebSockets-API:et i webbläsaren inte har någon konfiguration för inaktivering av komprimering per sändning.

Om komprimering av meddelanden via WebSockets önskas måste acceptkoden ange att den tillåter komprimering på följande sätt:

using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(
    new WebSocketAcceptContext { DangerousEnableCompression = true }))
{

}

WebSocketAcceptContext.ServerMaxWindowBits och WebSocketAcceptContext.DisableServerContextTakeover är avancerade alternativ som styr hur komprimering fungerar.

Komprimering förhandlas mellan klienten och servern när du först upprättar en anslutning. Du kan läsa mer om förhandlingen i Komprimeringstillägg för WebSocket RFC.

Anmärkning

Om komprimeringsförhandlingen inte godkänns av servern eller klienten upprättas anslutningen fortfarande. Anslutningen använder dock inte komprimering när meddelanden skickas och tas emot.

Skicka och ta emot meddelanden

Metoden AcceptWebSocketAsync uppgraderar TCP-anslutningen till en WebSocket-anslutning och tillhandahåller ett WebSocket objekt. Använd objektet WebSocket för att skicka och ta emot meddelanden.

Koden som visades tidigare och som accepterar WebSocket-begäran skickar WebSocket objektet till en Echo metod. Koden tar emot ett meddelande och skickar omedelbart tillbaka samma meddelande. Meddelanden skickas och tas emot i en loop tills klienten stänger anslutningen:

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

När du godkänner WebSocket-anslutningen innan du påbörjar loopen avslutas pipelinen för mellanprogram. När du stänger socketen spolas pipelinen av. Begäran slutar alltså att gå framåt i pipelinen när WebSocket godkänns. När loopen är klar och socketen stängs fortsätter begäran att gå tillbaka genom pipelinen.

Hantera frånkopplingar av klienten

Servern informeras inte automatiskt när klienten kopplas från på grund av förlust av anslutning. Servern tar endast emot ett frånkopplingsmeddelande om klienten skickar det, vilket inte kan göras om Internetanslutningen går förlorad. Om du vill vidta en åtgärd när det händer anger du en tidsgräns efter att inget har tagits emot från klienten inom en viss tidsperiod.

Om klienten inte alltid skickar meddelanden och du inte vill överskrida tidsgränsen bara för att anslutningen går inaktiv ska klienten använda en timer för att skicka ett pingmeddelande var X:e sekund. Om ett meddelande inte har kommit inom 2*X sekunder efter föregående meddelande på servern avslutar du anslutningen och rapporterar att klienten har kopplats från. Vänta två gånger det förväntade tidsintervallet för att lämna extra tid på grund av nätverksfördröjningar som kan fördröja pingmeddelandet.

Ursprungsbegränsning för WebSocket

De skydd som tillhandahålls av CORS gäller inte för WebSockets. Webbläsare gör inte:

  • Utför CORS-begäranden före flygning.
  • Respektera de begränsningar som anges i Access-Control rubriker när du gör WebSocket-begäranden.

Webbläsare skickar dock Origin-huvudet när de utfärdar WebSocket-begäranden. Program bör konfigureras för att verifiera dessa huvuden för att säkerställa att endast WebSockets som kommer från det förväntade ursprunget tillåts.

Om du har din server på "https://server.com"" och din klient på "https://client.com"", lägg till "https://client.com"" till listan AllowedOrigins för verifiering av 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);

Anmärkning

Origin-huvudet styrs av klienten och, precis som Referer-huvudet, kan förfalskas. Använd inte dessa huvuden som en autentiseringsmekanism.

Expresssupport för IIS/IIS

Windows Server 2012 eller senare och Windows 8 eller senare med IIS/IIS Express 8 eller senare har stöd för WebSocket-protokollet, men inte för WebSockets via HTTP/2.

Anmärkning

WebSockets aktiveras alltid när du använder IIS Express.

Aktivera WebSockets på IIS

Så här aktiverar du stöd för WebSocket-protokollet på Windows Server 2012 eller senare:

Anmärkning

De här stegen krävs inte när du använder IIS Express

  1. Använd guiden Lägg till roller och funktioner från menyn Hantera eller länken i Serverhanteraren.
  2. Välj Rollbaserad eller Funktionsbaserad installation. Välj Nästa.
  3. Välj lämplig server (den lokala servern är markerad som standard). Välj Nästa.
  4. Expandera Webbserver (IIS) i trädet Roller , expandera Webbserver och expandera sedan Programutveckling.
  5. Välj WebSocket Protocol. Välj Nästa.
  6. Om ytterligare funktioner inte behövs väljer du Nästa.
  7. Välj Installera.
  8. När installationen är klar klickar du på Stäng för att avsluta guiden.

Så här aktiverar du stöd för WebSocket-protokollet i Windows 8 eller senare:

Anmärkning

De här stegen krävs inte när du använder IIS Express

  1. Gå till Kontrollpanelen>Program>program och funktioner>Aktivera eller inaktivera Windows-funktioner (till vänster på skärmen).
  2. Öppna följande noder: Internet Information Services>World Wide Web Services>Application Development Features.
  3. Välj funktionen WebSocket Protocol. Välj OK.

Inaktivera WebSocket när du använder socket.io på Node.js

Om du använder WebSocket-stöd i socket.ioNode.jsinaktiverar du IIS WebSocket-standardmodulen med elementet webSocket i web.config eller applicationHost.config. Om det här steget inte utförs försöker IIS WebSocket-modulen hantera WebSocket-kommunikationen i stället för Node.js och appen.

<system.webServer>
  <webSocket enabled="false" />
</system.webServer>

Exempelapp

Exempelappen som medföljer den här artikeln är en ekoapp. Den har en webbsida som gör WebSocket-anslutningar, och servern skickar alla meddelanden som den tar emot tillbaka till klienten. Exempelappen stöder WebSockets via HTTP/2 när du använder ett målramverk med .NET 7 eller senare.

Kör appen:

  • Så här kör du appen i Visual Studio: Öppna exempelprojektet i Visual Studio och tryck på Ctrl+F5 för att köra utan felsökningsprogrammet.
  • Så här kör du appen i ett kommandogränssnitt: Kör kommandot dotnet run och navigera i en webbläsare till http://localhost:<port>.

Webbsidan visar anslutningsstatus:

Starttillstånd för webbsidan före WebSockets-anslutning

Välj Anslut för att skicka en WebSocket-begäran till den URL som visas. Ange ett testmeddelande och välj Skicka. När du är klar väljer du Stäng socket. Avsnittet Kommunikationslogg rapporterar varje åtgärd för att öppna, skicka och stänga när det händer.

Sluttillstånd för webbsidan efter att WebSockets-anslutning och testmeddelanden har skickats och tagits emot

Den här artikeln beskriver hur du kommer igång med WebSockets i ASP.NET Core. WebSocket (RFC 6455) är ett protokoll som möjliggör dubbelriktade beständiga kommunikationskanaler via TCP-anslutningar. Den används i appar som drar nytta av snabb kommunikation i realtid, till exempel chatt, instrumentpanel och spelappar.

Visa eller ladda ned exempelkod (ladda ned, hur du kör).

SignalR

ASP.NET Core SignalR är ett bibliotek som gör det enklare att lägga till webbfunktioner i realtid i appar. Den använder WebSockets när det är möjligt.

För de flesta program rekommenderar vi SignalR framför råa WebSockets. SignalR ger transportåterställning för miljöer där WebSockets inte är tillgängligt. Den innehåller också en grundläggande appmodell för fjärrproceduranrop. Och i de flesta scenarier SignalR har ingen betydande prestandanackdel jämfört med att använda råa WebSockets.

För vissa appar är gRPC på .NET ett alternativ till WebSockets.

Förutsättningar

  • Alla operativsystem som stöder ASP.NET Core:
    • Windows 7/Windows Server 2008 eller senare
    • Linux
    • macOS
  • Om appen körs i Windows med IIS:
  • Om appen körs på HTTP.sys:
    • Windows 8/Windows Server 2012 eller senare
  • För webbläsare som stöds, se Kan jag använda.

Konfigurera mellanprogrammet

Lägg till WebSockets-mellanprogrammet i Program.cs:

app.UseWebSockets();

Följande inställningar kan konfigureras:

  • KeepAliveInterval – Hur ofta du skickar "ping"-ramar till klienten för att säkerställa att proxyservrarna håller anslutningen öppen. Standardvärdet är två minuter.
  • AllowedOrigins – En lista över tillåtna ursprungshuvudvärden för WebSocket-begäranden. Som standard tillåts alla ursprung. Mer information finns i Ursprungsbegränsning för WebSocket i den här artikeln.
var webSocketOptions = new WebSocketOptions
{
    KeepAliveInterval = TimeSpan.FromMinutes(2)
};

app.UseWebSockets(webSocketOptions);

Acceptera WebSocket-förfrågningar

Någonstans senare i livscykeln för begäran (senare i Program.cs eller i en åtgärdsmetod, till exempel) kontrollerar du om det är en WebSocket-begäran och godkänner WebSocket-begäran.

Följande exempel är från senare i 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);
    }

});

En WebSocket-begäran kan komma in på valfri URL, men den här exempelkoden accepterar endast begäranden för /ws.

En liknande metod kan användas i en kontrollantmetod:

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

När du använder en WebSocket måste du hålla pipelinen för mellanprogram igång under hela anslutningen. Om du försöker skicka eller ta emot ett WebSocket-meddelande när pipelinen för mellanprogram har upphört kan du få ett undantag som liknar följande:

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'.

Om du använder en bakgrundstjänst för att skriva data till en WebSocket, ska du se till att pipelinen för mellanprogramvara körs. Gör detta med hjälp av en TaskCompletionSource<TResult>. Skicka TaskCompletionSource till din bakgrundstjänst och låt den anropa TrySetResult när du är klar med WebSocket. Sedan await egenskapen Task under begäran, som visas i följande exempel:

app.Run(async (context) =>
{
    using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
    var socketFinishedTcs = new TaskCompletionSource<object>();

    BackgroundSocketProcessor.AddSocket(webSocket, socketFinishedTcs);

    await socketFinishedTcs.Task;
});

Det stängda WebSocket-undantaget kan också inträffa när du returnerar för tidigt från en åtgärdsmetod. När du accepterar en socket i en åtgärdsmetod väntar du på att koden som använder socketen ska slutföras innan du återvänder från åtgärdsmetoden.

Använd aldrig Task.Wait, Task.Result eller liknande blockeringsanrop för att vänta tills socketen har slutförts, eftersom det kan orsaka allvarliga trådproblem. Använd awaitalltid .

Komprimering

Varning

Om du aktiverar komprimering över krypterade anslutningar kan en app utsättas för CRIME/BREACH attacker. Om du skickar känslig information bör du undvika att aktivera komprimering eller användning WebSocketMessageFlags.DisableCompression när du anropar WebSocket.SendAsync. Detta gäller för båda sidor av WebSocket. Observera att WebSockets-API:et i webbläsaren inte har någon konfiguration för inaktivering av komprimering per sändning.

Om komprimering av meddelanden via WebSockets önskas måste acceptkoden ange att den tillåter komprimering på följande sätt:

using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(
    new WebSocketAcceptContext { DangerousEnableCompression = true }))
{

}

WebSocketAcceptContext.ServerMaxWindowBits och WebSocketAcceptContext.DisableServerContextTakeover är avancerade alternativ som styr hur komprimering fungerar.

Komprimering förhandlas mellan klienten och servern när du först upprättar en anslutning. Du kan läsa mer om förhandlingen i Komprimeringstillägg för WebSocket RFC.

Anmärkning

Om komprimeringsförhandlingen inte godkänns av servern eller klienten upprättas anslutningen fortfarande. Anslutningen använder dock inte komprimering när meddelanden skickas och tas emot.

Skicka och ta emot meddelanden

Metoden AcceptWebSocketAsync uppgraderar TCP-anslutningen till en WebSocket-anslutning och tillhandahåller ett WebSocket objekt. Använd objektet WebSocket för att skicka och ta emot meddelanden.

Koden som visades tidigare och som accepterar WebSocket-begäran skickar WebSocket objektet till en Echo metod. Koden tar emot ett meddelande och skickar omedelbart tillbaka samma meddelande. Meddelanden skickas och tas emot i en loop tills klienten stänger anslutningen:

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

När du godkänner WebSocket-anslutningen innan du påbörjar loopen avslutas pipelinen för mellanprogram. När du stänger socketen spolas pipelinen av. Begäran slutar alltså att gå framåt i pipelinen när WebSocket godkänns. När loopen är klar och socketen stängs fortsätter begäran att gå tillbaka genom pipelinen.

Hantera frånkopplingar av klienten

Servern informeras inte automatiskt när klienten kopplas från på grund av förlust av anslutning. Servern tar endast emot ett frånkopplingsmeddelande om klienten skickar det, vilket inte kan göras om Internetanslutningen går förlorad. Om du vill vidta en åtgärd när det händer anger du en tidsgräns efter att inget har tagits emot från klienten inom en viss tidsperiod.

Om klienten inte alltid skickar meddelanden och du inte vill överskrida tidsgränsen bara för att anslutningen går inaktiv ska klienten använda en timer för att skicka ett pingmeddelande var X:e sekund. Om ett meddelande inte har kommit inom 2*X sekunder efter föregående meddelande på servern avslutar du anslutningen och rapporterar att klienten har kopplats från. Vänta två gånger det förväntade tidsintervallet för att lämna extra tid på grund av nätverksfördröjningar som kan fördröja pingmeddelandet.

Ursprungsbegränsning för WebSocket

De skydd som tillhandahålls av CORS gäller inte för WebSockets. Webbläsare gör inte:

  • Utför CORS-begäranden före flygning.
  • Respektera de begränsningar som anges i Access-Control rubriker när du gör WebSocket-begäranden.

Webbläsare skickar dock Origin-huvudet när de utfärdar WebSocket-begäranden. Program bör konfigureras för att verifiera dessa huvuden för att säkerställa att endast WebSockets som kommer från det förväntade ursprunget tillåts.

Om du har din server på "https://server.com"" och din klient på "https://client.com"", lägg till "https://client.com"" till listan AllowedOrigins för verifiering av 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);

Anmärkning

Origin-huvudet styrs av klienten och, precis som Referer-huvudet, kan förfalskas. Använd inte dessa huvuden som en autentiseringsmekanism.

Expresssupport för IIS/IIS

Windows Server 2012 eller senare och Windows 8 eller senare med IIS/IIS Express 8 eller senare har stöd för WebSocket-protokollet.

Anmärkning

WebSockets aktiveras alltid när du använder IIS Express.

Aktivera WebSockets på IIS

Så här aktiverar du stöd för WebSocket-protokollet på Windows Server 2012 eller senare:

Anmärkning

De här stegen krävs inte när du använder IIS Express

  1. Använd guiden Lägg till roller och funktioner från menyn Hantera eller länken i Serverhanteraren.
  2. Välj Rollbaserad eller Funktionsbaserad installation. Välj Nästa.
  3. Välj lämplig server (den lokala servern är markerad som standard). Välj Nästa.
  4. Expandera Webbserver (IIS) i trädet Roller , expandera Webbserver och expandera sedan Programutveckling.
  5. Välj WebSocket Protocol. Välj Nästa.
  6. Om ytterligare funktioner inte behövs väljer du Nästa.
  7. Välj Installera.
  8. När installationen är klar klickar du på Stäng för att avsluta guiden.

Så här aktiverar du stöd för WebSocket-protokollet i Windows 8 eller senare:

Anmärkning

De här stegen krävs inte när du använder IIS Express

  1. Gå till Kontrollpanelen>Program>program och funktioner>Aktivera eller inaktivera Windows-funktioner (till vänster på skärmen).
  2. Öppna följande noder: Internet Information Services>World Wide Web Services>Application Development Features.
  3. Välj funktionen WebSocket Protocol. Välj OK.

Inaktivera WebSocket när du använder socket.io på Node.js

Om du använder WebSocket-stöd i socket.ioNode.jsinaktiverar du IIS WebSocket-standardmodulen med elementet webSocket i web.config eller applicationHost.config. Om det här steget inte utförs försöker IIS WebSocket-modulen hantera WebSocket-kommunikationen i stället för Node.js och appen.

<system.webServer>
  <webSocket enabled="false" />
</system.webServer>

Exempelapp

Exempelappen som medföljer den här artikeln är en ekoapp. Den har en webbsida som gör WebSocket-anslutningar, och servern skickar alla meddelanden som den tar emot tillbaka till klienten. Exempelappen är inte konfigurerad att köras från Visual Studio med IIS Express, så kör appen i ett kommandogränssnitt med dotnet run och navigera i en webbläsare till http://localhost:<port>. Webbsidan visar anslutningsstatus:

Starttillstånd för webbsidan före WebSockets-anslutning

Välj Anslut för att skicka en WebSocket-begäran till den URL som visas. Ange ett testmeddelande och välj Skicka. När du är klar väljer du Stäng socket. Avsnittet Kommunikationslogg rapporterar varje åtgärd för att öppna, skicka och stänga när det händer.

Sluttillstånd för webbsidan efter att WebSockets-anslutning och testmeddelanden har skickats och tagits emot

Den här artikeln beskriver hur du kommer igång med WebSockets i ASP.NET Core. WebSocket (RFC 6455) är ett protokoll som möjliggör dubbelriktade beständiga kommunikationskanaler via TCP-anslutningar. Den används i appar som drar nytta av snabb kommunikation i realtid, till exempel chatt, instrumentpanel och spelappar.

Visa eller ladda ned exempelkod (hur du laddar ned). Så här kör du.

SignalR

ASP.NET Core SignalR är ett bibliotek som gör det enklare att lägga till webbfunktioner i realtid i appar. Den använder WebSockets när det är möjligt.

För de flesta program rekommenderar vi SignalR framför råa WebSockets. SignalR ger transportåterställning för miljöer där WebSockets inte är tillgängligt. Den innehåller också en grundläggande appmodell för fjärrproceduranrop. Och i de flesta scenarier SignalR har ingen betydande prestandanackdel jämfört med att använda råa WebSockets.

För vissa appar är gRPC på .NET ett alternativ till WebSockets.

Förutsättningar

  • Alla operativsystem som stöder ASP.NET Core:
    • Windows 7/Windows Server 2008 eller senare
    • Linux
    • macOS
  • Om appen körs i Windows med IIS:
  • Om appen körs på HTTP.sys:
    • Windows 8/Windows Server 2012 eller senare
  • För webbläsare som stöds, se Kan jag använda.

Konfigurera mellanprogrammet

Lägg till WebSockets-mellanprogrammet i Configure -metoden för Startup klassen:

app.UseWebSockets();

Anmärkning

Om du vill acceptera WebSocket-begäranden i en kontrollant måste anropet till app.UseWebSockets ske före app.UseEndpoints.

Följande inställningar kan konfigureras:

  • KeepAliveInterval – Hur ofta du skickar "ping"-ramar till klienten för att säkerställa att proxyservrarna håller anslutningen öppen. Standardvärdet är två minuter.
  • AllowedOrigins – En lista över tillåtna ursprungshuvudvärden för WebSocket-begäranden. Som standard tillåts alla ursprung. Mer information finns i "Ursprungsbegränsning för WebSocket" nedan.
var webSocketOptions = new WebSocketOptions()
{
    KeepAliveInterval = TimeSpan.FromSeconds(120),
};

app.UseWebSockets(webSocketOptions);

Acceptera WebSocket-förfrågningar

Någonstans senare i livscykeln för begäran (senare i Configure metoden eller i en åtgärdsmetod, till exempel) kontrollerar du om det är en WebSocket-begäran och godkänner WebSocket-begäran.

Följande exempel är från senare i Configure metoden:

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

});

En WebSocket-begäran kan komma in på valfri URL, men den här exempelkoden accepterar endast begäranden för /ws.

En liknande metod kan användas i en kontrollantmetod:

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

När du använder en WebSocket måste du hålla pipelinen för mellanprogram igång under hela anslutningen. Om du försöker skicka eller ta emot ett WebSocket-meddelande när pipelinen för mellanprogram har upphört kan du få ett undantag som liknar följande:

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'.

Om du använder en bakgrundstjänst för att skriva data till en WebSocket, ska du se till att pipelinen för mellanprogramvara körs. Gör detta med hjälp av en TaskCompletionSource<TResult>. Skicka TaskCompletionSource till din bakgrundstjänst och låt den anropa TrySetResult när du är klar med WebSocket. Sedan await egenskapen Task under begäran, som visas i följande exempel:

app.Use(async (context, next) =>
{
    using (WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync())
    {
        var socketFinishedTcs = new TaskCompletionSource<object>();

        BackgroundSocketProcessor.AddSocket(webSocket, socketFinishedTcs);

        await socketFinishedTcs.Task;
    }
});

Det stängda WebSocket-undantaget kan också inträffa när du returnerar för tidigt från en åtgärdsmetod. När du accepterar en socket i en åtgärdsmetod väntar du på att koden som använder socketen ska slutföras innan du återvänder från åtgärdsmetoden.

Använd aldrig Task.Wait, Task.Result eller liknande blockeringsanrop för att vänta tills socketen har slutförts, eftersom det kan orsaka allvarliga trådproblem. Använd awaitalltid .

Skicka och ta emot meddelanden

Metoden AcceptWebSocketAsync uppgraderar TCP-anslutningen till en WebSocket-anslutning och tillhandahåller ett WebSocket objekt. Använd objektet WebSocket för att skicka och ta emot meddelanden.

Koden som visades tidigare och som accepterar WebSocket-begäran skickar WebSocket objektet till en Echo metod. Koden tar emot ett meddelande och skickar omedelbart tillbaka samma meddelande. Meddelanden skickas och tas emot i en loop tills klienten stänger anslutningen:

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

När du godkänner WebSocket-anslutningen innan du påbörjar loopen avslutas pipelinen för mellanprogram. När du stänger socketen spolas pipelinen av. Begäran slutar alltså att gå framåt i pipelinen när WebSocket godkänns. När loopen är klar och socketen stängs fortsätter begäran att gå tillbaka genom pipelinen.

Hantera frånkopplingar av klienten

Servern informeras inte automatiskt när klienten kopplas från på grund av förlust av anslutning. Servern tar endast emot ett frånkopplingsmeddelande om klienten skickar det, vilket inte kan göras om Internetanslutningen går förlorad. Om du vill vidta en åtgärd när det händer anger du en tidsgräns efter att inget har tagits emot från klienten inom en viss tidsperiod.

Om klienten inte alltid skickar meddelanden och du inte vill överskrida tidsgränsen bara för att anslutningen går inaktiv ska klienten använda en timer för att skicka ett pingmeddelande var X:e sekund. Om ett meddelande inte har kommit inom 2*X sekunder efter föregående meddelande på servern avslutar du anslutningen och rapporterar att klienten har kopplats från. Vänta två gånger det förväntade tidsintervallet för att lämna extra tid på grund av nätverksfördröjningar som kan fördröja pingmeddelandet.

Anmärkning

Det interna ManagedWebSocket hanterar Ping/Pong-ramarna implicit för att hålla anslutningen vid liv om KeepAliveInterval alternativet är större än noll, vilket är standardvärdet 30 sekunder (TimeSpan.FromSeconds(30)).

Ursprungsbegränsning för WebSocket

De skydd som tillhandahålls av CORS gäller inte för WebSockets. Webbläsare gör inte:

  • Utför CORS-begäranden före flygning.
  • Respektera de begränsningar som anges i Access-Control rubriker när du gör WebSocket-begäranden.

Webbläsare skickar dock Origin-huvudet när de utfärdar WebSocket-begäranden. Program bör konfigureras för att verifiera dessa huvuden för att säkerställa att endast WebSockets som kommer från det förväntade ursprunget tillåts.

Om du har din server på "https://server.com"" och din klient på "https://client.com"", lägg till "https://client.com"" till listan AllowedOrigins för verifiering av 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);

Anmärkning

Origin-huvudet styrs av klienten och, precis som Referer-huvudet, kan förfalskas. Använd inte dessa huvuden som en autentiseringsmekanism.

Expresssupport för IIS/IIS

Windows Server 2012 eller senare och Windows 8 eller senare med IIS/IIS Express 8 eller senare har stöd för WebSocket-protokollet.

Anmärkning

WebSockets aktiveras alltid när du använder IIS Express.

Aktivera WebSockets på IIS

Så här aktiverar du stöd för WebSocket-protokollet på Windows Server 2012 eller senare:

Anmärkning

De här stegen krävs inte när du använder IIS Express

  1. Använd guiden Lägg till roller och funktioner från menyn Hantera eller länken i Serverhanteraren.
  2. Välj Rollbaserad eller Funktionsbaserad installation. Välj Nästa.
  3. Välj lämplig server (den lokala servern är markerad som standard). Välj Nästa.
  4. Expandera Webbserver (IIS) i trädet Roller , expandera Webbserver och expandera sedan Programutveckling.
  5. Välj WebSocket Protocol. Välj Nästa.
  6. Om ytterligare funktioner inte behövs väljer du Nästa.
  7. Välj Installera.
  8. När installationen är klar klickar du på Stäng för att avsluta guiden.

Så här aktiverar du stöd för WebSocket-protokollet i Windows 8 eller senare:

Anmärkning

De här stegen krävs inte när du använder IIS Express

  1. Gå till Kontrollpanelen>Program>program och funktioner>Aktivera eller inaktivera Windows-funktioner (till vänster på skärmen).
  2. Öppna följande noder: Internet Information Services>World Wide Web Services>Application Development Features.
  3. Välj funktionen WebSocket Protocol. Välj OK.

Inaktivera WebSocket när du använder socket.io på Node.js

Om du använder WebSocket-stöd i socket.ioNode.jsinaktiverar du IIS WebSocket-standardmodulen med elementet webSocket i web.config eller applicationHost.config. Om det här steget inte utförs försöker IIS WebSocket-modulen hantera WebSocket-kommunikationen i stället för Node.js och appen.

<system.webServer>
  <webSocket enabled="false" />
</system.webServer>

Exempelapp

Exempelappen som medföljer den här artikeln är en ekoapp. Den har en webbsida som gör WebSocket-anslutningar, och servern skickar alla meddelanden som den tar emot tillbaka till klienten. Exempelappen är inte konfigurerad att köras från Visual Studio med IIS Express, så kör appen i ett kommandogränssnitt med dotnet run och navigera i en webbläsare till http://localhost:5000. Webbsidan visar anslutningsstatus:

Starttillstånd för webbsidan före WebSockets-anslutning

Välj Anslut för att skicka en WebSocket-begäran till den URL som visas. Ange ett testmeddelande och välj Skicka. När du är klar väljer du Stäng socket. Avsnittet Kommunikationslogg rapporterar varje åtgärd för att öppna, skicka och stänga när det händer.

Sluttillstånd för webbsidan efter att WebSockets-anslutning och testmeddelanden har skickats och tagits emot