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
                    
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="Ecng.Net.SocketIO" Version="1.0.486" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Ecng.Net.SocketIO" Version="1.0.486" />
                    
Directory.Packages.props
<PackageReference Include="Ecng.Net.SocketIO" />
                    
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 Ecng.Net.SocketIO --version 1.0.486
                    
#r "nuget: Ecng.Net.SocketIO, 1.0.486"
                    
#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 Ecng.Net.SocketIO@1.0.486
                    
#: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=Ecng.Net.SocketIO&version=1.0.486
                    
Install as a Cake Addin
#tool nuget:?package=Ecng.Net.SocketIO&version=1.0.486
                    
Install as a Cake Tool

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

  1. Always handle errors: Provide error handlers to catch and log exceptions.

  2. Configure reconnection: Set appropriate reconnection attempts and intervals based on your use case.

  3. Use subscription IDs: Track subscriptions with IDs for automatic resend after reconnection.

  4. Monitor connection states: React to state changes to update your UI or trigger business logic.

  5. Dispose properly: Always dispose of WebSocketClient when done to clean up resources.

  6. Use async/await: Prefer async methods for better scalability.

  7. Implement backoff: Use increasing reconnection intervals to avoid overwhelming the server.

  8. 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 BufferSize and BufferSizeUncompress based 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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