# ASP.NET Core WebSockets Implementation: A Deep Dive into the Middleware and Transport Layers

> Discover ASP.NET Core WebSockets implementation. Explore the WebSocketMiddleware and transport layers for efficient real-time communication.

- Repository: [.NET Platform/aspnetcore](https://github.com/dotnet/aspnetcore)
- Tags: deep-dive
- Published: 2026-07-13

---

**ASP.NET Core WebSockets are implemented as a middleware component in [`WebSocketMiddleware.cs`](https://github.com/dotnet/aspnetcore/blob/main/WebSocketMiddleware.cs) that validates the handshake and exposes `IHttpWebSocketFeature`, while the actual network I/O is handled by server-specific engines like [`WebSocketsAsyncIOEngine.cs`](https://github.com/dotnet/aspnetcore/blob/main/WebSocketsAsyncIOEngine.cs) in the transport layer.**

The WebSocket implementation in the `dotnet/aspnetcore` repository follows a layered architecture that separates protocol negotiation from low-level socket operations. This design allows applications to enable WebSocket support with a single middleware registration while relying on server-specific transports like Kestrel or IIS to handle the actual frame I/O. Understanding this architecture helps developers troubleshoot connection issues and optimize their real-time communication pipelines.

## Architecture Overview

The implementation spans three distinct layers that work together to upgrade HTTP connections to WebSocket connections. First, the **middleware layer** detects valid WebSocket requests and manages the handshake negotiation. Second, the **feature layer** exposes configuration options and the `IHttpWebSocketFeature` interface that application code interacts with. Third, the **server transport layer** performs the actual protocol upgrade and manages the raw socket I/O for reading and writing WebSocket frames.

## The Middleware Layer

### WebSocketMiddleware and Handshake Validation

The entry point for WebSocket support is the `WebSocketMiddleware` class located in [`src/Middleware/WebSockets/src/WebSocketMiddleware.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/WebSockets/src/WebSocketMiddleware.cs). This middleware intercepts incoming HTTP requests and checks for the required upgrade headers. When it detects a valid WebSocket handshake request, it performs critical validation steps including origin checking, header validation, and protocol negotiation.

The middleware creates a `WebSocketHandshake` object that encapsulates the negotiation state. It checks for the presence of either `IHttpUpgradeFeature` (for HTTP/1.1) or `IHttpExtendedConnectFeature` (for HTTP/2 extended CONNECT) on the `HttpContext.Features` collection. If the request meets all requirements, the middleware injects an `IHttpWebSocketFeature` into the `HttpContext`, making the WebSocket functionality available to downstream components.

### Request Pipeline Integration

During the upgrade process, the middleware disables request timeouts to accommodate long-lived WebSocket connections. It then delegates the actual transport creation to the server-specific implementation before returning a fully functional `System.Net.WebSockets.WebSocket` instance to the application code. This abstraction allows the same middleware to work across different server implementations without code changes.

## Configuration and Features

### WebSocketOptions

Configuration is centralized in the `WebSocketOptions` class found in [`src/Middleware/WebSockets/src/WebSocketOptions.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/WebSockets/src/WebSocketOptions.cs). This class exposes settings for:

- **Keep-alive intervals** – Controls how often the server sends ping frames to maintain the connection
- **Allowed origins** – A whitelist of origins permitted to connect, preventing unauthorized cross-origin WebSocket requests
- **Compression settings** – Enables per-message deflate compression negotiation

### IHttpWebSocketFeature Interface

The `IHttpWebSocketFeature` interface is the contract that application code uses to interact with WebSocket functionality. When you call `context.WebSockets.AcceptWebSocketAsync()`, you are invoking the implementation provided by this feature. The feature exposes two critical properties: `IsWebSocketRequest` (boolean indicating if the current request is a valid WebSocket upgrade) and `AcceptAsync` (the method that performs the actual handshake and returns a `WebSocket` instance).

## Server Transport Layer

### WebSocketsAsyncIOEngine

The actual network operations happen in `WebSocketsAsyncIOEngine`, located in [`src/Servers/IIS/IIS/src/Core/IO/WebSocketsAsyncIOEngine.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Servers/IIS/IIS/src/Core/IO/WebSocketsAsyncIOEngine.cs). Despite the IIS path in its location, this engine is used by both **Kestrel** and **IIS** servers to handle low-level WebSocket frame I/O.

This engine reads and writes raw WebSocket frames on the underlying network stream. It manages the opaque transport that the middleware wraps using `System.Net.WebSockets.WebSocket.CreateFromStream()`. The engine handles the complexities of frame parsing, masking, and payload delivery without exposing these details to application code.

### Compression Support

For applications requiring compression, the middleware negotiates per-message deflate support using constants defined in [`src/Middleware/WebSockets/src/WebSocketDeflateConstants.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/WebSockets/src/WebSocketDeflateConstants.cs). The `HandshakeHelpers` class manages the negotiation of compression parameters during the initial handshake, allowing the transport layer to compress payloads transparently.

## Enabling WebSockets in Your Application

To add WebSocket support to your application, you must register the middleware and configure options in your [`Program.cs`](https://github.com/dotnet/aspnetcore/blob/main/Program.cs):

```csharp
var builder = WebApplication.CreateBuilder(args);

// Configure services
builder.Services.AddWebSockets(options =>
{
    options.KeepAliveInterval = TimeSpan.FromSeconds(30);
    options.AllowedOrigins.Add("https://example.com");
});

var app = builder.Build();

// Add middleware to pipeline
app.UseWebSockets();

// Map WebSocket endpoint
app.Map("/ws", async context =>
{
    if (!context.WebSockets.IsWebSocketRequest)
    {
        context.Response.StatusCode = 400;
        return;
    }

    var webSocket = await context.WebSockets.AcceptWebSocketAsync();
    var buffer = new byte[4 * 1024];
    
    while (webSocket.State == WebSocketState.Open)
    {
        var result = await webSocket.ReceiveAsync(
            new ArraySegment<byte>(buffer), CancellationToken.None);

        if (result.MessageType == WebSocketMessageType.Close)
        {
            await webSocket.CloseAsync(
                WebSocketCloseStatus.NormalClosure, 
                "Closing", 
                CancellationToken.None);
        }
        else
        {
            await webSocket.SendAsync(
                new ArraySegment<byte>(buffer, 0, result.Count),
                result.MessageType, 
                result.EndOfMessage, 
                CancellationToken.None);
        }
    }
});

```

For low-level access to the feature directly (bypassing the convenience `HttpContext.WebSockets` property):

```csharp
public async Task Invoke(HttpContext context)
{
    var wsFeature = context.Features.Get<IHttpWebSocketFeature>();
    if (wsFeature?.IsWebSocketRequest == true)
    {
        var ws = await wsFeature.AcceptAsync(new WebSocketAcceptContext());
        // ws is a System.Net.WebSockets.WebSocket ready for I/O
    }
}

```

## Summary

- **ASP.NET Core WebSockets implementation** is split between middleware ([`WebSocketMiddleware.cs`](https://github.com/dotnet/aspnetcore/blob/main/WebSocketMiddleware.cs)) for handshake validation and server-specific transport engines ([`WebSocketsAsyncIOEngine.cs`](https://github.com/dotnet/aspnetcore/blob/main/WebSocketsAsyncIOEngine.cs)) for frame I/O.
- The middleware injects `IHttpWebSocketFeature` into the `HttpContext.Features` collection, which provides the `AcceptWebSocketAsync()` method used by application code.
- Configuration is managed through `WebSocketOptions`, supporting keep-alive intervals, origin validation, and compression settings.
- The transport layer is shared between Kestrel and IIS, using the `WebSocketsAsyncIOEngine` class to handle raw socket operations.
- Extension methods in [`WebSocketMiddlewareExtensions.cs`](https://github.com/dotnet/aspnetcore/blob/main/WebSocketMiddlewareExtensions.cs) provide the `UseWebSockets()` and `AddWebSockets()` registration patterns.

## Frequently Asked Questions

### Where is WebSocketMiddleware defined in the ASP.NET Core source code?

`WebSocketMiddleware` is defined in [`src/Middleware/WebSockets/src/WebSocketMiddleware.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/WebSockets/src/WebSocketMiddleware.cs) within the `dotnet/aspnetcore` repository. This class handles the detection of WebSocket upgrade requests, validates the handshake headers, and creates the `WebSocketHandshake` object that manages the connection upgrade process.

### How does ASP.NET Core handle WebSocket compression?

Compression support is implemented through [`WebSocketDeflateConstants.cs`](https://github.com/dotnet/aspnetcore/blob/main/WebSocketDeflateConstants.cs) in the middleware layer, which defines the compression algorithm constants. During the handshake, the `WebSocketMiddleware` negotiates per-message deflate compression if enabled in `WebSocketOptions`. The actual compression and decompression happen at the transport layer, transparent to application code.

### Can ASP.NET Core WebSockets work with HTTP/2?

Yes, the implementation supports HTTP/2 extended CONNECT requests through the `IHttpExtendedConnectFeature` interface. When running on HTTP/2, the middleware checks for this feature instead of the traditional `IHttpUpgradeFeature` used in HTTP/1.1, allowing WebSocket connections to benefit from HTTP/2 multiplexing and header compression where supported.

### What is the difference between the WebSocket middleware and the transport layer?

The **middleware layer** ([`WebSocketMiddleware.cs`](https://github.com/dotnet/aspnetcore/blob/main/WebSocketMiddleware.cs)) handles protocol negotiation, origin validation, and the public API surface exposed via `HttpContext.WebSockets`. The **transport layer** ([`WebSocketsAsyncIOEngine.cs`](https://github.com/dotnet/aspnetcore/blob/main/WebSocketsAsyncIOEngine.cs)) handles the actual binary framing, network reads/writes, and connection management. This separation allows the same middleware to work across different server implementations (Kestrel and IIS) while each server provides its own optimized transport mechanism.