Skip to main content
net8.0

SwaggerUI integration for ASP.NET Core SignalR hubs with interactive invocation, streaming, and client events

Published
Feb 22, 2026
7mo ago
Total Downloads
2.6K
2,589

Install

dotnet add package SignalR.OpenApi.SwaggerUi --version 1.0.222.13
ProductVersions
.NET
net8.0

README

SignalR.OpenApi

Build NuGet

OpenAPI 3.1 specification generation and SwaggerUI support for ASP.NET Core SignalR hubs.

Features

  • Generates OpenAPI 3.1 specifications from SignalR hub methods
  • Interactive SwaggerUI with SignalR protocol invocation (no HTTP β€” real SignalR calls)
  • Streaming support: IAsyncEnumerable<T> and ChannelReader<T> with accumulated item history and stream state tracking
  • Client event monitoring: Auto-subscribes to typed hub (Hub<TClient>) events with real-time event log panel
  • Supports standard ASP.NET Core attributes ([Authorize], [Tags], [EndpointSummary], [Obsolete], etc.)
  • XML documentation comments for descriptions and examples
  • [JsonPolymorphic] / [JsonDerivedType] polymorphic schema support with OData-style sub-endpoints
  • Data Annotation validation attributes mapped to OpenAPI schema constraints
  • FluentValidation rules mapped to OpenAPI schema constraints
  • Security scheme detection from [Authorize] / [AllowAnonymous]
  • JWT Bearer token support in SwaggerUI (header or query string)
  • Connection status indicator with automatic reconnection handling
  • Form-urlencoded input mode for primitive and flat object parameters
  • Multiple named request/response examples via custom attributes
  • Embedded @microsoft/signalr bundle (no CDN dependency)
  • Zero proprietary attributes required for core functionality

Getting Started

Installation

dotnet add package SignalR.OpenApi
dotnet add package SignalR.OpenApi.SwaggerUi

Usage

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSignalR();
builder.Services.AddSignalROpenApi();
builder.Services.AddSignalRSwaggerUi();

var app = builder.Build();

app.MapHub<ChatHub>("/hubs/chat");
app.MapSignalROpenApi();
app.UseSignalRSwaggerUi();

app.Run();

The OpenAPI specification is served at /openapi/signalr-v1.json. The SwaggerUI is available at /signalr-swagger.

Configuration

builder.Services.AddSignalROpenApi(options =>
{
    options.DocumentTitle = "My SignalR API";
    options.DocumentVersion = "v1";
    options.StripAsyncSuffix = true;
});

builder.Services.AddSignalRSwaggerUi(options =>
{
    options.RoutePrefix = "signalr-swagger";    // SwaggerUI route (default)
    options.SpecUrl = "/openapi/signalr-v1.json"; // Spec endpoint (default)
    options.DocumentTitle = "SignalR API";       // Browser tab title (default)
});

SwaggerUI Features

Method Labels

SignalR operations display custom method labels in SwaggerUI:

Label Description
INVOKE Standard hub method invocation
STREAM Streaming method (IAsyncEnumerable<T> / ChannelReader<T>)
EVENT Client event from typed hub (Hub<TClient>)

Streaming

Streaming operations accumulate items into a growing response array as they arrive. The response shows:

{
  "state": "streaming",
  "count": 5,
  "items": [10, 9, 8, 7, 6]
}

When the stream completes, the state changes to "completed". If an error occurs, it shows "error: ...". A Stop Stream button appears while streaming is active to cancel the subscription.

Client Events

Client events (from Hub<TClient> interface methods) appear as EVENT operations. When you expand one, an event log panel shows:

  • Connection status: Connected / Disconnected indicator
  • Connect & Listen: Button to establish hub connection and start receiving events
  • Event log: Real-time list of received events with timestamps and JSON payloads
  • Clear Log: Button to reset the event history

Events are automatically subscribed when connecting to a hub via any invoke or stream operation.

Request Body Input Modes

Hub methods with parameters support two input modes, selectable via a content-type dropdown in SwaggerUI:

Content Type Input Mode Available When
application/json Raw JSON textarea Always
application/x-www-form-urlencoded Individual form fields Primitive params, single flat objects, polymorphic sub-endpoints

The dropdown appears above the request body when you click Try it out. Form field values are automatically coerced to the correct type (e.g., "5" β†’ 5 for integers, "true" β†’ true for booleans).

Note: Methods with multi-object parameters (two or more complex objects) only support application/json because SwaggerUI cannot render nested objects as form fields.

Polymorphic Parameters

Parameters using [JsonPolymorphic] / [JsonDerivedType] are supported via two mechanisms:

  1. Main endpoint (/hubs/Chat/SendNotification) β€” uses oneOf with a discriminator for the type selector dropdown in JSON mode.
  2. OData-style sub-endpoints (/hubs/Chat/SendNotification/text, /hubs/Chat/SendNotification/alert) β€” each derived type gets its own endpoint with a flat schema, supporting both JSON and form-urlencoded input.
[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")]
[JsonDerivedType(typeof(TextNotification), "text")]
[JsonDerivedType(typeof(AlertNotification), "alert")]
public abstract class Notification
{
    public required string Recipient { get; set; }
}

public class TextNotification : Notification
{
    public required string Content { get; set; }
}

public class AlertNotification : Notification
{
    public required string Title { get; set; }
    public required string Severity { get; set; }
}

Note: System.Text.Json polymorphic deserialization requires the type discriminator property to appear first in the JSON object. The SwaggerUI plugin handles this automatically for sub-endpoints.

Supported Attributes

Attribute OpenAPI Mapping
[Tags("group")] tags on operation
[EndpointSummary("...")] summary on operation
[EndpointDescription("...")] description on operation
[EndpointName("Name")] operationId on operation
[Description("...")] description on parameter/property
[Authorize] / [AllowAnonymous] security requirement
[ApiExplorerSettings(IgnoreApi = true)] Excluded from spec
[ExcludeFromDescription] Excluded from spec
[Produces("application/json")] Response content type
[Obsolete] deprecated: true
[JsonPolymorphic] / [JsonDerivedType] discriminator / oneOf with sub-endpoints
[Required], [StringLength], [Range] Schema constraints
XML <summary>, <param>, <returns> Descriptions
XML <example> Example values
[SignalROpenApiRequestExamples] Named request examples
[SignalROpenApiResponseExamples] Named response examples

Request Body Schema

Hub method parameters are mapped to the OpenAPI request body schema:

  • Single complex object parameter (e.g., SendMessage(SendMessageRequest request)): The object's properties are flattened directly into the request body β€” no wrapper property.
  • Multiple parameters (e.g., SendMessage(string user, string message) or Reply(ChatMessage original, ChatMessage reply)): Each parameter becomes a named property in a wrapper object.
  • Primitive parameters (e.g., string, int): Always wrapped with the parameter name as the property key.

Response Codes

  • 204 No Content: Hub methods returning void or Task (no return value)
  • 200 OK: Hub methods returning Task<T> or streaming results

Examples

Provide multiple named examples for request and response bodies using custom attributes and the ISignalROpenApiExamplesProvider<T> interface.

1. Define a request model and example provider

public class SendMessageRequest
{
    public string User { get; set; } = string.Empty;
    public string Message { get; set; } = string.Empty;
}

public class SendMessageExamplesProvider : ISignalROpenApiExamplesProvider<SendMessageRequest>
{
    public IEnumerable<SignalROpenApiExample<SendMessageRequest>> GetExamples()
    {
        yield return new SignalROpenApiExample<SendMessageRequest>(
            "Greeting",
            new SendMessageRequest { User = "Alice", Message = "Hello, everyone!" })
        {
            Summary = "A friendly greeting",
        };

        yield return new SignalROpenApiExample<SendMessageRequest>(
            "Question",
            new SendMessageRequest { User = "Bob", Message = "What time is the meeting?" })
        {
            Summary = "Asking a question",
        };
    }
}

2. Apply the attribute to a hub method

[SignalROpenApiRequestExamples(typeof(SendMessageExamplesProvider))]
public async Task SendMessage(string user, string message)
{
    await Clients.All.ReceiveMessage(user, message);
}

The examples appear in SwaggerUI's example dropdown for the request body. Response examples work the same way using [SignalROpenApiResponseExamples].

Example providers are resolved from DI first, with Activator.CreateInstance as a fallback.

FluentValidation Integration

The SignalR.OpenApi.FluentValidation package automatically maps FluentValidation rules to OpenAPI schema constraints.

Note: FluentValidation applies to complex object parameters only (classes with properties). Hub methods with primitive parameters (e.g., string user, string message) are not validated β€” use a request object instead (e.g., SendMessage(SendMessageRequest request)). When a hub method has a single complex object parameter, the schema is flattened β€” the object's properties appear directly in the request body without a wrapper property.

Setup

builder.Services.AddValidatorsFromAssemblyContaining<MyValidator>();
builder.Services.AddSignalROpenApi();
builder.Services.AddSignalRFluentValidation();

Supported Rules

FluentValidation Rule OpenAPI Schema
NotNull() / NotEmpty() required, nullable: false
NotEmpty() (string) minLength: 1
Length(min, max) / MaximumLength(n) minLength, maxLength
Matches(regex) pattern
GreaterThan(n) minimum + exclusiveMinimum
GreaterThanOrEqualTo(n) minimum
LessThan(n) maximum + exclusiveMaximum
LessThanOrEqualTo(n) maximum
InclusiveBetween(from, to) minimum, maximum
ExclusiveBetween(from, to) minimum, maximum + exclusive flags
EmailAddress() pattern (email regex)

Validators are resolved from DI via IValidator<T>. Nested child validators are supported.

Packages

Package Description
SignalR.OpenApi Core library: hub discovery, OpenAPI generation
SignalR.OpenApi.FluentValidation FluentValidation rules β†’ OpenAPI schema constraints
SignalR.OpenApi.SwaggerUi SwaggerUI with interactive SignalR invocation, streaming, and event monitoring

Related Projects

The following open-source projects also provide OpenAPI, SwaggerUI, or developer tooling for ASP.NET Core SignalR hubs. SignalR.OpenApi was designed with awareness of these projects and aims to combine the best aspects of each.

Feature SignalR.OpenApi SigSpec SignalRSwaggerGen TypedSignalR.Client.DevTools NSwag4SignalR
OpenAPI spec generation βœ… 3.1 βœ… Custom (SigSpec) βœ… Swagger 2.0 / OAS 3.0 βœ… Custom (spec.json) βœ… 3.0
OpenAPI library Microsoft.AspNetCore.OpenApi Custom Swashbuckle IDocumentFilter Custom NSwag IDocumentProcessor
Interactive UI βœ… SwaggerUI (Swashbuckle) ❌ ❌ Spec only βœ… Custom (Next.js / Bulma) βœ… SwaggerUI (NSwag)
Real SignalR invocation βœ… @microsoft/signalr ❌ ❌ βœ… @microsoft/signalr βœ… @microsoft/signalr
Streaming UI βœ… Accumulated history, state tracking, stop button ❌ ❌ βœ… Server-to-client & client-to-server βœ… PUT operations
Client event monitoring βœ… Real-time event log panel ❌ ❌ βœ… Event subscription βœ… GET operations
Hub discovery Reflection Reflection Attribute-based ([SignalRHub]) Source generator (MapHub<T>()) Endpoint metadata (HubMetadata)
FluentValidation β†’ schema βœ… ❌ ❌ ❌ ❌
Polymorphic types βœ… oneOf/discriminator + sub-endpoints ❌ ❌ ❌ ❌
Form-urlencoded input βœ… Flat params & objects ❌ ❌ ❌ ❌
Named examples βœ… Custom attributes + providers ❌ ❌ ❌ ❌
Auth (JWT / Windows) βœ… Built-in SwaggerUI ❌ βœ… [Authorize] detection βœ… accessTokenFactory ❌
Standard attributes βœ… [Tags], [EndpointSummary], [Authorize], [Obsolete], etc. Partial βœ… [Authorize], custom Partial Partial
Target framework .NET 8+ .NET Core 3.1+ .NET 5+ .NET 6+ .NET 10
NuGet packages 3 packages ❌ βœ… βœ… ❌

Other related projects

Project Description
nswag-fluentvalidation (ZymLabs) FluentValidation β†’ OpenAPI schema mapping for NSwag; rule-based architecture pattern
Swashbuckle.AspNetCore.Filters Request/response examples and security filters for Swashbuckle
Signalr.Hubs.TypeScriptGenerator TypeScript type generation from SignalR hubs (legacy .NET Framework / SignalR 2.x)

License

MIT

Adoption Assessment

Assess this package against its supported frameworks, license, maintenance signals and dependency graph before making it a project standard.

Compatibility metadata lists 1 target framework; confirm the exact target used by your application.

Related Guides & Workflows

Learn how to evaluate, integrate, or audit this package in your .NET project.