WebSockets-Unterstützung in ASP.NET CoreWebSockets support in ASP.NET Core

Von Tom Dykstra und Andrew Stanton-NurseBy Tom Dykstra and Andrew Stanton-Nurse

In diesem Artikel erfahren Sie, wie Sie mit WebSockets in ASP.NET beginnen.This article explains how to get started with WebSockets in ASP.NET Core. Bei WebSockets (RFC 6455) handelt es sich um ein Protokoll, das bidirektionale persistente Kommunikationskanäle über TCP-Verbindungen ermöglicht.WebSocket (RFC 6455) is a protocol that enables two-way persistent communication channels over TCP connections. Es wird in Apps verwendet, die von schneller Kommunikation in Echtzeit profitieren, z.B. Chats, Dashboards und Spiele-Apps.It's used in apps that benefit from fast, real-time communication, such as chat, dashboard, and game apps.

Zeigen Sie Beispielcode an, oder laden Sie diesen herunter (Vorgehensweise zum Herunterladen).View or download sample code (how to download). Laufvergleich.How to run.

SignalR

ASP.NET Core SignalR ist eine Bibliothek, die das Hinzufügen von Echtzeit-Webfunktionalität zu Apps erleichtert.ASP.NET Core SignalR is a library that simplifies adding real-time web functionality to apps. Sie verwendet wenn möglich immer WebSockets.It uses WebSockets whenever possible.

Für die meisten Anwendungen empfehlen wir SignalR über RAW-WebSockets.For most applications, we recommend SignalR over raw WebSockets. SignalR stellt ein Transportfallback für Umgebungen bereit, in denen WebSockets nicht verfügbar ist.SignalR provides transport fallback for environments where WebSockets is not available. Darüber hinaus bietet es ein einfaches App-Modell für Remoteprozeduraufrufe.It also provides a simple remote procedure call app model. In den meisten Szenarien hat SignalR außerdem keinen signifikanten Leistungsnachteil gegenüber der Verwendung von RAW-WebSockets.And in most scenarios, SignalR has no significant performance disadvantage compared to using raw WebSockets.

VoraussetzungenPrerequisites

  • ASP.NET Core 1.1 oder höherASP.NET Core 1.1 or later

  • Jedes Betriebssystem, das ASP.NET Core unterstützt:Any OS that supports ASP.NET Core:

    • Windows 7/Windows Server 2008 und höherWindows 7 / Windows Server 2008 or later
    • LinuxLinux
    • macOSmacOS
  • Wenn die App unter Windows mit IIS ausgeführt wird:If the app runs on Windows with IIS:

    • Windows 8/Windows Server 2012 und höherWindows 8 / Windows Server 2012 or later
    • IIS 8/IIS 8 ExpressIIS 8 / IIS 8 Express
    • WebSockets müssen in IIS aktiviert sein (weitere Informationen finden Sie im Abschnitt Unterstützung für IIS/IIS Express).WebSockets must be enabled (See the IIS/IIS Express support section.).
  • Wenn die App unter HTTP.sys ausgeführt wird:If the app runs on HTTP.sys:

    • Windows 8/Windows Server 2012 und höherWindows 8 / Windows Server 2012 or later
  • Weitere Informationen zu unterstützten Browsern finden Sie unter https://caniuse.com/#feat=websockets.For supported browsers, see https://caniuse.com/#feat=websockets.

NuGet-PaketNuGet package

Installieren Sie das Paket Microsoft.AspNetCore.WebSockets.Install the Microsoft.AspNetCore.WebSockets package.

Konfigurieren der MiddlewareConfigure the middleware

Fügen Sie die WebSockets-Middleware zur Configure-Methode der Startup-Klasse hinzu.Add the WebSockets middleware in the Configure method of the Startup class:

app.UseWebSockets();

Sie können die folgenden Einstellungen konfigurieren:The following settings can be configured:

  • KeepAliveInterval: Legt fest, wie oft Ping-Frames an den Client gesendet werden, um sicherzustellen, dass Proxys die Verbindung aufrechterhaltenKeepAliveInterval - How frequently to send "ping" frames to the client to ensure proxies keep the connection open. Der Standardwert beträgt zwei Minuten.The default is two minutes.
  • ReceiveBufferSize: Legt die Größe des Puffers fest, der zum Empfang von Daten verwendet wirdReceiveBufferSize - The size of the buffer used to receive data. Fortgeschrittene Benutzer müssen diese Angaben möglicherweise ändern, um die Leistung auf Grundlage der Größe ihrer Daten anzupassen.Advanced users may need to change this for performance tuning based on the size of the data. Der Standardwert ist 4 KB.The default is 4 KB.

Sie können die folgenden Einstellungen konfigurieren:The following settings can be configured:

  • KeepAliveInterval: Legt fest, wie oft Ping-Frames an den Client gesendet werden, um sicherzustellen, dass Proxys die Verbindung aufrechterhaltenKeepAliveInterval - How frequently to send "ping" frames to the client to ensure proxies keep the connection open. Der Standardwert beträgt zwei Minuten.The default is two minutes.
  • ReceiveBufferSize: Legt die Größe des Puffers fest, der zum Empfang von Daten verwendet wirdReceiveBufferSize - The size of the buffer used to receive data. Fortgeschrittene Benutzer müssen diese Angaben möglicherweise ändern, um die Leistung auf Grundlage der Größe ihrer Daten anzupassen.Advanced users may need to change this for performance tuning based on the size of the data. Der Standardwert ist 4 KB.The default is 4 KB.
  • AllowedOrigins – Eine Liste der zulässigen Origin-Headerwerte für WebSocket-Anforderungen.AllowedOrigins - A list of allowed Origin header values for WebSocket requests. Alle Ursprünge sind standardmäßig zulässig.By default, all origins are allowed. Weitere Informationen finden Sie unter „Beschränkung von WebSocket-Ursprüngen“ weiter unten.See "WebSocket origin restriction" below for details.
var webSocketOptions = new WebSocketOptions() 
{
    KeepAliveInterval = TimeSpan.FromSeconds(120),
    ReceiveBufferSize = 4 * 1024
};

app.UseWebSockets(webSocketOptions);

Akzeptieren der Anforderungen von WebSocketAccept WebSocket requests

Prüfen Sie zu einem späteren Zeitpunkt im Lebenszyklus einer Anforderung (z.B. später in der Configure-Methode oder in einer Aktionsmethode), ob es sich um eine WebSocket-Anforderung handelt, und akzeptieren Sie diese.Somewhere later in the request life cycle (later in the Configure method or in an action method, for example) check if it's a WebSocket request and accept the WebSocket request.

Das folgende Beispiel ist ein späterer Auszug der Configure-Methode.The following example is from later in the Configure method:

app.Use(async (context, next) =>
{
    if (context.Request.Path == "/ws")
    {
        if (context.WebSockets.IsWebSocketRequest)
        {
            WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
            await Echo(context, webSocket);
        }
        else
        {
            context.Response.StatusCode = 400;
        }
    }
    else
    {
        await next();
    }

});

WebSocket-Anforderungen können bei jeder URL eingehen. Dieser Beispielcode akzeptiert jedoch nur Anforderungen für /ws.A WebSocket request could come in on any URL, but this sample code only accepts requests for /ws.

Bei Verwendung eines WebSockets muss die Middlewarepipeline während der gesamten Dauer der Verbindung ausgeführt werden.When using a WebSocket, you must keep the middleware pipeline running for the duration of the connection. Wenn Sie versuchen, eine WebSocket-Nachricht zu senden oder zu empfangen, nachdem die Middlewarepipeline beendet wurde, erhalten Sie möglicherweise eine Ausnahme wie die folgende:If you attempt to send or receive a WebSocket message after the middleware pipeline ends, you may get an exception like the following:

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

Wenn Sie einen Hintergrunddienst zum Schreiben von Daten an ein WebSocket verwenden, stellen Sie sicher, dass die Middlewarepipeline dauerhaft ausgeführt wird.If you're using a background service to write data to a WebSocket, make sure you keep the middleware pipeline running. Verwenden Sie dafür ein TaskCompletionSource<TResult>.Do this by using a TaskCompletionSource<TResult>. Übergeben Sie die TaskCompletionSource an Ihren Hintergrunddienst, und lassen Sie sie TrySetResult aufrufen, wenn Sie das WebSocket beenden.Pass the TaskCompletionSource to your background service and have it call TrySetResult when you finish with the WebSocket. Verwenden Sie dann await für die Task-Eigenschaft während der Anforderung, wie im folgenden Beispiel gezeigt:Then await the Task property during the request, as shown in the following example:

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

    BackgroundSocketProcessor.AddSocket(socket, socketFinishedTcs); 

    await socketFinishedTcs.Task;
});

Die „closed“-Ausnahme von WebSocket kann auch auftreten, wenn Sie zu früh von einer Aktionsmethode zurückkehren.The WebSocket closed exception can also happen if you return too soon from an action method. Wenn Sie einen Socket in einer Aktionsmethode akzeptieren, warten Sie vor dem Zurückkehren von der Aktionsmethode, bis der Code, der den Socket verwendet, abgeschlossen ist.If you accept a socket in an action method, wait for the code that uses the socket to complete before returning from the action method.

Verwenden Sie nie Task.Wait(), Task.Result oder ähnliche Blockierungsaufrufe, um auf den Abschluss des Sockets zu warten, da dies zu schwerwiegenden Threadingproblemen führen kann.Never use Task.Wait(), Task.Result, or similar blocking calls to wait for the socket to complete, as that can cause serious threading issues. Verwenden Sie immer await.Always use await.

Senden und Empfangen von NachrichtenSend and receive messages

Die AcceptWebSocketAsync-Methode ändert die TCP-Verbindung in eine WebSocket-Verbindung und stellt ein WebSocket-Objekt bereit.The AcceptWebSocketAsync method upgrades the TCP connection to a WebSocket connection and provides a WebSocket object. Verwenden Sie das WebSocket-Objekt, um Nachrichten zu senden und zu empfangen.Use the WebSocket object to send and receive messages.

Der weiter oben gezeigte Code, der WebSocket-Anforderungen akzeptiert, übergibt das WebSocket-Objekt an eine Echo-Methode.The code shown earlier that accepts the WebSocket request passes the WebSocket object to an Echo method. Der Code empfängt eine Nachricht und sendet diese umgehend wieder zurück.The code receives a message and immediately sends back the same message. Nachrichten werden in einer Schleife gesendet und empfangen, bis der Client die Verbindung schließt:Messages are sent and received in a loop until the client closes the connection:

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

Wenn Sie die WebSocket-Verbindung vor Beginn der Schleife akzeptieren, endet die Middlewarepipeline.When accepting the WebSocket connection before beginning the loop, the middleware pipeline ends. Wenn Sie das Socket schließen, wird die Pipeline entladen.Upon closing the socket, the pipeline unwinds. Das bedeutet, dass sich die Anforderung in der Pipeline nicht mehr weiter bewegt, wenn der WebSocket akzeptiert wird.That is, the request stops moving forward in the pipeline when the WebSocket is accepted. Wenn die Schleife beendet und der Socket geschlossen ist, wird die Anforderung in der Pipeline weiter verarbeitet.When the loop is finished and the socket is closed, the request proceeds back up the pipeline.

Behandeln der Trennung der Verbindung mit dem ClientHandle client disconnects

Der Server wird nicht automatisch informiert, wenn die Verbindung mit dem Client wegen Konnektivitätsverlust getrennt wird.The server is not automatically informed when the client disconnects due to loss of connectivity. Der Server empfängt nur dann eine Trennungsnachricht, wenn der Client sie sendet, was bei Verlust der Verbindung nicht möglich ist.The server receives a disconnect message only if the client sends it, which can't be done if the internet connection is lost. Wenn Sie Maßnahmen ergreifen möchten, wenn dies der Fall ist, legen Sie ein Timeout fest für den Fall, dass innerhalb eines bestimmten Zeitfensters keine Eingabe vom Client empfangen wird.If you want to take some action when that happens, set a timeout after nothing is received from the client within a certain time window.

Wenn der Client nicht immer Nachrichten sendet und Sie kein Timeout festlegen möchten, nur weil die Verbindung in den Leerlauf übergeht, lassen Sie den Client einen Timer verwenden, um alle X Sekunden eine Ping-Nachricht zu senden.If the client isn't always sending messages and you don't want to timeout just because the connection goes idle, have the client use a timer to send a ping message every X seconds. Wenn auf dem Server nicht innerhalb von 2*X Sekunden nach einer Nachricht die nächste eingeht, beenden Sie die Verbindung, und melden Sie, dass der Client die Verbindung getrennt hat.On the server, if a message hasn't arrived within 2*X seconds after the previous one, terminate the connection and report that the client disconnected. Warten Sie für den doppelten Zeitraum des erwarteten Zeitintervalls, um zusätzliche Zeit für Netzwerkverzögerungen einzuräumen, die die Ping-Nachricht aufhalten könnten.Wait for twice the expected time interval to leave extra time for network delays that might hold up the ping message.

Beschränkung von WebSocket-UrsprüngenWebSocket origin restriction

Der von CORS erzeugte Schutz gilt nicht für WebSockets.The protections provided by CORS don't apply to WebSockets. Für Browser gilt Folgendes nicht:Browsers do not:

  • Ausführen von CORS-PreflightanforderungenPerform CORS pre-flight requests.
  • Berücksichtigen der Einschränkungen, die in den Access-Control-Headern bei der Erstellung von WebSocket-Anforderungen angegeben sindRespect the restrictions specified in Access-Control headers when making WebSocket requests.

Allerdings senden Browser den Origin-Header, wenn die WebSocket-Anforderungen ausgegeben werden.However, browsers do send the Origin header when issuing WebSocket requests. Anwendungen sollten zur Überprüfung dieser Header konfiguriert werden, um sicherzustellen, dass nur WebSockets von den erwarteten Ursprüngen zulässig sind.Applications should be configured to validate these headers to ensure that only WebSockets coming from the expected origins are allowed.

Wenn Sie Ihren Server unter „https://server.com“ und Ihren Client unter „https://client.com“ hosten, fügen Sie „https://client.com“ zur Liste AllowedOrigins hinzu, damit sie von WebSockets überprüft wird.If you're hosting your server on "https://server.com" and hosting your client on "https://client.com", add "https://client.com" to the AllowedOrigins list for WebSockets to verify.

var webSocketOptions = new WebSocketOptions()
{
    KeepAliveInterval = TimeSpan.FromSeconds(120),
    ReceiveBufferSize = 4 * 1024
};
webSocketOptions.AllowedOrigins.Add("https://client.com");
webSocketOptions.AllowedOrigins.Add("https://www.client.com");

app.UseWebSockets(webSocketOptions);

Hinweis

Der Origin-Header wird vom Client gesteuert und kann wie der Referer-Header überlistet werden.The Origin header is controlled by the client and, like the Referer header, can be faked. Verwenden Sie diese Header nicht als Authentifizierungsmechanismus.Do not use these headers as an authentication mechanism.

Unterstützung für IIS und IIS ExpressIIS/IIS Express support

In Windows Server 2012 oder höher und in Windows 8 oder höher mit IIS 8 oder IIS Express 8 oder höher ist die Unterstützung für das WebSocket-Protokoll enthalten.Windows Server 2012 or later and Windows 8 or later with IIS/IIS Express 8 or later has support for the WebSocket protocol.

Hinweis

WebSockets sind immer aktiviert, wenn Sie IIS Express verwenden.WebSockets are always enabled when using IIS Express.

Aktivieren von WebSockets in IISEnabling WebSockets on IIS

So aktivieren Sie die Unterstützung für das WebSocket-Protokoll unter Windows Server 2012 oder höher:To enable support for the WebSocket protocol on Windows Server 2012 or later:

Hinweis

Diese Schritte sind nicht erforderlich, wenn Sie IIS Express verwenden.These steps are not required when using IIS Express

  1. Verwenden Sie den Assistenten Rollen und Features hinzufügen im Menü Verwalten oder den Link in Server-Manager.Use the Add Roles and Features wizard from the Manage menu or the link in Server Manager.
  2. Klicken Sie auf Rollenbasierte oder featurebasierte Installation.Select Role-based or Feature-based Installation. Klicken Sie auf Weiter.Select Next.
  3. Wählen Sie den entsprechenden Server aus (standardmäßig ist der lokale Server ausgewählt).Select the appropriate server (the local server is selected by default). Klicken Sie auf Weiter.Select Next.
  4. Erweitern Sie Webserver (IIS) in der Struktur Rollen, und erweitern Sie Webserver und anschließend Anwendungsentwicklung.Expand Web Server (IIS) in the Roles tree, expand Web Server, and then expand Application Development.
  5. Wählen Sie WebSocket-Protokoll aus.Select WebSocket Protocol. Klicken Sie auf Weiter.Select Next.
  6. Wenn keine zusätzlichen Features erforderlich sind, klicken Sie auf Weiter.If additional features aren't needed, select Next.
  7. Klicken Sie auf Installieren.Select Install.
  8. Wenn die Installation abgeschlossen ist, klicken Sie auf Schließen, um den Assistenten zu beenden.When the installation completes, select Close to exit the wizard.

So aktivieren Sie die Unterstützung für das WebSocket-Protokoll unter Windows 8 oder höher:To enable support for the WebSocket protocol on Windows 8 or later:

Hinweis

Diese Schritte sind nicht erforderlich, wenn Sie IIS Express verwenden.These steps are not required when using IIS Express

  1. Navigieren Sie zu Systemsteuerung > Programme > Programme und Features > Windows-Features aktivieren oder deaktivieren (links auf dem Bildschirm).Navigate to Control Panel > Programs > Programs and Features > Turn Windows features on or off (left side of the screen).
  2. Öffnen Sie die folgenden Knoten: Internetinformationsdienste > WWW-Dienste > Anwendungsentwicklungsfeatures.Open the following nodes: Internet Information Services > World Wide Web Services > Application Development Features.
  3. Wählen Sie das Feature WebSocket-Protokoll aus.Select the WebSocket Protocol feature. Klicken Sie auf OK.Select OK.

Deaktivieren von WebSocket bei Verwendung von „socket.io“ in „Node.js“Disable WebSocket when using socket.io on Node.js

Wenn Sie die WebSocket-Unterstützung in socket.io in Node.js verwenden, deaktivieren Sie das IIS-WebSocket-Standardmodul mithilfe des webSocket-Elements in web.config oder applicationHost.config. Wenn dieser Schritt nicht durchgeführt wird, versucht das IIS-WebSocket-Modul, die WebSocket-Kommunikation statt Node.js und der App zu verarbeiten.If using the WebSocket support in socket.io on Node.js, disable the default IIS WebSocket module using the webSocket element in web.config or applicationHost.config. If this step isn't performed, the IIS WebSocket module attempts to handle the WebSocket communication rather than Node.js and the app.

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

Beispiel-AppSample app

Die Beispiel-App, die in diesem Artikel verwendet wird, ist eine Echo-App.The sample app that accompanies this article is an echo app. Sie verfügt über eine Webseite, die WebSocket-Verbindungen herstellt. Der Server schickt alle empfangenen Nachrichten zurück an den Client.It has a web page that makes WebSocket connections, and the server resends any messages it receives back to the client. Führen Sie die App über eine Eingabeaufforderung aus (sie ist nicht darauf ausgelegt, von Visual Studio mit IIS Express ausgeführt zu werden), und navigieren Sie zu http://localhost:5000.Run the app from a command prompt (it's not set up to run from Visual Studio with IIS Express) and navigate to http://localhost:5000. Die Webseite zeigt den Verbindungsstatus in der oberen linken Ecke an:The web page shows the connection status in the upper left:

Erster Zustand der Webseite

Klicken Sie auf Connect (Verbinden), um eine WebSocket-Anforderung an die gezeigte URL zu senden.Select Connect to send a WebSocket request to the URL shown. Geben Sie einen Testtext ein, und klicken Sie auf Send (Senden).Enter a test message and select Send. Wenn dies abgeschlossen ist, klicken Sie auf Close Socket (Socket schließen).When done, select Close Socket. Der Abschnitt Kommunikationsprotokoll meldet jede open-, send- und close-Aktion, wenn diese durchgeführt wird.The Communication Log section reports each open, send, and close action as it happens.

Erster Zustand der Webseite