Manage isolated client instances for multiple users using ExchangeUserClientProvider
When building trading bots or platforms that serve multiple users, each user typically has their own API keys for one or more exchanges. ExchangeUserClientProvider manages a separate set of REST and WebSocket clients per user, keyed by a string identifier, so credentials never bleed across accounts.
1
Create the provider
Instantiate ExchangeUserClientProvider directly or register it via dependency injection. Exchange-level options such as environment or proxy settings can be passed at construction time and apply to all user clients created by the provider.
using CryptoClients.Net.Clients;var provider = new ExchangeUserClientProvider();
2
Define per-user credentials
Build an ExchangeCredentials object for each user. Only populate the exchanges each user actually needs — omitted exchanges will have no credentials set.
using CryptoClients.Net.Models;using Binance.Net.Objects.Options;using Kucoin.Net.Objects.Options;using OKX.Net.Objects.Options;var user1Credentials = new ExchangeCredentials{ Binance = new BinanceCredentials("binance-key-1", "binance-secret-1"), Kucoin = new KucoinCredentials("kucoin-key-1", "kucoin-secret-1", "kucoin-pass-1"),};var user2Credentials = new ExchangeCredentials{ Binance = new BinanceCredentials("binance-key-2", "binance-secret-2"), OKX = new OKXCredentials("okx-key-2", "okx-secret-2", "okx-pass-2"),};
3
Pre-initialize user clients (optional)
Call InitializeUserClient once per user to eagerly create and cache both REST and WebSocket clients. After this call, subsequent GetRestClient / GetSocketClient calls for the same identifier do not require credentials to be passed again.
provider.InitializeUserClient("user-1", user1Credentials, environments: new Dictionary<string, string?>());provider.InitializeUserClient("user-2", user2Credentials, environments: new Dictionary<string, string?>());
Skipping InitializeUserClient is fine — credentials can be passed directly to GetRestClient or GetSocketClient on the first call for that user.
4
Retrieve per-user REST clients
GetRestClient returns a fully configured IExchangeRestClient scoped to the given user. The same underlying provider instance is re-used, so calling this multiple times for the same identifier is cheap.
// First call — credentials required (or use InitializeUserClient first)var restClient1 = provider.GetRestClient("user-1", user1Credentials);var restClient2 = provider.GetRestClient("user-2", user2Credentials);// Subsequent calls for the same user — credentials optionalvar restClient1Again = provider.GetRestClient("user-1");// Place an order as user 1var orderResult = await restClient1.Binance.SpotApi.Trading.PlaceOrderAsync( "ETHUSDT", Binance.Net.Enums.OrderSide.Buy, Binance.Net.Enums.SpotOrderType.Market, quoteQuantity: 50);
5
Retrieve per-user WebSocket clients
GetSocketClient works the same way and returns an IExchangeSocketClient with the user’s credentials already applied, ready for authenticated subscriptions.
var socketClient1 = provider.GetSocketClient("user-1");var socketClient2 = provider.GetSocketClient("user-2");// Subscribe to spot order updates for user 1var sub = await socketClient1.SubscribeToSpotOrderUpdatesAsync( "Binance", new SubscribeSpotOrderRequest(), update => { foreach (var order in update.Data) Console.WriteLine($"[user-1] Order {order.OrderId}: {order.Status}"); });
6
Clear cached clients when credentials change
When a user rotates their API keys, call ClearUserClients to discard the cached clients. The next call to GetRestClient or GetSocketClient with fresh credentials will create new client instances.
// Clear all exchanges for user-1provider.ClearUserClients("user-1");// Or clear only a specific exchangeprovider.ClearUserClients("user-1", exchange: "Binance");// Then re-initialize with the new credentialsvar newCredentials = new ExchangeCredentials{ Binance = new BinanceCredentials("new-key", "new-secret"),};var refreshedClient = provider.GetRestClient("user-1", newCredentials);
using CryptoClients.Net.Clients;using CryptoClients.Net.Models;using Binance.Net.Objects.Options;using Kucoin.Net.Objects.Options;var provider = new ExchangeUserClientProvider();var user1Credentials = new ExchangeCredentials{ Binance = new BinanceCredentials("key-1", "secret-1"), Kucoin = new KucoinCredentials("key-1", "secret-1", "pass-1"),};var user2Credentials = new ExchangeCredentials{ Binance = new BinanceCredentials("key-2", "secret-2"),};// Pre-initialize both usersprovider.InitializeUserClient("user-1", user1Credentials, new Dictionary<string, string?>());provider.InitializeUserClient("user-2", user2Credentials, new Dictionary<string, string?>());// Get isolated REST clientsvar restClient1 = provider.GetRestClient("user-1");var restClient2 = provider.GetRestClient("user-2");// Get isolated WebSocket clientsvar socketClient1 = provider.GetSocketClient("user-1");var socketClient2 = provider.GetSocketClient("user-2");Console.WriteLine("Clients ready for user-1 and user-2");
The user identifier is an arbitrary string — it can be a database primary key, a UUID, a username, or any value that uniquely identifies a user in your system.