From 128cab8e1ec3ecfa2401c1d55cc7eb9a4546cb48 Mon Sep 17 00:00:00 2001 From: Jan Korf Date: Sun, 7 Jun 2020 12:40:26 +0200 Subject: [PATCH] Added postParameterPosition/arraySeralization settings to authentication provider interface, fixed array serialization for request body --- .../Authentication/AuthenticationProvider.cs | 13 +- CryptoExchange.Net/CryptoExchange.Net.xml | 161 ++---------------- CryptoExchange.Net/ExtensionMethods.cs | 7 +- .../OrderBook/SymbolOrderBook.cs | 2 + CryptoExchange.Net/RestClient.cs | 31 +++- 5 files changed, 51 insertions(+), 163 deletions(-) diff --git a/CryptoExchange.Net/Authentication/AuthenticationProvider.cs b/CryptoExchange.Net/Authentication/AuthenticationProvider.cs index 8739fed..21857b1 100644 --- a/CryptoExchange.Net/Authentication/AuthenticationProvider.cs +++ b/CryptoExchange.Net/Authentication/AuthenticationProvider.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using CryptoExchange.Net.Objects; +using System.Collections.Generic; using System.Net.Http; namespace CryptoExchange.Net.Authentication @@ -29,8 +30,11 @@ namespace CryptoExchange.Net.Authentication /// /// /// + /// + /// /// - public virtual Dictionary AddAuthenticationToParameters(string uri, HttpMethod method, Dictionary parameters, bool signed) + public virtual Dictionary AddAuthenticationToParameters(string uri, HttpMethod method, Dictionary parameters, bool signed, + PostParameters postParameterPosition, ArrayParametersSerialization arraySerialization) { return parameters; } @@ -42,8 +46,11 @@ namespace CryptoExchange.Net.Authentication /// /// /// + /// + /// /// - public virtual Dictionary AddAuthenticationToHeaders(string uri, HttpMethod method, Dictionary parameters, bool signed) + public virtual Dictionary AddAuthenticationToHeaders(string uri, HttpMethod method, Dictionary parameters, bool signed, + PostParameters postParameterPosition, ArrayParametersSerialization arraySerialization) { return new Dictionary(); } diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index b6b143d..fae41b2 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -97,7 +97,7 @@ - + Add authentication to the parameter list @@ -105,9 +105,11 @@ + + - + Add authentication to the header dictionary @@ -115,6 +117,8 @@ + + @@ -2142,7 +2146,7 @@ The roundtrip time of the ping request - + Execute a request @@ -2152,7 +2156,9 @@ Cancellation token The parameters of the request Whether or not the request should be authenticated - Whether or not the resulting object should be checked for missing properties in the mapping (only outputs if log verbosity is Debug) + Whether or not the resulting object should be checked for missing properties in the mapping (only outputs if log verbosity is Debug) + Where the post parameters should be placed + How array paramters should be serialized @@ -2171,7 +2177,7 @@ Received data Null if not an error, Error otherwise - + Creates a request object @@ -2179,6 +2185,8 @@ The method of the request The parameters of the request Whether or not the request should be authenticated + Where the post parameters should be placed + How array paramters should be serialized @@ -2909,148 +2917,5 @@ - - - Specifies that is allowed as an input even if the - corresponding type disallows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that is disallowed as an input even if the - corresponding type allows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that a method that will never return under any circumstance. - - - - - Initializes a new instance of the class. - - - - - Specifies that the method will not return if the associated - parameter is passed the specified value. - - - - - Gets the condition parameter value. - Code after the method is considered unreachable by diagnostics if the argument - to the associated parameter matches this value. - - - - - Initializes a new instance of the - class with the specified parameter value. - - - The condition parameter value. - Code after the method is considered unreachable by diagnostics if the argument - to the associated parameter matches this value. - - - - - Specifies that an output may be even if the - corresponding type disallows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that when a method returns , - the parameter may be even if the corresponding type disallows it. - - - - - Gets the return value condition. - If the method returns this value, the associated parameter may be . - - - - - Initializes the attribute with the specified return value condition. - - - The return value condition. - If the method returns this value, the associated parameter may be . - - - - - Specifies that an output is not even if the - corresponding type allows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that the output will be non- if the - named parameter is non-. - - - - - Gets the associated parameter name. - The output will be non- if the argument to the - parameter specified is non-. - - - - - Initializes the attribute with the associated parameter name. - - - The associated parameter name. - The output will be non- if the argument to the - parameter specified is non-. - - - - - Specifies that when a method returns , - the parameter will not be even if the corresponding type allows it. - - - - - Gets the return value condition. - If the method returns this value, the associated parameter will not be . - - - - - Initializes the attribute with the specified return value condition. - - - The return value condition. - If the method returns this value, the associated parameter will not be . - - diff --git a/CryptoExchange.Net/ExtensionMethods.cs b/CryptoExchange.Net/ExtensionMethods.cs index 1090cf9..1ac235b 100644 --- a/CryptoExchange.Net/ExtensionMethods.cs +++ b/CryptoExchange.Net/ExtensionMethods.cs @@ -7,6 +7,7 @@ using System.Runtime.InteropServices; using System.Security; using System.Threading; using System.Threading.Tasks; +using System.Web; using CryptoExchange.Net.Logging; using CryptoExchange.Net.Objects; using Newtonsoft.Json; @@ -79,16 +80,16 @@ namespace CryptoExchange.Net foreach (var arrayEntry in arraysParameters) { if(serializationType == ArrayParametersSerialization.Array) - uriString += $"{string.Join("&", ((object[])(urlEncodeValues ? WebUtility.UrlEncode(arrayEntry.Value.ToString()) : arrayEntry.Value)).Select(v => $"{arrayEntry.Key}[]={v}"))}&"; + uriString += $"{string.Join("&", ((object[])(urlEncodeValues ? Uri.EscapeDataString(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 += string.Join("&", array.OfType().Select(a => $"{arrayEntry.Key}={Uri.EscapeDataString(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)}"))}"; + uriString += $"{string.Join("&", parameters.Where(p => !p.Value.GetType().IsArray).Select(s => $"{s.Key}={(urlEncodeValues ? Uri.EscapeDataString(s.Value.ToString()) : s.Value)}"))}"; uriString = uriString.TrimEnd('&'); return uriString; } diff --git a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs index 5b973fe..c27e470 100644 --- a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs +++ b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs @@ -218,6 +218,7 @@ namespace CryptoExchange.Net.OrderBook /// public async Task> StartAsync() { + log.Write(LogVerbosity.Debug, $"{Id} order book {Symbol} starting"); Status = OrderBookStatus.Connecting; _processTask = Task.Run(ProcessQueue); @@ -271,6 +272,7 @@ namespace CryptoExchange.Net.OrderBook /// public async Task StopAsync() { + log.Write(LogVerbosity.Debug, $"{Id} order book {Symbol} stopping"); Status = OrderBookStatus.Disconnected; _queueEvent.Set(); _processTask.Wait(); diff --git a/CryptoExchange.Net/RestClient.cs b/CryptoExchange.Net/RestClient.cs index 42043c4..d3a0f55 100644 --- a/CryptoExchange.Net/RestClient.cs +++ b/CryptoExchange.Net/RestClient.cs @@ -164,11 +164,13 @@ namespace CryptoExchange.Net /// Cancellation token /// The parameters of the request /// Whether or not the request should be authenticated - /// Whether or not the resulting object should be checked for missing properties in the mapping (only outputs if log verbosity is Debug) + /// Whether or not the resulting object should be checked for missing properties in the mapping (only outputs if log verbosity is Debug) + /// Where the post parameters should be placed + /// How array paramters should be serialized /// [return: NotNull] protected virtual async Task> SendRequest(Uri uri, HttpMethod method, CancellationToken cancellationToken, - Dictionary? parameters = null, bool signed = false, bool checkResult = true) where T : class + Dictionary? parameters = null, bool signed = false, bool checkResult = true, PostParameters? postPosition = null, ArrayParametersSerialization? arraySerialization = null) where T : class { log.Write(LogVerbosity.Debug, "Creating request for " + uri); if (signed && authProvider == null) @@ -177,7 +179,7 @@ namespace CryptoExchange.Net return new WebCallResult(null, null, null, new NoApiCredentialsError()); } - var request = ConstructRequest(uri, method, parameters, signed); + var request = ConstructRequest(uri, method, parameters, signed, postPosition ?? postParametersPosition, arraySerialization ?? this.arraySerialization); foreach (var limiter in RateLimiters) { var limitResult = limiter.LimitRequest(this, uri.AbsolutePath, RateLimitBehaviour); @@ -294,17 +296,19 @@ namespace CryptoExchange.Net /// The method of the request /// The parameters of the request /// Whether or not the request should be authenticated + /// Where the post parameters should be placed + /// How array paramters should be serialized /// - protected virtual IRequest ConstructRequest(Uri uri, HttpMethod method, Dictionary? parameters, bool signed) + protected virtual IRequest ConstructRequest(Uri uri, HttpMethod method, Dictionary? parameters, bool signed, PostParameters postPosition, ArrayParametersSerialization arraySerialization) { if (parameters == null) parameters = new Dictionary(); var uriString = uri.ToString(); if(authProvider != null) - parameters = authProvider.AddAuthenticationToParameters(uriString, method, parameters, signed); + parameters = authProvider.AddAuthenticationToParameters(uriString, method, parameters, signed, postPosition, arraySerialization); - if((method == HttpMethod.Get || method == HttpMethod.Delete || postParametersPosition == PostParameters.InUri) && parameters?.Any() == true) + if((method == HttpMethod.Get || method == HttpMethod.Delete || postPosition == PostParameters.InUri) && parameters?.Any() == true) uriString += "?" + parameters.CreateParamString(true, arraySerialization); var contentType = requestBodyFormat == RequestBodyFormat.Json ? Constants.JsonContentHeader : Constants.FormContentHeader; @@ -313,12 +317,12 @@ namespace CryptoExchange.Net var headers = new Dictionary(); if (authProvider != null) - headers = authProvider.AddAuthenticationToHeaders(uriString, method, parameters!, signed); + headers = authProvider.AddAuthenticationToHeaders(uriString, method, parameters!, signed, postPosition, arraySerialization); foreach (var header in headers) request.AddHeader(header.Key, header.Value); - if ((method == HttpMethod.Post || method == HttpMethod.Put) && postParametersPosition != PostParameters.InUri) + if ((method == HttpMethod.Post || method == HttpMethod.Put) && postPosition != PostParameters.InUri) { if(parameters?.Any() == true) WriteParamBody(request, parameters, contentType); @@ -346,7 +350,16 @@ namespace CryptoExchange.Net { var formData = HttpUtility.ParseQueryString(string.Empty); foreach (var kvp in parameters.OrderBy(p => p.Key)) - formData.Add(kvp.Key, kvp.Value.ToString()); + { + if (kvp.Value.GetType().IsArray) + { + var array = (Array)kvp.Value; + foreach(var value in array) + formData.Add(kvp.Key, value.ToString()); + } + else + formData.Add(kvp.Key, kvp.Value.ToString()); + } var stringData = formData.ToString(); request.SetContent(stringData, contentType); }