diff --git a/CryptoExchange.Net/Attributes/JsonConversionAttribute.cs b/CryptoExchange.Net/Attributes/JsonConversionAttribute.cs new file mode 100644 index 0000000..67c9021 --- /dev/null +++ b/CryptoExchange.Net/Attributes/JsonConversionAttribute.cs @@ -0,0 +1,11 @@ +using System; + +namespace CryptoExchange.Net.Attributes +{ + /// + /// Used for conversion in ArrayConverter + /// + public class JsonConversionAttribute: Attribute + { + } +} diff --git a/CryptoExchange.Net/Converters/ArrayConverter.cs b/CryptoExchange.Net/Converters/ArrayConverter.cs index 62cebc6..6a8d5e1 100644 --- a/CryptoExchange.Net/Converters/ArrayConverter.cs +++ b/CryptoExchange.Net/Converters/ArrayConverter.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Globalization; using System.Linq; using System.Reflection; +using CryptoExchange.Net.Attributes; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -74,7 +75,20 @@ namespace CryptoExchange.Net.Converters } var converterAttribute = (JsonConverterAttribute)property.GetCustomAttribute(typeof(JsonConverterAttribute)) ?? (JsonConverterAttribute)property.PropertyType.GetCustomAttribute(typeof(JsonConverterAttribute)); - var value = converterAttribute != null ? arr[attribute.Index].ToObject(property.PropertyType, new JsonSerializer { Converters = { (JsonConverter)Activator.CreateInstance(converterAttribute.ConverterType) } }) : arr[attribute.Index]; + var conversionAttribute = (JsonConversionAttribute)property.GetCustomAttribute(typeof(JsonConversionAttribute)) ?? (JsonConversionAttribute)property.PropertyType.GetCustomAttribute(typeof(JsonConversionAttribute)); + object value = null; + if (converterAttribute != null) + { + value = arr[attribute.Index].ToObject(property.PropertyType, new JsonSerializer {Converters = {(JsonConverter) Activator.CreateInstance(converterAttribute.ConverterType)}}); + } + else if (conversionAttribute != null) + { + value = arr[attribute.Index].ToObject(property.PropertyType); + } + else + { + value = arr[attribute.Index]; + } if (value != null && property.PropertyType.IsInstanceOfType(value)) property.SetValue(result, value); diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index fd9367b..4a27286 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -4,6 +4,11 @@ CryptoExchange.Net + + + Used for conversion in ArrayConverter + + Marks property as optional @@ -446,12 +451,13 @@ - + Create a query string of the specified parameters The parameters to use Whether or not the values should be url encoded + How to serialize array parameters @@ -1182,6 +1188,21 @@ Bid + + + Define how array parameters should be send + + + + + Send multiple key=value for each entry + + + + + Create an []=value array + + Base class for errors @@ -1846,6 +1867,11 @@ Request body content type + + + How to serialize array parameters + + Timeout for requests diff --git a/CryptoExchange.Net/ExtensionMethods.cs b/CryptoExchange.Net/ExtensionMethods.cs index f2485a8..cd80a5c 100644 --- a/CryptoExchange.Net/ExtensionMethods.cs +++ b/CryptoExchange.Net/ExtensionMethods.cs @@ -8,6 +8,7 @@ using System.Security; using System.Threading; using System.Threading.Tasks; using CryptoExchange.Net.Logging; +using CryptoExchange.Net.Objects; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -69,14 +70,22 @@ namespace CryptoExchange.Net /// /// The parameters to use /// Whether or not the values should be url encoded + /// How to serialize array parameters /// - public static string CreateParamString(this Dictionary parameters, bool urlEncodeValues) + public static string CreateParamString(this Dictionary parameters, bool urlEncodeValues, ArrayParametersSerialization serializationType) { var uriString = ""; var arraysParameters = parameters.Where(p => p.Value.GetType().IsArray).ToList(); foreach (var arrayEntry in arraysParameters) { - uriString += $"{string.Join("&", ((object[])(urlEncodeValues ? WebUtility.UrlEncode(arrayEntry.Value.ToString()) : arrayEntry.Value)).Select(v => $"{arrayEntry.Key}[]={v}"))}&"; + if(serializationType == ArrayParametersSerialization.Array) + uriString += $"{string.Join("&", ((object[])(urlEncodeValues ? WebUtility.UrlEncode(arrayEntry.Value.ToString()) : arrayEntry.Value)).Select(v => $"{arrayEntry.Key}[]={v}"))}&"; + else + { + var array = (Array)arrayEntry.Value; + uriString += string.Join("&", array.OfType().Select(a => $"{arrayEntry.Key}={WebUtility.UrlEncode(a.ToString())}")); + uriString += "&"; + } } uriString += $"{string.Join("&", parameters.Where(p => !p.Value.GetType().IsArray).Select(s => $"{s.Key}={(urlEncodeValues ? WebUtility.UrlEncode(s.Value.ToString()) : s.Value)}"))}"; diff --git a/CryptoExchange.Net/Objects/Enums.cs b/CryptoExchange.Net/Objects/Enums.cs index fc6b630..90c06ed 100644 --- a/CryptoExchange.Net/Objects/Enums.cs +++ b/CryptoExchange.Net/Objects/Enums.cs @@ -82,4 +82,19 @@ /// Bid } + + /// + /// Define how array parameters should be send + /// + public enum ArrayParametersSerialization + { + /// + /// Send multiple key=value for each entry + /// + MultipleValues, + /// + /// Create an []=value array + /// + Array + } } diff --git a/CryptoExchange.Net/RestClient.cs b/CryptoExchange.Net/RestClient.cs index 844607f..88fe5eb 100644 --- a/CryptoExchange.Net/RestClient.cs +++ b/CryptoExchange.Net/RestClient.cs @@ -39,6 +39,11 @@ namespace CryptoExchange.Net /// protected RequestBodyFormat requestBodyFormat = RequestBodyFormat.Json; + /// + /// How to serialize array parameters + /// + protected ArrayParametersSerialization arraySerialization = ArrayParametersSerialization.Array; + /// /// Timeout for requests /// @@ -222,7 +227,7 @@ namespace CryptoExchange.Net parameters = authProvider.AddAuthenticationToParameters(uriString, method, parameters, signed); if((method == Constants.GetMethod || method == Constants.DeleteMethod || postParametersPosition == PostParameters.InUri) && parameters?.Any() == true) - uriString += "?" + parameters.CreateParamString(true); + uriString += "?" + parameters.CreateParamString(true, arraySerialization); var request = RequestFactory.Create(uriString); request.ContentType = requestBodyFormat == RequestBodyFormat.Json ? Constants.JsonContentHeader : Constants.FormContentHeader; diff --git a/CryptoExchange.Net/SocketClient.cs b/CryptoExchange.Net/SocketClient.cs index cc53894..9558e73 100644 --- a/CryptoExchange.Net/SocketClient.cs +++ b/CryptoExchange.Net/SocketClient.cs @@ -175,7 +175,6 @@ namespace CryptoExchange.Net await socket.Close(handler).ConfigureAwait(false); return new CallResult(null, subResult.Error); } - } else handler.Confirmed = true; @@ -554,7 +553,7 @@ namespace CryptoExchange.Net /// public virtual async Task UnsubscribeAll() { - log.Write(LogVerbosity.Debug, $"Closing all {sockets.Count} subscriptions"); + log.Write(LogVerbosity.Debug, $"Closing all {sockets.Sum(s => s.Value.handlers.Count(h => h.UserSubscription))} subscriptions"); await Task.Run(() => {