WebSockets.Otp.Core 0.0.3

dotnet add package WebSockets.Otp.Core --version 0.0.3
                    
NuGet\Install-Package WebSockets.Otp.Core -Version 0.0.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="WebSockets.Otp.Core" Version="0.0.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="WebSockets.Otp.Core" Version="0.0.3" />
                    
Directory.Packages.props
<PackageReference Include="WebSockets.Otp.Core" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add WebSockets.Otp.Core --version 0.0.3
                    
#r "nuget: WebSockets.Otp.Core, 0.0.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package WebSockets.Otp.Core@0.0.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=WebSockets.Otp.Core&version=0.0.3
                    
Install as a Cake Addin
#tool nuget:?package=WebSockets.Otp.Core&version=0.0.3
                    
Install as a Cake Tool

WebSockets.Otp

NuGet Status NuGet Status NuGet Status

A minimal WebSocket library for ASP.NET Core inspired by REPR principles. Provides a clean endpoint-based API for building real-time applications.

Quick Start

1. Define your endpoint
[WsEndpoint("chat/message")]
public class ChatEndpoint : WsEndpoint<ChatMessage, ChatResponse>
{
    public override async Task HandleAsync(ChatMessage request, EndpointContext<ChatResponse> context)
    {
        await context.Send
            .Group("general-chat")
            .SendAsync(new ChatResponse
            {
                Username = request.Username,
                Message = request.Message,
                Timestamp = DateTime.UtcNow
            }, default);
    }
}

public class ChatMessage
{
    public string Username { get; set; }
    public string Message { get; set; }
}

public class ChatResponse
{
    public string Username { get; set; }
    public string Message { get; set; }
    public DateTime Timestamp { get; set; }
}
2. Configure services
// Program.cs
builder.Services.AddWsEndpoints();

app.MapEndpoints(
    "/ws",
    (opt) =>
    {
        opt.OnConnected = async (context) =>
        {
            await context.Groups.AddAsync("general-chat", context.ConnectionId);
        };
        opt.OnDisconnected = async (context) =>
        {
            await context.Groups.RemoveAsync("general-chat", context.ConnectionId);
        };
    });

Handshake

The first message sent over a WebSocket connection must be a handshake message. This is required before any endpoint can be invoked.

Client → Server

{"protocol":"json"}

Server → Client

{}

If the first message is not a valid handshake, the server will close the connection. This ensures protocol compatibility and allows for future protocol negotiation.

Endpoint Types

The library supports three endpoint patterns:

1. Simple Endpoint (No request/response)
[WsEndpoint("system/status")]
public class SystemStatusEndpoint : WsEndpoint
{
    public override async Task HandleAsync(EndpointContext context)
    {
        // Handle raw WebSocket messages
        var buffer = context.Payload.Span;
        // Custom processing logic
    }
}
2. Request-only Endpoint (Any type response)
[WsEndpoint("notifications/subscribe")]
public class SubscribeEndpoint : WsEndpoint<SubscribeRequest>
{
    public override async Task HandleAsync(SubscribeRequest request, EndpointContext context)
    {
        await context.Groups.AddAsync("notifications", context.ConnectionId);
        await connection.Send
            .SendAsync(new
            {
                Data = "response"
            }, default);
    }
}
3. Request/Response Endpoint
[WsEndpoint("calculator/add")]
public class AddEndpoint : WsEndpoint<AddRequest, AddResponse>
{
    public override async Task HandleAsync(AddRequest request, EndpointContext<AddResponse> context)
    {
        var result = request.A + request.B;
        await context.Send
            .Client(context.ConnectionId)
            .SendAsync(new AddResponse
            {
                Result = result,
                Operation = "addition"
            }, default);
    }
}

Advanced Features

1. Dependency Injection and lifetime management
[WsEndpoint("auth/validate", ServiceLifetime.Singleton)]
public class AuthEndpoint : WsEndpoint<AuthRequest, AuthResponse>
{
    private readonly IAuthService _authService;
    private readonly ILogger<AuthEndpoint> _logger;

    public AuthEndpoint(IAuthService authService, ILogger<AuthEndpoint> logger)
    {
        _authService = authService;
        _logger = logger;
    }

    public override async Task HandleAsync(AuthRequest request, EndpointContext<AuthResponse> context)
    {
        var isValid = await _authService.ValidateAsync(request.Token);
    }
}
2. Group Management
public class ChatEndpoint : WsEndpoint<ChatMessage>
{
    public override async Task HandleAsync(ChatMessage request, EndpointContext context)
    {
        // Add connection to group
        await context.Groups.AddAsync("chat-room", context.ConnectionId);

        // Send to specific group
        await context.Send
            .Group("chat-room")
            .SendAsync(new { Message = "Welcome!" });

        // Send to multiple groups
        await context.Send
            .Group("chat-room")
            .Group("custom")
            .SendAsync(new { Message = "Welcome!" });

        // Remove from group
        await context.Groups.RemoveAsync("chat-room", context.ConnectionId);
    }
}
3. Authorization

Authorization can be applied globally (per connection), per endpoint, or both. Endpoint-level attributes are evaluated in addition to global settings.

Global (per connection)

Applied to every endpoint mapped under the same base path:

app.MapEndpoints(
    "/ws",
    (opt) =>
    {
        opt.AuthorizationData =
        [
            new AuthorizeAttribute
            {
                AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme
            }
        ];
    });

Per endpoint

Applied only to the decorated endpoint:

[Authorize(Policy = "ws.chat")]
[WsEndpoint("chat/message/send")]
public class ChatEndpoint : WsEndpoint<ChatMessage>
{
    // ...
}

Combined

Global and endpoint-level authorization are additive a connection must satisfy both to reach the endpoint. Use global rules for connection-wide concerns (e.g. authentication scheme) and per-endpoint attributes for fine-grained policies.

4. Distributed Connections

Scale across multiple server instances by backing the connection registry with a shared store. Requires a Redis instance.

Install

dotnet add package WebSockets.Otp.Redis

Setup

Register a Redis multiplexer, then enable the Redis-backed connection manager:

builder.Services.AddSingleton<IConnectionMultiplexer>(
    _ => ConnectionMultiplexer.Connect("localhost:6379"));
builder.Services.AddRedisManager();
5. Custom Serializers

By default, the library uses JSON for message serialization. For custom types or alternative formats (e.g. MessagePack, Protobuf, XML), implement the ISerializer interface from WebSockets.Otp.Abstractions.Serializers and register it as a singleton.

Roadmap

  • Performance & memory optimization
  • Pre/Post processors
  • Rate limiting
  • Versioning
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.0.3 100 9/28/2026
0.0.2 90 9/28/2026
0.0.1 98 9/28/2026
0.0.1-prealpha 121 1/26/2026