This document provides detailed information about the features and usage of the Cyaim.WebSocketServer core library.
- Overview
- Quick Start
- Routing System
- Handlers
- Middleware
- Configuration Options
- Request and Response
- Advanced Features
Cyaim.WebSocketServer is a lightweight, high-performance WebSocket server library that provides MVC-like routing mechanisms, supporting full-duplex communication, multiplexing, and pipeline processing.
- ✅ Lightweight & High Performance - Based on ASP.NET Core, excellent performance
- ✅ Routing System - MVC-like routing mechanism, supports RESTful API
- ✅ Full Duplex Communication - Supports bidirectional communication
- ✅ Multiplexing - Single connection supports multiple requests/responses
- ✅ Pipeline Processing - Supports middleware pipeline pattern
- ✅ Type Safety - Strongly typed parameter binding and responses
dotnet add package Cyaim.WebSocketServerusing Cyaim.WebSocketServer.Infrastructure.Handlers.MvcHandler;
using Cyaim.WebSocketServer.Infrastructure.Configures;
var builder = WebApplication.CreateBuilder(args);
// Configure WebSocket route
builder.Services.ConfigureWebSocketRoute(x =>
{
// Define channels
x.WebSocketChannels = new Dictionary<string, WebSocketRouteOption.WebSocketChannelHandler>()
{
{ "/ws", new MvcChannelHandler(4 * 1024).ConnectionEntry }
};
x.ApplicationServiceCollection = builder.Services;
});var app = builder.Build();
// Configure WebSocket options
var webSocketOptions = new WebSocketOptions()
{
KeepAliveInterval = TimeSpan.FromSeconds(120)
};
app.UseWebSockets(webSocketOptions);
app.UseWebSocketServer();using Cyaim.WebSocketServer.Infrastructure.Attributes;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
[WebSocket]
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
return new[]
{
new WeatherForecast { Date = DateTime.Now, TemperatureC = 25 }
};
}
}Channels are entry points for WebSocket connections, with each channel corresponding to a handler.
x.WebSocketChannels = new Dictionary<string, WebSocketRouteOption.WebSocketChannelHandler>()
{
{ "/ws", mvcHandler.ConnectionEntry }, // MVC handler
{ "/api", customHandler.ConnectionEntry } // Custom handler
};Use the [WebSocket] attribute to mark WebSocket endpoints:
[WebSocket]
[HttpGet]
public string GetMessage()
{
return "Hello, WebSocket!";
}Note: The method parameter of the [WebSocket] attribute is case-insensitive.
MvcChannelHandler is the default MVC-style handler that supports routing to controllers and action methods.
// Receive and send buffer sizes (default 4KB)
var handler = new MvcChannelHandler(
receiveBufferSize: 4 * 1024,
sendBufferSize: 4 * 1024
);var handler = new MvcChannelHandler();
// Receive buffer sizes
handler.ReceiveTextBufferSize = 8 * 1024;
handler.ReceiveBinaryBufferSize = 8 * 1024;
// Send buffer sizes
handler.SendTextBufferSize = 8 * 1024;
handler.SendBinaryBufferSize = 8 * 1024;
// Response send timeout
handler.ResponseSendTimeout = TimeSpan.FromSeconds(30);Implement the IWebSocketHandler interface to create custom handlers:
public class CustomHandler : IWebSocketHandler
{
public WebSocketHandlerMetadata Metadata { get; } = new WebSocketHandlerMetadata
{
Describe = "Custom handler",
CanHandleBinary = true,
CanHandleText = true
};
public async Task ConnectionEntry(HttpContext context, WebSocket webSocket)
{
// Handle connection logic
}
}WebSocketRouteMiddleware is the core middleware responsible for:
- Routing WebSocket requests to corresponding channels
- Managing WebSocket connection lifecycle
- Handling connection upgrades
app.UseWebSockets(webSocketOptions);
app.UseWebSocketServer();builder.Services.ConfigureWebSocketRoute(x =>
{
// Channel configuration
x.WebSocketChannels = new Dictionary<string, WebSocketRouteOption.WebSocketChannelHandler>();
// Service collection (for dependency injection)
x.ApplicationServiceCollection = builder.Services;
// Bandwidth limit policy (optional)
x.BandwidthLimitPolicy = new BandwidthLimitPolicy
{
Enabled = true,
// ... configuration
};
// Cluster configuration (optional)
x.EnableCluster = false;
});var webSocketOptions = new WebSocketOptions()
{
// Keep-Alive interval
KeepAliveInterval = TimeSpan.FromSeconds(120),
// Receive buffer size (deprecated, configure in handler)
// ReceiveBufferSize = 4 * 1024
};Requests use JSON format, following the MvcRequestScheme structure:
{
"target": "ControllerName.ActionName",
"body": {
"param1": "value1",
"param2": 123
}
}Note: The target parameter is case-insensitive.
{
"target": "WeatherForecast.Get",
"body": {}
}{
"target": "WeatherForecast.Get",
"body": {
"city": "Beijing",
"date": "2024-01-01"
}
}Responses use JSON format, following the MvcResponseScheme structure:
{
"Target": "WeatherForecast.Get",
"Status": 0,
"Msg": null,
"RequestTime": 637395762382112345,
"CompleteTime": 637395762382134526,
"Body": {
// Method return value
}
}Target: Target method of the requestStatus: Status code (0 indicates success)Msg: Error message (if any)RequestTime: Request time (Ticks)CompleteTime: Completion time (Ticks)Body: Method return value
Two message types are supported:
- Text: Text messages (JSON format)
- Binary: Binary messages
MvcChannelHandler supports request pipelines, allowing custom logic to be inserted at different stages of request processing:
var handler = new MvcChannelHandler();
// Execute before request parsing
handler.RequestPipeline.TryAdd(
RequestPipelineStage.BeforeParse,
new ConcurrentQueue<PipelineItem>()
);
// Add pipeline item
handler.RequestPipeline[RequestPipelineStage.BeforeParse].Enqueue(
new PipelineItem
{
Name = "CustomMiddleware",
Handler = async (context, next) =>
{
// Custom logic
await next();
}
}
);BeforeParse: Before parsing requestAfterParse: After parsing requestBeforeInvoke: Before invoking methodAfterInvoke: After invoking methodBeforeSend: Before sending responseAfterSend: After sending response
Controllers support full dependency injection:
public class WeatherForecastController : ControllerBase
{
private readonly ILogger<WeatherForecastController> _logger;
private readonly IWeatherService _weatherService;
public WeatherForecastController(
ILogger<WeatherForecastController> logger,
IWeatherService weatherService)
{
_logger = logger;
_weatherService = weatherService;
}
[WebSocket]
[HttpGet]
public async Task<WeatherForecast> Get(string city)
{
return await _weatherService.GetWeatherAsync(city);
}
}Multiple parameter binding methods are supported:
[WebSocket]
public string GetMessage(string message)
{
return $"Received: {message}";
}Request:
{
"target": "Controller.GetMessage",
"body": {
"message": "Hello"
}
}public class RequestModel
{
public string Name { get; set; }
public int Age { get; set; }
}
[WebSocket]
public string Process(RequestModel model)
{
return $"Name: {model.Name}, Age: {model.Age}";
}Request:
{
"target": "Controller.Process",
"body": {
"name": "John",
"age": 30
}
}[WebSocket]
public string ProcessList(List<string> items)
{
return string.Join(", ", items);
}Request:
{
"target": "Controller.ProcessList",
"body": {
"items": ["item1", "item2", "item3"]
}
}Full support for async methods:
[WebSocket]
public async Task<string> GetAsync(string id)
{
var data = await _repository.GetAsync(id);
return data;
}Exceptions thrown by methods are caught and returned as error responses:
{
"Target": "Controller.Action",
"Status": 1,
"Msg": "Exception message",
"RequestTime": 123456789,
"CompleteTime": 123456790,
"Body": null
}Custom error handling can be implemented in the pipeline:
handler.RequestPipeline[RequestPipelineStage.AfterInvoke].Enqueue(
new PipelineItem
{
Name = "ErrorHandler",
Handler = async (context, next) =>
{
try
{
await next();
}
catch (Exception ex)
{
// Custom error handling
context.Response.Status = 1;
context.Response.Msg = ex.Message;
}
}
}
);Adjust buffer sizes based on message size:
// Small messages (< 4KB)
var handler = new MvcChannelHandler(4 * 1024, 4 * 1024);
// Medium messages (4KB - 64KB)
var handler = new MvcChannelHandler(64 * 1024, 64 * 1024);
// Large messages (> 64KB)
var handler = new MvcChannelHandler(256 * 1024, 256 * 1024);Use static dictionary to manage connections:
// Get all connections
var connections = MvcChannelHandler.Clients;
// Check if connection exists
if (MvcChannelHandler.Clients.TryGetValue(connectionId, out var webSocket))
{
// Connection exists
}MvcChannelHandler supports concurrent processing of multiple requests, with each connection processed independently.
- Use Dependency Injection - Fully utilize ASP.NET Core's dependency injection system
- Async Methods - Use async methods for I/O operations to improve performance
- Error Handling - Properly handle exceptions and return meaningful error messages
- Parameter Validation - Validate parameters in methods to ensure data validity
- Logging - Use logging to record important operations and errors
For complete examples, refer to: