1
0
mirror of https://github.com/JKorf/CryptoExchange.Net.git synced 2026-08-11 16:32:57 +00:00

Feature/9.0.0 (#236)

* Added support for Native AOT compilation
* Updated all IEnumerable response types to array response types
* Added Pass support for ApiCredentials, removing the need for most implementations to add their own ApiCredentials type
* Added KeepAliveTimeout setting setting ping frame timeouts for SocketApiClient
* Added IBookTickerRestClient Shared interface for requesting book tickers
* Added ISpotTriggerOrderRestClient Shared interface for managing spot trigger orders
* Added ISpotOrderClientIdClient Shared interface for managing spot orders by client order id
* Added IFuturesTriggerOrderRestClient Shared interface for managing futures trigger orders
* Added IFuturesOrderClientIdClient Shared interface for managing futures orders by client order id
* Added IFuturesTpSlRestClient Shared interface for setting TP/SL on open futures positions
* Added GenerateClientOrderId to ISpotOrderRestClient and IFuturesOrderRestClient interface
* Added OptionalExchangeParameters and Supported properties to EndpointOptions
* Refactor Shared interfaces quantity parameters and properties to use SharedQuantity
* Added SharedSymbol property to Shared interface models returning a symbol
* Added TriggerPrice, IsTriggerOrder, TakeProfitPrice, StopLossPrice and IsCloseOrder to SharedFuturesOrder response model
* Added MaxShortLeverage and MaxLongLeverage to SharedFuturesSymbol response model
* Added StopLossPrice and TakeProfitPrice to SharedPosition response model
* Added TriggerPrice and IsTriggerOrder to SharedSpotOrder response model
* Added QuoteVolume property to SharedSpotTicker response model
* Added AssetAlias configuration models
* Added static ExchangeSymbolCache for tracking symbol information from exchanges
* Added static CallResult.SuccessResult to be used instead of constructing success CallResult instance
* Added static ApplyRules, RandomHexString and RandomLong helper methods to ExchangeHelpers class
* Added AsErrorWithData To CallResult
* Added OriginalData property to CallResult
* Added support for adjusting the rate limit key per call, allowing for ratelimiting depending on request parameters
* Added implementation for integration testing ISymbolOrderBook instances
* Added implementation for integration testing socket subscriptions
* Added implementation for testing socket queries
* Updated request cancellation logging to Debug level
* Updated logging SourceContext to include the client type
* Updated some logging logic, errors no longer contain any data, exception are not logged as string but instead forwarded to structured logging
* Fixed warning for Enum parsing throwing exception and output warnings for each object in a response to only once to prevent slowing down execution
* Fixed memory leak in AsyncAutoRestEvent
* Fixed logging for ping frame timeout
* Fixed warning getting logged when user stops SymbolOrderBook instance
* Fixed socket client `UnsubscribeAll` not unsubscribing dedicated connections
* Fixed memory leak in Rest client cache
* Fixed integers bigger than int16 not getting correctly parsed to enums
* Fixed issue where the default options were overridden when using SetApiCredentials
* Removed Newtonsoft.Json dependency
* Removed legacy Rest client code
* Removed legacy ISpotClient and IFuturesClient support
This commit is contained in:
Jan Korf
2025-05-13 10:15:30 +02:00
committed by GitHub
parent 3d6267da93
commit 6b14cdbf06
182 changed files with 3159 additions and 3950 deletions
+30
View File
@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace CryptoExchange.Net.Objects
{
/// <summary>
/// An alias used by the exchange for an asset commonly known by another name
/// </summary>
public class AssetAlias
{
/// <summary>
/// The name of the asset on the exchange
/// </summary>
public string ExchangeAssetName { get; set; }
/// <summary>
/// The name of the asset as it's commonly known
/// </summary>
public string CommonAssetName { get; set; }
/// <summary>
/// ctor
/// </summary>
public AssetAlias(string exchangeName, string commonName)
{
ExchangeAssetName = exchangeName;
CommonAssetName = commonName;
}
}
}
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CryptoExchange.Net.Objects
{
/// <summary>
/// Exchange configuration for asset aliases
/// </summary>
public class AssetAliasConfiguration
{
/// <summary>
/// Defined aliases
/// </summary>
public AssetAlias[] Aliases { get; set; } = [];
/// <summary>
/// Auto convert asset names when using the Shared interfaces. Defaults to true
/// </summary>
public bool AutoConvertEnabled { get; set; } = true;
/// <summary>
/// Map the common name to an exchange name for an asset. If there is no alias the input name is returned
/// </summary>
public string CommonToExchangeName(string commonName) => !AutoConvertEnabled ? commonName : Aliases.SingleOrDefault(x => x.CommonAssetName == commonName)?.ExchangeAssetName ?? commonName;
/// <summary>
/// Map the exchange name to a common name for an asset. If there is no alias the input name is returned
/// </summary>
public string ExchangeToCommonName(string exchangeName) => !AutoConvertEnabled ? exchangeName : Aliases.SingleOrDefault(x => x.ExchangeAssetName == exchangeName)?.CommonAssetName ?? exchangeName;
}
}
+49 -22
View File
@@ -13,6 +13,11 @@ namespace CryptoExchange.Net.Objects
/// </summary>
public class CallResult
{
/// <summary>
/// Static success result
/// </summary>
public static CallResult SuccessResult { get; } = new CallResult(null);
/// <summary>
/// An error if the call didn't succeed, will always be filled if Success = false
/// </summary>
@@ -149,7 +154,7 @@ namespace CryptoExchange.Net.Objects
/// <returns></returns>
public CallResult AsDataless()
{
return new CallResult(null);
return SuccessResult;
}
/// <summary>
@@ -161,6 +166,18 @@ namespace CryptoExchange.Net.Objects
return new CallResult(error);
}
/// <summary>
/// Copy the CallResult to a new data type
/// </summary>
/// <typeparam name="K">The new type</typeparam>
/// <param name="data">The data</param>
/// <param name="error">The error returned</param>
/// <returns></returns>
public CallResult<K> AsErrorWithData<K>(Error error, K data)
{
return new CallResult<K>(data, OriginalData, error);
}
/// <summary>
/// Copy the WebCallResult to a new data type
/// </summary>
@@ -192,7 +209,7 @@ namespace CryptoExchange.Net.Objects
/// <summary>
/// The headers sent with the request
/// </summary>
public IEnumerable<KeyValuePair<string, IEnumerable<string>>>? RequestHeaders { get; set; }
public KeyValuePair<string, string[]>[]? RequestHeaders { get; set; }
/// <summary>
/// The request id
@@ -209,6 +226,11 @@ namespace CryptoExchange.Net.Objects
/// </summary>
public string? RequestBody { get; set; }
/// <summary>
/// The original data returned by the call, only available when `OutputOriginalData` is set to `true` in the client options
/// </summary>
public string? OriginalData { get; internal set; }
/// <summary>
/// The status code of the response. Note that a OK status does not always indicate success, check the Success parameter for this.
/// </summary>
@@ -217,7 +239,7 @@ namespace CryptoExchange.Net.Objects
/// <summary>
/// The response headers
/// </summary>
public IEnumerable<KeyValuePair<string, IEnumerable<string>>>? ResponseHeaders { get; set; }
public KeyValuePair<string, string[]>[]? ResponseHeaders { get; set; }
/// <summary>
/// The time between sending the request and receiving the response
@@ -227,30 +249,23 @@ namespace CryptoExchange.Net.Objects
/// <summary>
/// ctor
/// </summary>
/// <param name="code"></param>
/// <param name="responseHeaders"></param>
/// <param name="responseTime"></param>
/// <param name="requestId"></param>
/// <param name="requestUrl"></param>
/// <param name="requestBody"></param>
/// <param name="requestMethod"></param>
/// <param name="requestHeaders"></param>
/// <param name="error"></param>
public WebCallResult(
HttpStatusCode? code,
IEnumerable<KeyValuePair<string, IEnumerable<string>>>? responseHeaders,
KeyValuePair<string, string[]>[]? responseHeaders,
TimeSpan? responseTime,
string? originalData,
int? requestId,
string? requestUrl,
string? requestBody,
HttpMethod? requestMethod,
IEnumerable<KeyValuePair<string, IEnumerable<string>>>? requestHeaders,
KeyValuePair<string, string[]>[]? requestHeaders,
Error? error) : base(error)
{
ResponseStatusCode = code;
ResponseHeaders = responseHeaders;
ResponseTime = responseTime;
RequestId = requestId;
OriginalData = originalData;
RequestUrl = requestUrl;
RequestBody = requestBody;
@@ -271,7 +286,7 @@ namespace CryptoExchange.Net.Objects
/// <returns></returns>
public WebCallResult AsError(Error error)
{
return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, error);
return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, error);
}
/// <summary>
@@ -343,7 +358,7 @@ namespace CryptoExchange.Net.Objects
/// <summary>
/// The headers sent with the request
/// </summary>
public IEnumerable<KeyValuePair<string, IEnumerable<string>>>? RequestHeaders { get; set; }
public KeyValuePair<string, string[]>[]? RequestHeaders { get; set; }
/// <summary>
/// The request id
@@ -373,7 +388,7 @@ namespace CryptoExchange.Net.Objects
/// <summary>
/// The response headers
/// </summary>
public IEnumerable<KeyValuePair<string, IEnumerable<string>>>? ResponseHeaders { get; set; }
public KeyValuePair<string, string[]>[]? ResponseHeaders { get; set; }
/// <summary>
/// The time between sending the request and receiving the response
@@ -403,7 +418,7 @@ namespace CryptoExchange.Net.Objects
/// <param name="error"></param>
public WebCallResult(
HttpStatusCode? code,
IEnumerable<KeyValuePair<string, IEnumerable<string>>>? responseHeaders,
KeyValuePair<string, string[]>[]? responseHeaders,
TimeSpan? responseTime,
long? responseLength,
string? originalData,
@@ -411,7 +426,7 @@ namespace CryptoExchange.Net.Objects
string? requestUrl,
string? requestBody,
HttpMethod? requestMethod,
IEnumerable<KeyValuePair<string, IEnumerable<string>>>? requestHeaders,
KeyValuePair<string, string[]>[]? requestHeaders,
ResultDataSource dataSource,
[AllowNull] T data,
Error? error) : base(data, originalData, error)
@@ -435,7 +450,7 @@ namespace CryptoExchange.Net.Objects
/// <returns></returns>
public new WebCallResult AsDataless()
{
return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, Error);
return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, Error);
}
/// <summary>
/// Copy as a dataless result
@@ -443,7 +458,7 @@ namespace CryptoExchange.Net.Objects
/// <returns></returns>
public new WebCallResult AsDatalessError(Error error)
{
return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, error);
return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, error);
}
/// <summary>
@@ -474,6 +489,18 @@ namespace CryptoExchange.Net.Objects
return new WebCallResult<K>(ResponseStatusCode, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, DataSource, default, error);
}
/// <summary>
/// Copy the WebCallResult to a new data type
/// </summary>
/// <typeparam name="K">The new type</typeparam>
/// <param name="data">The data</param>
/// <param name="error">The error returned</param>
/// <returns></returns>
public new WebCallResult<K> AsErrorWithData<K>(Error error, K data)
{
return new WebCallResult<K>(ResponseStatusCode, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, DataSource, data, error);
}
/// <summary>
/// Copy the WebCallResult to an ExchangeWebResult of a new data type
/// </summary>
@@ -553,7 +580,7 @@ namespace CryptoExchange.Net.Objects
if (ResponseLength != null)
sb.Append($", {ResponseLength} bytes");
if (ResponseTime != null)
sb.Append($" received in {Math.Round(ResponseTime?.TotalMilliseconds ?? 0)}ms");
sb.Append($", received in {Math.Round(ResponseTime?.TotalMilliseconds ?? 0)}ms");
return sb.ToString();
}
+29 -90
View File
@@ -18,21 +18,18 @@ namespace CryptoExchange.Net.Objects
public string Message { get; set; }
/// <summary>
/// The data which caused the error
/// Underlying exception
/// </summary>
public object? Data { get; set; }
public Exception? Exception { get; set; }
/// <summary>
/// ctor
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
protected Error(int? code, string message, object? data)
protected Error (int? code, string message, Exception? exception)
{
Code = code;
Message = message;
Data = data;
Exception = exception;
}
/// <summary>
@@ -41,7 +38,7 @@ namespace CryptoExchange.Net.Objects
/// <returns></returns>
public override string ToString()
{
return Code != null ? $"[{GetType().Name}] {Code}: {Message} {Data}" : $"[{GetType().Name}] {Message} {Data}";
return Code != null ? $"[{GetType().Name}] {Code}: {Message}" : $"[{GetType().Name}] {Message}";
}
}
@@ -58,10 +55,12 @@ namespace CryptoExchange.Net.Objects
/// <summary>
/// ctor
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
protected CantConnectError(int? code, string message, object? data) : base(code, message, data) { }
public CantConnectError(Exception? exception) : base(null, "Can't connect to the server", exception) { }
/// <summary>
/// ctor
/// </summary>
protected CantConnectError(int? code, string message, Exception? exception) : base(code, message, exception) { }
}
/// <summary>
@@ -77,10 +76,7 @@ namespace CryptoExchange.Net.Objects
/// <summary>
/// ctor
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
protected NoApiCredentialsError(int? code, string message, object? data) : base(code, message, data) { }
protected NoApiCredentialsError(int? code, string message, Exception? exception) : base(code, message, exception) { }
}
/// <summary>
@@ -91,25 +87,12 @@ namespace CryptoExchange.Net.Objects
/// <summary>
/// ctor
/// </summary>
/// <param name="message"></param>
/// <param name="data"></param>
public ServerError(string message, object? data = null) : base(null, message, data) { }
public ServerError(string message) : base(null, message, null) { }
/// <summary>
/// ctor
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
public ServerError(int code, string message, object? data = null) : base(code, message, data) { }
/// <summary>
/// ctor
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
protected ServerError(int? code, string message, object? data) : base(code, message, data) { }
public ServerError(int? code, string message, Exception? exception = null) : base(code, message, exception) { }
}
/// <summary>
@@ -120,25 +103,12 @@ namespace CryptoExchange.Net.Objects
/// <summary>
/// ctor
/// </summary>
/// <param name="message"></param>
/// <param name="data"></param>
public WebError(string message, object? data = null) : base(null, message, data) { }
public WebError(string message, Exception? exception = null) : base(null, message, exception) { }
/// <summary>
/// ctor
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
public WebError(int code, string message, object? data = null) : base(code, message, data) { }
/// <summary>
/// ctor
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
protected WebError(int? code, string message, object? data): base(code, message, data) { }
public WebError(int code, string message, Exception? exception = null) : base(code, message, exception) { }
}
/// <summary>
@@ -149,17 +119,12 @@ namespace CryptoExchange.Net.Objects
/// <summary>
/// ctor
/// </summary>
/// <param name="message">The error message</param>
/// <param name="data">The data which caused the error</param>
public DeserializeError(string message, object? data) : base(null, message, data) { }
public DeserializeError(string message, Exception? exception = null) : base(null, message, exception) { }
/// <summary>
/// ctor
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
protected DeserializeError(int? code, string message, object? data): base(code, message, data) { }
protected DeserializeError(int? code, string message, Exception? exception = null) : base(code, message, exception) { }
}
/// <summary>
@@ -170,17 +135,12 @@ namespace CryptoExchange.Net.Objects
/// <summary>
/// ctor
/// </summary>
/// <param name="message">Error message</param>
/// <param name="data">Error data</param>
public UnknownError(string message, object? data = null) : base(null, message, data) { }
public UnknownError(string message, Exception? exception = null) : base(null, message, exception) { }
/// <summary>
/// ctor
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
protected UnknownError(int? code, string message, object? data): base(code, message, data) { }
protected UnknownError(int? code, string message, Exception? exception = null): base(code, message, exception) { }
}
/// <summary>
@@ -191,16 +151,12 @@ namespace CryptoExchange.Net.Objects
/// <summary>
/// ctor
/// </summary>
/// <param name="message"></param>
public ArgumentError(string message) : base(null, "Invalid parameter: " + message, null) { }
/// <summary>
/// ctor
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
protected ArgumentError(int? code, string message, object? data): base(code, message, data) { }
protected ArgumentError(int? code, string message, Exception? exception = null) : base(code, message, exception) { }
}
/// <summary>
@@ -216,10 +172,7 @@ namespace CryptoExchange.Net.Objects
/// <summary>
/// ctor
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
protected BaseRateLimitError(int? code, string message, object? data) : base(code, message, data) { }
protected BaseRateLimitError(int? code, string message, Exception? exception) : base(code, message, exception) { }
}
/// <summary>
@@ -236,10 +189,7 @@ namespace CryptoExchange.Net.Objects
/// <summary>
/// ctor
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
protected ClientRateLimitError(int? code, string message, object? data): base(code, message, data) { }
protected ClientRateLimitError(int? code, string message, Exception? exception = null) : base(code, message, exception) { }
}
/// <summary>
@@ -250,16 +200,12 @@ namespace CryptoExchange.Net.Objects
/// <summary>
/// ctor
/// </summary>
/// <param name="message"></param>
public ServerRateLimitError(string message) : base(null, "Server rate limit exceeded: " + message, null) { }
public ServerRateLimitError(string? message = null, Exception? exception = null) : base(null, "Server rate limit exceeded" + (message?.Length > 0 ? " : " + message : null), exception) { }
/// <summary>
/// ctor
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
protected ServerRateLimitError(int? code, string message, object? data) : base(code, message, data) { }
protected ServerRateLimitError(int? code, string message, Exception? exception = null) : base(code, message, exception) { }
}
/// <summary>
@@ -270,15 +216,12 @@ namespace CryptoExchange.Net.Objects
/// <summary>
/// ctor
/// </summary>
public CancellationRequestedError() : base(null, "Cancellation requested", null) { }
public CancellationRequestedError(Exception? exception = null) : base(null, "Cancellation requested", exception) { }
/// <summary>
/// ctor
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
public CancellationRequestedError(int? code, string message, object? data): base(code, message, data) { }
public CancellationRequestedError(int? code, string message, Exception? exception = null) : base(code, message, exception) { }
}
/// <summary>
@@ -289,15 +232,11 @@ namespace CryptoExchange.Net.Objects
/// <summary>
/// ctor
/// </summary>
/// <param name="message"></param>
public InvalidOperationError(string message) : base(null, message, null) { }
public InvalidOperationError(string message, Exception? exception = null) : base(null, message, exception) { }
/// <summary>
/// ctor
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
protected InvalidOperationError(int? code, string message, object? data): base(code, message, data) { }
protected InvalidOperationError(int? code, string message, Exception? exception = null) : base(code, message, exception) { }
}
}
@@ -46,7 +46,7 @@ namespace CryptoExchange.Net.Objects.Options
/// </summary>
public T Set<T>(T targetOptions) where T: LibraryOptions<TRestOptions, TSocketOptions, TApiCredentials, TEnvironment>
{
targetOptions.ApiCredentials = ApiCredentials;
targetOptions.ApiCredentials = (TApiCredentials?)ApiCredentials?.Copy();
targetOptions.Environment = Environment;
targetOptions.SocketClientLifeTime = SocketClientLifeTime;
targetOptions.Rest = Rest.Set(targetOptions.Rest);
@@ -94,7 +94,7 @@ namespace CryptoExchange.Net.Objects.Options
{
/// <summary>
/// Trade environment. Contains info about URL's to use to connect to the API. To swap environment select another environment for
/// the exhange's environment list or create a custom environment using either `[Exchange]Environment.CreateCustom()` or `[Exchange]Environment.[Environment]`, for example `KucoinEnvironment.TestNet` or `BinanceEnvironment.Live`
/// the exchange's environment list or create a custom environment using either `[Exchange]Environment.CreateCustom()` or `[Exchange]Environment.[Environment]`, for example `KucoinEnvironment.TestNet` or `BinanceEnvironment.Live`
/// </summary>
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public TEnvironment Environment { get; set; }
@@ -2,6 +2,7 @@
using CryptoExchange.Net.Converters.SystemTextJson;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
@@ -173,11 +174,14 @@ namespace CryptoExchange.Net.Objects
/// <summary>
/// Add an enum value as the string value as mapped using the <see cref="MapAttribute" />
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
#if NET5_0_OR_GREATER
public void AddEnum<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] T>(string key, T value)
#else
public void AddEnum<T>(string key, T value)
#endif
where T : struct, Enum
{
Add(key, EnumConverter.GetString(value)!);
Add(key, EnumConverter<T>.GetString(value)!);
}
/// <summary>
@@ -185,9 +189,14 @@ namespace CryptoExchange.Net.Objects
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
#if NET5_0_OR_GREATER
public void AddEnumAsInt<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] T>(string key, T value)
#else
public void AddEnumAsInt<T>(string key, T value)
#endif
where T : struct, Enum
{
var stringVal = EnumConverter.GetString(value)!;
var stringVal = EnumConverter<T>.GetString(value)!;
Add(key, int.Parse(stringVal)!);
}
@@ -196,22 +205,30 @@ namespace CryptoExchange.Net.Objects
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
#if NET5_0_OR_GREATER
public void AddOptionalEnum<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] T>(string key, T? value)
#else
public void AddOptionalEnum<T>(string key, T? value)
#endif
where T : struct, Enum
{
if (value != null)
Add(key, EnumConverter.GetString(value));
Add(key, EnumConverter<T>.GetString(value));
}
/// <summary>
/// Add an enum value as the string value as mapped using the <see cref="MapAttribute" />. Not added if value is null
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
#if NET5_0_OR_GREATER
public void AddOptionalEnumAsInt<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] T>(string key, T? value)
#else
public void AddOptionalEnumAsInt<T>(string key, T? value)
#endif
where T : struct, Enum
{
if (value != null)
{
var stringVal = EnumConverter.GetString(value);
var stringVal = EnumConverter<T>.GetString(value);
Add(key, int.Parse(stringVal));
}
}
@@ -50,6 +50,11 @@ namespace CryptoExchange.Net.Objects.Sockets
/// </summary>
public TimeSpan? KeepAliveInterval { get; set; }
/// <summary>
/// Timeout for keep alive response messages
/// </summary>
public TimeSpan? KeepAliveTimeout { get; set; }
/// <summary>
/// The rate limiter for the socket connection
/// </summary>
+1 -1
View File
@@ -56,7 +56,7 @@ namespace CryptoExchange.Net.Objects
if (!IsEnabled(logLevel))
return;
var logMessage = $"{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff} | {logLevel} | {(_categoryName == null ? "" : $"{_categoryName} | ")}{formatter(state, exception)}";
var logMessage = $"{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff} | {logLevel} | {(_categoryName == null ? "" : $"{_categoryName} | ")}{formatter(state, exception)}{(exception == null ? string.Empty : (", " + exception.ToLogString()))}";
Trace.WriteLine(logMessage);
}
}