1
0
mirror of https://github.com/JKorf/CryptoExchange.Net synced 2025-06-07 07:56:12 +00:00

Added net9.0 build target, added KeepAliveTimeout for websocket connections

This commit is contained in:
Jkorf 2024-12-23 14:14:47 +01:00
parent 0be1bb16e3
commit 290be7f5e0
30 changed files with 78 additions and 69 deletions

View File

@ -1,4 +1,4 @@
#if !NETSTANDARD2_1 #if NETSTANDARD2_0
namespace System.Diagnostics.CodeAnalysis namespace System.Diagnostics.CodeAnalysis
{ {
using System; using System;

View File

@ -26,7 +26,7 @@ namespace CryptoExchange.Net.Caching
/// <returns>Cached value if it was in cache</returns> /// <returns>Cached value if it was in cache</returns>
public object? Get(string key, TimeSpan maxAge) public object? Get(string key, TimeSpan maxAge)
{ {
_cache.TryGetValue(key, out CacheItem value); _cache.TryGetValue(key, out CacheItem? value);
if (value == null) if (value == null)
return null; return null;

View File

@ -15,7 +15,7 @@ namespace CryptoExchange.Net.Clients
/// <summary> /// <summary>
/// Version of the CryptoExchange.Net base library /// Version of the CryptoExchange.Net base library
/// </summary> /// </summary>
public Version CryptoExchangeLibVersion { get; } = typeof(BaseClient).Assembly.GetName().Version; public Version CryptoExchangeLibVersion { get; } = typeof(BaseClient).Assembly.GetName().Version!;
/// <summary> /// <summary>
/// Version of the client implementation /// Version of the client implementation
@ -27,7 +27,7 @@ namespace CryptoExchange.Net.Clients
lock(_versionLock) lock(_versionLock)
{ {
if (_exchangeVersion == null) if (_exchangeVersion == null)
_exchangeVersion = GetType().Assembly.GetName().Version; _exchangeVersion = GetType().Assembly.GetName().Version!;
return _exchangeVersion; return _exchangeVersion;
} }

View File

@ -807,7 +807,7 @@ namespace CryptoExchange.Net.Clients
if (parameterPosition == HttpMethodParameterPosition.InUri) if (parameterPosition == HttpMethodParameterPosition.InUri)
{ {
foreach (var parameter in parameters) foreach (var parameter in parameters)
uri = uri.AddQueryParmeter(parameter.Key, parameter.Value.ToString()); uri = uri.AddQueryParmeter(parameter.Key, parameter.Value.ToString()!);
} }
var headers = new Dictionary<string, string>(); var headers = new Dictionary<string, string>();

View File

@ -36,7 +36,7 @@ namespace CryptoExchange.Net.Converters.JsonNet
var result = Activator.CreateInstance(objectType); var result = Activator.CreateInstance(objectType);
var arr = JArray.Load(reader); var arr = JArray.Load(reader);
return ParseObject(arr, result, objectType); return ParseObject(arr, result!, objectType);
} }
private static object ParseObject(JArray arr, object result, Type objectType) private static object ParseObject(JArray arr, object result, Type objectType)
@ -58,25 +58,25 @@ namespace CryptoExchange.Net.Converters.JsonNet
var count = 0; var count = 0;
if (innerArray.Count == 0) if (innerArray.Count == 0)
{ {
var arrayResult = (IList)Activator.CreateInstance(property.PropertyType, new [] { 0 }); var arrayResult = (IList)Activator.CreateInstance(property.PropertyType, new [] { 0 })!;
property.SetValue(result, arrayResult); property.SetValue(result, arrayResult);
} }
else if (innerArray[0].Type == JTokenType.Array) else if (innerArray[0].Type == JTokenType.Array)
{ {
var arrayResult = (IList)Activator.CreateInstance(property.PropertyType, new [] { innerArray.Count }); var arrayResult = (IList)Activator.CreateInstance(property.PropertyType, new [] { innerArray.Count })!;
foreach (var obj in innerArray) foreach (var obj in innerArray)
{ {
var innerObj = Activator.CreateInstance(objType!); var innerObj = Activator.CreateInstance(objType!);
arrayResult[count] = ParseObject((JArray)obj, innerObj, objType!); arrayResult[count] = ParseObject((JArray)obj, innerObj!, objType!);
count++; count++;
} }
property.SetValue(result, arrayResult); property.SetValue(result, arrayResult);
} }
else else
{ {
var arrayResult = (IList)Activator.CreateInstance(property.PropertyType, new [] { 1 }); var arrayResult = (IList)Activator.CreateInstance(property.PropertyType, new [] { 1 })!;
var innerObj = Activator.CreateInstance(objType!); var innerObj = Activator.CreateInstance(objType!);
arrayResult[0] = ParseObject(innerArray, innerObj, objType!); arrayResult[0] = ParseObject(innerArray, innerObj!, objType!);
property.SetValue(result, arrayResult); property.SetValue(result, arrayResult);
} }
continue; continue;
@ -88,7 +88,7 @@ namespace CryptoExchange.Net.Converters.JsonNet
object? value; object? value;
if (converterAttribute != null) if (converterAttribute != null)
{ {
value = arr[attribute.Index].ToObject(property.PropertyType, new JsonSerializer {Converters = {(JsonConverter) Activator.CreateInstance(converterAttribute.ConverterType)}}); value = arr[attribute.Index].ToObject(property.PropertyType, new JsonSerializer {Converters = {(JsonConverter) Activator.CreateInstance(converterAttribute.ConverterType)!}});
} }
else if (conversionAttribute != null) else if (conversionAttribute != null)
{ {
@ -120,7 +120,7 @@ namespace CryptoExchange.Net.Converters.JsonNet
} }
else if ((property.PropertyType == typeof(decimal) else if ((property.PropertyType == typeof(decimal)
|| property.PropertyType == typeof(decimal?)) || property.PropertyType == typeof(decimal?))
&& (value != null && value.ToString().IndexOf("e", StringComparison.OrdinalIgnoreCase) >= 0)) && (value != null && value.ToString()!.IndexOf("e", StringComparison.OrdinalIgnoreCase) >= 0))
{ {
var v = value.ToString(); var v = value.ToString();
if (decimal.TryParse(v, NumberStyles.Float, CultureInfo.InvariantCulture, out var dec)) if (decimal.TryParse(v, NumberStyles.Float, CultureInfo.InvariantCulture, out var dec))
@ -164,7 +164,7 @@ namespace CryptoExchange.Net.Converters.JsonNet
last = arrayProp.Index; last = arrayProp.Index;
var converterAttribute = GetCustomAttribute<JsonConverterAttribute>(prop); var converterAttribute = GetCustomAttribute<JsonConverterAttribute>(prop);
if (converterAttribute != null) if (converterAttribute != null)
writer.WriteRawValue(JsonConvert.SerializeObject(prop.GetValue(value), (JsonConverter)Activator.CreateInstance(converterAttribute.ConverterType))); writer.WriteRawValue(JsonConvert.SerializeObject(prop.GetValue(value), (JsonConverter)Activator.CreateInstance(converterAttribute.ConverterType)!));
else if (!IsSimple(prop.PropertyType)) else if (!IsSimple(prop.PropertyType))
serializer.Serialize(writer, prop.GetValue(value)); serializer.Serialize(writer, prop.GetValue(value));
else else
@ -187,9 +187,9 @@ namespace CryptoExchange.Net.Converters.JsonNet
} }
private static T? GetCustomAttribute<T>(MemberInfo memberInfo) where T : Attribute => private static T? GetCustomAttribute<T>(MemberInfo memberInfo) where T : Attribute =>
(T?)_attributeByMemberInfoAndTypeCache.GetOrAdd((memberInfo, typeof(T)), tuple => memberInfo.GetCustomAttribute(typeof(T))); (T?)_attributeByMemberInfoAndTypeCache.GetOrAdd((memberInfo, typeof(T)), tuple => memberInfo.GetCustomAttribute(typeof(T))!);
private static T? GetCustomAttribute<T>(Type type) where T : Attribute => private static T? GetCustomAttribute<T>(Type type) where T : Attribute =>
(T?)_attributeByTypeAndTypeCache.GetOrAdd((type, typeof(T)), tuple => type.GetCustomAttribute(typeof(T))); (T?)_attributeByTypeAndTypeCache.GetOrAdd((type, typeof(T)), tuple => type.GetCustomAttribute(typeof(T))!);
} }
} }

View File

@ -27,7 +27,7 @@ namespace CryptoExchange.Net.Converters.JsonNet
{ {
try try
{ {
return decimal.Parse(reader.Value!.ToString(), NumberStyles.Float, CultureInfo.InvariantCulture); return decimal.Parse(reader.Value!.ToString()!, NumberStyles.Float, CultureInfo.InvariantCulture);
} }
catch (OverflowException) catch (OverflowException)
{ {
@ -40,7 +40,7 @@ namespace CryptoExchange.Net.Converters.JsonNet
{ {
try try
{ {
var value = reader.Value!.ToString(); var value = reader.Value!.ToString()!;
return decimal.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture); return decimal.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture);
} }
catch (OverflowException) catch (OverflowException)

View File

@ -34,7 +34,7 @@ namespace CryptoExchange.Net.Converters.JsonNet
/// </returns> /// </returns>
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{ {
var value = reader.Value?.ToString().ToLower().Trim(); var value = reader.Value?.ToString()!.ToLower().Trim();
if (value == null || value == "") if (value == null || value == "")
{ {
if (Nullable.GetUnderlyingType(objectType) != null) if (Nullable.GetUnderlyingType(objectType) != null)

View File

@ -297,7 +297,7 @@ namespace CryptoExchange.Net.Converters.JsonNet
// Try getting the underlying byte[] instead of the ToArray to prevent creating a copy // Try getting the underlying byte[] instead of the ToArray to prevent creating a copy
using var stream = MemoryMarshal.TryGetArray(data, out var arraySegment) using var stream = MemoryMarshal.TryGetArray(data, out var arraySegment)
? new MemoryStream(arraySegment.Array, arraySegment.Offset, arraySegment.Count) ? new MemoryStream(arraySegment.Array!, arraySegment.Offset, arraySegment.Count)
: new MemoryStream(data.ToArray()); : new MemoryStream(data.ToArray());
using var reader = new StreamReader(stream, Encoding.UTF8, false, Math.Max(2, data.Length), true); using var reader = new StreamReader(stream, Encoding.UTF8, false, Math.Max(2, data.Length), true);
using var jsonTextReader = new JsonTextReader(reader); using var jsonTextReader = new JsonTextReader(reader);

View File

@ -23,7 +23,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{ {
Type converterType = typeof(ArrayConverterInner<>).MakeGenericType(typeToConvert); Type converterType = typeof(ArrayConverterInner<>).MakeGenericType(typeToConvert);
return (JsonConverter)Activator.CreateInstance(converterType); return (JsonConverter)Activator.CreateInstance(converterType)!;
} }
private class ArrayPropertyInfo private class ArrayPropertyInfo
@ -79,7 +79,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
JsonSerializerOptions? typeOptions = null; JsonSerializerOptions? typeOptions = null;
if (prop.JsonConverterType != null) if (prop.JsonConverterType != null)
{ {
var converter = (JsonConverter)Activator.CreateInstance(prop.JsonConverterType); var converter = (JsonConverter)Activator.CreateInstance(prop.JsonConverterType)!;
typeOptions = new JsonSerializerOptions(); typeOptions = new JsonSerializerOptions();
typeOptions.Converters.Clear(); typeOptions.Converters.Clear();
typeOptions.Converters.Add(converter); typeOptions.Converters.Add(converter);
@ -90,7 +90,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
if (prop.PropertyInfo.PropertyType == typeof(string)) if (prop.PropertyInfo.PropertyType == typeof(string))
writer.WriteStringValue(Convert.ToString(objValue, CultureInfo.InvariantCulture)); writer.WriteStringValue(Convert.ToString(objValue, CultureInfo.InvariantCulture));
else else
writer.WriteRawValue(Convert.ToString(objValue, CultureInfo.InvariantCulture)); writer.WriteRawValue(Convert.ToString(objValue, CultureInfo.InvariantCulture)!);
} }
else else
{ {
@ -107,7 +107,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
if (reader.TokenType == JsonTokenType.Null) if (reader.TokenType == JsonTokenType.Null)
return default; return default;
var result = Activator.CreateInstance(typeToConvert); var result = Activator.CreateInstance(typeToConvert)!;
return (T)ParseObject(ref reader, result, typeToConvert, options); return (T)ParseObject(ref reader, result, typeToConvert, options);
} }
@ -177,7 +177,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
{ {
if (!_converterOptionsCache.TryGetValue(attribute.JsonConverterType, out var newOptions)) if (!_converterOptionsCache.TryGetValue(attribute.JsonConverterType, out var newOptions))
{ {
var converter = (JsonConverter)Activator.CreateInstance(attribute.JsonConverterType); var converter = (JsonConverter)Activator.CreateInstance(attribute.JsonConverterType)!;
newOptions = new JsonSerializerOptions newOptions = new JsonSerializerOptions
{ {
NumberHandling = SerializerOptions.WithConverters.NumberHandling, NumberHandling = SerializerOptions.WithConverters.NumberHandling,
@ -209,7 +209,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
} }
if (targetType.IsAssignableFrom(value?.GetType())) if (targetType.IsAssignableFrom(value?.GetType()))
attribute.PropertyInfo.SetValue(result, value == null ? null : value); attribute.PropertyInfo.SetValue(result, value);
else else
attribute.PropertyInfo.SetValue(result, value == null ? null : Convert.ChangeType(value, targetType, CultureInfo.InvariantCulture)); attribute.PropertyInfo.SetValue(result, value == null ? null : Convert.ChangeType(value, targetType, CultureInfo.InvariantCulture));
} }

View File

@ -17,7 +17,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
{ {
try try
{ {
return decimal.Parse(reader.GetString(), NumberStyles.Float, CultureInfo.InvariantCulture); return decimal.Parse(reader.GetString()!, NumberStyles.Float, CultureInfo.InvariantCulture);
} }
catch(OverflowException) catch(OverflowException)
{ {

View File

@ -21,7 +21,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{ {
Type converterType = typeof(BoolConverterInner<>).MakeGenericType(typeToConvert); Type converterType = typeof(BoolConverterInner<>).MakeGenericType(typeToConvert);
return (JsonConverter)Activator.CreateInstance(converterType); return (JsonConverter)Activator.CreateInstance(converterType)!;
} }
private class BoolConverterInner<T> : JsonConverter<T> private class BoolConverterInner<T> : JsonConverter<T>

View File

@ -27,7 +27,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{ {
Type converterType = typeof(DateTimeConverterInner<>).MakeGenericType(typeToConvert); Type converterType = typeof(DateTimeConverterInner<>).MakeGenericType(typeToConvert);
return (JsonConverter)Activator.CreateInstance(converterType); return (JsonConverter)Activator.CreateInstance(converterType)!;
} }
private class DateTimeConverterInner<T> : JsonConverter<T> private class DateTimeConverterInner<T> : JsonConverter<T>
@ -74,7 +74,9 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
{ {
if (value == null) if (value == null)
{
writer.WriteNullValue(); writer.WriteNullValue();
}
else else
{ {
var dtValue = (DateTime)(object)value; var dtValue = (DateTime)(object)value;

View File

@ -24,7 +24,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
/// <inheritdoc /> /// <inheritdoc />
public override JsonConverter CreateConverter(Type typeToConvert) public override JsonConverter CreateConverter(Type typeToConvert)
{ {
return (JsonConverter)Activator.CreateInstance(_type, _parameters); return (JsonConverter)Activator.CreateInstance(_type, _parameters)!;
} }
} }

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks> <TargetFrameworks>netstandard2.0;netstandard2.1;net9.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>CryptoExchange.Net</PackageId> <PackageId>CryptoExchange.Net</PackageId>

View File

@ -67,7 +67,7 @@ namespace CryptoExchange.Net
{ {
if (serializationType == ArrayParametersSerialization.Array) if (serializationType == ArrayParametersSerialization.Array)
{ {
uriString += $"{string.Join("&", ((object[])(urlEncodeValues ? Uri.EscapeDataString(arrayEntry.Value.ToString()) : arrayEntry.Value)).Select(v => $"{arrayEntry.Key}[]={string.Format(CultureInfo.InvariantCulture, "{0}", v)}"))}&"; uriString += $"{string.Join("&", ((object[])(urlEncodeValues ? Uri.EscapeDataString(arrayEntry.Value.ToString()!) : arrayEntry.Value)).Select(v => $"{arrayEntry.Key}[]={string.Format(CultureInfo.InvariantCulture, "{0}", v)}"))}&";
} }
else if (serializationType == ArrayParametersSerialization.MultipleValues) else if (serializationType == ArrayParametersSerialization.MultipleValues)
{ {
@ -111,7 +111,7 @@ namespace CryptoExchange.Net
formData.Add(kvp.Key, string.Format(CultureInfo.InvariantCulture, "{0}", kvp.Value)); formData.Add(kvp.Key, string.Format(CultureInfo.InvariantCulture, "{0}", kvp.Value));
} }
} }
return formData.ToString(); return formData.ToString()!;
} }
/// <summary> /// <summary>
@ -366,7 +366,7 @@ namespace CryptoExchange.Net
{ {
using var decompressedStream = new MemoryStream(); using var decompressedStream = new MemoryStream();
using var dataStream = MemoryMarshal.TryGetArray(data, out var arraySegment) using var dataStream = MemoryMarshal.TryGetArray(data, out var arraySegment)
? new MemoryStream(arraySegment.Array, arraySegment.Offset, arraySegment.Count) ? new MemoryStream(arraySegment.Array!, arraySegment.Offset, arraySegment.Count)
: new MemoryStream(data.ToArray()); : new MemoryStream(data.ToArray());
using var deflateStream = new GZipStream(new MemoryStream(data.ToArray()), CompressionMode.Decompress); using var deflateStream = new GZipStream(new MemoryStream(data.ToArray()), CompressionMode.Decompress);
deflateStream.CopyTo(decompressedStream); deflateStream.CopyTo(decompressedStream);

View File

@ -14,7 +14,7 @@ namespace CryptoExchange.Net.Objects
/// <param name="x"></param> /// <param name="x"></param>
/// <param name="y"></param> /// <param name="y"></param>
/// <returns></returns> /// <returns></returns>
public int Compare(byte[] x, byte[] y) public int Compare(byte[]? x, byte[]? y)
{ {
// Shortcuts: If both are null, they are the same. // Shortcuts: If both are null, they are the same.
if (x == null && y == null) return 0; if (x == null && y == null) return 0;

View File

@ -13,7 +13,7 @@ namespace CryptoExchange.Net.Objects
/// <param name="x"></param> /// <param name="x"></param>
/// <param name="y"></param> /// <param name="y"></param>
/// <returns></returns> /// <returns></returns>
public int Compare(string x, string y) public int Compare(string? x, string? y)
{ {
// Shortcuts: If both are null, they are the same. // Shortcuts: If both are null, they are the same.
if (x == null && y == null) return 0; if (x == null && y == null) return 0;

View File

@ -156,7 +156,7 @@ namespace CryptoExchange.Net.Objects
/// <param name="value"></param> /// <param name="value"></param>
public void AddSecondsString(string key, DateTime value) public void AddSecondsString(string key, DateTime value)
{ {
Add(key, DateTimeConverter.ConvertToSeconds(value).ToString()); Add(key, DateTimeConverter.ConvertToSeconds(value).ToString()!);
} }
/// <summary> /// <summary>
@ -167,7 +167,7 @@ namespace CryptoExchange.Net.Objects
public void AddOptionalSecondsString(string key, DateTime? value) public void AddOptionalSecondsString(string key, DateTime? value)
{ {
if (value != null) if (value != null)
Add(key, DateTimeConverter.ConvertToSeconds(value).ToString()); Add(key, DateTimeConverter.ConvertToSeconds(value).ToString()!);
} }
/// <summary> /// <summary>
@ -187,7 +187,7 @@ namespace CryptoExchange.Net.Objects
/// <param name="value"></param> /// <param name="value"></param>
public void AddEnumAsInt<T>(string key, T value) public void AddEnumAsInt<T>(string key, T value)
{ {
var stringVal = EnumConverter.GetString(value); var stringVal = EnumConverter.GetString(value)!;
Add(key, int.Parse(stringVal)!); Add(key, int.Parse(stringVal)!);
} }

View File

@ -843,9 +843,9 @@ namespace CryptoExchange.Net.OrderBook
internal class DescComparer<T> : IComparer<T> internal class DescComparer<T> : IComparer<T>
{ {
public int Compare(T x, T y) public int Compare(T? x, T? y)
{ {
return Comparer<T>.Default.Compare(y, x); return Comparer<T>.Default.Compare(y!, x!);
} }
} }
} }

View File

@ -20,7 +20,7 @@ namespace CryptoExchange.Net.RateLimiting.Guards
/// <summary> /// <summary>
/// Apply guard per connection /// Apply guard per connection
/// </summary> /// </summary>
public static Func<RequestDefinition, string, string?, string> PerConnection { get; } = new Func<RequestDefinition, string, string?, string>((def, host, key) => def.ConnectionId.ToString()); public static Func<RequestDefinition, string, string?, string> PerConnection { get; } = new Func<RequestDefinition, string, string?, string>((def, host, key) => def.ConnectionId.ToString()!);
/// <summary> /// <summary>
/// Apply guard per API key /// Apply guard per API key
/// </summary> /// </summary>

View File

@ -48,7 +48,7 @@ namespace CryptoExchange.Net.Requests
} }
/// <inheritdoc /> /// <inheritdoc />
public Uri Uri => _request.RequestUri; public Uri Uri => _request.RequestUri!;
/// <inheritdoc /> /// <inheritdoc />
public int RequestId { get; } public int RequestId { get; }

View File

@ -60,8 +60,8 @@ namespace CryptoExchange.Net.SharedApis
} }
else else
{ {
if (param.Names.All(x => ExchangeParameters.HasValue(exchangeParameters, exchange, x, param.ValueType) != true)) if (param.Names!.All(x => ExchangeParameters.HasValue(exchangeParameters, exchange, x, param.ValueType) != true))
return new ArgumentError($"One of exchange parameters `{string.Join(", ", param.Names)}` for exchange `{exchange}` should be provided. Example: {param.ExampleValue}"); return new ArgumentError($"One of exchange parameters `{string.Join(", ", param.Names!)}` for exchange `{exchange}` should be provided. Example: {param.ExampleValue}");
} }
} }
@ -113,13 +113,13 @@ namespace CryptoExchange.Net.SharedApis
{ {
if (!string.IsNullOrEmpty(param.Name)) if (!string.IsNullOrEmpty(param.Name))
{ {
if (typeof(T).GetProperty(param.Name).GetValue(request, null) == null) if (typeof(T).GetProperty(param.Name)!.GetValue(request, null) == null)
return new ArgumentError($"Required optional parameter `{param.Name}` for exchange `{exchange}` is missing. Example: {param.ExampleValue}"); return new ArgumentError($"Required optional parameter `{param.Name}` for exchange `{exchange}` is missing. Example: {param.ExampleValue}");
} }
else else
{ {
if (param.Names.All(x => typeof(T).GetProperty(param.Name).GetValue(request, null) == null)) if (param.Names!.All(x => typeof(T).GetProperty(param.Name!)!.GetValue(request, null) == null))
return new ArgumentError($"One of optional parameters `{string.Join(", ", param.Names)}` for exchange `{exchange}` should be provided. Example: {param.ExampleValue}"); return new ArgumentError($"One of optional parameters `{string.Join(", ", param.Names!)}` for exchange `{exchange}` should be provided. Example: {param.ExampleValue}");
} }
} }

View File

@ -64,7 +64,7 @@ namespace CryptoExchange.Net.SharedApis
public override string ToString(string exchange) public override string ToString(string exchange)
{ {
var sb = new StringBuilder(base.ToString(exchange)); var sb = new StringBuilder(base.ToString(exchange));
sb.AppendLine($"Supported limit values: [{(SupportedLimits == null ? string.Join(", ", SupportedLimits) : $"{MinLimit}..{MaxLimit}")}]"); sb.AppendLine($"Supported limit values: [{(SupportedLimits != null ? string.Join(", ", SupportedLimits) : $"{MinLimit}..{MaxLimit}")}]");
return sb.ToString(); return sb.ToString();
} }
} }

View File

@ -55,7 +55,7 @@ namespace CryptoExchange.Net.SharedApis
{ {
if (Name != null) if (Name != null)
return $"[{ValueType.Name}] {Name}: {Description} | example: {ExampleValue}"; return $"[{ValueType.Name}] {Name}: {Description} | example: {ExampleValue}";
return $"[{ValueType.Name}] {string.Join(" / ", Names)}: {Description} | example: {ExampleValue}"; return $"[{ValueType.Name}] {string.Join(" / ", Names!)}: {Description} | example: {ExampleValue}";
} }
} }
} }

View File

@ -195,9 +195,12 @@ namespace CryptoExchange.Net.Sockets
socket.Options.SetBuffer(_receiveBufferSize, _sendBufferSize); socket.Options.SetBuffer(_receiveBufferSize, _sendBufferSize);
if (Parameters.Proxy != null) if (Parameters.Proxy != null)
SetProxy(socket, Parameters.Proxy); SetProxy(socket, Parameters.Proxy);
#if NET6_0_OR_GREATER #if NET6_0_OR_GREATER
socket.Options.CollectHttpResponseDetails = true; socket.Options.CollectHttpResponseDetails = true;
#endif #endif
#if NET9_0_OR_GREATER
socket.Options.KeepAliveTimeout = TimeSpan.FromSeconds(10);
#endif
} }
catch (PlatformNotSupportedException) catch (PlatformNotSupportedException)
{ {
@ -235,13 +238,13 @@ namespace CryptoExchange.Net.Sockets
if (e is WebSocketException we) if (e is WebSocketException we)
{ {
#if (NET6_0_OR_GREATER) #if (NET6_0_OR_GREATER)
if (_socket.HttpStatusCode == HttpStatusCode.TooManyRequests) if (_socket.HttpStatusCode == HttpStatusCode.TooManyRequests)
{ {
await (OnConnectRateLimited?.Invoke() ?? Task.CompletedTask).ConfigureAwait(false); await (OnConnectRateLimited?.Invoke() ?? Task.CompletedTask).ConfigureAwait(false);
return new CallResult(new ServerRateLimitError(we.Message)); return new CallResult(new ServerRateLimitError(we.Message));
} }
#else #else
// ClientWebSocket.HttpStatusCode is only available in .NET6+ https://learn.microsoft.com/en-us/dotnet/api/system.net.websockets.clientwebsocket.httpstatuscode?view=net-8.0 // ClientWebSocket.HttpStatusCode is only available in .NET6+ https://learn.microsoft.com/en-us/dotnet/api/system.net.websockets.clientwebsocket.httpstatuscode?view=net-8.0
// Try to read 429 from the message instead // Try to read 429 from the message instead
if (we.Message.Contains("429")) if (we.Message.Contains("429"))
@ -249,7 +252,7 @@ namespace CryptoExchange.Net.Sockets
await (OnConnectRateLimited?.Invoke() ?? Task.CompletedTask).ConfigureAwait(false); await (OnConnectRateLimited?.Invoke() ?? Task.CompletedTask).ConfigureAwait(false);
return new CallResult(new ServerRateLimitError(we.Message)); return new CallResult(new ServerRateLimitError(we.Message));
} }
#endif #endif
} }
return new CallResult(new CantConnectError()); return new CallResult(new CantConnectError());
@ -604,14 +607,14 @@ namespace CryptoExchange.Net.Sockets
if (_socket.State == WebSocketState.CloseReceived) if (_socket.State == WebSocketState.CloseReceived)
{ {
// Close received means it server initiated, we should send a confirmation and close the socket // Close received means it server initiated, we should send a confirmation and close the socket
_logger.SocketReceivedCloseMessage(Id, receiveResult.CloseStatus.ToString(), receiveResult.CloseStatusDescription); _logger.SocketReceivedCloseMessage(Id, receiveResult.CloseStatus.ToString()!, receiveResult.CloseStatusDescription ?? string.Empty);
if (_closeTask?.IsCompleted != false) if (_closeTask?.IsCompleted != false)
_closeTask = CloseInternalAsync(); _closeTask = CloseInternalAsync();
} }
else else
{ {
// Means the socket is now closed and we were the one initiating it // Means the socket is now closed and we were the one initiating it
_logger.SocketReceivedCloseConfirmation(Id, receiveResult.CloseStatus.ToString(), receiveResult.CloseStatusDescription); _logger.SocketReceivedCloseConfirmation(Id, receiveResult.CloseStatus.ToString()!, receiveResult.CloseStatusDescription ?? string.Empty);
} }
break; break;
@ -626,7 +629,7 @@ namespace CryptoExchange.Net.Sockets
// Write the data to a memory stream to be reassembled later // Write the data to a memory stream to be reassembled later
if (multipartStream == null) if (multipartStream == null)
multipartStream = new MemoryStream(); multipartStream = new MemoryStream();
multipartStream.Write(buffer.Array, buffer.Offset, receiveResult.Count); multipartStream.Write(buffer.Array!, buffer.Offset, receiveResult.Count);
} }
else else
{ {
@ -640,7 +643,7 @@ namespace CryptoExchange.Net.Sockets
{ {
// Received the end of a multipart message, write to memory stream for reassembling // Received the end of a multipart message, write to memory stream for reassembling
_logger.SocketReceivedPartialMessage(Id, receiveResult.Count); _logger.SocketReceivedPartialMessage(Id, receiveResult.Count);
multipartStream!.Write(buffer.Array, buffer.Offset, receiveResult.Count); multipartStream!.Write(buffer.Array!, buffer.Offset, receiveResult.Count);
} }
break; break;

View File

@ -398,7 +398,7 @@ namespace CryptoExchange.Net.Sockets
/// <returns></returns> /// <returns></returns>
protected virtual Task HandleRequestRateLimitedAsync(int requestId) protected virtual Task HandleRequestRateLimitedAsync(int requestId)
{ {
Query query; Query? query;
lock (_listenersLock) lock (_listenersLock)
{ {
query = _listeners.OfType<Query>().FirstOrDefault(x => x.Id == requestId); query = _listeners.OfType<Query>().FirstOrDefault(x => x.Id == requestId);
@ -427,7 +427,7 @@ namespace CryptoExchange.Net.Sockets
/// <param name="requestId">Id of the request sent</param> /// <param name="requestId">Id of the request sent</param>
protected virtual Task HandleRequestSentAsync(int requestId) protected virtual Task HandleRequestSentAsync(int requestId)
{ {
Query query; Query? query;
lock (_listenersLock) lock (_listenersLock)
{ {
query = _listeners.OfType<Query>().FirstOrDefault(x => x.Id == requestId); query = _listeners.OfType<Query>().FirstOrDefault(x => x.Id == requestId);

View File

@ -378,7 +378,7 @@ namespace CryptoExchange.Net.Testing.Comparers
if (objectValue is bool boolVal && jsonValue.Value<bool>() != boolVal) if (objectValue is bool boolVal && jsonValue.Value<bool>() != boolVal)
throw new Exception($"{method}: {property} not equal: {jsonValue.Value<bool>()} vs {(bool)objectValue}"); throw new Exception($"{method}: {property} not equal: {jsonValue.Value<bool>()} vs {(bool)objectValue}");
if (jsonValue.Value<bool>() != bool.Parse(objectValue.ToString())) if (jsonValue.Value<bool>() != bool.Parse(objectValue.ToString()!))
throw new Exception($"{method}: {property} not equal: {jsonValue.Value<bool>()} vs {(bool)objectValue}"); throw new Exception($"{method}: {property} not equal: {jsonValue.Value<bool>()} vs {(bool)objectValue}");
} }
} }

View File

@ -211,7 +211,7 @@ namespace CryptoExchange.Net.Testing.Comparers
if (dictProp.Value.Type == JTokenType.Object) if (dictProp.Value.Type == JTokenType.Object)
{ {
CheckPropertyValue(method, dictProp.Value, dict[dictProp.Name]!, dict[dictProp.Name].GetType(), null, null, ignoreProperties); CheckPropertyValue(method, dictProp.Value, dict[dictProp.Name]!, dict[dictProp.Name]!.GetType(), null, null, ignoreProperties);
} }
else else
{ {

View File

@ -5,8 +5,11 @@ namespace CryptoExchange.Net.Testing
{ {
internal class EnumValueTraceListener : TraceListener internal class EnumValueTraceListener : TraceListener
{ {
public override void Write(string message) public override void Write(string? message)
{ {
if (message == null)
return;
if (message.Contains("Cannot map")) if (message.Contains("Cannot map"))
throw new Exception("Enum value error: " + message); throw new Exception("Enum value error: " + message);
@ -14,8 +17,11 @@ namespace CryptoExchange.Net.Testing
throw new Exception("Enum null error: " + message); throw new Exception("Enum null error: " + message);
} }
public override void WriteLine(string message) public override void WriteLine(string? message)
{ {
if (message == null)
return;
if (message.Contains("Cannot map")) if (message.Contains("Cannot map"))
throw new Exception("Enum value error: " + message); throw new Exception("Enum value error: " + message);

View File

@ -169,7 +169,7 @@ namespace CryptoExchange.Net.Testing
{ {
var assembly = Assembly.GetAssembly(clientType); var assembly = Assembly.GetAssembly(clientType);
var interfaceType = clientType.GetInterface("I" + clientType.Name); var interfaceType = clientType.GetInterface("I" + clientType.Name);
var clientInterfaces = assembly.GetTypes().Where(t => t.Name.StartsWith("I" + clientType.Name) && !t.Name.EndsWith("Shared")); var clientInterfaces = assembly!.GetTypes().Where(t => t.Name.StartsWith("I" + clientType.Name) && !t.Name.EndsWith("Shared"));
foreach (var clientInterface in clientInterfaces) foreach (var clientInterface in clientInterfaces)
{ {
@ -179,9 +179,7 @@ namespace CryptoExchange.Net.Testing
int methods = 0; int methods = 0;
foreach (var method in implementation.GetMethods().Where(m => implementationTypes.IsAssignableFrom(m.ReturnType))) foreach (var method in implementation.GetMethods().Where(m => implementationTypes.IsAssignableFrom(m.ReturnType)))
{ {
var interfaceMethod = clientInterface.GetMethod(method.Name, method.GetParameters().Select(p => p.ParameterType).ToArray()); var interfaceMethod = clientInterface.GetMethod(method.Name, method.GetParameters().Select(p => p.ParameterType).ToArray()) ?? throw new Exception($"Missing interface for method {method.Name} in {implementation.Name} implementing interface {clientInterface.Name}");
if (interfaceMethod == null)
throw new Exception($"Missing interface for method {method.Name} in {implementation.Name} implementing interface {clientInterface.Name}");
methods++; methods++;
} }