mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2025-06-08 16:36:15 +00:00
Added option to send additional headers for each request or for individual requests, added HttpMethod parameter position configuration to rest client
This commit is contained in:
parent
f5df46a8a5
commit
d1a2856a08
@ -10,6 +10,8 @@ using System.Linq;
|
||||
using CryptoExchange.Net.Interfaces;
|
||||
using CryptoExchange.Net.RateLimiter;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CryptoExchange.Net.UnitTests
|
||||
{
|
||||
@ -22,7 +24,7 @@ namespace CryptoExchange.Net.UnitTests
|
||||
// arrange
|
||||
var client = new TestRestClient();
|
||||
var expected = new TestObject() { DecimalData = 1.23M, IntData = 10, StringData = "Some data" };
|
||||
client.SetResponse(JsonConvert.SerializeObject(expected));
|
||||
client.SetResponse(JsonConvert.SerializeObject(expected), out _);
|
||||
|
||||
// act
|
||||
var result = client.Request<TestObject>().Result;
|
||||
@ -37,7 +39,7 @@ namespace CryptoExchange.Net.UnitTests
|
||||
{
|
||||
// arrange
|
||||
var client = new TestRestClient();
|
||||
client.SetResponse("{\"property\": 123");
|
||||
client.SetResponse("{\"property\": 123", out _);
|
||||
|
||||
// act
|
||||
var result = client.Request<TestObject>().Result;
|
||||
@ -119,6 +121,46 @@ namespace CryptoExchange.Net.UnitTests
|
||||
Assert.IsTrue(client.RequestTimeout == TimeSpan.FromMinutes(1));
|
||||
}
|
||||
|
||||
[TestCase("GET", HttpMethodParameterPosition.InUri)] // No need to test InBody for GET since thats not valid
|
||||
[TestCase("POST", HttpMethodParameterPosition.InBody)]
|
||||
[TestCase("POST", HttpMethodParameterPosition.InUri)]
|
||||
[TestCase("DELETE", HttpMethodParameterPosition.InBody)]
|
||||
[TestCase("DELETE", HttpMethodParameterPosition.InUri)]
|
||||
[TestCase("PUT", HttpMethodParameterPosition.InUri)]
|
||||
[TestCase("PUT", HttpMethodParameterPosition.InBody)]
|
||||
public async Task Setting_Should_ResultInOptionsSet(string method, HttpMethodParameterPosition pos)
|
||||
{
|
||||
// arrange
|
||||
// act
|
||||
var client = new TestRestClient(new RestClientOptions("")
|
||||
{
|
||||
BaseAddress = "http://test.address.com",
|
||||
});
|
||||
|
||||
client.SetParameterPosition(new HttpMethod(method), pos);
|
||||
|
||||
client.SetResponse("{}", out var request);
|
||||
|
||||
await client.RequestWithParams<TestObject>(new HttpMethod(method), new Dictionary<string, object>
|
||||
{
|
||||
{ "TestParam1", "Value1" },
|
||||
{ "TestParam2", 2 },
|
||||
},
|
||||
new Dictionary<string, string>
|
||||
{
|
||||
{ "TestHeader", "123" }
|
||||
});
|
||||
|
||||
// assert
|
||||
Assert.AreEqual(request.Method, new HttpMethod(method));
|
||||
Assert.AreEqual(request.Content?.Contains("TestParam1") == true, pos == HttpMethodParameterPosition.InBody);
|
||||
Assert.AreEqual(request.Uri.ToString().Contains("TestParam1"), pos == HttpMethodParameterPosition.InUri);
|
||||
Assert.AreEqual(request.Content?.Contains("TestParam2") == true, pos == HttpMethodParameterPosition.InBody);
|
||||
Assert.AreEqual(request.Uri.ToString().Contains("TestParam2"), pos == HttpMethodParameterPosition.InUri);
|
||||
Assert.AreEqual(request.GetHeaders().First().Key, "TestHeader");
|
||||
Assert.IsTrue(request.GetHeaders().First().Value.Contains("123"));
|
||||
}
|
||||
|
||||
[TestCase]
|
||||
public void SettingRateLimitingBehaviourToFail_Should_FailLimitedRequests()
|
||||
{
|
||||
@ -128,12 +170,12 @@ namespace CryptoExchange.Net.UnitTests
|
||||
RateLimiters = new List<IRateLimiter> { new RateLimiterTotal(1, TimeSpan.FromSeconds(1)) },
|
||||
RateLimitingBehaviour = RateLimitingBehaviour.Fail
|
||||
});
|
||||
client.SetResponse("{\"property\": 123}");
|
||||
client.SetResponse("{\"property\": 123}", out _);
|
||||
|
||||
|
||||
// act
|
||||
var result1 = client.Request<TestObject>().Result;
|
||||
client.SetResponse("{\"property\": 123}");
|
||||
client.SetResponse("{\"property\": 123}", out _);
|
||||
var result2 = client.Request<TestObject>().Result;
|
||||
|
||||
|
||||
@ -151,13 +193,13 @@ namespace CryptoExchange.Net.UnitTests
|
||||
RateLimiters = new List<IRateLimiter> { new RateLimiterTotal(1, TimeSpan.FromSeconds(1)) },
|
||||
RateLimitingBehaviour = RateLimitingBehaviour.Wait
|
||||
});
|
||||
client.SetResponse("{\"property\": 123}");
|
||||
client.SetResponse("{\"property\": 123}", out _);
|
||||
|
||||
|
||||
// act
|
||||
var sw = Stopwatch.StartNew();
|
||||
var result1 = client.Request<TestObject>().Result;
|
||||
client.SetResponse("{\"property\": 123}"); // reset response stream
|
||||
client.SetResponse("{\"property\": 123}", out _); // reset response stream
|
||||
var result2 = client.Request<TestObject>().Result;
|
||||
sw.Stop();
|
||||
|
||||
@ -178,17 +220,17 @@ namespace CryptoExchange.Net.UnitTests
|
||||
LogLevel = LogLevel.Debug,
|
||||
ApiCredentials = new ApiCredentials("TestKey", "TestSecret")
|
||||
});
|
||||
client.SetResponse("{\"property\": 123}");
|
||||
client.SetResponse("{\"property\": 123}", out _);
|
||||
|
||||
|
||||
// act
|
||||
var sw = Stopwatch.StartNew();
|
||||
var result1 = client.Request<TestObject>().Result;
|
||||
client.SetKey("TestKey2", "TestSecret2"); // set to different key
|
||||
client.SetResponse("{\"property\": 123}"); // reset response stream
|
||||
client.SetResponse("{\"property\": 123}", out _); // reset response stream
|
||||
var result2 = client.Request<TestObject>().Result;
|
||||
client.SetKey("TestKey", "TestSecret"); // set back to original key, should delay
|
||||
client.SetResponse("{\"property\": 123}"); // reset response stream
|
||||
client.SetResponse("{\"property\": 123}", out _); // reset response stream
|
||||
var result3 = client.Request<TestObject>().Result;
|
||||
sw.Stop();
|
||||
|
||||
|
@ -38,12 +38,12 @@ namespace CryptoExchange.Net.UnitTests
|
||||
{
|
||||
}
|
||||
|
||||
public override Dictionary<string, string> AddAuthenticationToHeaders(string uri, HttpMethod method, Dictionary<string, object> parameters, bool signed, PostParameters postParameters, ArrayParametersSerialization arraySerialization)
|
||||
public override Dictionary<string, string> AddAuthenticationToHeaders(string uri, HttpMethod method, Dictionary<string, object> parameters, bool signed, HttpMethodParameterPosition postParameters, ArrayParametersSerialization arraySerialization)
|
||||
{
|
||||
return base.AddAuthenticationToHeaders(uri, method, parameters, signed, postParameters, arraySerialization);
|
||||
}
|
||||
|
||||
public override Dictionary<string, object> AddAuthenticationToParameters(string uri, HttpMethod method, Dictionary<string, object> parameters, bool signed, PostParameters postParameters, ArrayParametersSerialization arraySerialization)
|
||||
public override Dictionary<string, object> AddAuthenticationToParameters(string uri, HttpMethod method, Dictionary<string, object> parameters, bool signed, HttpMethodParameterPosition postParameters, ArrayParametersSerialization arraySerialization)
|
||||
{
|
||||
return base.AddAuthenticationToParameters(uri, method, parameters, signed, postParameters, arraySerialization);
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CryptoExchange.Net.Authentication;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CryptoExchange.Net.UnitTests.TestImplementations
|
||||
{
|
||||
@ -26,12 +27,17 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
||||
RequestFactory = new Mock<IRequestFactory>().Object;
|
||||
}
|
||||
|
||||
public void SetParameterPosition(HttpMethod method, HttpMethodParameterPosition position)
|
||||
{
|
||||
ParameterPositions[method] = position;
|
||||
}
|
||||
|
||||
public void SetKey(string key, string secret)
|
||||
{
|
||||
SetAuthenticationProvider(new UnitTests.TestAuthProvider(new ApiCredentials(key, secret)));
|
||||
}
|
||||
|
||||
public void SetResponse(string responseData, Stream requestStream = null)
|
||||
public void SetResponse(string responseData, out IRequest requestObj)
|
||||
{
|
||||
var expectedBytes = Encoding.UTF8.GetBytes(responseData);
|
||||
var responseStream = new MemoryStream();
|
||||
@ -42,13 +48,23 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
||||
response.Setup(c => c.IsSuccessStatusCode).Returns(true);
|
||||
response.Setup(c => c.GetResponseStreamAsync()).Returns(Task.FromResult((Stream)responseStream));
|
||||
|
||||
var headers = new Dictionary<string, IEnumerable<string>>();
|
||||
var request = new Mock<IRequest>();
|
||||
request.Setup(c => c.Uri).Returns(new Uri("http://www.test.com"));
|
||||
request.Setup(c => c.GetResponseAsync(It.IsAny<CancellationToken>())).Returns(Task.FromResult(response.Object));
|
||||
request.Setup(c => c.SetContent(It.IsAny<string>(), It.IsAny<string>())).Callback(new Action<string, string>((content, type) => { request.Setup(r => r.Content).Returns(content); }));
|
||||
request.Setup(c => c.AddHeader(It.IsAny<string>(), It.IsAny<string>())).Callback<string, string>((key, val) => headers.Add(key, new List<string> { val }));
|
||||
request.Setup(c => c.GetHeaders()).Returns(() => headers);
|
||||
|
||||
var factory = Mock.Get(RequestFactory);
|
||||
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<string>(), It.IsAny<int>()))
|
||||
.Callback<HttpMethod, string, int>((method, uri, id) =>
|
||||
{
|
||||
request.Setup(a => a.Uri).Returns(new Uri(uri));
|
||||
request.Setup(a => a.Method).Returns(method);
|
||||
})
|
||||
.Returns(request.Object);
|
||||
requestObj = request.Object;
|
||||
}
|
||||
|
||||
public void SetErrorWithoutResponse(HttpStatusCode code, string message)
|
||||
@ -75,12 +91,16 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
||||
response.Setup(c => c.IsSuccessStatusCode).Returns(false);
|
||||
response.Setup(c => c.GetResponseStreamAsync()).Returns(Task.FromResult((Stream)responseStream));
|
||||
|
||||
var headers = new Dictionary<string, IEnumerable<string>>();
|
||||
var request = new Mock<IRequest>();
|
||||
request.Setup(c => c.Uri).Returns(new Uri("http://www.test.com"));
|
||||
request.Setup(c => c.GetResponseAsync(It.IsAny<CancellationToken>())).Returns(Task.FromResult(response.Object));
|
||||
request.Setup(c => c.AddHeader(It.IsAny<string>(), It.IsAny<string>())).Callback<string, string>((key, val) => headers.Add(key, new List<string> { val }));
|
||||
request.Setup(c => c.GetHeaders()).Returns(headers);
|
||||
|
||||
var factory = Mock.Get(RequestFactory);
|
||||
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<string>(), It.IsAny<int>()))
|
||||
.Callback<HttpMethod, string, int>((method, uri, id) => request.Setup(a => a.Uri).Returns(new Uri(uri)))
|
||||
.Returns(request.Object);
|
||||
}
|
||||
|
||||
@ -88,6 +108,11 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
||||
{
|
||||
return await SendRequestAsync<T>(new Uri("http://www.test.com"), HttpMethod.Get, ct);
|
||||
}
|
||||
|
||||
public async Task<CallResult<T>> RequestWithParams<T>(HttpMethod method, Dictionary<string, object> parameters, Dictionary<string, string> headers) where T : class
|
||||
{
|
||||
return await SendRequestAsync<T>(new Uri("http://www.test.com"), method, default, parameters, additionalHeaders: headers);
|
||||
}
|
||||
}
|
||||
|
||||
public class TestAuthProvider : AuthenticationProvider
|
||||
|
@ -30,11 +30,11 @@ namespace CryptoExchange.Net.Authentication
|
||||
/// <param name="method">The HTTP method of the request</param>
|
||||
/// <param name="parameters">The provided parameters for the request</param>
|
||||
/// <param name="signed">Wether or not the request needs to be signed. If not typically the parameters list can just be returned</param>
|
||||
/// <param name="postParameterPosition">Where post parameters are placed, in the URI or in the request body</param>
|
||||
/// <param name="parameterPosition">Where parameters are placed, in the URI or in the request body</param>
|
||||
/// <param name="arraySerialization">How array parameters are serialized</param>
|
||||
/// <returns>Should return the original parameter list including any authentication parameters needed</returns>
|
||||
public virtual Dictionary<string, object> AddAuthenticationToParameters(string uri, HttpMethod method, Dictionary<string, object> parameters, bool signed,
|
||||
PostParameters postParameterPosition, ArrayParametersSerialization arraySerialization)
|
||||
HttpMethodParameterPosition parameterPosition, ArrayParametersSerialization arraySerialization)
|
||||
{
|
||||
return parameters;
|
||||
}
|
||||
@ -46,11 +46,11 @@ namespace CryptoExchange.Net.Authentication
|
||||
/// <param name="method">The HTTP method of the request</param>
|
||||
/// <param name="parameters">The provided parameters for the request</param>
|
||||
/// <param name="signed">Wether or not the request needs to be signed. If not typically the parameters list can just be returned</param>
|
||||
/// <param name="postParameterPosition">Where post parameters are placed, in the URI or in the request body</param>
|
||||
/// <param name="parameterPosition">Where post parameters are placed, in the URI or in the request body</param>
|
||||
/// <param name="arraySerialization">How array parameters are serialized</param>
|
||||
/// <returns>Should return a dictionary containing any header key/value pairs needed for authenticating the request</returns>
|
||||
public virtual Dictionary<string, string> AddAuthenticationToHeaders(string uri, HttpMethod method, Dictionary<string, object> parameters, bool signed,
|
||||
PostParameters postParameterPosition, ArrayParametersSerialization arraySerialization)
|
||||
HttpMethodParameterPosition parameterPosition, ArrayParametersSerialization arraySerialization)
|
||||
{
|
||||
return new Dictionary<string, string>();
|
||||
}
|
||||
|
@ -97,7 +97,7 @@
|
||||
</summary>
|
||||
<param name="credentials"></param>
|
||||
</member>
|
||||
<member name="M:CryptoExchange.Net.Authentication.AuthenticationProvider.AddAuthenticationToParameters(System.String,System.Net.Http.HttpMethod,System.Collections.Generic.Dictionary{System.String,System.Object},System.Boolean,CryptoExchange.Net.Objects.PostParameters,CryptoExchange.Net.Objects.ArrayParametersSerialization)">
|
||||
<member name="M:CryptoExchange.Net.Authentication.AuthenticationProvider.AddAuthenticationToParameters(System.String,System.Net.Http.HttpMethod,System.Collections.Generic.Dictionary{System.String,System.Object},System.Boolean,CryptoExchange.Net.Objects.HttpMethodParameterPosition,CryptoExchange.Net.Objects.ArrayParametersSerialization)">
|
||||
<summary>
|
||||
Add authentication to the parameter list based on the provided credentials
|
||||
</summary>
|
||||
@ -105,11 +105,11 @@
|
||||
<param name="method">The HTTP method of the request</param>
|
||||
<param name="parameters">The provided parameters for the request</param>
|
||||
<param name="signed">Wether or not the request needs to be signed. If not typically the parameters list can just be returned</param>
|
||||
<param name="postParameterPosition">Where post parameters are placed, in the URI or in the request body</param>
|
||||
<param name="parameterPosition">Where parameters are placed, in the URI or in the request body</param>
|
||||
<param name="arraySerialization">How array parameters are serialized</param>
|
||||
<returns>Should return the original parameter list including any authentication parameters needed</returns>
|
||||
</member>
|
||||
<member name="M:CryptoExchange.Net.Authentication.AuthenticationProvider.AddAuthenticationToHeaders(System.String,System.Net.Http.HttpMethod,System.Collections.Generic.Dictionary{System.String,System.Object},System.Boolean,CryptoExchange.Net.Objects.PostParameters,CryptoExchange.Net.Objects.ArrayParametersSerialization)">
|
||||
<member name="M:CryptoExchange.Net.Authentication.AuthenticationProvider.AddAuthenticationToHeaders(System.String,System.Net.Http.HttpMethod,System.Collections.Generic.Dictionary{System.String,System.Object},System.Boolean,CryptoExchange.Net.Objects.HttpMethodParameterPosition,CryptoExchange.Net.Objects.ArrayParametersSerialization)">
|
||||
<summary>
|
||||
Add authentication to the header dictionary based on the provided credentials
|
||||
</summary>
|
||||
@ -117,7 +117,7 @@
|
||||
<param name="method">The HTTP method of the request</param>
|
||||
<param name="parameters">The provided parameters for the request</param>
|
||||
<param name="signed">Wether or not the request needs to be signed. If not typically the parameters list can just be returned</param>
|
||||
<param name="postParameterPosition">Where post parameters are placed, in the URI or in the request body</param>
|
||||
<param name="parameterPosition">Where post parameters are placed, in the URI or in the request body</param>
|
||||
<param name="arraySerialization">How array parameters are serialized</param>
|
||||
<returns>Should return a dictionary containing any header key/value pairs needed for authenticating the request</returns>
|
||||
</member>
|
||||
@ -1163,6 +1163,12 @@
|
||||
<param name="key"></param>
|
||||
<param name="value"></param>
|
||||
</member>
|
||||
<member name="M:CryptoExchange.Net.Interfaces.IRequest.GetHeaders">
|
||||
<summary>
|
||||
Get all headers
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:CryptoExchange.Net.Interfaces.IRequest.GetResponseAsync(System.Threading.CancellationToken)">
|
||||
<summary>
|
||||
Get the response
|
||||
@ -1934,19 +1940,19 @@
|
||||
Wait till the request can be send
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:CryptoExchange.Net.Objects.PostParameters">
|
||||
<member name="T:CryptoExchange.Net.Objects.HttpMethodParameterPosition">
|
||||
<summary>
|
||||
Where the parameters for a post request should be added
|
||||
Where the parameters for a HttpMethod should be added in a request
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:CryptoExchange.Net.Objects.PostParameters.InBody">
|
||||
<member name="F:CryptoExchange.Net.Objects.HttpMethodParameterPosition.InBody">
|
||||
<summary>
|
||||
Post parameters in body
|
||||
Parameters in body
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:CryptoExchange.Net.Objects.PostParameters.InUri">
|
||||
<member name="F:CryptoExchange.Net.Objects.HttpMethodParameterPosition.InUri">
|
||||
<summary>
|
||||
Post parameters in url
|
||||
Parameters in url
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:CryptoExchange.Net.Objects.RequestBodyFormat">
|
||||
@ -2802,6 +2808,9 @@
|
||||
<member name="M:CryptoExchange.Net.Requests.Request.AddHeader(System.String,System.String)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:CryptoExchange.Net.Requests.Request.GetHeaders">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:CryptoExchange.Net.Requests.Request.SetContent(System.Byte[])">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
@ -2855,9 +2864,9 @@
|
||||
The factory for creating requests. Used for unit testing
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:CryptoExchange.Net.RestClient.postParametersPosition">
|
||||
<member name="P:CryptoExchange.Net.RestClient.ParameterPositions">
|
||||
<summary>
|
||||
Where to place post parameters by default
|
||||
Where to put the parameters for requests with different Http methods
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:CryptoExchange.Net.RestClient.requestBodyFormat">
|
||||
@ -2900,6 +2909,11 @@
|
||||
Total requests made by this client
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:CryptoExchange.Net.RestClient.StandardRequestHeaders">
|
||||
<summary>
|
||||
Request headers to be sent with each request
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:CryptoExchange.Net.RestClient.#ctor(System.String,CryptoExchange.Net.Objects.RestClientOptions,CryptoExchange.Net.Authentication.AuthenticationProvider)">
|
||||
<summary>
|
||||
ctor
|
||||
@ -2931,7 +2945,7 @@
|
||||
</summary>
|
||||
<returns>The roundtrip time of the ping request</returns>
|
||||
</member>
|
||||
<member name="M:CryptoExchange.Net.RestClient.SendRequestAsync``1(System.Uri,System.Net.Http.HttpMethod,System.Threading.CancellationToken,System.Collections.Generic.Dictionary{System.String,System.Object},System.Boolean,System.Boolean,System.Nullable{CryptoExchange.Net.Objects.PostParameters},System.Nullable{CryptoExchange.Net.Objects.ArrayParametersSerialization},System.Int32,Newtonsoft.Json.JsonSerializer)">
|
||||
<member name="M:CryptoExchange.Net.RestClient.SendRequestAsync``1(System.Uri,System.Net.Http.HttpMethod,System.Threading.CancellationToken,System.Collections.Generic.Dictionary{System.String,System.Object},System.Boolean,System.Boolean,System.Nullable{CryptoExchange.Net.Objects.HttpMethodParameterPosition},System.Nullable{CryptoExchange.Net.Objects.ArrayParametersSerialization},System.Int32,Newtonsoft.Json.JsonSerializer,System.Collections.Generic.Dictionary{System.String,System.String})">
|
||||
<summary>
|
||||
Execute a request to the uri and deserialize the response into the provided type parameter
|
||||
</summary>
|
||||
@ -2942,10 +2956,11 @@
|
||||
<param name="parameters">The parameters of the request</param>
|
||||
<param name="signed">Whether or not the request should be authenticated</param>
|
||||
<param name="checkResult">Whether or not the resulting object should be checked for missing properties in the mapping (only outputs if log verbosity is Debug)</param>
|
||||
<param name="postPosition">Where the post parameters should be placed, overwrites the value set in the client</param>
|
||||
<param name="parameterPosition">Where the parameters should be placed, overwrites the value set in the client</param>
|
||||
<param name="arraySerialization">How array parameters should be serialized, overwrites the value set in the client</param>
|
||||
<param name="credits">Credits used for the request</param>
|
||||
<param name="deserializer">The JsonSerializer to use for deserialization</param>
|
||||
<param name="additionalHeaders">Additional headers to send with the request</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:CryptoExchange.Net.RestClient.GetResponseAsync``1(CryptoExchange.Net.Interfaces.IRequest,Newtonsoft.Json.JsonSerializer,System.Threading.CancellationToken)">
|
||||
@ -2966,7 +2981,7 @@
|
||||
<param name="data">Received data</param>
|
||||
<returns>Null if not an error, Error otherwise</returns>
|
||||
</member>
|
||||
<member name="M:CryptoExchange.Net.RestClient.ConstructRequest(System.Uri,System.Net.Http.HttpMethod,System.Collections.Generic.Dictionary{System.String,System.Object},System.Boolean,CryptoExchange.Net.Objects.PostParameters,CryptoExchange.Net.Objects.ArrayParametersSerialization,System.Int32)">
|
||||
<member name="M:CryptoExchange.Net.RestClient.ConstructRequest(System.Uri,System.Net.Http.HttpMethod,System.Collections.Generic.Dictionary{System.String,System.Object},System.Boolean,CryptoExchange.Net.Objects.HttpMethodParameterPosition,CryptoExchange.Net.Objects.ArrayParametersSerialization,System.Int32,System.Collections.Generic.Dictionary{System.String,System.String})">
|
||||
<summary>
|
||||
Creates a request object
|
||||
</summary>
|
||||
@ -2974,9 +2989,10 @@
|
||||
<param name="method">The method of the request</param>
|
||||
<param name="parameters">The parameters of the request</param>
|
||||
<param name="signed">Whether or not the request should be authenticated</param>
|
||||
<param name="postPosition">Where the post parameters should be placed</param>
|
||||
<param name="parameterPosition">Where the parameters should be placed</param>
|
||||
<param name="arraySerialization">How array parameters should be serialized</param>
|
||||
<param name="requestId">Unique id of a request</param>
|
||||
<param name="additionalHeaders">Additional headers to send with the request</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:CryptoExchange.Net.RestClient.WriteParamBody(CryptoExchange.Net.Interfaces.IRequest,System.Collections.Generic.Dictionary{System.String,System.Object},System.String)">
|
||||
@ -3924,148 +3940,5 @@
|
||||
<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>
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@ -48,6 +49,13 @@ namespace CryptoExchange.Net.Interfaces
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
void AddHeader(string key, string value);
|
||||
|
||||
/// <summary>
|
||||
/// Get all headers
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Dictionary<string, IEnumerable<string>> GetHeaders();
|
||||
|
||||
/// <summary>
|
||||
/// Get the response
|
||||
/// </summary>
|
||||
|
@ -16,16 +16,16 @@
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Where the parameters for a post request should be added
|
||||
/// Where the parameters for a HttpMethod should be added in a request
|
||||
/// </summary>
|
||||
public enum PostParameters
|
||||
public enum HttpMethodParameterPosition
|
||||
{
|
||||
/// <summary>
|
||||
/// Post parameters in body
|
||||
/// Parameters in body
|
||||
/// </summary>
|
||||
InBody,
|
||||
/// <summary>
|
||||
/// Post parameters in url
|
||||
/// Parameters in url
|
||||
/// </summary>
|
||||
InUri
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
@ -63,6 +65,12 @@ namespace CryptoExchange.Net.Requests
|
||||
request.Headers.Add(key, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, IEnumerable<string>> GetHeaders()
|
||||
{
|
||||
return request.Headers.ToDictionary(h => h.Key, h => h.Value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetContent(byte[] data)
|
||||
{
|
||||
|
@ -32,9 +32,15 @@ namespace CryptoExchange.Net
|
||||
public IRequestFactory RequestFactory { get; set; } = new RequestFactory();
|
||||
|
||||
/// <summary>
|
||||
/// Where to place post parameters by default
|
||||
/// Where to put the parameters for requests with different Http methods
|
||||
/// </summary>
|
||||
protected PostParameters postParametersPosition = PostParameters.InBody;
|
||||
protected Dictionary<HttpMethod, HttpMethodParameterPosition> ParameterPositions { get; set; } = new Dictionary<HttpMethod, HttpMethodParameterPosition>
|
||||
{
|
||||
{ HttpMethod.Get, HttpMethodParameterPosition.InUri },
|
||||
{ HttpMethod.Post, HttpMethodParameterPosition.InBody },
|
||||
{ HttpMethod.Delete, HttpMethodParameterPosition.InBody },
|
||||
{ HttpMethod.Put, HttpMethodParameterPosition.InBody }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Request body content type
|
||||
@ -73,6 +79,11 @@ namespace CryptoExchange.Net
|
||||
/// </summary>
|
||||
public int TotalRequestsMade { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Request headers to be sent with each request
|
||||
/// </summary>
|
||||
protected Dictionary<string, string>? StandardRequestHeaders { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
@ -167,16 +178,25 @@ namespace CryptoExchange.Net
|
||||
/// <param name="parameters">The parameters of the request</param>
|
||||
/// <param name="signed">Whether or not the request should be authenticated</param>
|
||||
/// <param name="checkResult">Whether or not the resulting object should be checked for missing properties in the mapping (only outputs if log verbosity is Debug)</param>
|
||||
/// <param name="postPosition">Where the post parameters should be placed, overwrites the value set in the client</param>
|
||||
/// <param name="parameterPosition">Where the parameters should be placed, overwrites the value set in the client</param>
|
||||
/// <param name="arraySerialization">How array parameters should be serialized, overwrites the value set in the client</param>
|
||||
/// <param name="credits">Credits used for the request</param>
|
||||
/// <param name="deserializer">The JsonSerializer to use for deserialization</param>
|
||||
/// <param name="additionalHeaders">Additional headers to send with the request</param>
|
||||
/// <returns></returns>
|
||||
[return: NotNull]
|
||||
protected virtual async Task<WebCallResult<T>> SendRequestAsync<T>(Uri uri, HttpMethod method, CancellationToken cancellationToken,
|
||||
Dictionary<string, object>? parameters = null, bool signed = false, bool checkResult = true,
|
||||
PostParameters? postPosition = null, ArrayParametersSerialization? arraySerialization = null, int credits = 1,
|
||||
JsonSerializer? deserializer = null) where T : class
|
||||
protected virtual async Task<WebCallResult<T>> SendRequestAsync<T>(
|
||||
Uri uri,
|
||||
HttpMethod method,
|
||||
CancellationToken cancellationToken,
|
||||
Dictionary<string, object>? parameters = null,
|
||||
bool signed = false,
|
||||
bool checkResult = true,
|
||||
HttpMethodParameterPosition? parameterPosition = null,
|
||||
ArrayParametersSerialization? arraySerialization = null,
|
||||
int credits = 1,
|
||||
JsonSerializer? deserializer = null,
|
||||
Dictionary<string, string>? additionalHeaders = null) where T : class
|
||||
{
|
||||
var requestId = NextId();
|
||||
log.Write(LogLevel.Debug, $"[{requestId}] Creating request for " + uri);
|
||||
@ -186,7 +206,8 @@ namespace CryptoExchange.Net
|
||||
return new WebCallResult<T>(null, null, null, new NoApiCredentialsError());
|
||||
}
|
||||
|
||||
var request = ConstructRequest(uri, method, parameters, signed, postPosition ?? postParametersPosition, arraySerialization ?? this.arraySerialization, requestId);
|
||||
var paramsPosition = parameterPosition ?? ParameterPositions[method];
|
||||
var request = ConstructRequest(uri, method, parameters, signed, paramsPosition, arraySerialization ?? this.arraySerialization, requestId, additionalHeaders);
|
||||
foreach (var limiter in RateLimiters)
|
||||
{
|
||||
var limitResult = limiter.LimitRequest(this, uri.AbsolutePath, RateLimitBehaviour, credits);
|
||||
@ -201,9 +222,16 @@ namespace CryptoExchange.Net
|
||||
}
|
||||
|
||||
string? paramString = null;
|
||||
if (method == HttpMethod.Post)
|
||||
if (parameterPosition == HttpMethodParameterPosition.InBody)
|
||||
paramString = " with request body " + request.Content;
|
||||
|
||||
if (log.Level == LogLevel.Trace)
|
||||
{
|
||||
var headers = request.GetHeaders();
|
||||
if (headers.Any())
|
||||
paramString = " with headers " + string.Join(", ", headers.Select(h => h.Key + $"=[{string.Join(",", h.Value)}]"));
|
||||
}
|
||||
|
||||
log.Write(LogLevel.Debug, $"[{requestId}] Sending {method}{(signed ? " signed" : "")} request to {request.Uri}{paramString ?? " "}{(apiProxy == null ? "" : $" via proxy {apiProxy.Host}")}");
|
||||
return await GetResponseAsync<T>(request, deserializer, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
@ -320,20 +348,29 @@ namespace CryptoExchange.Net
|
||||
/// <param name="method">The method of the request</param>
|
||||
/// <param name="parameters">The parameters of the request</param>
|
||||
/// <param name="signed">Whether or not the request should be authenticated</param>
|
||||
/// <param name="postPosition">Where the post parameters should be placed</param>
|
||||
/// <param name="parameterPosition">Where the parameters should be placed</param>
|
||||
/// <param name="arraySerialization">How array parameters should be serialized</param>
|
||||
/// <param name="requestId">Unique id of a request</param>
|
||||
/// <param name="additionalHeaders">Additional headers to send with the request</param>
|
||||
/// <returns></returns>
|
||||
protected virtual IRequest ConstructRequest(Uri uri, HttpMethod method, Dictionary<string, object>? parameters, bool signed, PostParameters postPosition, ArrayParametersSerialization arraySerialization, int requestId)
|
||||
protected virtual IRequest ConstructRequest(
|
||||
Uri uri,
|
||||
HttpMethod method,
|
||||
Dictionary<string, object>? parameters,
|
||||
bool signed,
|
||||
HttpMethodParameterPosition parameterPosition,
|
||||
ArrayParametersSerialization arraySerialization,
|
||||
int requestId,
|
||||
Dictionary<string, string>? additionalHeaders)
|
||||
{
|
||||
if (parameters == null)
|
||||
parameters = new Dictionary<string, object>();
|
||||
|
||||
var uriString = uri.ToString();
|
||||
if (authProvider != null)
|
||||
parameters = authProvider.AddAuthenticationToParameters(uriString, method, parameters, signed, postPosition, arraySerialization);
|
||||
parameters = authProvider.AddAuthenticationToParameters(uriString, method, parameters, signed, parameterPosition, arraySerialization);
|
||||
|
||||
if ((method == HttpMethod.Get || method == HttpMethod.Delete || postPosition == PostParameters.InUri) && parameters?.Any() == true)
|
||||
if (parameterPosition == HttpMethodParameterPosition.InUri && parameters?.Any() == true)
|
||||
uriString += "?" + parameters.CreateParamString(true, arraySerialization);
|
||||
|
||||
var contentType = requestBodyFormat == RequestBodyFormat.Json ? Constants.JsonContentHeader : Constants.FormContentHeader;
|
||||
@ -342,12 +379,26 @@ namespace CryptoExchange.Net
|
||||
|
||||
var headers = new Dictionary<string, string>();
|
||||
if (authProvider != null)
|
||||
headers = authProvider.AddAuthenticationToHeaders(uriString, method, parameters!, signed, postPosition, arraySerialization);
|
||||
headers = authProvider.AddAuthenticationToHeaders(uriString, method, parameters!, signed, parameterPosition, arraySerialization);
|
||||
|
||||
foreach (var header in headers)
|
||||
request.AddHeader(header.Key, header.Value);
|
||||
|
||||
if ((method == HttpMethod.Post || method == HttpMethod.Put) && postPosition != PostParameters.InUri)
|
||||
if (additionalHeaders != null)
|
||||
{
|
||||
foreach (var header in additionalHeaders)
|
||||
request.AddHeader(header.Key, header.Value);
|
||||
}
|
||||
|
||||
if(StandardRequestHeaders != null)
|
||||
{
|
||||
foreach (var header in StandardRequestHeaders)
|
||||
// Only add it if it isn't overwritten
|
||||
if(additionalHeaders?.ContainsKey(header.Key) != true)
|
||||
request.AddHeader(header.Key, header.Value);
|
||||
}
|
||||
|
||||
if (parameterPosition == HttpMethodParameterPosition.InBody)
|
||||
{
|
||||
if (parameters?.Any() == true)
|
||||
WriteParamBody(request, parameters, contentType);
|
||||
|
Loading…
x
Reference in New Issue
Block a user