Ecng.Net.SocketIO
1.0.486
dotnet add package Ecng.Net.SocketIO --version 1.0.486
NuGet\Install-Package Ecng.Net.SocketIO -Version 1.0.486
<PackageReference Include="Ecng.Net.SocketIO" Version="1.0.486" />
<PackageVersion Include="Ecng.Net.SocketIO" Version="1.0.486" />
<PackageReference Include="Ecng.Net.SocketIO" />
paket add Ecng.Net.SocketIO --version 1.0.486
#r "nuget: Ecng.Net.SocketIO, 1.0.486"
#:package Ecng.Net.SocketIO@1.0.486
#addin nuget:?package=Ecng.Net.SocketIO&version=1.0.486
#tool nuget:?package=Ecng.Net.SocketIO&version=1.0.486
Ecng.Net.SocketIO
A high-performance .NET client library for WebSocket communication with automatic reconnection, message resending, and comprehensive connection state management.
Features
- WebSocket Client Implementation - Full-featured WebSocket client with async/await support
- Automatic Reconnection - Configurable reconnection attempts with exponential backoff
- Command Resending - Automatic resend of commands after reconnection
- Connection State Tracking - Track and aggregate connection states across multiple connections
- JSON Serialization - Built-in JSON serialization for object messages
- Flexible Logging - Customizable logging hooks for info, error, and verbose messages
- RestSharp Integration - Helper methods for REST API calls with authentication
- Thread-Safe - Safe to use in multi-threaded environments
Installation
Add the package reference to your project:
<PackageReference Include="Ecng.Net.SocketIO" Version="x.x.x" />
Quick Start
Basic WebSocket Connection
using Ecng.Net;
var socket = new WebSocketClient(
url: "wss://example.com/socket",
stateChanged: state => Console.WriteLine($"State: {state}"),
error: ex => Console.WriteLine($"Error: {ex.Message}"),
process: (msg, ct) =>
{
Console.WriteLine($"Received: {msg.AsString()}");
return ValueTask.CompletedTask;
},
infoLog: (fmt, args) => Console.WriteLine(fmt, args),
errorLog: (fmt, args) => Console.Error.WriteLine(fmt, args),
verboseLog: (fmt, args) => Console.WriteLine($"[VERBOSE] {fmt}", args)
);
await socket.ConnectAsync(CancellationToken.None);
Sending Messages
// Send JSON object
await socket.SendAsync(new { type = "subscribe", channel = "trades" });
// Send string
await socket.SendAsync("Hello, WebSocket!");
// Send raw bytes
byte[] data = Encoding.UTF8.GetBytes("Raw message");
await socket.SendAsync(data, WebSocketMessageType.Text);
Core Components
WebSocketClient
The main class for WebSocket communication.
Constructor Parameters
public WebSocketClient(
string url, // WebSocket URL (ws:// or wss://)
Action<ConnectionStates> stateChanged, // Connection state change callback
Action<Exception> error, // Error handler
Func<WebSocketMessage, CancellationToken, ValueTask> process, // Message processor
Action<string, object> infoLog, // Info log handler
Action<string, object> errorLog, // Error log handler
Action<string, object> verboseLog // Verbose log handler (can be null)
)
Configuration Properties
// Reconnection settings
socket.ReconnectAttempts = 10; // -1 for infinite, 0 for no reconnect
socket.ReconnectInterval = TimeSpan.FromSeconds(5);
socket.ResendInterval = TimeSpan.FromSeconds(2);
socket.ResendTimeout = TimeSpan.FromMilliseconds(500);
// Message encoding
socket.Encoding = Encoding.UTF8;
// Buffer sizes
socket.BufferSize = 1024 * 1024; // 1MB for compressed data
socket.BufferSizeUncompress = 10 * 1024 * 1024; // 10MB for uncompressed
// JSON serialization
socket.Indent = true;
socket.SendSettings = new JsonSerializerSettings { ... };
// Auto-resend control
socket.DisableAutoResend = false;
Connection Management
// Connect
await socket.ConnectAsync(cancellationToken);
socket.Connect(); // Synchronous version
// Disconnect
socket.Disconnect();
// Check connection state
bool isConnected = socket.IsConnected;
ConnectionStates currentState = socket.State;
// Abort connection immediately
socket.Abort();
Sending Messages with Subscription Tracking
// Send with subscription ID for automatic resend after reconnect
long subscriptionId = 12345;
await socket.SendAsync(
obj: new { action = "subscribe", symbol = "BTCUSD" },
subId: subscriptionId
);
// Unsubscribe (negative ID removes from resend queue)
await socket.SendAsync(
obj: new { action = "unsubscribe", symbol = "BTCUSD" },
subId: -subscriptionId
);
// Manual resend management
socket.RemoveResend(subscriptionId); // Remove specific subscription
socket.RemoveResend(); // Remove all subscriptions
Advanced Features
// Custom initialization
socket.Init += ws =>
{
ws.Options.SetRequestHeader("X-Custom-Header", "value");
ws.Options.KeepAliveInterval = TimeSpan.FromSeconds(30);
};
// Post-connect hook
socket.PostConnect += async (isReconnect, ct) =>
{
if (isReconnect)
Console.WriteLine("Reconnected! Resubscribing...");
await Task.CompletedTask;
};
// Pre-process received data (e.g., decompression)
socket.PreProcess2 = (input, output) =>
{
// Decompress or transform data
input.CopyTo(output);
return input.Length;
};
// Send ping frame
await socket.SendOpCode(0x9);
WebSocketMessage
Represents an incoming message from the WebSocket.
// In your message processor
Func<WebSocketMessage, CancellationToken, ValueTask> process = (msg, ct) =>
{
// Get as string
string text = msg.AsString();
// Deserialize to object
var trade = msg.AsObject<TradeData>();
// Deserialize to dynamic
dynamic data = msg.AsObject();
// Get JSON reader for streaming
using var reader = msg.AsReader();
// Access raw bytes
ReadOnlyMemory<byte> bytes = msg.Memory;
return ValueTask.CompletedTask;
};
Connection States
The ConnectionStates enum represents the current state of the connection:
public enum ConnectionStates
{
Disconnected, // Not connected
Disconnecting, // In process of disconnecting
Connecting, // In process of connecting
Connected, // Successfully connected
Reconnecting, // Attempting to reconnect
Restored, // Connection restored after reconnect
Failed // Connection failed
}
ConnectionStateTracker
Track and aggregate states across multiple connections.
var tracker = new ConnectionStateTracker();
// Add connections
tracker.Add(socket1);
tracker.Add(socket2);
// Monitor overall state
tracker.StateChanged += state =>
Console.WriteLine($"Overall state: {state}");
// Connect all
await tracker.ConnectAsync(CancellationToken.None);
// Disconnect all
tracker.Disconnect();
// Remove connections
tracker.Remove(socket1);
The tracker aggregates states with the following logic:
- Connected: All connections are connected
- Reconnecting: Any connection is reconnecting
- Restored: All connections are connected or restored
- Failed: All connections have failed
- Disconnected: All connections are disconnected or failed
IConnection Interface
Standard interface for connection management:
public interface IConnection
{
event Action<ConnectionStates> StateChanged;
ValueTask ConnectAsync(CancellationToken cancellationToken);
void Disconnect();
}
Both WebSocketClient and ConnectionStateTracker implement this interface.
RestSharp Integration
The library includes helper methods for REST API calls, often used alongside WebSocket connections.
Basic REST Request
using Ecng.Net;
using RestSharp;
var request = new RestRequest(Method.Get);
request.AddQueryParameter("symbol", "BTCUSD");
var response = await request.InvokeAsync<PriceData>(
url: new Uri("https://api.example.com/price"),
caller: this,
logVerbose: (fmt, args) => Console.WriteLine(fmt, args),
token: CancellationToken.None
);
Console.WriteLine($"Price: {response.Price}");
Authentication
// Bearer token authentication
request.SetBearer(secureToken);
// Custom authenticator
var authenticator = new MyCustomAuthenticator();
var response = await request.InvokeAsync2<Data>(
url: apiUrl,
caller: this,
logVerbose: logger,
token: cancellationToken,
auth: authenticator
);
Error Handling
try
{
var response = await request.InvokeAsync<Data>(url, this, logger, token);
}
catch (RestSharpException ex)
{
Console.WriteLine($"HTTP {ex.Response.StatusCode}: {ex.Response.Content}");
Console.WriteLine($"Error: {ex.Message}");
}
Advanced REST Features
// Custom content converter
var response = await request.InvokeAsync<Data>(
url: apiUrl,
caller: this,
logVerbose: logger,
token: cancellationToken,
contentConverter: content => content.Replace("null", "\"\"")
);
// Handle specific error status codes
var response = await request.InvokeAsync3<Data>(
url: apiUrl,
caller: this,
logVerbose: logger,
token: cancellationToken,
handleErrorStatus: statusCode =>
{
if (statusCode == HttpStatusCode.TooManyRequests)
{
// Custom handling
return true; // Handled
}
return false; // Not handled, will throw
}
);
// Add body as string
request.AddBodyAsStr("{\"key\": \"value\"}");
// Remove parameters
request.RemoveWhere(p => p.Name == "old_param");
// Convert parameters to query string
string queryString = request.Parameters.ToQueryString();
JWT Decoding
string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...";
var parts = token.DecodeJWT();
foreach (var part in parts)
{
Console.WriteLine(part);
}
Complete Examples
Crypto Exchange WebSocket Client
public class CryptoExchangeClient : IDisposable
{
private readonly WebSocketClient _socket;
private long _subscriptionCounter;
public CryptoExchangeClient(string wsUrl)
{
_socket = new WebSocketClient(
url: wsUrl,
stateChanged: OnStateChanged,
error: OnError,
process: ProcessMessage,
infoLog: (fmt, args) => Console.WriteLine($"[INFO] {fmt}", args),
errorLog: (fmt, args) => Console.Error.WriteLine($"[ERROR] {fmt}", args),
verboseLog: null
)
{
ReconnectAttempts = -1, // Infinite reconnection
ReconnectInterval = TimeSpan.FromSeconds(5),
ResendTimeout = TimeSpan.FromSeconds(1)
};
_socket.Init += ws =>
{
ws.Options.KeepAliveInterval = TimeSpan.FromSeconds(20);
};
_socket.PostConnect += async (isReconnect, ct) =>
{
if (isReconnect)
{
Console.WriteLine("Reconnected! Subscriptions will be restored automatically.");
}
};
}
public async Task ConnectAsync()
{
await _socket.ConnectAsync(CancellationToken.None);
}
public async Task SubscribeToTradesAsync(string symbol)
{
var subId = ++_subscriptionCounter;
await _socket.SendAsync(
obj: new
{
type = "subscribe",
channel = "trades",
symbol = symbol
},
subId: subId
);
Console.WriteLine($"Subscribed to {symbol} trades (ID: {subId})");
}
public async Task UnsubscribeFromTradesAsync(long subscriptionId, string symbol)
{
await _socket.SendAsync(
obj: new
{
type = "unsubscribe",
channel = "trades",
symbol = symbol
},
subId: -subscriptionId // Negative to remove from resend queue
);
}
private void OnStateChanged(ConnectionStates state)
{
Console.WriteLine($"Connection state: {state}");
if (state == ConnectionStates.Connected)
{
// Connection established
}
else if (state == ConnectionStates.Restored)
{
// Connection restored after disconnect
}
else if (state == ConnectionStates.Failed)
{
// Connection failed after all retry attempts
}
}
private void OnError(Exception ex)
{
Console.Error.WriteLine($"WebSocket error: {ex}");
}
private async ValueTask ProcessMessage(WebSocketMessage msg, CancellationToken ct)
{
try
{
var message = msg.AsObject<dynamic>();
if (message.type == "trade")
{
Console.WriteLine($"Trade: {message.symbol} @ {message.price}");
}
else if (message.type == "error")
{
Console.Error.WriteLine($"Server error: {message.message}");
}
}
catch (Exception ex)
{
Console.Error.WriteLine($"Error processing message: {ex.Message}");
}
await ValueTask.CompletedTask;
}
public void Dispose()
{
_socket?.Disconnect();
_socket?.Dispose();
}
}
// Usage
await using var client = new CryptoExchangeClient("wss://api.exchange.com/ws");
await client.ConnectAsync();
await client.SubscribeToTradesAsync("BTCUSD");
// Keep running
await Task.Delay(Timeout.Infinite);
Multi-Connection Manager
public class MultiExchangeClient
{
private readonly ConnectionStateTracker _tracker;
private readonly WebSocketClient _exchangeA;
private readonly WebSocketClient _exchangeB;
public MultiExchangeClient()
{
_tracker = new ConnectionStateTracker();
_exchangeA = CreateClient("wss://exchange-a.com/ws", "Exchange A");
_exchangeB = CreateClient("wss://exchange-b.com/ws", "Exchange B");
_tracker.Add(_exchangeA);
_tracker.Add(_exchangeB);
_tracker.StateChanged += state =>
{
Console.WriteLine($"Overall connection state: {state}");
if (state == ConnectionStates.Connected)
{
Console.WriteLine("All exchanges connected!");
}
};
}
private WebSocketClient CreateClient(string url, string name)
{
return new WebSocketClient(
url: url,
stateChanged: state => Console.WriteLine($"{name}: {state}"),
error: ex => Console.Error.WriteLine($"{name} error: {ex.Message}"),
process: (msg, ct) =>
{
Console.WriteLine($"{name}: {msg.AsString()}");
return ValueTask.CompletedTask;
},
infoLog: (fmt, args) => Console.WriteLine($"[{name}] {fmt}", args),
errorLog: (fmt, args) => Console.Error.WriteLine($"[{name}] {fmt}", args),
verboseLog: null
)
{
ReconnectAttempts = 5,
ReconnectInterval = TimeSpan.FromSeconds(3)
};
}
public async Task ConnectAllAsync()
{
await _tracker.ConnectAsync(CancellationToken.None);
}
public void DisconnectAll()
{
_tracker.Disconnect();
}
}
WebSocket with REST API Integration
public class TradingClient
{
private readonly WebSocketClient _wsClient;
private readonly Uri _restApiUrl;
public TradingClient(string wsUrl, string restUrl)
{
_restApiUrl = new Uri(restUrl);
_wsClient = new WebSocketClient(
url: wsUrl,
stateChanged: state => Console.WriteLine($"WS State: {state}"),
error: ex => Console.Error.WriteLine($"WS Error: {ex}"),
process: ProcessWebSocketMessage,
infoLog: (fmt, args) => Console.WriteLine(fmt, args),
errorLog: (fmt, args) => Console.Error.WriteLine(fmt, args),
verboseLog: null
);
}
public async Task<AccountInfo> GetAccountInfoAsync()
{
var request = new RestRequest("/account", Method.Get);
request.SetBearer(GetAuthToken());
try
{
var account = await request.InvokeAsync<AccountInfo>(
url: new Uri(_restApiUrl, request.Resource),
caller: this,
logVerbose: (fmt, args) => Console.WriteLine(fmt, args),
token: CancellationToken.None
);
return account;
}
catch (RestSharpException ex)
{
Console.Error.WriteLine($"REST API Error: {ex.Message}");
Console.Error.WriteLine($"Status: {ex.Response.StatusCode}");
Console.Error.WriteLine($"Content: {ex.Response.Content}");
throw;
}
}
public async Task PlaceOrderAsync(string symbol, decimal price, decimal quantity)
{
var request = new RestRequest("/orders", Method.Post);
request.SetBearer(GetAuthToken());
request.AddBodyAsStr(new
{
symbol = symbol,
price = price,
quantity = quantity
}.ToJson());
var order = await request.InvokeAsync<Order>(
url: new Uri(_restApiUrl, request.Resource),
caller: this,
logVerbose: (fmt, args) => Console.WriteLine(fmt, args),
token: CancellationToken.None
);
Console.WriteLine($"Order placed: {order.Id}");
}
private async ValueTask ProcessWebSocketMessage(WebSocketMessage msg, CancellationToken ct)
{
var data = msg.AsObject<dynamic>();
if (data.type == "order_update")
{
Console.WriteLine($"Order {data.orderId} status: {data.status}");
}
await ValueTask.CompletedTask;
}
private SecureString GetAuthToken()
{
// Return your authentication token
throw new NotImplementedException();
}
}
Best Practices
Always handle errors: Provide error handlers to catch and log exceptions.
Configure reconnection: Set appropriate reconnection attempts and intervals based on your use case.
Use subscription IDs: Track subscriptions with IDs for automatic resend after reconnection.
Monitor connection states: React to state changes to update your UI or trigger business logic.
Dispose properly: Always dispose of WebSocketClient when done to clean up resources.
Use async/await: Prefer async methods for better scalability.
Implement backoff: Use increasing reconnection intervals to avoid overwhelming the server.
Log appropriately: Use different log levels (info, error, verbose) for debugging and monitoring.
Thread Safety
The WebSocketClient class is designed to be thread-safe for the following operations:
- Sending messages
- Connection/disconnection
- State management
- Subscription tracking
However, you should not share a single WebSocketMessage instance across threads, as it contains read-only memory references.
Performance Considerations
- Buffer Sizes: Adjust
BufferSizeandBufferSizeUncompressbased on your message sizes. - Resend Interval: Lower intervals increase network traffic; higher intervals delay recovery.
- Reconnect Attempts: Balance between reliability and resource usage.
- Verbose Logging: Disable in production for better performance.
License
This library is part of the Ecng framework.
Support
For issues, questions, or contributions, please refer to the main StockSharp repository.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. 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 was computed. 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. |
-
net10.0
- Ecng.Localization (>= 1.0.224)
- Ecng.Net (>= 1.0.452)
- RestSharp (>= 112.1.0)
-
net6.0
- Ecng.Localization (>= 1.0.224)
- Ecng.Net (>= 1.0.452)
- RestSharp (>= 112.1.0)
NuGet packages (6)
Showing the top 5 NuGet packages that depend on Ecng.Net.SocketIO:
| Package | Downloads |
|---|---|
|
StockSharp.AlphaVantage
AlphaVantage |
|
|
StockSharp.IEX
Trading and algorithmic trading platform (stock markets, forex, bitcoins and options). .NET API for InteractiveBrokers, GainCapital, OANDA, FIX/FAST, Binance etc. More info on web site https://stocksharp.com/store/api/ |
|
|
StockSharp.Binance
Binance |
|
|
StockSharp.Okex
OKX connector |
|
|
StockSharp.Bitmex
Bitmex |
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on Ecng.Net.SocketIO:
| Repository | Stars |
|---|---|
|
StockSharp/StockSharp
Algorithmic trading and quantitative trading open source platform to develop trading robots (stock markets, forex, crypto, bitcoins, and options).
|
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.486 | 0 | 12/21/2025 |
| 1.0.485 | 160 | 12/19/2025 |
| 1.0.484 | 179 | 12/19/2025 |
| 1.0.483 | 224 | 12/18/2025 |
| 1.0.482 | 246 | 12/17/2025 |
| 1.0.481 | 269 | 12/15/2025 |
| 1.0.480 | 242 | 12/15/2025 |
| 1.0.479 | 214 | 12/14/2025 |
| 1.0.478 | 144 | 12/14/2025 |
| 1.0.477 | 151 | 12/13/2025 |
| 1.0.476 | 157 | 12/13/2025 |
| 1.0.475 | 126 | 12/12/2025 |
| 1.0.474 | 108 | 12/12/2025 |
| 1.0.473 | 105 | 12/12/2025 |
| 1.0.472 | 107 | 12/12/2025 |
| 1.0.471 | 103 | 12/12/2025 |
| 1.0.470 | 108 | 12/12/2025 |
| 1.0.469 | 107 | 12/12/2025 |
| 1.0.468 | 711 | 12/2/2025 |
| 1.0.467 | 663 | 12/2/2025 |
| 1.0.466 | 664 | 12/2/2025 |
| 1.0.465 | 261 | 11/30/2025 |
| 1.0.464 | 130 | 11/29/2025 |
| 1.0.463 | 127 | 11/28/2025 |
| 1.0.462 | 134 | 11/28/2025 |
| 1.0.461 | 179 | 11/27/2025 |
| 1.0.460 | 218 | 11/24/2025 |
| 1.0.459 | 189 | 11/24/2025 |
| 1.0.458 | 184 | 11/23/2025 |
| 1.0.457 | 161 | 11/23/2025 |
| 1.0.456 | 216 | 11/22/2025 |
| 1.0.455 | 427 | 11/20/2025 |
| 1.0.454 | 399 | 11/20/2025 |
| 1.0.453 | 402 | 11/20/2025 |
| 1.0.452 | 420 | 11/18/2025 |
| 1.0.451 | 401 | 11/18/2025 |
| 1.0.450 | 330 | 11/13/2025 |
| 1.0.449 | 268 | 11/10/2025 |
| 1.0.448 | 1,088 | 11/1/2025 |
| 1.0.447 | 194 | 10/31/2025 |
| 1.0.446 | 206 | 10/28/2025 |
| 1.0.445 | 299 | 10/27/2025 |
| 1.0.444 | 193 | 10/27/2025 |
| 1.0.443 | 123 | 10/25/2025 |
| 1.0.442 | 150 | 10/24/2025 |
| 1.0.441 | 259 | 10/20/2025 |
| 1.0.440 | 296 | 10/12/2025 |
| 1.0.439 | 143 | 10/11/2025 |
| 1.0.438 | 286 | 10/7/2025 |
| 1.0.437 | 223 | 10/6/2025 |
| 1.0.436 | 266 | 10/3/2025 |
| 1.0.435 | 239 | 10/1/2025 |
| 1.0.434 | 204 | 10/1/2025 |
| 1.0.433 | 203 | 9/30/2025 |
| 1.0.432 | 207 | 9/28/2025 |
| 1.0.431 | 221 | 9/25/2025 |
| 1.0.430 | 2,959 | 9/5/2025 |
| 1.0.429 | 238 | 9/2/2025 |
| 1.0.428 | 593 | 8/30/2025 |
| 1.0.427 | 258 | 8/30/2025 |
| 1.0.426 | 260 | 8/20/2025 |
| 1.0.425 | 204 | 8/20/2025 |
| 1.0.424 | 217 | 8/19/2025 |
| 1.0.423 | 226 | 8/15/2025 |
| 1.0.422 | 317 | 8/10/2025 |
| 1.0.421 | 1,040 | 7/16/2025 |
| 1.0.420 | 271 | 7/14/2025 |
| 1.0.419 | 245 | 7/13/2025 |
| 1.0.418 | 218 | 7/13/2025 |
| 1.0.417 | 200 | 7/12/2025 |
| 1.0.416 | 683 | 7/8/2025 |
| 1.0.415 | 256 | 7/4/2025 |
| 1.0.414 | 251 | 7/2/2025 |
| 1.0.413 | 416 | 6/24/2025 |
| 1.0.412 | 1,025 | 6/16/2025 |
| 1.0.411 | 405 | 6/9/2025 |
| 1.0.410 | 284 | 6/8/2025 |
| 1.0.409 | 610 | 5/21/2025 |
| 1.0.408 | 256 | 5/21/2025 |
| 1.0.407 | 241 | 5/17/2025 |
| 1.0.406 | 645 | 5/12/2025 |
| 1.0.405 | 340 | 5/12/2025 |
| 1.0.404 | 307 | 5/12/2025 |
| 1.0.403 | 233 | 5/11/2025 |
| 1.0.402 | 241 | 5/11/2025 |
| 1.0.401 | 197 | 5/10/2025 |
| 1.0.400 | 162 | 5/10/2025 |
| 1.0.399 | 282 | 5/6/2025 |
| 1.0.398 | 207 | 5/3/2025 |
| 1.0.397 | 378 | 4/17/2025 |
| 1.0.396 | 328 | 4/15/2025 |
| 1.0.395 | 227 | 4/12/2025 |
| 1.0.394 | 300 | 4/9/2025 |
| 1.0.393 | 260 | 4/6/2025 |
| 1.0.392 | 213 | 4/5/2025 |
| 1.0.391 | 1,086 | 3/22/2025 |
| 1.0.390 | 281 | 3/20/2025 |
| 1.0.389 | 275 | 3/20/2025 |
| 1.0.388 | 258 | 3/19/2025 |
| 1.0.387 | 831 | 2/26/2025 |
| 1.0.386 | 239 | 2/26/2025 |
| 1.0.385 | 759 | 2/8/2025 |
| 1.0.384 | 242 | 2/8/2025 |
| 1.0.383 | 218 | 2/8/2025 |
| 1.0.382 | 220 | 2/6/2025 |
| 1.0.381 | 210 | 2/6/2025 |
| 1.0.380 | 228 | 2/6/2025 |
| 1.0.379 | 231 | 2/6/2025 |
| 1.0.378 | 210 | 2/6/2025 |
| 1.0.377 | 210 | 2/5/2025 |
| 1.0.376 | 216 | 2/5/2025 |
| 1.0.375 | 230 | 2/5/2025 |
| 1.0.374 | 253 | 2/3/2025 |
| 1.0.373 | 239 | 2/2/2025 |
| 1.0.372 | 255 | 2/1/2025 |
| 1.0.371 | 239 | 1/31/2025 |
| 1.0.370 | 240 | 1/30/2025 |
| 1.0.369 | 222 | 1/26/2025 |
| 1.0.368 | 260 | 1/21/2025 |
| 1.0.367 | 244 | 1/20/2025 |
| 1.0.366 | 211 | 1/20/2025 |
| 1.0.365 | 222 | 1/19/2025 |
| 1.0.364 | 212 | 1/19/2025 |
| 1.0.363 | 238 | 1/15/2025 |
| 1.0.362 | 210 | 1/15/2025 |
| 1.0.361 | 200 | 1/14/2025 |
| 1.0.360 | 195 | 1/12/2025 |
| 1.0.359 | 185 | 1/12/2025 |
| 1.0.358 | 199 | 1/12/2025 |
| 1.0.357 | 172 | 1/12/2025 |
| 1.0.356 | 216 | 1/10/2025 |
| 1.0.355 | 1,055 | 12/30/2024 |
| 1.0.354 | 245 | 12/27/2024 |
| 1.0.353 | 271 | 12/19/2024 |
| 1.0.352 | 728 | 11/20/2024 |
| 1.0.351 | 243 | 11/19/2024 |
| 1.0.350 | 228 | 11/19/2024 |
| 1.0.349 | 788 | 11/18/2024 |
| 1.0.348 | 459 | 11/15/2024 |
| 1.0.347 | 215 | 11/14/2024 |
| 1.0.346 | 234 | 11/14/2024 |
| 1.0.345 | 241 | 11/14/2024 |
| 1.0.344 | 191 | 11/14/2024 |
| 1.0.343 | 216 | 11/14/2024 |
| 1.0.342 | 258 | 11/7/2024 |
| 1.0.341 | 270 | 10/31/2024 |
| 1.0.340 | 327 | 10/20/2024 |
| 1.0.339 | 253 | 10/20/2024 |
| 1.0.338 | 263 | 10/20/2024 |
| 1.0.337 | 256 | 10/19/2024 |
| 1.0.336 | 269 | 10/19/2024 |
| 1.0.335 | 270 | 10/19/2024 |
| 1.0.334 | 267 | 10/19/2024 |
| 1.0.333 | 266 | 10/19/2024 |
| 1.0.332 | 247 | 10/19/2024 |
| 1.0.331 | 270 | 10/19/2024 |
| 1.0.330 | 303 | 10/18/2024 |
| 1.0.329 | 262 | 10/17/2024 |
| 1.0.328 | 220 | 10/17/2024 |
| 1.0.327 | 238 | 10/17/2024 |
| 1.0.326 | 796 | 10/14/2024 |
| 1.0.325 | 226 | 10/13/2024 |
| 1.0.324 | 223 | 10/13/2024 |
| 1.0.323 | 241 | 10/12/2024 |
| 1.0.322 | 436 | 10/9/2024 |
| 1.0.321 | 240 | 10/9/2024 |
| 1.0.320 | 439 | 10/5/2024 |
| 1.0.319 | 766 | 9/18/2024 |
| 1.0.318 | 225 | 9/18/2024 |
| 1.0.317 | 245 | 9/18/2024 |
| 1.0.316 | 241 | 9/17/2024 |
| 1.0.315 | 737 | 9/3/2024 |
| 1.0.314 | 282 | 9/1/2024 |
| 1.0.313 | 950 | 8/9/2024 |
| 1.0.312 | 241 | 8/9/2024 |
| 1.0.311 | 261 | 8/8/2024 |
| 1.0.310 | 696 | 7/25/2024 |
| 1.0.309 | 256 | 7/23/2024 |
| 1.0.308 | 283 | 7/17/2024 |
| 1.0.307 | 546 | 7/4/2024 |
| 1.0.306 | 608 | 6/12/2024 |
| 1.0.305 | 250 | 6/12/2024 |
| 1.0.304 | 246 | 6/12/2024 |
| 1.0.303 | 440 | 5/28/2024 |
| 1.0.302 | 605 | 5/4/2024 |
| 1.0.301 | 397 | 4/23/2024 |
| 1.0.300 | 263 | 4/21/2024 |
| 1.0.299 | 289 | 4/14/2024 |
| 1.0.298 | 554 | 3/28/2024 |
| 1.0.297 | 325 | 3/17/2024 |
| 1.0.296 | 530 | 3/9/2024 |
| 1.0.295 | 346 | 2/23/2024 |
| 1.0.294 | 278 | 2/23/2024 |
| 1.0.293 | 487 | 2/18/2024 |
| 1.0.292 | 278 | 2/18/2024 |
| 1.0.291 | 251 | 2/17/2024 |
| 1.0.290 | 269 | 2/16/2024 |
| 1.0.289 | 387 | 2/14/2024 |
| 1.0.288 | 269 | 2/13/2024 |
| 1.0.287 | 338 | 2/8/2024 |
| 1.0.286 | 342 | 2/5/2024 |
| 1.0.285 | 261 | 2/4/2024 |
| 1.0.284 | 430 | 1/23/2024 |
| 1.0.283 | 248 | 1/23/2024 |
| 1.0.282 | 316 | 1/12/2024 |
| 1.0.281 | 685 | 1/2/2024 |
| 1.0.280 | 300 | 12/29/2023 |
| 1.0.279 | 350 | 12/17/2023 |
| 1.0.278 | 508 | 12/15/2023 |
| 1.0.277 | 279 | 12/15/2023 |
| 1.0.276 | 260 | 12/15/2023 |
| 1.0.275 | 290 | 12/13/2023 |
| 1.0.274 | 287 | 12/13/2023 |
| 1.0.273 | 292 | 12/10/2023 |
| 1.0.272 | 681 | 11/18/2023 |
| 1.0.271 | 225 | 11/18/2023 |
| 1.0.270 | 251 | 11/18/2023 |
| 1.0.269 | 231 | 11/17/2023 |
| 1.0.268 | 209 | 11/12/2023 |
| 1.0.267 | 206 | 11/12/2023 |
| 1.0.266 | 228 | 11/10/2023 |
| 1.0.265 | 195 | 11/10/2023 |
| 1.0.264 | 235 | 11/9/2023 |
| 1.0.263 | 195 | 11/9/2023 |
| 1.0.262 | 214 | 11/9/2023 |
| 1.0.261 | 238 | 11/3/2023 |
| 1.0.260 | 225 | 11/1/2023 |
| 1.0.259 | 208 | 11/1/2023 |
| 1.0.258 | 1,471 | 9/8/2023 |
| 1.0.257 | 261 | 9/8/2023 |
| 1.0.256 | 281 | 9/3/2023 |
| 1.0.255 | 346 | 8/27/2023 |
| 1.0.254 | 272 | 8/24/2023 |
| 1.0.253 | 241 | 8/21/2023 |
| 1.0.252 | 313 | 8/15/2023 |
| 1.0.251 | 282 | 8/14/2023 |
| 1.0.250 | 264 | 8/14/2023 |
| 1.0.249 | 292 | 8/10/2023 |
| 1.0.248 | 1,012 | 7/29/2023 |
| 1.0.247 | 1,086 | 7/1/2023 |
| 1.0.246 | 305 | 6/29/2023 |
| 1.0.245 | 796 | 5/27/2023 |
| 1.0.244 | 349 | 5/21/2023 |
| 1.0.243 | 294 | 5/19/2023 |
| 1.0.242 | 1,079 | 5/8/2023 |
| 1.0.241 | 353 | 5/7/2023 |
| 1.0.240 | 339 | 5/7/2023 |
| 1.0.239 | 315 | 5/7/2023 |
| 1.0.238 | 363 | 5/1/2023 |
| 1.0.237 | 410 | 4/22/2023 |
| 1.0.236 | 371 | 4/21/2023 |
| 1.0.235 | 333 | 4/21/2023 |
| 1.0.234 | 1,224 | 4/13/2023 |
| 1.0.233 | 1,132 | 4/3/2023 |
| 1.0.232 | 485 | 3/27/2023 |
| 1.0.231 | 431 | 3/21/2023 |
| 1.0.230 | 431 | 3/17/2023 |
| 1.0.229 | 425 | 3/13/2023 |
| 1.0.228 | 1,181 | 3/6/2023 |
| 1.0.227 | 495 | 2/26/2023 |
| 1.0.226 | 937 | 2/21/2023 |
| 1.0.225 | 454 | 2/20/2023 |
| 1.0.224 | 466 | 2/16/2023 |
| 1.0.223 | 454 | 2/15/2023 |
| 1.0.222 | 428 | 2/14/2023 |
| 1.0.221 | 425 | 2/14/2023 |
| 1.0.220 | 1,351 | 2/9/2023 |
| 1.0.219 | 829 | 2/7/2023 |
| 1.0.218 | 483 | 2/4/2023 |
| 1.0.217 | 465 | 2/4/2023 |
| 1.0.216 | 479 | 2/3/2023 |
| 1.0.215 | 444 | 2/3/2023 |
| 1.0.214 | 438 | 2/3/2023 |
| 1.0.213 | 883 | 2/2/2023 |
| 1.0.212 | 829 | 1/30/2023 |
| 1.0.211 | 463 | 1/30/2023 |
| 1.0.210 | 507 | 1/25/2023 |
| 1.0.209 | 504 | 1/23/2023 |
| 1.0.208 | 450 | 1/23/2023 |
| 1.0.207 | 487 | 1/18/2023 |
| 1.0.206 | 513 | 1/15/2023 |
| 1.0.205 | 511 | 1/6/2023 |
| 1.0.204 | 1,416 | 1/1/2023 |
| 1.0.203 | 479 | 12/31/2022 |
| 1.0.202 | 966 | 12/30/2022 |
| 1.0.201 | 498 | 12/29/2022 |
| 1.0.200 | 507 | 12/23/2022 |
| 1.0.199 | 1,386 | 12/12/2022 |
| 1.0.198 | 1,068 | 12/8/2022 |
| 1.0.197 | 481 | 12/4/2022 |
| 1.0.196 | 486 | 12/4/2022 |
| 1.0.195 | 489 | 12/2/2022 |
| 1.0.194 | 513 | 11/30/2022 |
| 1.0.193 | 477 | 11/29/2022 |
| 1.0.192 | 474 | 11/28/2022 |
| 1.0.191 | 513 | 11/26/2022 |
| 1.0.190 | 511 | 11/26/2022 |
| 1.0.189 | 515 | 11/25/2022 |
| 1.0.188 | 510 | 11/25/2022 |
| 1.0.187 | 524 | 11/18/2022 |
| 1.0.186 | 1,593 | 11/11/2022 |
| 1.0.185 | 543 | 11/11/2022 |
| 1.0.184 | 504 | 11/10/2022 |
| 1.0.183 | 571 | 11/5/2022 |
| 1.0.182 | 545 | 11/4/2022 |
| 1.0.181 | 529 | 11/2/2022 |
| 1.0.180 | 520 | 11/2/2022 |
| 1.0.179 | 1,429 | 11/1/2022 |
| 1.0.178 | 1,655 | 10/16/2022 |
| 1.0.177 | 737 | 9/25/2022 |
| 1.0.176 | 665 | 9/10/2022 |
| 1.0.175 | 2,978 | 9/8/2022 |
| 1.0.174 | 651 | 9/8/2022 |
| 1.0.173 | 655 | 9/8/2022 |
| 1.0.172 | 631 | 9/4/2022 |
| 1.0.171 | 633 | 9/4/2022 |
| 1.0.170 | 5,352 | 8/24/2022 |
| 1.0.169 | 713 | 8/8/2022 |
| 1.0.168 | 633 | 8/8/2022 |
| 1.0.167 | 1,264 | 7/31/2022 |
| 1.0.166 | 649 | 7/31/2022 |
| 1.0.165 | 662 | 7/26/2022 |
| 1.0.164 | 629 | 7/26/2022 |
| 1.0.163 | 3,194 | 7/21/2022 |
| 1.0.162 | 680 | 7/19/2022 |
| 1.0.161 | 3,153 | 7/18/2022 |
| 1.0.160 | 688 | 7/13/2022 |
| 1.0.159 | 670 | 7/8/2022 |
| 1.0.158 | 685 | 6/30/2022 |
| 1.0.157 | 704 | 6/20/2022 |
| 1.0.156 | 651 | 6/18/2022 |
| 1.0.155 | 694 | 6/6/2022 |
| 1.0.154 | 742 | 5/27/2022 |
| 1.0.153 | 5,207 | 4/30/2022 |
| 1.0.152 | 683 | 4/20/2022 |
| 1.0.151 | 707 | 4/10/2022 |
| 1.0.150 | 674 | 4/7/2022 |
| 1.0.149 | 659 | 4/7/2022 |
| 1.0.148 | 715 | 4/2/2022 |
| 1.0.147 | 675 | 3/29/2022 |
| 1.0.146 | 662 | 3/27/2022 |
| 1.0.145 | 666 | 3/27/2022 |
| 1.0.144 | 3,917 | 3/24/2022 |
| 1.0.143 | 2,683 | 2/20/2022 |
| 1.0.142 | 644 | 2/20/2022 |
| 1.0.141 | 655 | 2/20/2022 |
| 1.0.140 | 682 | 2/20/2022 |
| 1.0.139 | 697 | 2/20/2022 |
| 1.0.138 | 661 | 2/20/2022 |
| 1.0.137 | 657 | 2/20/2022 |
| 1.0.136 | 670 | 2/20/2022 |
| 1.0.135 | 677 | 2/20/2022 |
| 1.0.134 | 665 | 2/19/2022 |
| 1.0.133 | 4,565 | 2/10/2022 |
| 1.0.132 | 779 | 1/27/2022 |
| 1.0.131 | 705 | 1/27/2022 |
| 1.0.130 | 3,567 | 1/24/2022 |
| 1.0.129 | 650 | 1/24/2022 |
| 1.0.128 | 691 | 1/23/2022 |
| 1.0.127 | 7,017 | 12/29/2021 |
| 1.0.126 | 540 | 12/27/2021 |
| 1.0.125 | 482 | 12/27/2021 |
| 1.0.124 | 500 | 12/27/2021 |
| 1.0.123 | 1,756 | 12/20/2021 |
| 1.0.122 | 544 | 12/17/2021 |
| 1.0.121 | 534 | 12/16/2021 |
| 1.0.120 | 518 | 12/15/2021 |
| 1.0.119 | 507 | 12/14/2021 |
| 1.0.118 | 529 | 12/14/2021 |
| 1.0.117 | 487 | 12/13/2021 |
| 1.0.116 | 650 | 12/12/2021 |
| 1.0.115 | 1,627 | 12/10/2021 |
| 1.0.114 | 540 | 12/7/2021 |
| 1.0.113 | 537 | 12/7/2021 |
| 1.0.112 | 1,973 | 12/6/2021 |
| 1.0.111 | 534 | 12/6/2021 |
| 1.0.110 | 539 | 12/5/2021 |
| 1.0.109 | 1,228 | 12/3/2021 |
| 1.0.108 | 1,038 | 12/3/2021 |
| 1.0.107 | 573 | 12/2/2021 |
| 1.0.106 | 2,452 | 11/29/2021 |
| 1.0.105 | 5,265 | 11/23/2021 |
| 1.0.104 | 525 | 11/23/2021 |
| 1.0.103 | 1,614 | 11/22/2021 |
| 1.0.102 | 617 | 11/17/2021 |
| 1.0.101 | 576 | 11/14/2021 |
| 1.0.100 | 1,742 | 11/13/2021 |
| 1.0.99 | 590 | 11/11/2021 |
| 1.0.98 | 573 | 11/11/2021 |
| 1.0.97 | 561 | 11/10/2021 |
| 1.0.96 | 564 | 11/9/2021 |
| 1.0.95 | 2,595 | 11/6/2021 |
| 1.0.94 | 602 | 11/6/2021 |
| 1.0.93 | 2,168 | 11/5/2021 |
| 1.0.92 | 627 | 11/5/2021 |
| 1.0.91 | 587 | 11/4/2021 |
| 1.0.90 | 561 | 11/4/2021 |
| 1.0.89 | 612 | 11/3/2021 |
| 1.0.88 | 680 | 10/30/2021 |
| 1.0.87 | 2,044 | 10/21/2021 |
| 1.0.86 | 650 | 10/17/2021 |
| 1.0.85 | 660 | 10/17/2021 |
| 1.0.84 | 3,044 | 10/14/2021 |
| 1.0.83 | 584 | 10/13/2021 |
| 1.0.82 | 605 | 10/13/2021 |
| 1.0.81 | 585 | 10/12/2021 |
| 1.0.80 | 2,136 | 10/11/2021 |
| 1.0.79 | 567 | 10/9/2021 |
| 1.0.78 | 1,950 | 10/7/2021 |
| 1.0.77 | 2,150 | 10/7/2021 |
| 1.0.76 | 565 | 10/7/2021 |
| 1.0.75 | 597 | 10/6/2021 |
| 1.0.74 | 651 | 9/28/2021 |
| 1.0.73 | 2,364 | 9/23/2021 |
| 1.0.72 | 702 | 9/11/2021 |
| 1.0.71 | 600 | 9/10/2021 |
| 1.0.70 | 667 | 9/9/2021 |
| 1.0.69 | 569 | 9/8/2021 |
| 1.0.68 | 628 | 9/8/2021 |
| 1.0.67 | 2,154 | 9/6/2021 |
| 1.0.66 | 697 | 8/31/2021 |
| 1.0.65 | 559 | 8/30/2021 |
| 1.0.64 | 2,607 | 7/31/2021 |
| 1.0.63 | 3,039 | 7/30/2021 |
| 1.0.62 | 679 | 7/26/2021 |
| 1.0.61 | 4,482 | 7/5/2021 |
| 1.0.60 | 639 | 7/1/2021 |
| 1.0.59 | 3,818 | 6/4/2021 |
| 1.0.58 | 5,067 | 4/26/2021 |
| 1.0.57 | 2,180 | 4/19/2021 |
| 1.0.56 | 5,720 | 4/8/2021 |
| 1.0.55 | 1,805 | 4/7/2021 |
| 1.0.54 | 617 | 4/7/2021 |
| 1.0.53 | 1,875 | 4/3/2021 |
| 1.0.52 | 7,983 | 3/22/2021 |
| 1.0.51 | 5,768 | 3/4/2021 |
| 1.0.50 | 2,158 | 2/26/2021 |
| 1.0.49 | 8,274 | 2/2/2021 |
| 1.0.48 | 3,228 | 1/26/2021 |
| 1.0.47 | 2,996 | 1/24/2021 |
| 1.0.46 | 655 | 1/24/2021 |
| 1.0.45 | 710 | 1/23/2021 |
| 1.0.44 | 3,897 | 1/20/2021 |
| 1.0.43 | 711 | 1/20/2021 |
| 1.0.42 | 2,081 | 1/18/2021 |
| 1.0.41 | 624 | 1/18/2021 |
| 1.0.40 | 2,059 | 1/16/2021 |
| 1.0.39 | 6,309 | 12/17/2020 |
| 1.0.38 | 693 | 12/16/2020 |
| 1.0.37 | 3,211 | 12/14/2020 |
| 1.0.36 | 2,119 | 12/9/2020 |
| 1.0.35 | 672 | 12/9/2020 |
| 1.0.34 | 678 | 12/7/2020 |
| 1.0.33 | 785 | 12/6/2020 |
| 1.0.32 | 735 | 12/2/2020 |
| 1.0.31 | 703 | 12/2/2020 |
| 1.0.30 | 2,195 | 12/1/2020 |
| 1.0.29 | 7,359 | 11/12/2020 |
| 1.0.29-atestpub | 559 | 11/11/2020 |
| 1.0.28 | 3,333 | 10/11/2020 |
| 1.0.27 | 8,610 | 9/9/2020 |
| 1.0.26 | 2,624 | 9/3/2020 |
| 1.0.25 | 2,681 | 8/20/2020 |
| 1.0.24 | 6,154 | 8/9/2020 |
| 1.0.23 | 2,705 | 7/28/2020 |
| 1.0.22 | 2,637 | 7/19/2020 |
| 1.0.21 | 4,449 | 7/6/2020 |
| 1.0.20 | 6,623 | 6/6/2020 |
| 1.0.19 | 2,612 | 6/4/2020 |
| 1.0.18 | 4,381 | 5/29/2020 |
| 1.0.17 | 4,422 | 5/21/2020 |
| 1.0.16 | 762 | 5/17/2020 |
| 1.0.15 | 4,519 | 5/12/2020 |
| 1.0.14 | 8,235 | 5/4/2020 |
| 1.0.13 | 784 | 4/24/2020 |
| 1.0.12 | 764 | 4/22/2020 |
| 1.0.11 | 751 | 4/22/2020 |
| 1.0.10 | 769 | 4/21/2020 |
| 1.0.9 | 3,225 | 4/18/2020 |
| 1.0.8 | 2,575 | 4/16/2020 |
| 1.0.7 | 780 | 4/16/2020 |
| 1.0.6 | 2,251 | 4/15/2020 |
| 1.0.5 | 2,662 | 4/11/2020 |
| 1.0.4 | 2,555 | 4/3/2020 |
| 1.0.3 | 773 | 4/1/2020 |
| 1.0.2 | 2,483 | 3/27/2020 |
| 1.0.1 | 2,602 | 3/22/2020 |
| 1.0.0 | 886 | 3/22/2020 |
WebSocketClient async callbacks with CancellationToken support.
Added comprehensive README.md documentation for all projects