- Features
- Installation
- Quick Start
- Core Concepts
- Advanced Usage
- API Reference
- Inspiration
- Contributing
- License
- 🔄 Automatic Reconnection - Built-in reconnection logic with configurable strategies
- 📡 Reactive Streams - Observable sequences for messages, connections, and disconnections
- 🧵 Thread-Safe - Safe concurrent message sending and receiving
- 📦 Message Queuing - Automatic buffering with channel-based send queue
- ⚡ High Performance - Built on
System.Threading.ChannelsandArrayPool<byte> - 🎯 Type-Safe - Strong typing with text/binary message support
- 🔒 Proper Resource Management - Full
IAsyncDisposablesupport with graceful shutdown
- 👥 Multi-Client Support - Handle multiple WebSocket connections simultaneously
- 📊 Client Tracking - Built-in client metadata and connection management
- 🔔 Event Streams - Observables for client connect/disconnect events
- 🎯 Selective Messaging - Send to specific clients or broadcast to all
- 🛡️ Robust Cleanup - Automatic client cleanup on disconnect
dotnet add package WebSocket.RxRequirements: .NET 10.0 or higher
usingWebSocket.Rx;usingR3;// Create and configure clientawaitusingvarclient=newReactiveWebSocketClient(newUri("wss://echo.websocket.org")){IsReconnectionEnabled=true,KeepAliveInterval=TimeSpan.FromSeconds(30),IsTextMessageConversionEnabled=true};// Subscribe to messagesclient.MessageReceived.Subscribe(msg =>Console.WriteLine($"Received: {msg.Text}"));// Subscribe to connection eventsclient.ConnectionHappened.Subscribe(info =>Console.WriteLine($"Connected: {info.Reason}"));client.DisconnectionHappened.Subscribe(info =>Console.WriteLine($"Disconnected: {info.Reason}"));// Connect and send messagesawaitclient.StartAsync();awaitclient.SendAsTextAsync("Hello WebSocket!");usingWebSocket.Rx;usingR3;// Create and start serverawaitusingvarserver=newReactiveWebSocketServer("http://localhost:8080/"){IsTextMessageConversionEnabled=true};// Subscribe to client eventsserver.ClientConnected.Subscribe(client =>Console.WriteLine($"Client connected: {client.Metadata.Id}"));server.Messages.Subscribe(msg =>{Console.WriteLine($"From {msg.Metadata.Id}: {msg.Message.Text}");// Echo back to senderserver.SendAsTextAsync(msg.Metadata.Id,$"Echo: {msg.Message.Text}");});awaitserver.StartAsync();Console.WriteLine($"Server running with {server.ClientCount} clients");WebSocket.Rx is built around reactive streams using R3:
// Filter and transform messagesclient.MessageReceived.Where(msg =>msg.MessageType==MessageType.Text).Select(msg =>msg.Text.ToUpper()).Subscribe(text =>Console.WriteLine(text));// Debounce reconnection eventsclient.ConnectionHappened.Throttle(TimeSpan.FromSeconds(1)).Subscribe(info =>Console.WriteLine("Stable connection established"));// Send text message (queued)awaitclient.SendAsTextAsync("Hello");// Send binary message (queued)awaitclient.SendAsBinaryAsync(newbyte[]{0x01,0x02});// Send instant (bypasses queue)awaitclient.SendInstantAsync("Urgent message");// Try send (non-blocking)boolsent=client.TrySendAsText("Optional message");// Start connectionawaitclient.StartAsync();// Reconnect manuallyawaitclient.ReconnectAsync();// Stop gracefullyawaitclient.StopAsync(WebSocketCloseStatus.NormalClosure,"Goodbye");// Dispose (automatic cleanup)awaitclient.DisposeAsync();varclient=newReactiveWebSocketClient(newUri("wss://example.com")){// Connection settingsConnectTimeout=TimeSpan.FromSeconds(10),KeepAliveInterval=TimeSpan.FromSeconds(30),KeepAliveTimeout=TimeSpan.FromSeconds(10),// ReconnectionIsReconnectionEnabled=true,// Message handlingIsTextMessageConversionEnabled=true,MessageEncoding=Encoding.UTF8};// Broadcast to all clientsforeach(varclientIdinserver.ConnectedClients.Keys){awaitserver.SendAsTextAsync(clientId,"Broadcast message");}// Send to specific clientsvartargetClients=server.ConnectedClients.Where(c =>c.Value.CustomData?.Contains("premium")==true).Select(c =>c.Key);foreach(varclientIdintargetClients){awaitserver.SendAsTextAsync(clientId,"Premium feature alert!");}client.DisconnectionHappened.Subscribe(info =>{Console.WriteLine($"Disconnect reason: {info.Reason}");if(info.Exception!=null){Console.WriteLine($"Error: {info.Exception.Message}");}});// Wait for connection before sendingclient.ConnectionHappened.Take(1).Subscribe(_ =>client.SendAsTextAsync("Connected!"));// Process messages in batchesclient.MessageReceived.Buffer(TimeSpan.FromSeconds(1)).Where(batch =>batch.Count>0).Subscribe(batch =>Console.WriteLine($"Processed {batch.Count} messages"));| Property | Type | Description |
|---|---|---|
Url | Uri | WebSocket server URL |
IsStarted | bool | Client started state |
IsRunning | bool | Client running state |
IsReconnectionEnabled | bool | Enable auto-reconnect |
MessageReceived | Observable<ReceivedMessage> | Message stream |
ConnectionHappened | Observable<Connected> | Connection stream |
DisconnectionHappened | Observable<Disconnected> | Disconnection stream |
Key Methods:
Task StartAsync()- Start the clientTask StopAsync(status, description)- Stop gracefullyTask ReconnectAsync()- Manual reconnectTask SendAsTextAsync(message)- Send text (queued)Task SendAsBinaryAsync(data)- Send binary (queued)ValueTask DisposeAsync()- Clean up resources
| Property | Type | Description |
|---|---|---|
IsRunning | bool | Server running state |
ClientCount | int | Number of connected clients |
ConnectedClients | IReadOnlyDictionary<Guid, Metadata> | Client metadata |
ClientConnected | Observable<ClientConnected> | Client connect stream |
ClientDisconnected | Observable<ClientDisconnected> | Client disconnect stream |
Messages | Observable<ServerReceivedMessage> | Server message stream |
Key Methods:
Task StartAsync()- Start the serverTask<bool> StopAsync(status, description)- Stop serverTask<bool> SendAsTextAsync(clientId, message)- Send to clientValueTask DisposeAsync()- Clean up resources
This library is inspired by and builds upon the excellent work of:
Websocket.Client by Marfusios
WebSocket.Rx takes inspiration from Websocket.Client's elegant reactive approach to WebSocket communication. Key influences include:
- Reactive-First Design - Using observables for all events and messages
- Automatic Reconnection - Built-in reconnection logic for robust connections
- Clean API - Intuitive and easy-to-use interface
While honoring the spirit of Websocket.Client, WebSocket.Rx offers:
- ✅ R3 Integration - Built on the modern R3 reactive library (successor to Rx.NET)
- ✅ Server Support - Full-featured WebSocket server implementation
- ✅ Modern .NET - Built for .NET 10+ with latest performance optimizations
- ✅ IAsyncDisposable - Proper async resource cleanup
- ✅ Channel-Based Queuing - High-performance message queue using
System.Threading.Channels - ✅ Enhanced Memory Management - Uses
ArrayPool<byte>andRecyclableMemoryStream
Both libraries share the same core philosophy: WebSocket communication should be simple, reactive, and reliable.
Contributions are welcome! This library grows with the community's needs.
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Write tests for your changes
- Ensure all tests pass:
dotnet test - Submit a Pull Request
- ✅ Follow existing code style and conventions
- ✅ Include unit tests for new features
- ✅ Update documentation for API changes
- ✅ Keep PRs focused and atomic
- ✅ Write meaningful commit messages
git clone https://github.com/st0o0/WebSocket.Rx.git
cd WebSocket.Rx
dotnet restore
dotnet build
dotnet testThis project is licensed under the MIT License - see the LICENSE file for details.
Built with ❤️ for the .NET community
