mirror of
				https://github.com/JKorf/CryptoExchange.Net
				synced 2025-10-31 02:17:45 +00:00 
			
		
		
		
	Merge pull request #6 from ridicoulous/sharedHttpClient
shared http client for multiple instances of RestClient
This commit is contained in:
		
						commit
						f444fb8478
					
				| @ -633,13 +633,13 @@ | ||||
|             <param name="uri"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:CryptoExchange.Net.Interfaces.IRequestFactory.Configure(System.TimeSpan,CryptoExchange.Net.Objects.ApiProxy,System.Boolean)"> | ||||
|         <member name="M:CryptoExchange.Net.Interfaces.IRequestFactory.Configure(System.TimeSpan,CryptoExchange.Net.Objects.ApiProxy,System.Net.Http.HttpClient)"> | ||||
|             <summary> | ||||
|             Configure the requests created by this factory | ||||
|             </summary> | ||||
|             <param name="requestTimeout">Request timeout to use</param> | ||||
|             <param name="proxy">Proxy settings to use</param>        | ||||
|             <param name="isTracingEnabled">Should generate unique id for requests</param> | ||||
|             <param name="httpClient">Optional shared http client instance</param> | ||||
|         </member> | ||||
|         <member name="T:CryptoExchange.Net.Interfaces.IResponse"> | ||||
|             <summary> | ||||
| @ -1622,12 +1622,24 @@ | ||||
|             The time the server has to respond to a request before timing out | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:CryptoExchange.Net.Objects.RestClientOptions.HttpClient"> | ||||
|             <summary> | ||||
|             http client | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:CryptoExchange.Net.Objects.RestClientOptions.#ctor(System.String)"> | ||||
|             <summary> | ||||
|             ctor | ||||
|             </summary> | ||||
|             <param name="baseAddress"></param> | ||||
|         </member> | ||||
|         <member name="M:CryptoExchange.Net.Objects.RestClientOptions.#ctor(System.Net.Http.HttpClient,System.String)"> | ||||
|             <summary> | ||||
|             ctor | ||||
|             </summary> | ||||
|             <param name="baseAddress"></param> | ||||
|             <param name="httpClient">Shared http client</param> | ||||
|         </member> | ||||
|         <member name="M:CryptoExchange.Net.Objects.RestClientOptions.Copy``1"> | ||||
|             <summary> | ||||
|             Create a copy of the options | ||||
| @ -2030,13 +2042,12 @@ | ||||
|             Request object | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:CryptoExchange.Net.Requests.Request.#ctor(System.Net.Http.HttpRequestMessage,System.Net.Http.HttpClient,System.Boolean)"> | ||||
|         <member name="M:CryptoExchange.Net.Requests.Request.#ctor(System.Net.Http.HttpRequestMessage,System.Net.Http.HttpClient)"> | ||||
|             <summary> | ||||
|             Create request object for web request | ||||
|             </summary> | ||||
|             <param name="request"></param> | ||||
|             <param name="client"></param>         | ||||
|             <param name="isTracingEnabled">if true, should assign unique id for request</param> | ||||
|         </member> | ||||
|         <member name="P:CryptoExchange.Net.Requests.Request.Content"> | ||||
|             <inheritdoc /> | ||||
| @ -2070,7 +2081,7 @@ | ||||
|             WebRequest factory | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:CryptoExchange.Net.Requests.RequestFactory.Configure(System.TimeSpan,CryptoExchange.Net.Objects.ApiProxy,System.Boolean)"> | ||||
|         <member name="M:CryptoExchange.Net.Requests.RequestFactory.Configure(System.TimeSpan,CryptoExchange.Net.Objects.ApiProxy,System.Net.Http.HttpClient)"> | ||||
|             <inheritdoc /> | ||||
|         </member> | ||||
|         <member name="M:CryptoExchange.Net.Requests.RequestFactory.Create(System.Net.Http.HttpMethod,System.String)"> | ||||
| @ -2958,5 +2969,148 @@ | ||||
|         <member name="M:CryptoExchange.Net.Sockets.WebsocketFactory.CreateWebsocket(CryptoExchange.Net.Logging.Log,System.String,System.Collections.Generic.IDictionary{System.String,System.String},System.Collections.Generic.IDictionary{System.String,System.String})"> | ||||
|             <inheritdoc /> | ||||
|         </member> | ||||
|         <member name="T:System.Diagnostics.CodeAnalysis.AllowNullAttribute"> | ||||
|             <summary> | ||||
|                 Specifies that <see langword="null"/> is allowed as an input even if the | ||||
|                 corresponding type disallows it. | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:System.Diagnostics.CodeAnalysis.AllowNullAttribute.#ctor"> | ||||
|             <summary> | ||||
|                 Initializes a new instance of the <see cref="T:System.Diagnostics.CodeAnalysis.AllowNullAttribute"/> class. | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="T:System.Diagnostics.CodeAnalysis.DisallowNullAttribute"> | ||||
|             <summary> | ||||
|                 Specifies that <see langword="null"/> is disallowed as an input even if the | ||||
|                 corresponding type allows it. | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:System.Diagnostics.CodeAnalysis.DisallowNullAttribute.#ctor"> | ||||
|             <summary> | ||||
|                 Initializes a new instance of the <see cref="T:System.Diagnostics.CodeAnalysis.DisallowNullAttribute"/> class. | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="T:System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute"> | ||||
|             <summary> | ||||
|                 Specifies that a method that will never return under any circumstance. | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute.#ctor"> | ||||
|             <summary> | ||||
|                 Initializes a new instance of the <see cref="T:System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute"/> class. | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="T:System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute"> | ||||
|             <summary> | ||||
|                 Specifies that the method will not return if the associated <see cref="T:System.Boolean"/> | ||||
|                 parameter is passed the specified value. | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute.ParameterValue"> | ||||
|             <summary> | ||||
|                 Gets the condition parameter value. | ||||
|                 Code after the method is considered unreachable by diagnostics if the argument | ||||
|                 to the associated parameter matches this value. | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute.#ctor(System.Boolean)"> | ||||
|             <summary> | ||||
|                 Initializes a new instance of the <see cref="T:System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute"/> | ||||
|                 class with the specified parameter value. | ||||
|             </summary> | ||||
|             <param name="parameterValue"> | ||||
|                 The condition parameter value. | ||||
|                 Code after the method is considered unreachable by diagnostics if the argument | ||||
|                 to the associated parameter matches this value. | ||||
|             </param> | ||||
|         </member> | ||||
|         <member name="T:System.Diagnostics.CodeAnalysis.MaybeNullAttribute"> | ||||
|             <summary> | ||||
|                 Specifies that an output may be <see langword="null"/> even if the | ||||
|                 corresponding type disallows it. | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:System.Diagnostics.CodeAnalysis.MaybeNullAttribute.#ctor"> | ||||
|             <summary> | ||||
|                 Initializes a new instance of the <see cref="T:System.Diagnostics.CodeAnalysis.MaybeNullAttribute"/> class. | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="T:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute"> | ||||
|             <summary> | ||||
|                 Specifies that when a method returns <see cref="P:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute.ReturnValue"/>,  | ||||
|                 the parameter may be <see langword="null"/> even if the corresponding type disallows it. | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute.ReturnValue"> | ||||
|             <summary> | ||||
|                 Gets the return value condition. | ||||
|                 If the method returns this value, the associated parameter may be <see langword="null"/>. | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute.#ctor(System.Boolean)"> | ||||
|             <summary> | ||||
|                  Initializes the attribute with the specified return value condition. | ||||
|             </summary> | ||||
|             <param name="returnValue"> | ||||
|                 The return value condition. | ||||
|                 If the method returns this value, the associated parameter may be <see langword="null"/>. | ||||
|             </param> | ||||
|         </member> | ||||
|         <member name="T:System.Diagnostics.CodeAnalysis.NotNullAttribute"> | ||||
|             <summary> | ||||
|                 Specifies that an output is not <see langword="null"/> even if the | ||||
|                 corresponding type allows it. | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:System.Diagnostics.CodeAnalysis.NotNullAttribute.#ctor"> | ||||
|             <summary> | ||||
|                 Initializes a new instance of the <see cref="T:System.Diagnostics.CodeAnalysis.NotNullAttribute"/> class. | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="T:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute"> | ||||
|             <summary> | ||||
|                 Specifies that the output will be non-<see langword="null"/> if the | ||||
|                 named parameter is non-<see langword="null"/>. | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute.ParameterName"> | ||||
|             <summary> | ||||
|                 Gets the associated parameter name. | ||||
|                 The output will be non-<see langword="null"/> if the argument to the | ||||
|                 parameter specified is non-<see langword="null"/>. | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute.#ctor(System.String)"> | ||||
|             <summary> | ||||
|                 Initializes the attribute with the associated parameter name. | ||||
|             </summary> | ||||
|             <param name="parameterName"> | ||||
|                 The associated parameter name. | ||||
|                 The output will be non-<see langword="null"/> if the argument to the | ||||
|                 parameter specified is non-<see langword="null"/>. | ||||
|             </param> | ||||
|         </member> | ||||
|         <member name="T:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute"> | ||||
|             <summary> | ||||
|                 Specifies that when a method returns <see cref="P:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute.ReturnValue"/>, | ||||
|                 the parameter will not be <see langword="null"/> even if the corresponding type allows it. | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute.ReturnValue"> | ||||
|             <summary> | ||||
|                 Gets the return value condition. | ||||
|                 If the method returns this value, the associated parameter will not be <see langword="null"/>. | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute.#ctor(System.Boolean)"> | ||||
|             <summary> | ||||
|                 Initializes the attribute with the specified return value condition. | ||||
|             </summary> | ||||
|             <param name="returnValue"> | ||||
|                 The return value condition. | ||||
|                 If the method returns this value, the associated parameter will not be <see langword="null"/>. | ||||
|             </param> | ||||
|         </member> | ||||
|     </members> | ||||
| </doc> | ||||
|  | ||||
| @ -22,6 +22,7 @@ namespace CryptoExchange.Net.Interfaces | ||||
|         /// </summary> | ||||
|         /// <param name="requestTimeout">Request timeout to use</param> | ||||
|         /// <param name="proxy">Proxy settings to use</param>        | ||||
|         void Configure(TimeSpan requestTimeout, ApiProxy? proxy); | ||||
|         /// <param name="httpClient">Optional shared http client instance</param> | ||||
|         void Configure(TimeSpan requestTimeout, ApiProxy? proxy, HttpClient? httpClient=null); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Net.Http; | ||||
| using CryptoExchange.Net.Authentication; | ||||
| using CryptoExchange.Net.Interfaces; | ||||
| using CryptoExchange.Net.Logging; | ||||
| @ -126,7 +127,10 @@ namespace CryptoExchange.Net.Objects | ||||
|         /// The time the server has to respond to a request before timing out | ||||
|         /// </summary> | ||||
|         public TimeSpan RequestTimeout { get; set; } = TimeSpan.FromSeconds(30); | ||||
|       | ||||
|         /// <summary> | ||||
|         /// http client | ||||
|         /// </summary> | ||||
|         public  HttpClient? HttpClient; | ||||
|         /// <summary> | ||||
|         /// ctor | ||||
|         /// </summary> | ||||
| @ -134,7 +138,15 @@ namespace CryptoExchange.Net.Objects | ||||
|         public RestClientOptions(string baseAddress): base(baseAddress) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// ctor | ||||
|         /// </summary> | ||||
|         /// <param name="baseAddress"></param> | ||||
|         /// <param name="httpClient">Shared http client</param> | ||||
|         public RestClientOptions(HttpClient httpClient, string baseAddress) : base(baseAddress) | ||||
|         { | ||||
|             HttpClient = httpClient; | ||||
|         } | ||||
|         /// <summary> | ||||
|         /// Create a copy of the options | ||||
|         /// </summary> | ||||
| @ -150,7 +162,8 @@ namespace CryptoExchange.Net.Objects | ||||
|                 LogWriters = LogWriters, | ||||
|                 RateLimiters = RateLimiters, | ||||
|                 RateLimitingBehaviour = RateLimitingBehaviour, | ||||
|                 RequestTimeout = RequestTimeout | ||||
|                 RequestTimeout = RequestTimeout, | ||||
|                 HttpClient = HttpClient | ||||
|             }; | ||||
| 
 | ||||
|             if (ApiCredentials != null) | ||||
|  | ||||
| @ -12,9 +12,11 @@ namespace CryptoExchange.Net.Requests | ||||
|     public class RequestFactory : IRequestFactory | ||||
|     { | ||||
|         private HttpClient? httpClient;         | ||||
|         private bool isTracingEnabled; | ||||
| 
 | ||||
|         /// <inheritdoc /> | ||||
|         public void Configure(TimeSpan requestTimeout, ApiProxy? proxy) | ||||
|         public void Configure(TimeSpan requestTimeout, ApiProxy? proxy, HttpClient? client = null) | ||||
|         { | ||||
|             if (client == null) | ||||
|             { | ||||
|                 HttpMessageHandler handler = new HttpClientHandler() | ||||
|                 { | ||||
| @ -27,6 +29,11 @@ namespace CryptoExchange.Net.Requests | ||||
| 
 | ||||
|                 httpClient = new HttpClient(handler) { Timeout = requestTimeout }; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 httpClient = client;                 | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <inheritdoc /> | ||||
|         public IRequest Create(HttpMethod method, string uri) | ||||
|  | ||||
| @ -24,7 +24,7 @@ namespace CryptoExchange.Net | ||||
|     /// <summary> | ||||
|     /// Base rest client | ||||
|     /// </summary> | ||||
|     public abstract class RestClient: BaseClient, IRestClient | ||||
|     public abstract class RestClient : BaseClient, IRestClient | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// The factory for creating requests. Used for unit testing | ||||
| @ -77,13 +77,13 @@ namespace CryptoExchange.Net | ||||
|         /// </summary> | ||||
|         /// <param name="exchangeOptions"></param> | ||||
|         /// <param name="authenticationProvider"></param> | ||||
|         protected RestClient(RestClientOptions exchangeOptions, AuthenticationProvider? authenticationProvider): base(exchangeOptions, authenticationProvider) | ||||
|         protected RestClient(RestClientOptions exchangeOptions, AuthenticationProvider? authenticationProvider) : base(exchangeOptions, authenticationProvider) | ||||
|         { | ||||
|             if (exchangeOptions == null) | ||||
|                 throw new ArgumentNullException(nameof(exchangeOptions)); | ||||
| 
 | ||||
|             RequestTimeout = exchangeOptions.RequestTimeout; | ||||
|             RequestFactory.Configure(exchangeOptions.RequestTimeout, exchangeOptions.Proxy); | ||||
|             RequestFactory.Configure(exchangeOptions.RequestTimeout, exchangeOptions.Proxy, exchangeOptions.HttpClient); | ||||
|             RateLimitBehaviour = exchangeOptions.RateLimitingBehaviour; | ||||
|             var rateLimiters = new List<IRateLimiter>(); | ||||
|             foreach (var rateLimiter in exchangeOptions.RateLimiters) | ||||
| @ -134,10 +134,10 @@ namespace CryptoExchange.Net | ||||
|             { | ||||
|                 reply = await ping.SendPingAsync(uri.Host).ConfigureAwait(false); | ||||
|             } | ||||
|             catch(PingException e) | ||||
|             catch (PingException e) | ||||
|             { | ||||
|                 if (e.InnerException == null) | ||||
|                     return new CallResult<long>(0, new CantConnectError {Message = "Ping failed: " + e.Message}); | ||||
|                     return new CallResult<long>(0, new CantConnectError { Message = "Ping failed: " + e.Message }); | ||||
| 
 | ||||
|                 if (e.InnerException is SocketException exception) | ||||
|                     return new CallResult<long>(0, new CantConnectError { Message = "Ping failed: " + exception.SocketErrorCode }); | ||||
| @ -149,7 +149,7 @@ namespace CryptoExchange.Net | ||||
|                 ping.Dispose(); | ||||
|             } | ||||
| 
 | ||||
|             if(ct.IsCancellationRequested) | ||||
|             if (ct.IsCancellationRequested) | ||||
|                 return new CallResult<long>(0, new CancellationRequestedError()); | ||||
| 
 | ||||
|             return reply.Status == IPStatus.Success ? new CallResult<long>(reply.RoundtripTime, null) : new CallResult<long>(0, new CantConnectError { Message = "Ping failed: " + reply.Status }); | ||||
| @ -185,7 +185,7 @@ namespace CryptoExchange.Net | ||||
|                 var limitResult = limiter.LimitRequest(this, uri.AbsolutePath, RateLimitBehaviour); | ||||
|                 if (!limitResult.Success) | ||||
|                 { | ||||
|                     log.Write(LogVerbosity.Debug, $"Request {uri.AbsolutePath} failed because of rate limit"); | ||||
|                     log.Write(LogVerbosity.Debug, $"Request {request.RequestId} {uri.AbsolutePath} failed because of rate limit"); | ||||
|                     return new WebCallResult<T>(null, null, null, limitResult.Error); | ||||
|                 } | ||||
| 
 | ||||
| @ -197,7 +197,7 @@ namespace CryptoExchange.Net | ||||
|             if (method == HttpMethod.Post) | ||||
|                 paramString = " with request body " + request.Content; | ||||
| 
 | ||||
|             log.Write(LogVerbosity.Debug, $"Sending {method}{(signed ? " signed" : "")} request to {request.Uri}{paramString ?? " "}{(apiProxy == null? "": $" via proxy {apiProxy.Host}")} with id {request.RequestId}"); | ||||
|             log.Write(LogVerbosity.Debug, $"Sending {method}{(signed ? " signed" : "")} request to {request.Uri}{paramString ?? " "}{(apiProxy == null ? "" : $" via proxy {apiProxy.Host}")} with id {request.RequestId}"); | ||||
|             return await GetResponse<T>(request, cancellationToken).ConfigureAwait(false); | ||||
|         } | ||||
| 
 | ||||
| @ -230,7 +230,7 @@ namespace CryptoExchange.Net | ||||
|                         if (!parseResult.Success) | ||||
|                             return WebCallResult<T>.CreateErrorResult(response.StatusCode, response.ResponseHeaders, new ServerError(data)); | ||||
|                         var error = await TryParseError(parseResult.Data); | ||||
|                         if(error != null) | ||||
|                         if (error != null) | ||||
|                             return WebCallResult<T>.CreateErrorResult(response.StatusCode, response.ResponseHeaders, error); | ||||
| 
 | ||||
|                         var deserializeResult = Deserialize<T>(parseResult.Data); | ||||
| @ -253,7 +253,7 @@ namespace CryptoExchange.Net | ||||
|                     responseStream.Close(); | ||||
|                     response.Close(); | ||||
|                     var parseResult = ValidateJson(data); | ||||
|                     return new WebCallResult<T>(statusCode, headers, default, parseResult.Success ? ParseErrorResponse(parseResult.Data) :new ServerError(data)); | ||||
|                     return new WebCallResult<T>(statusCode, headers, default, parseResult.Success ? ParseErrorResponse(parseResult.Data) : new ServerError(data)); | ||||
|                 } | ||||
|             } | ||||
|             catch (HttpRequestException requestException) | ||||
| @ -263,7 +263,7 @@ namespace CryptoExchange.Net | ||||
|             } | ||||
|             catch (TaskCanceledException canceledException) | ||||
|             { | ||||
|                 if(canceledException.CancellationToken == cancellationToken) | ||||
|                 if (canceledException.CancellationToken == cancellationToken) | ||||
|                 { | ||||
|                     // Cancellation token cancelled | ||||
|                     log.Write(LogVerbosity.Warning, $"Request {request.RequestId} cancel requested"); | ||||
| @ -305,10 +305,10 @@ namespace CryptoExchange.Net | ||||
|                 parameters = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             var uriString = uri.ToString(); | ||||
|             if(authProvider != null) | ||||
|             if (authProvider != null) | ||||
|                 parameters = authProvider.AddAuthenticationToParameters(uriString, method, parameters, signed, postPosition, arraySerialization); | ||||
| 
 | ||||
|             if((method == HttpMethod.Get || method == HttpMethod.Delete || postPosition == 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; | ||||
| @ -324,7 +324,7 @@ namespace CryptoExchange.Net | ||||
| 
 | ||||
|             if ((method == HttpMethod.Post || method == HttpMethod.Put) && postPosition != PostParameters.InUri) | ||||
|             { | ||||
|                 if(parameters?.Any() == true) | ||||
|                 if (parameters?.Any() == true) | ||||
|                     WriteParamBody(request, parameters, contentType); | ||||
|                 else | ||||
|                     request.SetContent(requestBodyEmptyContent, contentType); | ||||
| @ -346,7 +346,7 @@ namespace CryptoExchange.Net | ||||
|                 var stringData = JsonConvert.SerializeObject(parameters.OrderBy(p => p.Key).ToDictionary(p => p.Key, p => p.Value)); | ||||
|                 request.SetContent(stringData, contentType); | ||||
|             } | ||||
|             else if(requestBodyFormat == RequestBodyFormat.FormData) | ||||
|             else if (requestBodyFormat == RequestBodyFormat.FormData) | ||||
|             { | ||||
|                 var formData = HttpUtility.ParseQueryString(string.Empty); | ||||
|                 foreach (var kvp in parameters.OrderBy(p => p.Key)) | ||||
| @ -354,7 +354,7 @@ namespace CryptoExchange.Net | ||||
|                     if (kvp.Value.GetType().IsArray) | ||||
|                     { | ||||
|                         var array = (Array)kvp.Value; | ||||
|                         foreach(var value in array) | ||||
|                         foreach (var value in array) | ||||
|                             formData.Add(kvp.Key, value.ToString()); | ||||
|                     } | ||||
|                     else | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user