diff --git a/CryptoExchange.Net.Protobuf/CryptoExchange.Net.Protobuf.csproj b/CryptoExchange.Net.Protobuf/CryptoExchange.Net.Protobuf.csproj
index d80f1a1..a299f13 100644
--- a/CryptoExchange.Net.Protobuf/CryptoExchange.Net.Protobuf.csproj
+++ b/CryptoExchange.Net.Protobuf/CryptoExchange.Net.Protobuf.csproj
@@ -6,9 +6,9 @@
CryptoExchange.Net.Protobuf
JKorf
Protobuf support for CryptoExchange.Net
- 9.5.0
- 9.5.0
- 9.5.0
+ 9.6.0
+ 9.6.0
+ 9.6.0
false
CryptoExchange;CryptoExchange.Net
git
@@ -41,7 +41,7 @@
CryptoExchange.Net.Protobuf.xml
-
+
\ No newline at end of file
diff --git a/CryptoExchange.Net.Protobuf/README.md b/CryptoExchange.Net.Protobuf/README.md
index 1492551..9fa3bd9 100644
--- a/CryptoExchange.Net.Protobuf/README.md
+++ b/CryptoExchange.Net.Protobuf/README.md
@@ -5,6 +5,9 @@
Protobuf support for CryptoExchange.Net.
## Release notes
+* Version 9.6.0 - 25 Aug 2025
+ * Updated CryptoExchange.Net version to 9.6.0
+
* Version 9.5.0 - 19 Aug 2025
* Updated CryptoExchange.Net version to 9.5.0
diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/Sockets/TestSubscription.cs b/CryptoExchange.Net.UnitTests/TestImplementations/Sockets/TestSubscription.cs
index dd6007b..f9cb121 100644
--- a/CryptoExchange.Net.UnitTests/TestImplementations/Sockets/TestSubscription.cs
+++ b/CryptoExchange.Net.UnitTests/TestImplementations/Sockets/TestSubscription.cs
@@ -28,7 +28,7 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations.Sockets
return new CallResult(null);
}
- public override Query GetSubQuery(SocketConnection connection) => new TestQuery("sub", new object(), false, 1);
- public override Query GetUnsubQuery() => new TestQuery("unsub", new object(), false, 1);
+ protected override Query GetSubQuery(SocketConnection connection) => new TestQuery("sub", new object(), false, 1);
+ protected override Query GetUnsubQuery(SocketConnection connection) => new TestQuery("unsub", new object(), false, 1);
}
}
diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/Sockets/TestSubscriptionWithResponseCheck.cs b/CryptoExchange.Net.UnitTests/TestImplementations/Sockets/TestSubscriptionWithResponseCheck.cs
index c7a975c..6c1e616 100644
--- a/CryptoExchange.Net.UnitTests/TestImplementations/Sockets/TestSubscriptionWithResponseCheck.cs
+++ b/CryptoExchange.Net.UnitTests/TestImplementations/Sockets/TestSubscriptionWithResponseCheck.cs
@@ -28,7 +28,7 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations.Sockets
return new CallResult(null);
}
- public override Query GetSubQuery(SocketConnection connection) => new TestChannelQuery(_channel, "subscribe", false, 1);
- public override Query GetUnsubQuery() => new TestChannelQuery(_channel, "unsubscribe", false, 1);
+ protected override Query GetSubQuery(SocketConnection connection) => new TestChannelQuery(_channel, "subscribe", false, 1);
+ protected override Query GetUnsubQuery(SocketConnection connection) => new TestChannelQuery(_channel, "unsubscribe", false, 1);
}
}
diff --git a/CryptoExchange.Net/Clients/RestApiClient.cs b/CryptoExchange.Net/Clients/RestApiClient.cs
index 88f74e9..aa98487 100644
--- a/CryptoExchange.Net/Clients/RestApiClient.cs
+++ b/CryptoExchange.Net/Clients/RestApiClient.cs
@@ -18,707 +18,711 @@ using CryptoExchange.Net.RateLimiting.Interfaces;
using CryptoExchange.Net.Requests;
using Microsoft.Extensions.Logging;
-namespace CryptoExchange.Net.Clients;
-
-///
-/// Base rest API client for interacting with a REST API
-///
-public abstract class RestApiClient : BaseApiClient, IRestApiClient
+namespace CryptoExchange.Net.Clients
{
- ///
- public IRequestFactory RequestFactory { get; set; } = new RequestFactory();
-
- ///
- public abstract TimeSyncInfo? GetTimeSyncInfo();
-
- ///
- public abstract TimeSpan? GetTimeOffset();
-
- ///
- public int TotalRequestsMade { get; set; }
-
///
- /// Request body content type
+ /// Base rest API client for interacting with a REST API
///
- protected internal RequestBodyFormat RequestBodyFormat = RequestBodyFormat.Json;
-
- ///
- /// How to serialize array parameters when making requests
- ///
- protected internal ArrayParametersSerialization ArraySerialization = ArrayParametersSerialization.Array;
-
- ///
- /// What request body should be set when no data is send (only used in combination with postParametersPosition.InBody)
- ///
- protected internal string RequestBodyEmptyContent = "{}";
-
- ///
- /// Request headers to be sent with each request
- ///
- protected Dictionary StandardRequestHeaders { get; set; } = [];
-
- ///
- /// Whether parameters need to be ordered
- ///
- protected internal bool OrderParameters { get; set; } = true;
-
- ///
- /// Parameter order comparer
- ///
- protected IComparer ParameterOrderComparer { get; } = new OrderedStringComparer();
-
- ///
- /// Where to put the parameters for requests with different Http methods
- ///
- public Dictionary ParameterPositions { get; set; } = new Dictionary
+ public abstract class RestApiClient : BaseApiClient, IRestApiClient
{
- { HttpMethod.Get, HttpMethodParameterPosition.InUri },
- { HttpMethod.Post, HttpMethodParameterPosition.InBody },
- { HttpMethod.Delete, HttpMethodParameterPosition.InBody },
- { HttpMethod.Put, HttpMethodParameterPosition.InBody },
- { new HttpMethod("Patch"), HttpMethodParameterPosition.InBody },
- };
+ ///
+ public IRequestFactory RequestFactory { get; set; } = new RequestFactory();
- ///
- public new RestExchangeOptions ClientOptions => (RestExchangeOptions)base.ClientOptions;
+ ///
+ public abstract TimeSyncInfo? GetTimeSyncInfo();
- ///
- public new RestApiOptions ApiOptions => (RestApiOptions)base.ApiOptions;
+ ///
+ public abstract TimeSpan? GetTimeOffset();
- ///
- /// Memory cache
- ///
- private readonly static MemoryCache _cache = new MemoryCache();
+ ///
+ public int TotalRequestsMade { get; set; }
- ///
- /// ctor
- ///
- /// Logger
- /// HttpClient to use
- /// Base address for this API client
- /// The base client options
- /// The Api client options
- public RestApiClient(ILogger logger, HttpClient? httpClient, string baseAddress, RestExchangeOptions options, RestApiOptions apiOptions)
- : base(logger,
- apiOptions.OutputOriginalData ?? options.OutputOriginalData,
- apiOptions.ApiCredentials ?? options.ApiCredentials,
- baseAddress,
- options,
- apiOptions)
- {
- RequestFactory.Configure(options.Proxy, options.RequestTimeout, httpClient);
- }
+ ///
+ /// Request body content type
+ ///
+ protected internal RequestBodyFormat RequestBodyFormat = RequestBodyFormat.Json;
- ///
- /// Create a message accessor instance
- ///
- ///
- protected abstract IStreamMessageAccessor CreateAccessor();
+ ///
+ /// How to serialize array parameters when making requests
+ ///
+ protected internal ArrayParametersSerialization ArraySerialization = ArrayParametersSerialization.Array;
- ///
- /// Create a serializer instance
- ///
- ///
- protected abstract IMessageSerializer CreateSerializer();
+ ///
+ /// What request body should be set when no data is send (only used in combination with postParametersPosition.InBody)
+ ///
+ protected internal string RequestBodyEmptyContent = "{}";
- ///
- /// Send a request to the base address based on the request definition
- ///
- /// Host and schema
- /// Request definition
- /// Request parameters
- /// Cancellation token
- /// Additional headers for this request
- /// Override the request weight for this request definition, for example when the weight depends on the parameters
- ///
- protected virtual async Task SendAsync(
- string baseAddress,
- RequestDefinition definition,
- ParameterCollection? parameters,
- CancellationToken cancellationToken,
- Dictionary? additionalHeaders = null,
- int? weight = null)
- {
- var result = await SendAsync