From 200459efe08591aaf3872a22d6e8a758cdcc91b2 Mon Sep 17 00:00:00 2001 From: marc90 Date: Thu, 19 Sep 2019 22:33:15 +0300 Subject: [PATCH 01/35] Add custom header field to each request #8 https://github.com/iwate/ODataHttpClient/issues/8 --- .../Factories/HeadersFactory.cs | 30 +++++ .../ODataHttpClient.Tests.csproj | 8 +- src/ODataHttpClient.Tests/RequestTest.cs | 102 ++++++++++++++-- src/ODataHttpClient/Models/BatchRequest.cs | 6 +- src/ODataHttpClient/Models/IRequest.cs | 4 +- src/ODataHttpClient/Models/IResponse.cs | 9 ++ src/ODataHttpClient/Models/Request.cs | 109 +++++++++++++----- src/ODataHttpClient/Models/RequestFactory.cs | 5 + src/ODataHttpClient/Models/Response.cs | 79 +++++++------ src/ODataHttpClient/ODataClient.cs | 21 ++-- 10 files changed, 280 insertions(+), 93 deletions(-) create mode 100644 src/ODataHttpClient.Tests/Factories/HeadersFactory.cs create mode 100644 src/ODataHttpClient/Models/IResponse.cs diff --git a/src/ODataHttpClient.Tests/Factories/HeadersFactory.cs b/src/ODataHttpClient.Tests/Factories/HeadersFactory.cs new file mode 100644 index 0000000..2fe2b29 --- /dev/null +++ b/src/ODataHttpClient.Tests/Factories/HeadersFactory.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; + +namespace ODataHttpClient.Tests.Factories +{ + public static class HeadersFactory + { + public static HttpRequestHeaders Create(string[] keys, string[] values) + { + var headers = new HttpRequestMessage().Headers; + if (keys.Length != values.Length) + return headers; + + for (int i = 0; i < keys.Length; i++) + headers.TryAddWithoutValidation(keys[i], values[i]); + + return headers; + } + + public static HttpRequestHeaders Create(IDictionary keyValues) + { + var headers = new HttpRequestMessage().Headers; + foreach (var pair in keyValues) + headers.TryAddWithoutValidation(pair.Key, pair.Value); + + return headers; + } + } +} \ No newline at end of file diff --git a/src/ODataHttpClient.Tests/ODataHttpClient.Tests.csproj b/src/ODataHttpClient.Tests/ODataHttpClient.Tests.csproj index 60f76ee..11e889a 100644 --- a/src/ODataHttpClient.Tests/ODataHttpClient.Tests.csproj +++ b/src/ODataHttpClient.Tests/ODataHttpClient.Tests.csproj @@ -1,4 +1,4 @@ - + netcoreapp2.1 @@ -11,9 +11,9 @@ - - runtime; build; native; contentfiles; analyzers - all + + runtime; build; native; contentfiles; analyzers + all diff --git a/src/ODataHttpClient.Tests/RequestTest.cs b/src/ODataHttpClient.Tests/RequestTest.cs index f2d5fa7..38dda0a 100644 --- a/src/ODataHttpClient.Tests/RequestTest.cs +++ b/src/ODataHttpClient.Tests/RequestTest.cs @@ -2,6 +2,7 @@ using System.Net.Http; using System.Net.Http.Headers; using ODataHttpClient.Models; +using ODataHttpClient.Tests.Factories; using Xunit; namespace ODataHttpClient.Tests @@ -10,7 +11,9 @@ public class RequestTest { const string uri = "http://services.odata.org/V3/OData/OData.svc/Products"; const string batchUri = "http://services.odata.org/V3/OData/OData.svc/$batch"; - [Fact] + const string headerKey = "If-Match"; + const string headerValue = "*"; + [Fact] public void NonBodyRequest() { var request = Request.Create(HttpMethod.Get, uri); @@ -45,37 +48,91 @@ public void CreateGetRequest() var request = Request.Get(uri); Assert.Equal(HttpMethod.Get, request.Method); } - [Fact] + [Fact] + public void CreateGetRequestWithHeader() + { + var request = Request.Get(uri, HeadersFactory.Create( + new[] { headerKey }, + new[] { headerValue })); + Assert.Equal(HttpMethod.Get, request.Method); + Assert.True(request.Headers.Contains(headerKey)); + } + [Fact] public void CreateHeadRequest() { var request = Request.Head(uri); Assert.Equal(HttpMethod.Head, request.Method); } - [Fact] + [Fact] + public void CreateHeadRequestWithHeader() + { + var request = Request.Head(uri, HeadersFactory.Create( + new[] { headerKey }, + new[] { headerValue })); + Assert.Equal(HttpMethod.Head, request.Method); + Assert.True(request.Headers.Contains(headerKey)); + } + [Fact] public void CreateDeleteRequest() { var request = Request.Delete(uri); Assert.Equal(HttpMethod.Delete, request.Method); } - [Fact] + [Fact] + public void CreateDeleteRequestWithHeader() + { + var request = Request.Delete(uri, HeadersFactory.Create( + new[] { headerKey }, + new[] { headerValue })); + Assert.Equal(HttpMethod.Delete, request.Method); + Assert.True(request.Headers.Contains(headerKey)); + } + [Fact] public void CreatePostRequest() { var request = Request.Post(uri, new {}); Assert.Equal(HttpMethod.Post, request.Method); } - [Fact] + [Fact] + public void CreatePostRequestWithHeader() + { + var request = Request.Post(uri, new { }, HeadersFactory.Create( + new string[] { headerKey }, + new string[] { headerValue })); + Assert.Equal(HttpMethod.Post, request.Method); + Assert.True(request.Headers.Contains(headerKey)); + } + [Fact] public void CreatePutRequest() { var request = Request.Put(uri, new {}); Assert.Equal(HttpMethod.Put, request.Method); } - [Fact] + [Fact] + public void CreatePutRequestWithHeader() + { + var request = Request.Put(uri, new { }, HeadersFactory.Create( + new[] { headerKey }, + new[] { headerValue })); + Assert.Equal(HttpMethod.Put, request.Method); + Assert.True(request.Headers.Contains(headerKey)); + } + [Fact] public void CreatePatchRequest() { var request = Request.Patch(uri, new {}); Assert.Equal(new HttpMethod("PATCH"), request.Method); } - [Fact] + [Fact] + public void CreatePatchRequestWithHeader() + { + var request = Request.Patch(uri, new { }, HeadersFactory.Create( + new[] { headerKey }, + new[] { headerValue })); + Assert.Equal(new HttpMethod("PATCH"), request.Method); + Assert.True(request.Headers.Contains(headerKey)); + } + [Fact] public void BatchRequest() { var message = new BatchRequest(batchUri) @@ -109,5 +166,34 @@ public void BatchRequest() Assert.Equal("1", req1.Headers.GetValues("Content-ID")?.FirstOrDefault()); Assert.Equal("2", req2.Headers.GetValues("Content-ID")?.FirstOrDefault()); } - } + [Fact] + public void BatchRequestWithHeader() + { + var message = new BatchRequest(batchUri) + { + Requests = + { + Request.Post(uri, new {}), + Request.Post(uri, new {}) + } + }.CreateMessage(HeadersFactory.Create( + new[] { headerKey }, + new[] { headerValue })); + + Assert.True(message.Content.IsMimeMultipartContent()); + Assert.True(message.Headers.Contains(headerKey)); + } + [Fact] + public void CreateRequestWithHeaderByFactory() + { + var body = "text"; + var request = new RequestFactory() + .Create(HttpMethod.Get, uri, + body, HeadersFactory.Create( + new[] { headerKey }, + new[] { headerValue }), null); + Assert.Equal(HttpMethod.Get, request.Method); + Assert.True(request.Headers.Contains(headerKey)); + } + } } \ No newline at end of file diff --git a/src/ODataHttpClient/Models/BatchRequest.cs b/src/ODataHttpClient/Models/BatchRequest.cs index dd627b4..0bf7301 100644 --- a/src/ODataHttpClient/Models/BatchRequest.cs +++ b/src/ODataHttpClient/Models/BatchRequest.cs @@ -10,6 +10,7 @@ public class BatchRequest : IBatchRequest { public string Uri { get; } public ICollection Requests { get; set; } + public HttpRequestHeaders Headers { get; private set; } public BatchRequest(string uri) { Uri = uri; @@ -59,7 +60,7 @@ protected HttpContent CreateContent() return batch; } - public HttpRequestMessage CreateMessage() + public HttpRequestMessage CreateMessage(HttpRequestHeaders headers = null) { var message = new HttpRequestMessage(HttpMethod.Post, Uri) { @@ -67,6 +68,9 @@ public HttpRequestMessage CreateMessage() }; message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("multipart/mixed")); + if (headers is null) return message; + foreach (var header in headers) + message.Headers.Add(header.Key, header.Value); return message; } diff --git a/src/ODataHttpClient/Models/IRequest.cs b/src/ODataHttpClient/Models/IRequest.cs index 5210c21..6990ee6 100644 --- a/src/ODataHttpClient/Models/IRequest.cs +++ b/src/ODataHttpClient/Models/IRequest.cs @@ -1,9 +1,11 @@ using System.Net.Http; +using System.Net.Http.Headers; namespace ODataHttpClient.Models { public interface IRequest { - HttpRequestMessage CreateMessage(); + HttpRequestHeaders Headers { get; } + HttpRequestMessage CreateMessage(HttpRequestHeaders headers = null); } } diff --git a/src/ODataHttpClient/Models/IResponse.cs b/src/ODataHttpClient/Models/IResponse.cs new file mode 100644 index 0000000..1f72f77 --- /dev/null +++ b/src/ODataHttpClient/Models/IResponse.cs @@ -0,0 +1,9 @@ +using System.Net.Http.Headers; + +namespace ODataHttpClient.Models +{ + public interface IResponse + { + HttpRequestHeaders Headers { get; } + } +} \ No newline at end of file diff --git a/src/ODataHttpClient/Models/Request.cs b/src/ODataHttpClient/Models/Request.cs index 30bd696..5e1c223 100644 --- a/src/ODataHttpClient/Models/Request.cs +++ b/src/ODataHttpClient/Models/Request.cs @@ -3,55 +3,77 @@ using ODataHttpClient.Serializers; using System; using System.Collections.Generic; -using System.Linq; using System.Net.Http; using System.Net.Http.Headers; using System.Text; namespace ODataHttpClient.Models { - public class Request : IRequest + public class Request : IRequest { internal const string DEFAULT_TYPE_KEY = "odata.type"; private static Type stringType = typeof(string); public HttpMethod Method { get; private set; } - public string Uri { get; private set; } + public HttpRequestHeaders Headers { get; private set; } + public string Uri { get; private set; } public string MediaType { get; private set; } public string Body { get; private set; } private Request(){} - public HttpRequestMessage CreateMessage() - { - var message = new HttpRequestMessage(Method, Uri); - - message.Version = new Version(1, 1); - message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream")); - message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain")); - - if (Body != null) - message.Content = new StringContent(Body, Encoding.UTF8, MediaType); - - return message; - } - public static Request Create(HttpMethod method, string uri) + public HttpRequestMessage CreateMessage(HttpRequestHeaders headers = null) + { + var message = new HttpRequestMessage(Method, Uri); + message.Version = new Version(1, 1); + InitMessageHeaders(headers, message); + + if (Body != null) + message.Content = new StringContent(Body, Encoding.UTF8, MediaType); + + return message; + } + + private static void InitMessageHeaders(HttpRequestHeaders headers, HttpRequestMessage message) + { + message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream")); + message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain")); + + if (headers is null) return; + foreach (var header in headers) + message.Headers.Add(header.Key, header.Value); + } + + + public static Request Create(HttpMethod method, string uri) + { + return new Request + { + Method = method, + Uri = uri, + Body = null + }; + } + + public static Request Create(HttpMethod method, string uri, HttpRequestHeaders headers) { return new Request { Method = method, Uri = uri, Body = null, + Headers = headers }; } - public static Request Create(HttpMethod method, string uri, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + + public static Request Create(HttpMethod method, string uri, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null, HttpRequestHeaders headers = null) { - return Create(method, uri, body, type != null ? new[] { new KeyValuePair(typeKey, type) } : null, serializer ?? JsonSerializer.Default); + return Create(method, uri, body, type != null ? new[] { new KeyValuePair(typeKey, type) } : null, serializer ?? JsonSerializer.Default, headers); } - public static Request Create(HttpMethod method, string uri, T body, IEnumerable> additionals, IJsonSerializer serializer) + public static Request Create(HttpMethod method, string uri, T body, IEnumerable> additionals, IJsonSerializer serializer, HttpRequestHeaders headers = null) { - string content, mime = null; + string content, mime = null; var type = typeof(T); @@ -77,6 +99,7 @@ public static Request Create(HttpMethod method, string uri, T body, IEnumerab Uri = uri, MediaType = mime, Body = content, + Headers = headers }; } @@ -84,29 +107,53 @@ public static Request Create(HttpMethod method, string uri, T body, IEnumerab public static Request Get(string uri) => Create(HttpMethod.Get, uri); public static Request Get(string uri, object @params) => Get(Parameterizer.Parameterize(uri, @params)); + public static Request Get(string uri, HttpRequestHeaders headers) => Create(HttpMethod.Get, uri, headers); + public static Request Get(string uri, object @params, HttpRequestHeaders headers) => Get(Parameterizer.Parameterize(uri, @params), headers); - public static Request Head(string uri) => Create(HttpMethod.Head, uri); + public static Request Head(string uri) => Create(HttpMethod.Head, uri); public static Request Head(string uri, object @params) => Head(Parameterizer.Parameterize(uri, @params)); + public static Request Head(string uri, HttpRequestHeaders headers) => Create(HttpMethod.Head, uri, headers); + public static Request Head(string uri, object @params, HttpRequestHeaders headers) => Head(Parameterizer.Parameterize(uri, @params), headers); - public static Request Delete(string uri) => Create(HttpMethod.Delete, uri); + public static Request Delete(string uri) => Create(HttpMethod.Delete, uri); public static Request Delete(string uri, object @params) => Delete(Parameterizer.Parameterize(uri, @params)); + public static Request Delete(string uri, HttpRequestHeaders headers) => Create(HttpMethod.Delete, uri, headers); + public static Request Delete(string uri, object @params, HttpRequestHeaders headers) => Delete(Parameterizer.Parameterize(uri, @params), headers); - public static Request Post(string uri, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + public static Request Post(string uri, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) => Create(HttpMethod.Post, uri, body, type, typeKey, serializer); public static Request Post(string uri, object @params, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) => Post(Parameterizer.Parameterize(uri, @params), body, type, typeKey, serializer); - public static Request Put(string uri, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + public static Request Post(string uri, T body, HttpRequestHeaders headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + => Create(HttpMethod.Post, uri, body, type, typeKey, serializer, headers); + + public static Request Post(string uri, object @params, T body, HttpRequestHeaders headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + => Post(Parameterizer.Parameterize(uri, @params), body, headers, type, typeKey, serializer); + + public static Request Put(string uri, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) => Create(HttpMethod.Put, uri, body, type, typeKey, serializer); - - public static Request Put(string uri, object @params, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) - => Put(Parameterizer.Parameterize(uri, @params), body, type, typeKey, serializer); - public static Request Patch(string uri, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + public static Request Put(string uri, object @params, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + => Put(Parameterizer.Parameterize(uri, @params), body, type, typeKey, serializer); + + public static Request Put(string uri, object @params, T body, HttpRequestHeaders headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + => Put(Parameterizer.Parameterize(uri, @params), body, headers, type, typeKey, serializer); + + public static Request Put(string uri, T body, HttpRequestHeaders headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + => Create(HttpMethod.Put, uri, body, type, typeKey, serializer, headers); + + public static Request Patch(string uri, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) => Create(new HttpMethod("PATCH"), uri, body, type, typeKey, serializer); public static Request Patch(string uri, object @params, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) => Patch(Parameterizer.Parameterize(uri, @params), body, type, typeKey, serializer); - } + + public static Request Patch(string uri, T body, HttpRequestHeaders headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + => Create(new HttpMethod("PATCH"), uri, body, type, typeKey, serializer, headers); + + public static Request Patch(string uri, object @params, T body, HttpRequestHeaders headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + => Patch(Parameterizer.Parameterize(uri, @params), body, headers, type, typeKey, serializer); + } } diff --git a/src/ODataHttpClient/Models/RequestFactory.cs b/src/ODataHttpClient/Models/RequestFactory.cs index 70dfbb6..f354f7b 100644 --- a/src/ODataHttpClient/Models/RequestFactory.cs +++ b/src/ODataHttpClient/Models/RequestFactory.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Net.Http; +using System.Net.Http.Headers; namespace ODataHttpClient.Models { @@ -20,6 +21,10 @@ public Request Create(HttpMethod method, string uri, T body, IEnumerable Request.Create(method, uri, body, additionals, JsonSerializer); public Request Create(HttpMethod method, string uri, T body, string type = null, string typeKey = Request.DEFAULT_TYPE_KEY) => Request.Create(method, uri, body, type, typeKey, JsonSerializer); + public Request Create(HttpMethod method, string uri, T body, HttpRequestHeaders headers, IEnumerable> additionals) + => Request.Create(method, uri, body, additionals, JsonSerializer, headers); + public Request Create(HttpMethod method, string uri, T body, HttpRequestHeaders headers, string type = null, string typeKey = Request.DEFAULT_TYPE_KEY) + => Request.Create(method, uri, body, type, typeKey, JsonSerializer, headers); public Request Get(string uri) => Request.Get(uri); diff --git a/src/ODataHttpClient/Models/Response.cs b/src/ODataHttpClient/Models/Response.cs index bd5890d..7eea7e6 100644 --- a/src/ODataHttpClient/Models/Response.cs +++ b/src/ODataHttpClient/Models/Response.cs @@ -1,12 +1,13 @@ using ODataHttpClient.Serializers; using System; -using System.IO; +using System.IO; using System.Net; +using System.Net.Http.Headers; using System.Text; namespace ODataHttpClient.Models { - public class Response + public class Response : IResponse { private IJsonSerializer _serializer = JsonSerializer.Default; public bool Success { get; private set; } @@ -15,7 +16,9 @@ public class Response public string ErrorMessage { get; private set; } public byte[] Binary { get; private set; } public string Body { get => Binary != null ? Encoding.UTF8.GetString(Binary) : null; } - private Response(){} + public HttpRequestHeaders Headers { get; private set; } + + private Response(){} public T ReadAs(string jsonPath = null) { @@ -41,28 +44,28 @@ public T ReadAs(string jsonPath, IJsonSerializer serializer) var type = typeof(T); - if (MediaType == "text/plain") - { - if (type == typeof(string)) - return (T)(object)Body; - - if (type == typeof(int) || type == typeof(int?)) - return (T)(object)Convert.ToInt32(Body); - - if (type == typeof(long) || type == typeof(long?)) - return (T)(object)Convert.ToInt64(Body); - - if (type == typeof(double) || type == typeof(double?)) - return (T)(object)Convert.ToDouble(Body); - - if (type == typeof(decimal) || type == typeof(decimal?)) - return (T)(object)Convert.ToDecimal(Body); - - if (type == typeof(DateTime) || type == typeof(DateTime?)) - return (T)(object)Convert.ToDateTime(Body); - - if (type == typeof(DateTimeOffset) || type == typeof(DateTimeOffset?)) - return (T)(object)DateTimeOffset.Parse(Body); + if (MediaType == "text/plain") + { + if (type == typeof(string)) + return (T)(object)Body; + + if (type == typeof(int) || type == typeof(int?)) + return (T)(object)Convert.ToInt32(Body); + + if (type == typeof(long) || type == typeof(long?)) + return (T)(object)Convert.ToInt64(Body); + + if (type == typeof(double) || type == typeof(double?)) + return (T)(object)Convert.ToDouble(Body); + + if (type == typeof(decimal) || type == typeof(decimal?)) + return (T)(object)Convert.ToDecimal(Body); + + if (type == typeof(DateTime) || type == typeof(DateTime?)) + return (T)(object)Convert.ToDateTime(Body); + + if (type == typeof(DateTimeOffset) || type == typeof(DateTimeOffset?)) + return (T)(object)DateTimeOffset.Parse(Body); } if (MediaType == "application/octet-stream") @@ -77,30 +80,30 @@ public T ReadAs(string jsonPath, IJsonSerializer serializer) throw new NotSupportedException(); } - public static Response CreateError(HttpStatusCode code, byte[] body) + public static Response CreateError(HttpStatusCode code, byte[] body, HttpRequestHeaders headers) { - return CreateError(code, body != null ? Encoding.UTF8.GetString(body) : null); + return CreateError(code, body != null ? Encoding.UTF8.GetString(body) : null, headers); } - public static Response CreateError(HttpStatusCode code, string message) + public static Response CreateError(HttpStatusCode code, string message, HttpRequestHeaders headers) { - return new Response { Success = false, StatusCode = code, ErrorMessage = message }; + return new Response { Success = false, StatusCode = code, ErrorMessage = message, Headers = headers }; } - public static Response CreateSuccess(HttpStatusCode code, string mime, string body) + public static Response CreateSuccess(HttpStatusCode code, string mime, string body, HttpRequestHeaders headers = null) { - return CreateSuccess(code, mime, body, JsonSerializer.Default); + return CreateSuccess(code, mime, body, JsonSerializer.Default, headers); } - public static Response CreateSuccess(HttpStatusCode code, string mime, byte[] body) + public static Response CreateSuccess(HttpStatusCode code, string mime, byte[] body, HttpRequestHeaders headers = null) { - return CreateSuccess(code, mime, body, JsonSerializer.Default); + return CreateSuccess(code, mime, body, JsonSerializer.Default, headers); } - public static Response CreateSuccess(HttpStatusCode code, string mime, string body, IJsonSerializer serializer) + public static Response CreateSuccess(HttpStatusCode code, string mime, string body, IJsonSerializer serializer, HttpRequestHeaders headers) { - return CreateSuccess(code, mime, body != null ? Encoding.UTF8.GetBytes(body) : null, serializer); + return CreateSuccess(code, mime, body != null ? Encoding.UTF8.GetBytes(body) : null, serializer, headers); } - public static Response CreateSuccess(HttpStatusCode code, string mime, byte[] body, IJsonSerializer serializer) + public static Response CreateSuccess(HttpStatusCode code, string mime, byte[] body, IJsonSerializer serializer, HttpRequestHeaders headers) { - return new Response { Success = true, StatusCode = code, MediaType = mime, Binary = body, _serializer = serializer }; + return new Response { Success = true, StatusCode = code, MediaType = mime, Binary = body, _serializer = serializer, Headers = headers }; } - } + } } diff --git a/src/ODataHttpClient/ODataClient.cs b/src/ODataHttpClient/ODataClient.cs index f5dbfae..18df1de 100644 --- a/src/ODataHttpClient/ODataClient.cs +++ b/src/ODataHttpClient/ODataClient.cs @@ -40,21 +40,22 @@ public ODataClient(HttpClient httpClient, ICredentialBuilder credentialBuilder, RequestFactory = new RequestFactory(serializer); } - protected async Task ParseAsync(HttpStatusCode status, HttpContent content) + protected async Task ParseAsync(HttpStatusCode status, HttpContent content, HttpRequestHeaders headers = null) { var code = (int)status; var body = content != null ? await content.ReadAsByteArrayAsync() : null; var mime = content?.Headers.ContentType?.MediaType; if (code == 404) - return Response.CreateSuccess(status, mime, (byte[])null); + return Response.CreateSuccess(status, mime, (byte[])null, headers); if (code >= 400) - return Response.CreateError(status, body); + return Response.CreateError(status, body, headers); - return Response.CreateSuccess(status, mime, body); + return Response.CreateSuccess(status, mime, body, headers); } - protected async Task> ParseMultiAsync(MultipartMemoryStreamProvider multipart) + + protected async Task> ParseMultiAsync(MultipartMemoryStreamProvider multipart, HttpRequestHeaders headers = null) { var result = new List(); foreach (var content in multipart.Contents) @@ -80,13 +81,13 @@ protected async Task> ParseMultiAsync(MultipartMemoryStrea public async Task SendAsync(IRequest request) { - var message = request.CreateMessage(); + var message = request.CreateMessage(request.Headers); _credentialBuilder?.Build(_httpClient, message); var response = await _httpClient.SendAsync(message); - return await ParseAsync(response.StatusCode, response.Content); + return await ParseAsync(response.StatusCode, response.Content, request.Headers); } public async Task> SendAsync(IBatchRequest batchRequest) { @@ -94,7 +95,7 @@ public async Task> SendAsync(IBatchRequest batchRequest) } public async Task> BatchAsync(IBatchRequest request) { - var message = request.CreateMessage(); + var message = request.CreateMessage(request.Headers); message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); _credentialBuilder?.Build(_httpClient, message); @@ -102,11 +103,11 @@ public async Task> BatchAsync(IBatchRequest request) var response = await _httpClient.SendAsync(message); if (!response.Content.IsMimeMultipartContent()) - return new[] { await ParseAsync(response.StatusCode, response.Content) }; + return new[] { await ParseAsync(response.StatusCode, response.Content, request.Headers) }; var multipart = await response.Content.ReadAsMultipartAsync(); - return await ParseMultiAsync(multipart); + return await ParseMultiAsync(multipart, request.Headers); } public static void UseV4Global() From f72263c34748612df3cd8967c412f0dad951e165 Mon Sep 17 00:00:00 2001 From: marc90 Date: Thu, 19 Sep 2019 22:47:58 +0300 Subject: [PATCH 02/35] Add custom header field to each request #8 https://github.com/iwate/ODataHttpClient/issues/8 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 944dbff..e3524fd 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ The simplest implementation of OData client. var client = new HttpClient(); var odata = new ODataClient(client); - var reqest = Request.Get($"{endpoint}/Products?$inlinecount=allpages"); + var request = Request.Get($"{endpoint}/Products?$inlinecount=allpages"); var response = await odata.SendAsync(request); if (response.Success) @@ -60,7 +60,7 @@ The simplest implementation of OData client. var client = new HttpClient(); var odata = new ODataClient(client); - var reqest = Request.Get($"{endpoint}/Products?$filter=ReleaseDate ge @Date", new { Date = new DateTime(2000, 1, 1) }); + var request = Request.Get($"{endpoint}/Products?$filter=ReleaseDate ge @Date", new { Date = new DateTime(2000, 1, 1) }); var response = await odata.SendAsync(request); if (response.Success) From 145163a3333a8e40a47dc4ef2126091a707ac7d9 Mon Sep 17 00:00:00 2001 From: marc90 Date: Sat, 21 Sep 2019 10:48:17 +0300 Subject: [PATCH 03/35] Add custom header field to each request #8 https://github.com/iwate/ODataHttpClient/issues/8 --- src/ODataHttpClient.Tests/RequestTest.cs | 1 - src/ODataHttpClient/Models/BatchRequest.cs | 16 ++++++++++++++-- .../Models}/HeadersFactory.cs | 2 +- src/ODataHttpClient/Models/IRequest.cs | 3 ++- src/ODataHttpClient/Models/IResponse.cs | 9 --------- src/ODataHttpClient/Models/Request.cs | 14 +++++++++++++- src/ODataHttpClient/Models/RequestFactory.cs | 6 +++++- src/ODataHttpClient/Models/Response.cs | 16 ++++++++-------- src/ODataHttpClient/ODataClient.cs | 10 +++++----- 9 files changed, 48 insertions(+), 29 deletions(-) rename src/{ODataHttpClient.Tests/Factories => ODataHttpClient/Models}/HeadersFactory.cs (95%) delete mode 100644 src/ODataHttpClient/Models/IResponse.cs diff --git a/src/ODataHttpClient.Tests/RequestTest.cs b/src/ODataHttpClient.Tests/RequestTest.cs index 38dda0a..45b2f9d 100644 --- a/src/ODataHttpClient.Tests/RequestTest.cs +++ b/src/ODataHttpClient.Tests/RequestTest.cs @@ -2,7 +2,6 @@ using System.Net.Http; using System.Net.Http.Headers; using ODataHttpClient.Models; -using ODataHttpClient.Tests.Factories; using Xunit; namespace ODataHttpClient.Tests diff --git a/src/ODataHttpClient/Models/BatchRequest.cs b/src/ODataHttpClient/Models/BatchRequest.cs index 0bf7301..7fdc5b8 100644 --- a/src/ODataHttpClient/Models/BatchRequest.cs +++ b/src/ODataHttpClient/Models/BatchRequest.cs @@ -60,11 +60,23 @@ protected HttpContent CreateContent() return batch; } - public HttpRequestMessage CreateMessage(HttpRequestHeaders headers = null) + public HttpRequestMessage CreateMessage() { var message = new HttpRequestMessage(HttpMethod.Post, Uri) { - Content = CreateContent(), + Content = CreateContent() + }; + + message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("multipart/mixed")); + + return message; + } + + public HttpRequestMessage CreateMessage(HttpRequestHeaders headers) + { + var message = new HttpRequestMessage(HttpMethod.Post, Uri) + { + Content = CreateContent() }; message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("multipart/mixed")); diff --git a/src/ODataHttpClient.Tests/Factories/HeadersFactory.cs b/src/ODataHttpClient/Models/HeadersFactory.cs similarity index 95% rename from src/ODataHttpClient.Tests/Factories/HeadersFactory.cs rename to src/ODataHttpClient/Models/HeadersFactory.cs index 2fe2b29..93c1982 100644 --- a/src/ODataHttpClient.Tests/Factories/HeadersFactory.cs +++ b/src/ODataHttpClient/Models/HeadersFactory.cs @@ -2,7 +2,7 @@ using System.Net.Http; using System.Net.Http.Headers; -namespace ODataHttpClient.Tests.Factories +namespace ODataHttpClient.Models { public static class HeadersFactory { diff --git a/src/ODataHttpClient/Models/IRequest.cs b/src/ODataHttpClient/Models/IRequest.cs index 6990ee6..8cee7cf 100644 --- a/src/ODataHttpClient/Models/IRequest.cs +++ b/src/ODataHttpClient/Models/IRequest.cs @@ -6,6 +6,7 @@ namespace ODataHttpClient.Models public interface IRequest { HttpRequestHeaders Headers { get; } - HttpRequestMessage CreateMessage(HttpRequestHeaders headers = null); + HttpRequestMessage CreateMessage(); + HttpRequestMessage CreateMessage(HttpRequestHeaders headers); } } diff --git a/src/ODataHttpClient/Models/IResponse.cs b/src/ODataHttpClient/Models/IResponse.cs deleted file mode 100644 index 1f72f77..0000000 --- a/src/ODataHttpClient/Models/IResponse.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Net.Http.Headers; - -namespace ODataHttpClient.Models -{ - public interface IResponse - { - HttpRequestHeaders Headers { get; } - } -} \ No newline at end of file diff --git a/src/ODataHttpClient/Models/Request.cs b/src/ODataHttpClient/Models/Request.cs index 5e1c223..4da5887 100644 --- a/src/ODataHttpClient/Models/Request.cs +++ b/src/ODataHttpClient/Models/Request.cs @@ -20,8 +20,20 @@ public class Request : IRequest public string Body { get; private set; } private Request(){} + + public HttpRequestMessage CreateMessage() + { + var message = new HttpRequestMessage(Method, Uri); + message.Version = new Version(1, 1); + InitMessageHeaders(null, message); + + if (Body != null) + message.Content = new StringContent(Body, Encoding.UTF8, MediaType); + + return message; + } - public HttpRequestMessage CreateMessage(HttpRequestHeaders headers = null) + public HttpRequestMessage CreateMessage(HttpRequestHeaders headers) { var message = new HttpRequestMessage(Method, Uri); message.Version = new Version(1, 1); diff --git a/src/ODataHttpClient/Models/RequestFactory.cs b/src/ODataHttpClient/Models/RequestFactory.cs index f354f7b..8906ed7 100644 --- a/src/ODataHttpClient/Models/RequestFactory.cs +++ b/src/ODataHttpClient/Models/RequestFactory.cs @@ -25,7 +25,11 @@ public Request Create(HttpMethod method, string uri, T body, HttpRequestHeade => Request.Create(method, uri, body, additionals, JsonSerializer, headers); public Request Create(HttpMethod method, string uri, T body, HttpRequestHeaders headers, string type = null, string typeKey = Request.DEFAULT_TYPE_KEY) => Request.Create(method, uri, body, type, typeKey, JsonSerializer, headers); - + public Request Create(HttpMethod method, string uri, T body, IDictionary headers, IEnumerable> additionals) + => Request.Create(method, uri, body, additionals, JsonSerializer, HeadersFactory.Create(headers)); + public Request Create(HttpMethod method, string uri, T body, IDictionary headers, string type = null, string typeKey = Request.DEFAULT_TYPE_KEY) + => Request.Create(method, uri, body, type, typeKey, JsonSerializer, HeadersFactory.Create(headers)); + public Request Get(string uri) => Request.Get(uri); diff --git a/src/ODataHttpClient/Models/Response.cs b/src/ODataHttpClient/Models/Response.cs index 7eea7e6..473485c 100644 --- a/src/ODataHttpClient/Models/Response.cs +++ b/src/ODataHttpClient/Models/Response.cs @@ -7,7 +7,7 @@ namespace ODataHttpClient.Models { - public class Response : IResponse + public class Response { private IJsonSerializer _serializer = JsonSerializer.Default; public bool Success { get; private set; } @@ -16,7 +16,7 @@ public class Response : IResponse public string ErrorMessage { get; private set; } public byte[] Binary { get; private set; } public string Body { get => Binary != null ? Encoding.UTF8.GetString(Binary) : null; } - public HttpRequestHeaders Headers { get; private set; } + public HttpResponseHeaders Headers { get; private set; } private Response(){} @@ -80,28 +80,28 @@ public T ReadAs(string jsonPath, IJsonSerializer serializer) throw new NotSupportedException(); } - public static Response CreateError(HttpStatusCode code, byte[] body, HttpRequestHeaders headers) + public static Response CreateError(HttpStatusCode code, byte[] body, HttpResponseHeaders headers) { return CreateError(code, body != null ? Encoding.UTF8.GetString(body) : null, headers); } - public static Response CreateError(HttpStatusCode code, string message, HttpRequestHeaders headers) + public static Response CreateError(HttpStatusCode code, string message, HttpResponseHeaders headers) { return new Response { Success = false, StatusCode = code, ErrorMessage = message, Headers = headers }; } - public static Response CreateSuccess(HttpStatusCode code, string mime, string body, HttpRequestHeaders headers = null) + public static Response CreateSuccess(HttpStatusCode code, string mime, string body, HttpResponseHeaders headers = null) { return CreateSuccess(code, mime, body, JsonSerializer.Default, headers); } - public static Response CreateSuccess(HttpStatusCode code, string mime, byte[] body, HttpRequestHeaders headers = null) + public static Response CreateSuccess(HttpStatusCode code, string mime, byte[] body, HttpResponseHeaders headers = null) { return CreateSuccess(code, mime, body, JsonSerializer.Default, headers); } - public static Response CreateSuccess(HttpStatusCode code, string mime, string body, IJsonSerializer serializer, HttpRequestHeaders headers) + public static Response CreateSuccess(HttpStatusCode code, string mime, string body, IJsonSerializer serializer, HttpResponseHeaders headers) { return CreateSuccess(code, mime, body != null ? Encoding.UTF8.GetBytes(body) : null, serializer, headers); } - public static Response CreateSuccess(HttpStatusCode code, string mime, byte[] body, IJsonSerializer serializer, HttpRequestHeaders headers) + public static Response CreateSuccess(HttpStatusCode code, string mime, byte[] body, IJsonSerializer serializer, HttpResponseHeaders headers) { return new Response { Success = true, StatusCode = code, MediaType = mime, Binary = body, _serializer = serializer, Headers = headers }; } diff --git a/src/ODataHttpClient/ODataClient.cs b/src/ODataHttpClient/ODataClient.cs index 18df1de..e0bffb9 100644 --- a/src/ODataHttpClient/ODataClient.cs +++ b/src/ODataHttpClient/ODataClient.cs @@ -40,7 +40,7 @@ public ODataClient(HttpClient httpClient, ICredentialBuilder credentialBuilder, RequestFactory = new RequestFactory(serializer); } - protected async Task ParseAsync(HttpStatusCode status, HttpContent content, HttpRequestHeaders headers = null) + protected async Task ParseAsync(HttpStatusCode status, HttpContent content, HttpResponseHeaders headers = null) { var code = (int)status; var body = content != null ? await content.ReadAsByteArrayAsync() : null; @@ -55,7 +55,7 @@ protected async Task ParseAsync(HttpStatusCode status, HttpContent con return Response.CreateSuccess(status, mime, body, headers); } - protected async Task> ParseMultiAsync(MultipartMemoryStreamProvider multipart, HttpRequestHeaders headers = null) + protected async Task> ParseMultiAsync(MultipartMemoryStreamProvider multipart, HttpResponseHeaders headers = null) { var result = new List(); foreach (var content in multipart.Contents) @@ -87,7 +87,7 @@ public async Task SendAsync(IRequest request) var response = await _httpClient.SendAsync(message); - return await ParseAsync(response.StatusCode, response.Content, request.Headers); + return await ParseAsync(response.StatusCode, response.Content, response.Headers); } public async Task> SendAsync(IBatchRequest batchRequest) { @@ -103,11 +103,11 @@ public async Task> BatchAsync(IBatchRequest request) var response = await _httpClient.SendAsync(message); if (!response.Content.IsMimeMultipartContent()) - return new[] { await ParseAsync(response.StatusCode, response.Content, request.Headers) }; + return new[] { await ParseAsync(response.StatusCode, response.Content, response.Headers) }; var multipart = await response.Content.ReadAsMultipartAsync(); - return await ParseMultiAsync(multipart, request.Headers); + return await ParseMultiAsync(multipart, response.Headers); } public static void UseV4Global() From d5dd9aeb5ddbaefa6edd76ae4b77a474ada371f8 Mon Sep 17 00:00:00 2001 From: marc90 Date: Tue, 24 Sep 2019 10:14:40 +0300 Subject: [PATCH 04/35] Add custom header field to each request #8 https://github.com/iwate/ODataHttpClient/issues/8 --- src/ODataHttpClient.Tests/RequestTest.cs | 19 +------------- src/ODataHttpClient/Models/BatchRequest.cs | 15 ----------- src/ODataHttpClient/Models/IRequest.cs | 2 -- src/ODataHttpClient/Models/Request.cs | 28 +++----------------- src/ODataHttpClient/ODataClient.cs | 30 +++++++++++++++++----- 5 files changed, 27 insertions(+), 67 deletions(-) diff --git a/src/ODataHttpClient.Tests/RequestTest.cs b/src/ODataHttpClient.Tests/RequestTest.cs index 45b2f9d..85e47c3 100644 --- a/src/ODataHttpClient.Tests/RequestTest.cs +++ b/src/ODataHttpClient.Tests/RequestTest.cs @@ -165,24 +165,7 @@ public void BatchRequest() Assert.Equal("1", req1.Headers.GetValues("Content-ID")?.FirstOrDefault()); Assert.Equal("2", req2.Headers.GetValues("Content-ID")?.FirstOrDefault()); } - [Fact] - public void BatchRequestWithHeader() - { - var message = new BatchRequest(batchUri) - { - Requests = - { - Request.Post(uri, new {}), - Request.Post(uri, new {}) - } - }.CreateMessage(HeadersFactory.Create( - new[] { headerKey }, - new[] { headerValue })); - - Assert.True(message.Content.IsMimeMultipartContent()); - Assert.True(message.Headers.Contains(headerKey)); - } - [Fact] + [Fact] public void CreateRequestWithHeaderByFactory() { var body = "text"; diff --git a/src/ODataHttpClient/Models/BatchRequest.cs b/src/ODataHttpClient/Models/BatchRequest.cs index 7fdc5b8..d6751d3 100644 --- a/src/ODataHttpClient/Models/BatchRequest.cs +++ b/src/ODataHttpClient/Models/BatchRequest.cs @@ -71,20 +71,5 @@ public HttpRequestMessage CreateMessage() return message; } - - public HttpRequestMessage CreateMessage(HttpRequestHeaders headers) - { - var message = new HttpRequestMessage(HttpMethod.Post, Uri) - { - Content = CreateContent() - }; - - message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("multipart/mixed")); - if (headers is null) return message; - foreach (var header in headers) - message.Headers.Add(header.Key, header.Value); - - return message; - } } } diff --git a/src/ODataHttpClient/Models/IRequest.cs b/src/ODataHttpClient/Models/IRequest.cs index 8cee7cf..cb62367 100644 --- a/src/ODataHttpClient/Models/IRequest.cs +++ b/src/ODataHttpClient/Models/IRequest.cs @@ -5,8 +5,6 @@ namespace ODataHttpClient.Models { public interface IRequest { - HttpRequestHeaders Headers { get; } HttpRequestMessage CreateMessage(); - HttpRequestMessage CreateMessage(HttpRequestHeaders headers); } } diff --git a/src/ODataHttpClient/Models/Request.cs b/src/ODataHttpClient/Models/Request.cs index 4da5887..c2aab5f 100644 --- a/src/ODataHttpClient/Models/Request.cs +++ b/src/ODataHttpClient/Models/Request.cs @@ -25,7 +25,9 @@ public HttpRequestMessage CreateMessage() { var message = new HttpRequestMessage(Method, Uri); message.Version = new Version(1, 1); - InitMessageHeaders(null, message); + message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream")); + message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain")); if (Body != null) message.Content = new StringContent(Body, Encoding.UTF8, MediaType); @@ -33,30 +35,6 @@ public HttpRequestMessage CreateMessage() return message; } - public HttpRequestMessage CreateMessage(HttpRequestHeaders headers) - { - var message = new HttpRequestMessage(Method, Uri); - message.Version = new Version(1, 1); - InitMessageHeaders(headers, message); - - if (Body != null) - message.Content = new StringContent(Body, Encoding.UTF8, MediaType); - - return message; - } - - private static void InitMessageHeaders(HttpRequestHeaders headers, HttpRequestMessage message) - { - message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream")); - message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain")); - - if (headers is null) return; - foreach (var header in headers) - message.Headers.Add(header.Key, header.Value); - } - - public static Request Create(HttpMethod method, string uri) { return new Request diff --git a/src/ODataHttpClient/ODataClient.cs b/src/ODataHttpClient/ODataClient.cs index e0bffb9..130f323 100644 --- a/src/ODataHttpClient/ODataClient.cs +++ b/src/ODataHttpClient/ODataClient.cs @@ -67,13 +67,13 @@ protected async Task> ParseMultiAsync(MultipartMemoryStrea var part = await content.ReadAsHttpResponseMessageAsync(); - result.Add(await ParseAsync(part.StatusCode, part.Content)); + result.Add(await ParseAsync(part.StatusCode, part.Content, headers)); } else if (content.IsMimeMultipartContent()) { var children = await content.ReadAsMultipartAsync(); - result.AddRange(await ParseMultiAsync(children)); + result.AddRange(await ParseMultiAsync(children, headers)); } } return result; @@ -81,8 +81,8 @@ protected async Task> ParseMultiAsync(MultipartMemoryStrea public async Task SendAsync(IRequest request) { - var message = request.CreateMessage(request.Headers); - + var message = request.CreateMessage(); + SetUpHeaders(request as Request, message); _credentialBuilder?.Build(_httpClient, message); var response = await _httpClient.SendAsync(message); @@ -95,10 +95,10 @@ public async Task> SendAsync(IBatchRequest batchRequest) } public async Task> BatchAsync(IBatchRequest request) { - var message = request.CreateMessage(request.Headers); - + var message = request.CreateMessage(); message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); _credentialBuilder?.Build(_httpClient, message); + SetUpHeaders(request as BatchRequest, message); var response = await _httpClient.SendAsync(message); @@ -109,11 +109,27 @@ public async Task> BatchAsync(IBatchRequest request) return await ParseMultiAsync(multipart, response.Headers); } - public static void UseV4Global() { JsonSerializer.Default = JsonSerializer.General; Request.Parameterizer = new ODataV4Parameterizer(); } + + private static void SetUpHeaders(Request request, HttpRequestMessage message) + { + if (request?.Headers == null) + { + return; + } + foreach (var header in request.Headers) message.Headers.Add(header.Key, header.Value); + } + private static void SetUpHeaders(BatchRequest request, HttpRequestMessage message) + { + if (request?.Headers == null) + { + return; + } + foreach (var header in request.Headers) message.Headers.Add(header.Key, header.Value); + } } } From 5ea174caa9a293d1c015a4ab3a344566392955ef Mon Sep 17 00:00:00 2001 From: yoshiyuki taniguchi Date: Wed, 25 Sep 2019 12:08:18 +0900 Subject: [PATCH 05/35] remove unused using --- src/ODataHttpClient/Models/IRequest.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ODataHttpClient/Models/IRequest.cs b/src/ODataHttpClient/Models/IRequest.cs index cb62367..5210c21 100644 --- a/src/ODataHttpClient/Models/IRequest.cs +++ b/src/ODataHttpClient/Models/IRequest.cs @@ -1,5 +1,4 @@ using System.Net.Http; -using System.Net.Http.Headers; namespace ODataHttpClient.Models { From 59d1b61d1f09446a9f8e699c4e421e49ad903d4d Mon Sep 17 00:00:00 2001 From: yoshiyuki taniguchi Date: Wed, 25 Sep 2019 12:09:52 +0900 Subject: [PATCH 06/35] change HttpRequestHeaders to IReadOnlyDictionary reason: HttpRequestHeaders ctor is internal. --- src/ODataHttpClient.Tests/RequestTest.cs | 45 ++++++++------------ src/ODataHttpClient/Models/BatchRequest.cs | 2 +- src/ODataHttpClient/Models/HeadersFactory.cs | 30 ------------- src/ODataHttpClient/Models/Request.cs | 32 +++++++------- src/ODataHttpClient/Models/RequestFactory.cs | 10 ++--- 5 files changed, 37 insertions(+), 82 deletions(-) delete mode 100644 src/ODataHttpClient/Models/HeadersFactory.cs diff --git a/src/ODataHttpClient.Tests/RequestTest.cs b/src/ODataHttpClient.Tests/RequestTest.cs index 85e47c3..96a44d1 100644 --- a/src/ODataHttpClient.Tests/RequestTest.cs +++ b/src/ODataHttpClient.Tests/RequestTest.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Net.Http.Headers; @@ -12,6 +13,8 @@ public class RequestTest const string batchUri = "http://services.odata.org/V3/OData/OData.svc/$batch"; const string headerKey = "If-Match"; const string headerValue = "*"; + static IReadOnlyDictionary headers = new Dictionary { [headerKey] = headerValue }; + [Fact] public void NonBodyRequest() { @@ -50,11 +53,9 @@ public void CreateGetRequest() [Fact] public void CreateGetRequestWithHeader() { - var request = Request.Get(uri, HeadersFactory.Create( - new[] { headerKey }, - new[] { headerValue })); + var request = Request.Get(uri, headers); Assert.Equal(HttpMethod.Get, request.Method); - Assert.True(request.Headers.Contains(headerKey)); + Assert.True(((Request)request).Headers.ContainsKey(headerKey)); } [Fact] public void CreateHeadRequest() @@ -65,11 +66,9 @@ public void CreateHeadRequest() [Fact] public void CreateHeadRequestWithHeader() { - var request = Request.Head(uri, HeadersFactory.Create( - new[] { headerKey }, - new[] { headerValue })); + var request = Request.Head(uri, headers); Assert.Equal(HttpMethod.Head, request.Method); - Assert.True(request.Headers.Contains(headerKey)); + Assert.True(((Request)request).Headers.ContainsKey(headerKey)); } [Fact] public void CreateDeleteRequest() @@ -80,11 +79,9 @@ public void CreateDeleteRequest() [Fact] public void CreateDeleteRequestWithHeader() { - var request = Request.Delete(uri, HeadersFactory.Create( - new[] { headerKey }, - new[] { headerValue })); + var request = Request.Delete(uri, headers); Assert.Equal(HttpMethod.Delete, request.Method); - Assert.True(request.Headers.Contains(headerKey)); + Assert.True(((Request)request).Headers.ContainsKey(headerKey)); } [Fact] public void CreatePostRequest() @@ -95,11 +92,9 @@ public void CreatePostRequest() [Fact] public void CreatePostRequestWithHeader() { - var request = Request.Post(uri, new { }, HeadersFactory.Create( - new string[] { headerKey }, - new string[] { headerValue })); + var request = Request.Post(uri, new { }, headers); Assert.Equal(HttpMethod.Post, request.Method); - Assert.True(request.Headers.Contains(headerKey)); + Assert.True(((Request)request).Headers.ContainsKey(headerKey)); } [Fact] public void CreatePutRequest() @@ -110,11 +105,9 @@ public void CreatePutRequest() [Fact] public void CreatePutRequestWithHeader() { - var request = Request.Put(uri, new { }, HeadersFactory.Create( - new[] { headerKey }, - new[] { headerValue })); + var request = Request.Put(uri, new { }, headers); Assert.Equal(HttpMethod.Put, request.Method); - Assert.True(request.Headers.Contains(headerKey)); + Assert.True(((Request)request).Headers.ContainsKey(headerKey)); } [Fact] public void CreatePatchRequest() @@ -125,11 +118,9 @@ public void CreatePatchRequest() [Fact] public void CreatePatchRequestWithHeader() { - var request = Request.Patch(uri, new { }, HeadersFactory.Create( - new[] { headerKey }, - new[] { headerValue })); + var request = Request.Patch(uri, new { }, headers); Assert.Equal(new HttpMethod("PATCH"), request.Method); - Assert.True(request.Headers.Contains(headerKey)); + Assert.True(((Request)request).Headers.ContainsKey(headerKey)); } [Fact] public void BatchRequest() @@ -171,11 +162,9 @@ public void CreateRequestWithHeaderByFactory() var body = "text"; var request = new RequestFactory() .Create(HttpMethod.Get, uri, - body, HeadersFactory.Create( - new[] { headerKey }, - new[] { headerValue }), null); + body, headers, null); Assert.Equal(HttpMethod.Get, request.Method); - Assert.True(request.Headers.Contains(headerKey)); + Assert.True(((Request)request).Headers.ContainsKey(headerKey)); } } } \ No newline at end of file diff --git a/src/ODataHttpClient/Models/BatchRequest.cs b/src/ODataHttpClient/Models/BatchRequest.cs index d6751d3..5dfa16f 100644 --- a/src/ODataHttpClient/Models/BatchRequest.cs +++ b/src/ODataHttpClient/Models/BatchRequest.cs @@ -10,7 +10,7 @@ public class BatchRequest : IBatchRequest { public string Uri { get; } public ICollection Requests { get; set; } - public HttpRequestHeaders Headers { get; private set; } + public IReadOnlyDictionary Headers { get; private set; } public BatchRequest(string uri) { Uri = uri; diff --git a/src/ODataHttpClient/Models/HeadersFactory.cs b/src/ODataHttpClient/Models/HeadersFactory.cs deleted file mode 100644 index 93c1982..0000000 --- a/src/ODataHttpClient/Models/HeadersFactory.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using System.Net.Http; -using System.Net.Http.Headers; - -namespace ODataHttpClient.Models -{ - public static class HeadersFactory - { - public static HttpRequestHeaders Create(string[] keys, string[] values) - { - var headers = new HttpRequestMessage().Headers; - if (keys.Length != values.Length) - return headers; - - for (int i = 0; i < keys.Length; i++) - headers.TryAddWithoutValidation(keys[i], values[i]); - - return headers; - } - - public static HttpRequestHeaders Create(IDictionary keyValues) - { - var headers = new HttpRequestMessage().Headers; - foreach (var pair in keyValues) - headers.TryAddWithoutValidation(pair.Key, pair.Value); - - return headers; - } - } -} \ No newline at end of file diff --git a/src/ODataHttpClient/Models/Request.cs b/src/ODataHttpClient/Models/Request.cs index c2aab5f..7d7a341 100644 --- a/src/ODataHttpClient/Models/Request.cs +++ b/src/ODataHttpClient/Models/Request.cs @@ -14,7 +14,7 @@ public class Request : IRequest internal const string DEFAULT_TYPE_KEY = "odata.type"; private static Type stringType = typeof(string); public HttpMethod Method { get; private set; } - public HttpRequestHeaders Headers { get; private set; } + public IReadOnlyDictionary Headers { get; private set; } public string Uri { get; private set; } public string MediaType { get; private set; } public string Body { get; private set; } @@ -45,7 +45,7 @@ public static Request Create(HttpMethod method, string uri) }; } - public static Request Create(HttpMethod method, string uri, HttpRequestHeaders headers) + public static Request Create(HttpMethod method, string uri, IReadOnlyDictionary headers) { return new Request { @@ -56,12 +56,12 @@ public static Request Create(HttpMethod method, string uri, HttpRequestHeaders h }; } - public static Request Create(HttpMethod method, string uri, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null, HttpRequestHeaders headers = null) + public static Request Create(HttpMethod method, string uri, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null, IReadOnlyDictionary headers = null) { return Create(method, uri, body, type != null ? new[] { new KeyValuePair(typeKey, type) } : null, serializer ?? JsonSerializer.Default, headers); } - public static Request Create(HttpMethod method, string uri, T body, IEnumerable> additionals, IJsonSerializer serializer, HttpRequestHeaders headers = null) + public static Request Create(HttpMethod method, string uri, T body, IEnumerable> additionals, IJsonSerializer serializer, IReadOnlyDictionary headers = null) { string content, mime = null; @@ -97,18 +97,18 @@ public static Request Create(HttpMethod method, string uri, T body, IEnumerab public static Request Get(string uri) => Create(HttpMethod.Get, uri); public static Request Get(string uri, object @params) => Get(Parameterizer.Parameterize(uri, @params)); - public static Request Get(string uri, HttpRequestHeaders headers) => Create(HttpMethod.Get, uri, headers); - public static Request Get(string uri, object @params, HttpRequestHeaders headers) => Get(Parameterizer.Parameterize(uri, @params), headers); + public static Request Get(string uri, IReadOnlyDictionary headers) => Create(HttpMethod.Get, uri, headers); + public static Request Get(string uri, object @params, IReadOnlyDictionary headers) => Get(Parameterizer.Parameterize(uri, @params), headers); public static Request Head(string uri) => Create(HttpMethod.Head, uri); public static Request Head(string uri, object @params) => Head(Parameterizer.Parameterize(uri, @params)); - public static Request Head(string uri, HttpRequestHeaders headers) => Create(HttpMethod.Head, uri, headers); - public static Request Head(string uri, object @params, HttpRequestHeaders headers) => Head(Parameterizer.Parameterize(uri, @params), headers); + public static Request Head(string uri, IReadOnlyDictionary headers) => Create(HttpMethod.Head, uri, headers); + public static Request Head(string uri, object @params, IReadOnlyDictionary headers) => Head(Parameterizer.Parameterize(uri, @params), headers); public static Request Delete(string uri) => Create(HttpMethod.Delete, uri); public static Request Delete(string uri, object @params) => Delete(Parameterizer.Parameterize(uri, @params)); - public static Request Delete(string uri, HttpRequestHeaders headers) => Create(HttpMethod.Delete, uri, headers); - public static Request Delete(string uri, object @params, HttpRequestHeaders headers) => Delete(Parameterizer.Parameterize(uri, @params), headers); + public static Request Delete(string uri, IReadOnlyDictionary headers) => Create(HttpMethod.Delete, uri, headers); + public static Request Delete(string uri, object @params, IReadOnlyDictionary headers) => Delete(Parameterizer.Parameterize(uri, @params), headers); public static Request Post(string uri, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) => Create(HttpMethod.Post, uri, body, type, typeKey, serializer); @@ -116,10 +116,10 @@ public static Request Post(string uri, T body, string type = null, string typ public static Request Post(string uri, object @params, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) => Post(Parameterizer.Parameterize(uri, @params), body, type, typeKey, serializer); - public static Request Post(string uri, T body, HttpRequestHeaders headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + public static Request Post(string uri, T body, IReadOnlyDictionary headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) => Create(HttpMethod.Post, uri, body, type, typeKey, serializer, headers); - public static Request Post(string uri, object @params, T body, HttpRequestHeaders headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + public static Request Post(string uri, object @params, T body, IReadOnlyDictionary headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) => Post(Parameterizer.Parameterize(uri, @params), body, headers, type, typeKey, serializer); public static Request Put(string uri, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) @@ -128,10 +128,10 @@ public static Request Put(string uri, T body, string type = null, string type public static Request Put(string uri, object @params, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) => Put(Parameterizer.Parameterize(uri, @params), body, type, typeKey, serializer); - public static Request Put(string uri, object @params, T body, HttpRequestHeaders headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + public static Request Put(string uri, object @params, T body, IReadOnlyDictionary headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) => Put(Parameterizer.Parameterize(uri, @params), body, headers, type, typeKey, serializer); - public static Request Put(string uri, T body, HttpRequestHeaders headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + public static Request Put(string uri, T body, IReadOnlyDictionary headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) => Create(HttpMethod.Put, uri, body, type, typeKey, serializer, headers); public static Request Patch(string uri, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) @@ -140,10 +140,10 @@ public static Request Patch(string uri, T body, string type = null, string ty public static Request Patch(string uri, object @params, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) => Patch(Parameterizer.Parameterize(uri, @params), body, type, typeKey, serializer); - public static Request Patch(string uri, T body, HttpRequestHeaders headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + public static Request Patch(string uri, T body, IReadOnlyDictionary headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) => Create(new HttpMethod("PATCH"), uri, body, type, typeKey, serializer, headers); - public static Request Patch(string uri, object @params, T body, HttpRequestHeaders headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + public static Request Patch(string uri, object @params, T body, IReadOnlyDictionary headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) => Patch(Parameterizer.Parameterize(uri, @params), body, headers, type, typeKey, serializer); } } diff --git a/src/ODataHttpClient/Models/RequestFactory.cs b/src/ODataHttpClient/Models/RequestFactory.cs index 8906ed7..871264d 100644 --- a/src/ODataHttpClient/Models/RequestFactory.cs +++ b/src/ODataHttpClient/Models/RequestFactory.cs @@ -21,15 +21,11 @@ public Request Create(HttpMethod method, string uri, T body, IEnumerable Request.Create(method, uri, body, additionals, JsonSerializer); public Request Create(HttpMethod method, string uri, T body, string type = null, string typeKey = Request.DEFAULT_TYPE_KEY) => Request.Create(method, uri, body, type, typeKey, JsonSerializer); - public Request Create(HttpMethod method, string uri, T body, HttpRequestHeaders headers, IEnumerable> additionals) + public Request Create(HttpMethod method, string uri, T body, IReadOnlyDictionary headers, IEnumerable> additionals) => Request.Create(method, uri, body, additionals, JsonSerializer, headers); - public Request Create(HttpMethod method, string uri, T body, HttpRequestHeaders headers, string type = null, string typeKey = Request.DEFAULT_TYPE_KEY) + public Request Create(HttpMethod method, string uri, T body, IReadOnlyDictionary headers, string type = null, string typeKey = Request.DEFAULT_TYPE_KEY) => Request.Create(method, uri, body, type, typeKey, JsonSerializer, headers); - public Request Create(HttpMethod method, string uri, T body, IDictionary headers, IEnumerable> additionals) - => Request.Create(method, uri, body, additionals, JsonSerializer, HeadersFactory.Create(headers)); - public Request Create(HttpMethod method, string uri, T body, IDictionary headers, string type = null, string typeKey = Request.DEFAULT_TYPE_KEY) - => Request.Create(method, uri, body, type, typeKey, JsonSerializer, HeadersFactory.Create(headers)); - + public Request Get(string uri) => Request.Get(uri); From b73ab19a070a42bb71877e6f059be70eec67d0f2 Mon Sep 17 00:00:00 2001 From: yoshiyuki taniguchi Date: Wed, 25 Sep 2019 12:21:50 +0900 Subject: [PATCH 07/35] reformat file --- src/ODataHttpClient/Models/Request.cs | 124 ++++++++++++------------- src/ODataHttpClient/Models/Response.cs | 6 +- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/src/ODataHttpClient/Models/Request.cs b/src/ODataHttpClient/Models/Request.cs index 7d7a341..fd54a9a 100644 --- a/src/ODataHttpClient/Models/Request.cs +++ b/src/ODataHttpClient/Models/Request.cs @@ -9,50 +9,50 @@ namespace ODataHttpClient.Models { - public class Request : IRequest + public class Request : IRequest { internal const string DEFAULT_TYPE_KEY = "odata.type"; private static Type stringType = typeof(string); public HttpMethod Method { get; private set; } - public IReadOnlyDictionary Headers { get; private set; } - public string Uri { get; private set; } + public IReadOnlyDictionary Headers { get; private set; } + public string Uri { get; private set; } public string MediaType { get; private set; } public string Body { get; private set; } - private Request(){} - + private Request() { } + public HttpRequestMessage CreateMessage() { - var message = new HttpRequestMessage(Method, Uri); - message.Version = new Version(1, 1); - message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream")); - message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain")); - - if (Body != null) - message.Content = new StringContent(Body, Encoding.UTF8, MediaType); - - return message; + var message = new HttpRequestMessage(Method, Uri); + message.Version = new Version(1, 1); + message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream")); + message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain")); + + if (Body != null) + message.Content = new StringContent(Body, Encoding.UTF8, MediaType); + + return message; } - public static Request Create(HttpMethod method, string uri) - { - return new Request - { - Method = method, - Uri = uri, - Body = null - }; - } - - public static Request Create(HttpMethod method, string uri, IReadOnlyDictionary headers) + public static Request Create(HttpMethod method, string uri) + { + return new Request + { + Method = method, + Uri = uri, + Body = null + }; + } + + public static Request Create(HttpMethod method, string uri, IReadOnlyDictionary headers) { return new Request { Method = method, Uri = uri, Body = null, - Headers = headers + Headers = headers }; } @@ -61,10 +61,10 @@ public static Request Create(HttpMethod method, string uri, T body, string ty return Create(method, uri, body, type != null ? new[] { new KeyValuePair(typeKey, type) } : null, serializer ?? JsonSerializer.Default, headers); } - public static Request Create(HttpMethod method, string uri, T body, IEnumerable> additionals, IJsonSerializer serializer, IReadOnlyDictionary headers = null) + public static Request Create(HttpMethod method, string uri, T body, IEnumerable> additionals, IJsonSerializer serializer, IReadOnlyDictionary headers = null) { - string content, mime = null; - + string content, mime = null; + var type = typeof(T); if (type.IsValueType || type == stringType) @@ -89,61 +89,61 @@ public static Request Create(HttpMethod method, string uri, T body, IEnumerab Uri = uri, MediaType = mime, Body = content, - Headers = headers + Headers = headers }; } public static IParameterizer Parameterizer { get; set; } = new ODataParameterizer(); - + public static Request Get(string uri) => Create(HttpMethod.Get, uri); public static Request Get(string uri, object @params) => Get(Parameterizer.Parameterize(uri, @params)); - public static Request Get(string uri, IReadOnlyDictionary headers) => Create(HttpMethod.Get, uri, headers); - public static Request Get(string uri, object @params, IReadOnlyDictionary headers) => Get(Parameterizer.Parameterize(uri, @params), headers); + public static Request Get(string uri, IReadOnlyDictionary headers) => Create(HttpMethod.Get, uri, headers); + public static Request Get(string uri, object @params, IReadOnlyDictionary headers) => Get(Parameterizer.Parameterize(uri, @params), headers); - public static Request Head(string uri) => Create(HttpMethod.Head, uri); + public static Request Head(string uri) => Create(HttpMethod.Head, uri); public static Request Head(string uri, object @params) => Head(Parameterizer.Parameterize(uri, @params)); - public static Request Head(string uri, IReadOnlyDictionary headers) => Create(HttpMethod.Head, uri, headers); - public static Request Head(string uri, object @params, IReadOnlyDictionary headers) => Head(Parameterizer.Parameterize(uri, @params), headers); + public static Request Head(string uri, IReadOnlyDictionary headers) => Create(HttpMethod.Head, uri, headers); + public static Request Head(string uri, object @params, IReadOnlyDictionary headers) => Head(Parameterizer.Parameterize(uri, @params), headers); - public static Request Delete(string uri) => Create(HttpMethod.Delete, uri); + public static Request Delete(string uri) => Create(HttpMethod.Delete, uri); public static Request Delete(string uri, object @params) => Delete(Parameterizer.Parameterize(uri, @params)); - public static Request Delete(string uri, IReadOnlyDictionary headers) => Create(HttpMethod.Delete, uri, headers); - public static Request Delete(string uri, object @params, IReadOnlyDictionary headers) => Delete(Parameterizer.Parameterize(uri, @params), headers); + public static Request Delete(string uri, IReadOnlyDictionary headers) => Create(HttpMethod.Delete, uri, headers); + public static Request Delete(string uri, object @params, IReadOnlyDictionary headers) => Delete(Parameterizer.Parameterize(uri, @params), headers); - public static Request Post(string uri, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + public static Request Post(string uri, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) => Create(HttpMethod.Post, uri, body, type, typeKey, serializer); - - public static Request Post(string uri, object @params, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + + public static Request Post(string uri, object @params, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) => Post(Parameterizer.Parameterize(uri, @params), body, type, typeKey, serializer); - public static Request Post(string uri, T body, IReadOnlyDictionary headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) - => Create(HttpMethod.Post, uri, body, type, typeKey, serializer, headers); + public static Request Post(string uri, T body, IReadOnlyDictionary headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + => Create(HttpMethod.Post, uri, body, type, typeKey, serializer, headers); - public static Request Post(string uri, object @params, T body, IReadOnlyDictionary headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) - => Post(Parameterizer.Parameterize(uri, @params), body, headers, type, typeKey, serializer); + public static Request Post(string uri, object @params, T body, IReadOnlyDictionary headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + => Post(Parameterizer.Parameterize(uri, @params), body, headers, type, typeKey, serializer); - public static Request Put(string uri, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + public static Request Put(string uri, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) => Create(HttpMethod.Put, uri, body, type, typeKey, serializer); - public static Request Put(string uri, object @params, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) - => Put(Parameterizer.Parameterize(uri, @params), body, type, typeKey, serializer); + public static Request Put(string uri, object @params, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + => Put(Parameterizer.Parameterize(uri, @params), body, type, typeKey, serializer); - public static Request Put(string uri, object @params, T body, IReadOnlyDictionary headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) - => Put(Parameterizer.Parameterize(uri, @params), body, headers, type, typeKey, serializer); + public static Request Put(string uri, object @params, T body, IReadOnlyDictionary headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + => Put(Parameterizer.Parameterize(uri, @params), body, headers, type, typeKey, serializer); - public static Request Put(string uri, T body, IReadOnlyDictionary headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) - => Create(HttpMethod.Put, uri, body, type, typeKey, serializer, headers); + public static Request Put(string uri, T body, IReadOnlyDictionary headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + => Create(HttpMethod.Put, uri, body, type, typeKey, serializer, headers); - public static Request Patch(string uri, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + public static Request Patch(string uri, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) => Create(new HttpMethod("PATCH"), uri, body, type, typeKey, serializer); - - public static Request Patch(string uri, object @params, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + + public static Request Patch(string uri, object @params, T body, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) => Patch(Parameterizer.Parameterize(uri, @params), body, type, typeKey, serializer); - public static Request Patch(string uri, T body, IReadOnlyDictionary headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) - => Create(new HttpMethod("PATCH"), uri, body, type, typeKey, serializer, headers); + public static Request Patch(string uri, T body, IReadOnlyDictionary headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + => Create(new HttpMethod("PATCH"), uri, body, type, typeKey, serializer, headers); - public static Request Patch(string uri, object @params, T body, IReadOnlyDictionary headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) - => Patch(Parameterizer.Parameterize(uri, @params), body, headers, type, typeKey, serializer); - } + public static Request Patch(string uri, object @params, T body, IReadOnlyDictionary headers, string type = null, string typeKey = DEFAULT_TYPE_KEY, IJsonSerializer serializer = null) + => Patch(Parameterizer.Parameterize(uri, @params), body, headers, type, typeKey, serializer); + } } diff --git a/src/ODataHttpClient/Models/Response.cs b/src/ODataHttpClient/Models/Response.cs index 473485c..1191d8d 100644 --- a/src/ODataHttpClient/Models/Response.cs +++ b/src/ODataHttpClient/Models/Response.cs @@ -16,9 +16,9 @@ public class Response public string ErrorMessage { get; private set; } public byte[] Binary { get; private set; } public string Body { get => Binary != null ? Encoding.UTF8.GetString(Binary) : null; } - public HttpResponseHeaders Headers { get; private set; } + public HttpResponseHeaders Headers { get; private set; } - private Response(){} + private Response() { } public T ReadAs(string jsonPath = null) { @@ -105,5 +105,5 @@ public static Response CreateSuccess(HttpStatusCode code, string mime, byte[] bo { return new Response { Success = true, StatusCode = code, MediaType = mime, Binary = body, _serializer = serializer, Headers = headers }; } - } + } } From 8631a02cef9f0f41ca8679dbbfdca2a372c88bd9 Mon Sep 17 00:00:00 2001 From: yoshiyuki taniguchi Date: Wed, 25 Sep 2019 12:27:43 +0900 Subject: [PATCH 08/35] move addition accept header --- src/ODataHttpClient/Models/BatchRequest.cs | 1 + src/ODataHttpClient/ODataClient.cs | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ODataHttpClient/Models/BatchRequest.cs b/src/ODataHttpClient/Models/BatchRequest.cs index 5dfa16f..3c6a9fb 100644 --- a/src/ODataHttpClient/Models/BatchRequest.cs +++ b/src/ODataHttpClient/Models/BatchRequest.cs @@ -68,6 +68,7 @@ public HttpRequestMessage CreateMessage() }; message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("multipart/mixed")); + message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); return message; } diff --git a/src/ODataHttpClient/ODataClient.cs b/src/ODataHttpClient/ODataClient.cs index 130f323..26c25d1 100644 --- a/src/ODataHttpClient/ODataClient.cs +++ b/src/ODataHttpClient/ODataClient.cs @@ -96,7 +96,6 @@ public async Task> SendAsync(IBatchRequest batchRequest) public async Task> BatchAsync(IBatchRequest request) { var message = request.CreateMessage(); - message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); _credentialBuilder?.Build(_httpClient, message); SetUpHeaders(request as BatchRequest, message); From e9eab42c90ec583167119cdfc0149f5308522161 Mon Sep 17 00:00:00 2001 From: yoshiyuki taniguchi Date: Wed, 25 Sep 2019 12:32:06 +0900 Subject: [PATCH 09/35] move setup headers --- src/ODataHttpClient/Models/BatchRequest.cs | 17 ++++++++++++----- src/ODataHttpClient/Models/Request.cs | 6 ++++++ src/ODataHttpClient/ODataClient.cs | 19 ------------------- 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/src/ODataHttpClient/Models/BatchRequest.cs b/src/ODataHttpClient/Models/BatchRequest.cs index 3c6a9fb..6049fdd 100644 --- a/src/ODataHttpClient/Models/BatchRequest.cs +++ b/src/ODataHttpClient/Models/BatchRequest.cs @@ -9,7 +9,7 @@ namespace ODataHttpClient.Models public class BatchRequest : IBatchRequest { public string Uri { get; } - public ICollection Requests { get; set; } + public ICollection Requests { get; set; } public IReadOnlyDictionary Headers { get; private set; } public BatchRequest(string uri) { @@ -19,7 +19,8 @@ public BatchRequest(string uri) protected HttpContent CreateContent() { - HttpMessageContent create(IRequest req, int index) { + HttpMessageContent create(IRequest req, int index) + { var message = req.CreateMessage(); message.Headers.Add("Content-ID", $"{index + 1}"); var content = new HttpMessageContent(message); @@ -30,7 +31,7 @@ protected HttpContent CreateContent() MultipartContent batch = new MultipartContent("mixed", "batch" + Guid.NewGuid()); MultipartContent changeset = null; - foreach((var req, int index) in Requests.Select((req, index) => (req, index))) + foreach ((var req, int index) in Requests.Select((req, index) => (req, index))) { if (req.Method == HttpMethod.Get || req.Method == HttpMethod.Head) { @@ -43,14 +44,14 @@ protected HttpContent CreateContent() } else { - if (changeset == null) + if (changeset == null) { changeset = new MultipartContent("mixed", "changeset" + Guid.NewGuid()); } changeset.Add(create(req, index)); } } - + if (changeset != null) { batch.Add(changeset); @@ -70,6 +71,12 @@ public HttpRequestMessage CreateMessage() message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("multipart/mixed")); message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + if (Headers != null) + { + foreach (var pair in Headers) + message.Headers.Add(pair.Key, pair.Value); + } + return message; } } diff --git a/src/ODataHttpClient/Models/Request.cs b/src/ODataHttpClient/Models/Request.cs index fd54a9a..fa1a51b 100644 --- a/src/ODataHttpClient/Models/Request.cs +++ b/src/ODataHttpClient/Models/Request.cs @@ -29,6 +29,12 @@ public HttpRequestMessage CreateMessage() message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream")); message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain")); + if (Headers != null) + { + foreach (var pair in Headers) + message.Headers.Add(pair.Key, pair.Value); + } + if (Body != null) message.Content = new StringContent(Body, Encoding.UTF8, MediaType); diff --git a/src/ODataHttpClient/ODataClient.cs b/src/ODataHttpClient/ODataClient.cs index 26c25d1..c012e1d 100644 --- a/src/ODataHttpClient/ODataClient.cs +++ b/src/ODataHttpClient/ODataClient.cs @@ -82,7 +82,6 @@ protected async Task> ParseMultiAsync(MultipartMemoryStrea public async Task SendAsync(IRequest request) { var message = request.CreateMessage(); - SetUpHeaders(request as Request, message); _credentialBuilder?.Build(_httpClient, message); var response = await _httpClient.SendAsync(message); @@ -97,7 +96,6 @@ public async Task> BatchAsync(IBatchRequest request) { var message = request.CreateMessage(); _credentialBuilder?.Build(_httpClient, message); - SetUpHeaders(request as BatchRequest, message); var response = await _httpClient.SendAsync(message); @@ -113,22 +111,5 @@ public static void UseV4Global() JsonSerializer.Default = JsonSerializer.General; Request.Parameterizer = new ODataV4Parameterizer(); } - - private static void SetUpHeaders(Request request, HttpRequestMessage message) - { - if (request?.Headers == null) - { - return; - } - foreach (var header in request.Headers) message.Headers.Add(header.Key, header.Value); - } - private static void SetUpHeaders(BatchRequest request, HttpRequestMessage message) - { - if (request?.Headers == null) - { - return; - } - foreach (var header in request.Headers) message.Headers.Add(header.Key, header.Value); - } } } From bc4259cbe737521956681cce0df407e0bfbb9ed6 Mon Sep 17 00:00:00 2001 From: yoshiyuki taniguchi Date: Fri, 1 Nov 2019 12:32:33 +0900 Subject: [PATCH 10/35] #10 fix parse error --- src/ODataHttpClient.Tests/ResponseTest.cs | 12 +++++++++++- src/ODataHttpClient/Models/Response.cs | 23 +++++++++++++++++++++-- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/ODataHttpClient.Tests/ResponseTest.cs b/src/ODataHttpClient.Tests/ResponseTest.cs index 5b5f582..d152a57 100644 --- a/src/ODataHttpClient.Tests/ResponseTest.cs +++ b/src/ODataHttpClient.Tests/ResponseTest.cs @@ -2,6 +2,7 @@ using System.IO; using System.Linq; using System.Net; +using System.Text; using ODataHttpClient.Models; using ODataHttpClient.Serializers; using Xunit; @@ -128,7 +129,16 @@ public void ReadBinaryAsStream() Assert.Equal(3, stream.ReadByte()); Assert.Equal(4, stream.ReadByte()); } - + } + + [Fact] + public void ReadBOMTextAsInt() + { + var body = Encoding.UTF8.GetPreamble().Concat(Encoding.UTF8.GetBytes("100")).ToArray(); + var response = Response.CreateSuccess(HttpStatusCode.OK, "text/plain", body); + + Assert.Equal(100, response.ReadAs()); + Assert.Equal(100, response.ReadAs()); } } } \ No newline at end of file diff --git a/src/ODataHttpClient/Models/Response.cs b/src/ODataHttpClient/Models/Response.cs index 1191d8d..b109759 100644 --- a/src/ODataHttpClient/Models/Response.cs +++ b/src/ODataHttpClient/Models/Response.cs @@ -1,6 +1,7 @@ using ODataHttpClient.Serializers; using System; using System.IO; +using System.Linq; using System.Net; using System.Net.Http.Headers; using System.Text; @@ -15,7 +16,7 @@ public class Response public string MediaType { get; private set; } public string ErrorMessage { get; private set; } public byte[] Binary { get; private set; } - public string Body { get => Binary != null ? Encoding.UTF8.GetString(Binary) : null; } + public string Body { get => GetStringFromUTF8(Binary); } public HttpResponseHeaders Headers { get; private set; } private Response() { } @@ -80,9 +81,27 @@ public T ReadAs(string jsonPath, IJsonSerializer serializer) throw new NotSupportedException(); } + private static readonly byte[] _utf8Preamble = Encoding.UTF8.GetPreamble(); + private static bool IsUTF8WithBOM(byte[] binary) => binary.Take(_utf8Preamble.Length).SequenceEqual(_utf8Preamble); + private static (int start, int len) GetUTF8StartAndLength(byte[] binary) + { + if (IsUTF8WithBOM(binary)) + return (_utf8Preamble.Length, binary.Length - _utf8Preamble.Length); + + return (0, binary.Length); + } + public static string GetStringFromUTF8(byte[] binary) + { + if (binary == null) + return null; + + var (start, len) = GetUTF8StartAndLength(binary); + return Encoding.UTF8.GetString(binary, start, len); + } + public static Response CreateError(HttpStatusCode code, byte[] body, HttpResponseHeaders headers) { - return CreateError(code, body != null ? Encoding.UTF8.GetString(body) : null, headers); + return CreateError(code, GetStringFromUTF8(body), headers); } public static Response CreateError(HttpStatusCode code, string message, HttpResponseHeaders headers) { From eabafc5d5f3b1056064ff5f9a3242ae9216b93e5 Mon Sep 17 00:00:00 2001 From: yoshiyuki taniguchi Date: Fri, 1 Nov 2019 12:32:57 +0900 Subject: [PATCH 11/35] version up --- src/ODataHttpClient/ODataHttpClient.csproj | 2 +- src/ODataHttpClient/ODataHttpClient.nuspec | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ODataHttpClient/ODataHttpClient.csproj b/src/ODataHttpClient/ODataHttpClient.csproj index 5e15105..2ddeac8 100644 --- a/src/ODataHttpClient/ODataHttpClient.csproj +++ b/src/ODataHttpClient/ODataHttpClient.csproj @@ -2,7 +2,7 @@ ODataHttpClient - 1.6.6 + 1.6.7 netstandard2.0 ODataHttpClient.nuspec diff --git a/src/ODataHttpClient/ODataHttpClient.nuspec b/src/ODataHttpClient/ODataHttpClient.nuspec index 5316e1f..843e177 100644 --- a/src/ODataHttpClient/ODataHttpClient.nuspec +++ b/src/ODataHttpClient/ODataHttpClient.nuspec @@ -11,7 +11,10 @@ https://github.com/iwate/ODataHttpClient/blob/master/LICENSE https://iwate.github.io/ODataHttpClient The simplest implementation of OData client. - + v1.6.6 + + v1.6.7 + - Add additaionl headers + - fix parse error as UTF8 with BOM ++ v1.6.6 - Add constructor - Support any provider has multi format of batch response + v1.6.5 From 02d7609b11da60e392e4ebb911f7643e10bd3e72 Mon Sep 17 00:00:00 2001 From: yoshiyuki taniguchi Date: Fri, 17 Jan 2020 17:43:04 +0900 Subject: [PATCH 12/35] fix multi part response headers --- src/ODataHttpClient/ODataClient.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ODataHttpClient/ODataClient.cs b/src/ODataHttpClient/ODataClient.cs index c012e1d..4c26bd4 100644 --- a/src/ODataHttpClient/ODataClient.cs +++ b/src/ODataHttpClient/ODataClient.cs @@ -55,7 +55,8 @@ protected async Task ParseAsync(HttpStatusCode status, HttpContent con return Response.CreateSuccess(status, mime, body, headers); } - protected async Task> ParseMultiAsync(MultipartMemoryStreamProvider multipart, HttpResponseHeaders headers = null) + + protected async Task> ParseMultiAsync(MultipartMemoryStreamProvider multipart, HttpResponseHeaders headers = null) { var result = new List(); foreach (var content in multipart.Contents) @@ -67,7 +68,7 @@ protected async Task> ParseMultiAsync(MultipartMemoryStrea var part = await content.ReadAsHttpResponseMessageAsync(); - result.Add(await ParseAsync(part.StatusCode, part.Content, headers)); + result.Add(await ParseAsync(part.StatusCode, part.Content, part.Headers)); } else if (content.IsMimeMultipartContent()) { From 5be2033e0ef359c4a0e0810db0ed4f421b180afd Mon Sep 17 00:00:00 2001 From: yoshiyuki taniguchi Date: Mon, 20 Jan 2020 13:48:35 +0900 Subject: [PATCH 13/35] copy content-id #12 if content-id is not in part and is in content, copy it. --- src/ODataHttpClient/ODataClient.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ODataHttpClient/ODataClient.cs b/src/ODataHttpClient/ODataClient.cs index 4c26bd4..5e99abe 100644 --- a/src/ODataHttpClient/ODataClient.cs +++ b/src/ODataHttpClient/ODataClient.cs @@ -68,6 +68,12 @@ protected async Task> ParseMultiAsync(MultipartMemoryStrea var part = await content.ReadAsHttpResponseMessageAsync(); + if (!part.Headers.Contains("Content-ID") + && content.Headers.TryGetValues("Content-ID", out var contentId)) + { + part.Headers.Add("Content-ID", contentId); + } + result.Add(await ParseAsync(part.StatusCode, part.Content, part.Headers)); } else if (content.IsMimeMultipartContent()) From 427033b516700ac4136ed52c7a4b8f68d2eee6d8 Mon Sep 17 00:00:00 2001 From: yoshiyuki taniguchi Date: Wed, 22 Jan 2020 16:18:00 +0900 Subject: [PATCH 14/35] version up --- src/ODataHttpClient/ODataHttpClient.csproj | 2 +- src/ODataHttpClient/ODataHttpClient.nuspec | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ODataHttpClient/ODataHttpClient.csproj b/src/ODataHttpClient/ODataHttpClient.csproj index 2ddeac8..fe161e0 100644 --- a/src/ODataHttpClient/ODataHttpClient.csproj +++ b/src/ODataHttpClient/ODataHttpClient.csproj @@ -2,7 +2,7 @@ ODataHttpClient - 1.6.7 + 1.6.8 netstandard2.0 ODataHttpClient.nuspec diff --git a/src/ODataHttpClient/ODataHttpClient.nuspec b/src/ODataHttpClient/ODataHttpClient.nuspec index 843e177..b62a383 100644 --- a/src/ODataHttpClient/ODataHttpClient.nuspec +++ b/src/ODataHttpClient/ODataHttpClient.nuspec @@ -11,7 +11,9 @@ https://github.com/iwate/ODataHttpClient/blob/master/LICENSE https://iwate.github.io/ODataHttpClient The simplest implementation of OData client. - + v1.6.7 + + v1.6.8 + - [Bug fix] Fix response headers of batch ++ v1.6.7 - Add additaionl headers - fix parse error as UTF8 with BOM + v1.6.6 From 942cc8746471c7cddfc5d078f54126ed3eb3e578 Mon Sep 17 00:00:00 2001 From: Takaaki Suzuki Date: Fri, 17 Apr 2020 14:47:16 +0900 Subject: [PATCH 15/35] Allows to cancel SendAsync --- src/ODataHttpClient/ODataClient.cs | 237 +++++++++++++++-------------- 1 file changed, 119 insertions(+), 118 deletions(-) diff --git a/src/ODataHttpClient/ODataClient.cs b/src/ODataHttpClient/ODataClient.cs index 5e99abe..ce982a7 100644 --- a/src/ODataHttpClient/ODataClient.cs +++ b/src/ODataHttpClient/ODataClient.cs @@ -1,122 +1,123 @@ -using ODataHttpClient.Credentials; -using ODataHttpClient.Models; -using ODataHttpClient.Parameterizers; -using ODataHttpClient.Serializers; -using System; -using System.Collections.Generic; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; - -[assembly: CLSCompliant(true)] -namespace ODataHttpClient -{ - public class ODataClient - { - private static readonly NameValueHeaderValue _responseMsgType = new NameValueHeaderValue("msgtype","response"); - private readonly HttpClient _httpClient; - private readonly ICredentialBuilder _credentialBuilder; - public RequestFactory RequestFactory { get; } - public ODataClient(HttpClient httpClient) - : this(httpClient, JsonSerializer.Default) - {} - public ODataClient(HttpClient httpClient, IJsonSerializer serializer) - : this(httpClient, null, serializer) - {} - public ODataClient(HttpClient httpClient, ICredentialBuilder credentialBuilder) - : this(httpClient, credentialBuilder, JsonSerializer.Default) - { } - public ODataClient(HttpClient httpClient, string username, string password) - : this(httpClient, username, password, JsonSerializer.Default) - {} - public ODataClient(HttpClient httpClient, string username, string password, IJsonSerializer serializer) - : this(httpClient, new BasicAuthCredential(username, password), serializer) - {} - public ODataClient(HttpClient httpClient, ICredentialBuilder credentialBuilder, IJsonSerializer serializer) - { - _httpClient = httpClient; - _credentialBuilder = credentialBuilder; - RequestFactory = new RequestFactory(serializer); - } - - protected async Task ParseAsync(HttpStatusCode status, HttpContent content, HttpResponseHeaders headers = null) - { - var code = (int)status; - var body = content != null ? await content.ReadAsByteArrayAsync() : null; - var mime = content?.Headers.ContentType?.MediaType; - - if (code == 404) - return Response.CreateSuccess(status, mime, (byte[])null, headers); - - if (code >= 400) - return Response.CreateError(status, body, headers); - - return Response.CreateSuccess(status, mime, body, headers); - } - - - protected async Task> ParseMultiAsync(MultipartMemoryStreamProvider multipart, HttpResponseHeaders headers = null) - { - var result = new List(); - foreach (var content in multipart.Contents) - { - if (content.Headers.ContentType.MediaType == "application/http") - { - if (!content.Headers.ContentType.Parameters.Contains(_responseMsgType)) - content.Headers.ContentType.Parameters.Add(_responseMsgType); - - var part = await content.ReadAsHttpResponseMessageAsync(); - +using ODataHttpClient.Credentials; +using ODataHttpClient.Models; +using ODataHttpClient.Parameterizers; +using ODataHttpClient.Serializers; +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading; +using System.Threading.Tasks; + +[assembly: CLSCompliant(true)] +namespace ODataHttpClient +{ + public class ODataClient + { + private static readonly NameValueHeaderValue _responseMsgType = new NameValueHeaderValue("msgtype","response"); + private readonly HttpClient _httpClient; + private readonly ICredentialBuilder _credentialBuilder; + public RequestFactory RequestFactory { get; } + public ODataClient(HttpClient httpClient) + : this(httpClient, JsonSerializer.Default) + {} + public ODataClient(HttpClient httpClient, IJsonSerializer serializer) + : this(httpClient, null, serializer) + {} + public ODataClient(HttpClient httpClient, ICredentialBuilder credentialBuilder) + : this(httpClient, credentialBuilder, JsonSerializer.Default) + { } + public ODataClient(HttpClient httpClient, string username, string password) + : this(httpClient, username, password, JsonSerializer.Default) + {} + public ODataClient(HttpClient httpClient, string username, string password, IJsonSerializer serializer) + : this(httpClient, new BasicAuthCredential(username, password), serializer) + {} + public ODataClient(HttpClient httpClient, ICredentialBuilder credentialBuilder, IJsonSerializer serializer) + { + _httpClient = httpClient; + _credentialBuilder = credentialBuilder; + RequestFactory = new RequestFactory(serializer); + } + + protected async Task ParseAsync(HttpStatusCode status, HttpContent content, HttpResponseHeaders headers = null) + { + var code = (int)status; + var body = content != null ? await content.ReadAsByteArrayAsync() : null; + var mime = content?.Headers.ContentType?.MediaType; + + if (code == 404) + return Response.CreateSuccess(status, mime, (byte[])null, headers); + + if (code >= 400) + return Response.CreateError(status, body, headers); + + return Response.CreateSuccess(status, mime, body, headers); + } + + + protected async Task> ParseMultiAsync(MultipartMemoryStreamProvider multipart, HttpResponseHeaders headers = null, CancellationToken cancellationToken = default) + { + var result = new List(); + foreach (var content in multipart.Contents) + { + if (content.Headers.ContentType.MediaType == "application/http") + { + if (!content.Headers.ContentType.Parameters.Contains(_responseMsgType)) + content.Headers.ContentType.Parameters.Add(_responseMsgType); + + var part = await content.ReadAsHttpResponseMessageAsync(cancellationToken); + if (!part.Headers.Contains("Content-ID") && content.Headers.TryGetValues("Content-ID", out var contentId)) { part.Headers.Add("Content-ID", contentId); - } - - result.Add(await ParseAsync(part.StatusCode, part.Content, part.Headers)); - } - else if (content.IsMimeMultipartContent()) - { - var children = await content.ReadAsMultipartAsync(); - - result.AddRange(await ParseMultiAsync(children, headers)); - } - } - return result; - } - - public async Task SendAsync(IRequest request) - { - var message = request.CreateMessage(); - _credentialBuilder?.Build(_httpClient, message); - - var response = await _httpClient.SendAsync(message); - - return await ParseAsync(response.StatusCode, response.Content, response.Headers); - } - public async Task> SendAsync(IBatchRequest batchRequest) - { - return await BatchAsync(batchRequest); - } - public async Task> BatchAsync(IBatchRequest request) - { - var message = request.CreateMessage(); - _credentialBuilder?.Build(_httpClient, message); - - var response = await _httpClient.SendAsync(message); - - if (!response.Content.IsMimeMultipartContent()) - return new[] { await ParseAsync(response.StatusCode, response.Content, response.Headers) }; - - var multipart = await response.Content.ReadAsMultipartAsync(); - - return await ParseMultiAsync(multipart, response.Headers); - } - public static void UseV4Global() - { - JsonSerializer.Default = JsonSerializer.General; - Request.Parameterizer = new ODataV4Parameterizer(); - } - } -} + } + + result.Add(await ParseAsync(part.StatusCode, part.Content, part.Headers)); + } + else if (content.IsMimeMultipartContent()) + { + var children = await content.ReadAsMultipartAsync(cancellationToken); + + result.AddRange(await ParseMultiAsync(children, headers, cancellationToken)); + } + } + return result; + } + + public async Task SendAsync(IRequest request, CancellationToken cancellationToken = default) + { + var message = request.CreateMessage(); + _credentialBuilder?.Build(_httpClient, message); + + var response = await _httpClient.SendAsync(message, cancellationToken); + + return await ParseAsync(response.StatusCode, response.Content, response.Headers); + } + public Task> SendAsync(IBatchRequest batchRequest, CancellationToken cancellationToken = default) + { + return BatchAsync(batchRequest, cancellationToken); + } + public async Task> BatchAsync(IBatchRequest request, CancellationToken cancellationToken = default) + { + var message = request.CreateMessage(); + _credentialBuilder?.Build(_httpClient, message); + + var response = await _httpClient.SendAsync(message, cancellationToken); + + if (!response.Content.IsMimeMultipartContent()) + return new[] { await ParseAsync(response.StatusCode, response.Content, response.Headers) }; + + var multipart = await response.Content.ReadAsMultipartAsync(cancellationToken); + + return await ParseMultiAsync(multipart, response.Headers, cancellationToken); + } + public static void UseV4Global() + { + JsonSerializer.Default = JsonSerializer.General; + Request.Parameterizer = new ODataV4Parameterizer(); + } + } +} From de4b8897d47cd18504687b57ba14748c6f222063 Mon Sep 17 00:00:00 2001 From: Takaaki Suzuki Date: Fri, 17 Apr 2020 15:05:56 +0900 Subject: [PATCH 16/35] Returns more concrete type --- src/ODataHttpClient/ODataClient.cs | 236 ++++++++++++++--------------- 1 file changed, 118 insertions(+), 118 deletions(-) diff --git a/src/ODataHttpClient/ODataClient.cs b/src/ODataHttpClient/ODataClient.cs index 5e99abe..e9a1fc5 100644 --- a/src/ODataHttpClient/ODataClient.cs +++ b/src/ODataHttpClient/ODataClient.cs @@ -1,122 +1,122 @@ -using ODataHttpClient.Credentials; -using ODataHttpClient.Models; -using ODataHttpClient.Parameterizers; -using ODataHttpClient.Serializers; -using System; -using System.Collections.Generic; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; - -[assembly: CLSCompliant(true)] -namespace ODataHttpClient -{ - public class ODataClient - { - private static readonly NameValueHeaderValue _responseMsgType = new NameValueHeaderValue("msgtype","response"); - private readonly HttpClient _httpClient; - private readonly ICredentialBuilder _credentialBuilder; - public RequestFactory RequestFactory { get; } - public ODataClient(HttpClient httpClient) - : this(httpClient, JsonSerializer.Default) - {} - public ODataClient(HttpClient httpClient, IJsonSerializer serializer) - : this(httpClient, null, serializer) - {} - public ODataClient(HttpClient httpClient, ICredentialBuilder credentialBuilder) - : this(httpClient, credentialBuilder, JsonSerializer.Default) - { } - public ODataClient(HttpClient httpClient, string username, string password) - : this(httpClient, username, password, JsonSerializer.Default) - {} - public ODataClient(HttpClient httpClient, string username, string password, IJsonSerializer serializer) - : this(httpClient, new BasicAuthCredential(username, password), serializer) - {} - public ODataClient(HttpClient httpClient, ICredentialBuilder credentialBuilder, IJsonSerializer serializer) - { - _httpClient = httpClient; - _credentialBuilder = credentialBuilder; - RequestFactory = new RequestFactory(serializer); - } - - protected async Task ParseAsync(HttpStatusCode status, HttpContent content, HttpResponseHeaders headers = null) - { - var code = (int)status; - var body = content != null ? await content.ReadAsByteArrayAsync() : null; - var mime = content?.Headers.ContentType?.MediaType; - - if (code == 404) - return Response.CreateSuccess(status, mime, (byte[])null, headers); - - if (code >= 400) - return Response.CreateError(status, body, headers); - - return Response.CreateSuccess(status, mime, body, headers); - } - - - protected async Task> ParseMultiAsync(MultipartMemoryStreamProvider multipart, HttpResponseHeaders headers = null) - { - var result = new List(); - foreach (var content in multipart.Contents) - { - if (content.Headers.ContentType.MediaType == "application/http") - { - if (!content.Headers.ContentType.Parameters.Contains(_responseMsgType)) - content.Headers.ContentType.Parameters.Add(_responseMsgType); - - var part = await content.ReadAsHttpResponseMessageAsync(); - +using ODataHttpClient.Credentials; +using ODataHttpClient.Models; +using ODataHttpClient.Parameterizers; +using ODataHttpClient.Serializers; +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; + +[assembly: CLSCompliant(true)] +namespace ODataHttpClient +{ + public class ODataClient + { + private static readonly NameValueHeaderValue _responseMsgType = new NameValueHeaderValue("msgtype","response"); + private readonly HttpClient _httpClient; + private readonly ICredentialBuilder _credentialBuilder; + public RequestFactory RequestFactory { get; } + public ODataClient(HttpClient httpClient) + : this(httpClient, JsonSerializer.Default) + {} + public ODataClient(HttpClient httpClient, IJsonSerializer serializer) + : this(httpClient, null, serializer) + {} + public ODataClient(HttpClient httpClient, ICredentialBuilder credentialBuilder) + : this(httpClient, credentialBuilder, JsonSerializer.Default) + { } + public ODataClient(HttpClient httpClient, string username, string password) + : this(httpClient, username, password, JsonSerializer.Default) + {} + public ODataClient(HttpClient httpClient, string username, string password, IJsonSerializer serializer) + : this(httpClient, new BasicAuthCredential(username, password), serializer) + {} + public ODataClient(HttpClient httpClient, ICredentialBuilder credentialBuilder, IJsonSerializer serializer) + { + _httpClient = httpClient; + _credentialBuilder = credentialBuilder; + RequestFactory = new RequestFactory(serializer); + } + + protected async Task ParseAsync(HttpStatusCode status, HttpContent content, HttpResponseHeaders headers = null) + { + var code = (int)status; + var body = content != null ? await content.ReadAsByteArrayAsync() : null; + var mime = content?.Headers.ContentType?.MediaType; + + if (code == 404) + return Response.CreateSuccess(status, mime, (byte[])null, headers); + + if (code >= 400) + return Response.CreateError(status, body, headers); + + return Response.CreateSuccess(status, mime, body, headers); + } + + + protected async Task> ParseMultiAsync(MultipartMemoryStreamProvider multipart, HttpResponseHeaders headers = null) + { + var result = new List(); + foreach (var content in multipart.Contents) + { + if (content.Headers.ContentType.MediaType == "application/http") + { + if (!content.Headers.ContentType.Parameters.Contains(_responseMsgType)) + content.Headers.ContentType.Parameters.Add(_responseMsgType); + + var part = await content.ReadAsHttpResponseMessageAsync(); + if (!part.Headers.Contains("Content-ID") && content.Headers.TryGetValues("Content-ID", out var contentId)) { part.Headers.Add("Content-ID", contentId); - } - - result.Add(await ParseAsync(part.StatusCode, part.Content, part.Headers)); - } - else if (content.IsMimeMultipartContent()) - { - var children = await content.ReadAsMultipartAsync(); - - result.AddRange(await ParseMultiAsync(children, headers)); - } - } - return result; - } - - public async Task SendAsync(IRequest request) - { - var message = request.CreateMessage(); - _credentialBuilder?.Build(_httpClient, message); - - var response = await _httpClient.SendAsync(message); - - return await ParseAsync(response.StatusCode, response.Content, response.Headers); - } - public async Task> SendAsync(IBatchRequest batchRequest) - { - return await BatchAsync(batchRequest); - } - public async Task> BatchAsync(IBatchRequest request) - { - var message = request.CreateMessage(); - _credentialBuilder?.Build(_httpClient, message); - - var response = await _httpClient.SendAsync(message); - - if (!response.Content.IsMimeMultipartContent()) - return new[] { await ParseAsync(response.StatusCode, response.Content, response.Headers) }; - - var multipart = await response.Content.ReadAsMultipartAsync(); - - return await ParseMultiAsync(multipart, response.Headers); - } - public static void UseV4Global() - { - JsonSerializer.Default = JsonSerializer.General; - Request.Parameterizer = new ODataV4Parameterizer(); - } - } -} + } + + result.Add(await ParseAsync(part.StatusCode, part.Content, part.Headers)); + } + else if (content.IsMimeMultipartContent()) + { + var children = await content.ReadAsMultipartAsync(); + + result.AddRange(await ParseMultiAsync(children, headers)); + } + } + return result; + } + + public async Task SendAsync(IRequest request) + { + var message = request.CreateMessage(); + _credentialBuilder?.Build(_httpClient, message); + + var response = await _httpClient.SendAsync(message); + + return await ParseAsync(response.StatusCode, response.Content, response.Headers); + } + public async Task> SendAsync(IBatchRequest batchRequest) + { + return await BatchAsync(batchRequest); + } + public async Task> BatchAsync(IBatchRequest request) + { + var message = request.CreateMessage(); + _credentialBuilder?.Build(_httpClient, message); + + var response = await _httpClient.SendAsync(message); + + if (!response.Content.IsMimeMultipartContent()) + return new[] { await ParseAsync(response.StatusCode, response.Content, response.Headers) }; + + var multipart = await response.Content.ReadAsMultipartAsync(); + + return await ParseMultiAsync(multipart, response.Headers); + } + public static void UseV4Global() + { + JsonSerializer.Default = JsonSerializer.General; + Request.Parameterizer = new ODataV4Parameterizer(); + } + } +} From faed1d93dca61358181d31e8f7a0f49c2b844b0d Mon Sep 17 00:00:00 2001 From: Takaaki Suzuki Date: Fri, 17 Apr 2020 15:11:57 +0900 Subject: [PATCH 17/35] Use latest NuGet package --- .../ODataHttpClient.Tests.csproj | 11 +++++++---- src/ODataHttpClient/ODataHttpClient.csproj | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/ODataHttpClient.Tests/ODataHttpClient.Tests.csproj b/src/ODataHttpClient.Tests/ODataHttpClient.Tests.csproj index 11e889a..a437820 100644 --- a/src/ODataHttpClient.Tests/ODataHttpClient.Tests.csproj +++ b/src/ODataHttpClient.Tests/ODataHttpClient.Tests.csproj @@ -11,13 +11,16 @@ - + runtime; build; native; contentfiles; analyzers all - - - + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/ODataHttpClient/ODataHttpClient.csproj b/src/ODataHttpClient/ODataHttpClient.csproj index fe161e0..0604171 100644 --- a/src/ODataHttpClient/ODataHttpClient.csproj +++ b/src/ODataHttpClient/ODataHttpClient.csproj @@ -8,8 +8,8 @@ - - + + From 5590ef0e50b3032956eec90639e7478d4537627f Mon Sep 17 00:00:00 2001 From: Takaaki Suzuki Date: Fri, 17 Apr 2020 15:16:08 +0900 Subject: [PATCH 18/35] Use .NET Core 3.1 --- src/ODataHttpClient.Tests/ODataHttpClient.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ODataHttpClient.Tests/ODataHttpClient.Tests.csproj b/src/ODataHttpClient.Tests/ODataHttpClient.Tests.csproj index a437820..d164ae4 100644 --- a/src/ODataHttpClient.Tests/ODataHttpClient.Tests.csproj +++ b/src/ODataHttpClient.Tests/ODataHttpClient.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp2.1 + netcoreapp3.1 false From 027b1fba63ab152f7b1d982cbf044541841fd3e2 Mon Sep 17 00:00:00 2001 From: Takaaki Suzuki Date: Fri, 17 Apr 2020 15:21:37 +0900 Subject: [PATCH 19/35] JSON.NET isn't need because Microsoft.AspNet.WebApi.Client refers to JSON.NET. --- src/ODataHttpClient/ODataHttpClient.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ODataHttpClient/ODataHttpClient.csproj b/src/ODataHttpClient/ODataHttpClient.csproj index 0604171..076794f 100644 --- a/src/ODataHttpClient/ODataHttpClient.csproj +++ b/src/ODataHttpClient/ODataHttpClient.csproj @@ -9,7 +9,6 @@ - From 83b0105c7aa62de11421803425a6265b0b8c3d44 Mon Sep 17 00:00:00 2001 From: Takaaki Suzuki Date: Fri, 17 Apr 2020 15:25:11 +0900 Subject: [PATCH 20/35] fix version range --- src/ODataHttpClient/ODataHttpClient.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ODataHttpClient/ODataHttpClient.csproj b/src/ODataHttpClient/ODataHttpClient.csproj index 076794f..043232a 100644 --- a/src/ODataHttpClient/ODataHttpClient.csproj +++ b/src/ODataHttpClient/ODataHttpClient.csproj @@ -8,7 +8,7 @@ - + From b61cd95e280d67ce1e39045c2b7d2dff0979c5db Mon Sep 17 00:00:00 2001 From: Takaaki Suzuki Date: Fri, 17 Apr 2020 16:15:26 +0900 Subject: [PATCH 21/35] fix merge mistake --- src/ODataHttpClient/ODataClient.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ODataHttpClient/ODataClient.cs b/src/ODataHttpClient/ODataClient.cs index 941e9f7..8156ed8 100644 --- a/src/ODataHttpClient/ODataClient.cs +++ b/src/ODataHttpClient/ODataClient.cs @@ -57,7 +57,6 @@ protected async Task ParseAsync(HttpStatusCode status, HttpContent con } - protected async Task> ParseMultiAsync(MultipartMemoryStreamProvider multipart, HttpResponseHeaders headers = null) protected async Task> ParseMultiAsync(MultipartMemoryStreamProvider multipart, HttpResponseHeaders headers = null, CancellationToken cancellationToken = default) { var result = new List(); From e424860ee3bd8b96a3b03d59412d8e916665ff7e Mon Sep 17 00:00:00 2001 From: Takaaki Suzuki Date: Fri, 17 Apr 2020 16:19:51 +0900 Subject: [PATCH 22/35] Revert "JSON.NET isn't need because Microsoft.AspNet.WebApi.Client refers to JSON.NET." This reverts commit 027b1fba63ab152f7b1d982cbf044541841fd3e2. # Conflicts: # src/ODataHttpClient/ODataHttpClient.csproj --- src/ODataHttpClient/ODataHttpClient.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ODataHttpClient/ODataHttpClient.csproj b/src/ODataHttpClient/ODataHttpClient.csproj index 043232a..2b11140 100644 --- a/src/ODataHttpClient/ODataHttpClient.csproj +++ b/src/ODataHttpClient/ODataHttpClient.csproj @@ -9,6 +9,7 @@ + From d22e8b582c7388cf941490a9a264ca48ba95f300 Mon Sep 17 00:00:00 2001 From: Takaaki Suzuki Date: Fri, 17 Apr 2020 16:54:28 +0900 Subject: [PATCH 23/35] Revert main project's package version --- src/ODataHttpClient/ODataHttpClient.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ODataHttpClient/ODataHttpClient.csproj b/src/ODataHttpClient/ODataHttpClient.csproj index 2b11140..fe161e0 100644 --- a/src/ODataHttpClient/ODataHttpClient.csproj +++ b/src/ODataHttpClient/ODataHttpClient.csproj @@ -8,8 +8,8 @@ - - + + From fc350a28df877724ee6bef345c9b4bfe4b67674a Mon Sep 17 00:00:00 2001 From: Yoshiyuki TANIGUCHI Date: Fri, 17 Apr 2020 17:55:15 +0900 Subject: [PATCH 24/35] Update config.yml version up sdk --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 962485a..0266e2f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,7 +2,7 @@ version: 2 jobs: build: docker: - - image: microsoft/dotnet:2.1-sdk + - image: mcr.microsoft.com/dotnet/core/sdk:3.1 working_directory: ~/repo steps: - checkout @@ -21,7 +21,7 @@ jobs: key: v1-repo-{{ .Environment.CIRCLE_SHA1 }} push_preview: docker: - - image: microsoft/dotnet:2.1-sdk + - image: mcr.microsoft.com/dotnet/core/sdk:3.1 working_directory: ~/repo steps: - restore_cache: @@ -35,7 +35,7 @@ jobs: dotnet nuget push ./bin/Release/*.nupkg -s https://api.nuget.org/v3/index.json -k $NUGET_TOKEN push: docker: - - image: microsoft/dotnet:2.1-sdk + - image: mcr.microsoft.com/dotnet/core/sdk:3.1 working_directory: ~/repo steps: - restore_cache: From 65506e88285c350a761865689857e1a50c538492 Mon Sep 17 00:00:00 2001 From: yoshiyuki taniguchi Date: Tue, 21 Apr 2020 10:30:12 +0900 Subject: [PATCH 25/35] versionup --- src/ODataHttpClient/ODataHttpClient.csproj | 2 +- src/ODataHttpClient/ODataHttpClient.nuspec | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ODataHttpClient/ODataHttpClient.csproj b/src/ODataHttpClient/ODataHttpClient.csproj index fe161e0..a8cfe8a 100644 --- a/src/ODataHttpClient/ODataHttpClient.csproj +++ b/src/ODataHttpClient/ODataHttpClient.csproj @@ -2,7 +2,7 @@ ODataHttpClient - 1.6.8 + 1.6.9 netstandard2.0 ODataHttpClient.nuspec diff --git a/src/ODataHttpClient/ODataHttpClient.nuspec b/src/ODataHttpClient/ODataHttpClient.nuspec index b62a383..84684fd 100644 --- a/src/ODataHttpClient/ODataHttpClient.nuspec +++ b/src/ODataHttpClient/ODataHttpClient.nuspec @@ -11,7 +11,11 @@ https://github.com/iwate/ODataHttpClient/blob/master/LICENSE https://iwate.github.io/ODataHttpClient The simplest implementation of OData client. - + v1.6.8 + + v1.6.9 + - Change BatchAsync return type from IEnumeable to IReadOnlyList + - Add cancellalation token param + - Running unit test on netcoreapp3.1 ++ v1.6.8 - [Bug fix] Fix response headers of batch + v1.6.7 - Add additaionl headers From f7996a0377845a4658aeb1dff7d7ed1bcc9b520b Mon Sep 17 00:00:00 2001 From: yoshiyuki taniguchi Date: Fri, 17 Jul 2020 13:48:40 +0900 Subject: [PATCH 26/35] add feature switch --- src/ODataHttpClient/ODataClient.cs | 14 ++++++++------ src/ODataHttpClient/ODataHttpClient.csproj | 2 +- src/ODataHttpClient/ODataHttpClient.nuspec | 4 +++- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/ODataHttpClient/ODataClient.cs b/src/ODataHttpClient/ODataClient.cs index 8156ed8..32cc6b0 100644 --- a/src/ODataHttpClient/ODataClient.cs +++ b/src/ODataHttpClient/ODataClient.cs @@ -18,8 +18,10 @@ public class ODataClient private static readonly NameValueHeaderValue _responseMsgType = new NameValueHeaderValue("msgtype","response"); private readonly HttpClient _httpClient; private readonly ICredentialBuilder _credentialBuilder; + public static bool DefaultNotFoundIsSuccess = true; + public bool NotFoundIsSuccess { get; set; } = DefaultNotFoundIsSuccess; public RequestFactory RequestFactory { get; } - public ODataClient(HttpClient httpClient) + public ODataClient(HttpClient httpClient) : this(httpClient, JsonSerializer.Default) {} public ODataClient(HttpClient httpClient, IJsonSerializer serializer) @@ -41,13 +43,13 @@ public ODataClient(HttpClient httpClient, ICredentialBuilder credentialBuilder, RequestFactory = new RequestFactory(serializer); } - protected async Task ParseAsync(HttpStatusCode status, HttpContent content, HttpResponseHeaders headers = null) + protected async Task ParseAsync(HttpStatusCode status, HttpContent content, HttpResponseHeaders headers = null, bool notfoundIsSuccess = true) { var code = (int)status; var body = content != null ? await content.ReadAsByteArrayAsync() : null; var mime = content?.Headers.ContentType?.MediaType; - if (code == 404) + if (code == 404 && notfoundIsSuccess) return Response.CreateSuccess(status, mime, (byte[])null, headers); if (code >= 400) @@ -75,7 +77,7 @@ protected async Task> ParseMultiAsync(MultipartMemoryStr part.Headers.Add("Content-ID", contentId); } - result.Add(await ParseAsync(part.StatusCode, part.Content, part.Headers)); + result.Add(await ParseAsync(part.StatusCode, part.Content, part.Headers, NotFoundIsSuccess)); } else if (content.IsMimeMultipartContent()) { @@ -94,7 +96,7 @@ public async Task SendAsync(IRequest request, CancellationToken cancel var response = await _httpClient.SendAsync(message, cancellationToken); - return await ParseAsync(response.StatusCode, response.Content, response.Headers); + return await ParseAsync(response.StatusCode, response.Content, response.Headers, NotFoundIsSuccess); } public Task> SendAsync(IBatchRequest batchRequest, CancellationToken cancellationToken = default) { @@ -108,7 +110,7 @@ public async Task> BatchAsync(IBatchRequest request, Can var response = await _httpClient.SendAsync(message, cancellationToken); if (!response.Content.IsMimeMultipartContent()) - return new[] { await ParseAsync(response.StatusCode, response.Content, response.Headers) }; + return new[] { await ParseAsync(response.StatusCode, response.Content, response.Headers, NotFoundIsSuccess) }; var multipart = await response.Content.ReadAsMultipartAsync(cancellationToken); diff --git a/src/ODataHttpClient/ODataHttpClient.csproj b/src/ODataHttpClient/ODataHttpClient.csproj index a8cfe8a..608267b 100644 --- a/src/ODataHttpClient/ODataHttpClient.csproj +++ b/src/ODataHttpClient/ODataHttpClient.csproj @@ -2,7 +2,7 @@ ODataHttpClient - 1.6.9 + 1.6.10 netstandard2.0 ODataHttpClient.nuspec diff --git a/src/ODataHttpClient/ODataHttpClient.nuspec b/src/ODataHttpClient/ODataHttpClient.nuspec index 84684fd..813fdf9 100644 --- a/src/ODataHttpClient/ODataHttpClient.nuspec +++ b/src/ODataHttpClient/ODataHttpClient.nuspec @@ -11,7 +11,9 @@ https://github.com/iwate/ODataHttpClient/blob/master/LICENSE https://iwate.github.io/ODataHttpClient The simplest implementation of OData client. - + v1.6.9 + +v1.6.10 + - Add feature switch: notfound is success/error flag. ++ v1.6.9 - Change BatchAsync return type from IEnumeable to IReadOnlyList - Add cancellalation token param - Running unit test on netcoreapp3.1 From 1a3a3031566511741c23b870610c2f7d1a1218df Mon Sep 17 00:00:00 2001 From: yoshiyuki taniguchi Date: Fri, 17 Jul 2020 13:52:41 +0900 Subject: [PATCH 27/35] modify readme --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index e3524fd..58a97c8 100644 --- a/README.md +++ b/README.md @@ -130,3 +130,16 @@ If you change general json format, can select a way of three. var request = Request.Get("...", serializer); // pass serializer var response = await odata.SendAsync(request); var data = response.ReadAs(serializer); // pass serializer + +## NotFound(404) + +In default, ODataHttpClient decide 404 response code to success. If you change to error, can select a way of followings. + +### 1. Global level settings + + ODataHttpClient.DefaultNotFoundIsSuccess = false; + +### 2. Instance level settings + + var odata = new ODataHttpClient(httpClient) { NotFoundIsSuccess = false }; + From b25f47a618e08687b13db38f749f6241f1e541d7 Mon Sep 17 00:00:00 2001 From: yoshiyuki taniguchi Date: Tue, 21 Jul 2020 13:28:28 +0900 Subject: [PATCH 28/35] add not found is success request lebel feaure switch --- src/ODataHttpClient/ODataClient.cs | 20 ++++++++++---------- src/ODataHttpClient/ODataHttpClient.csproj | 2 +- src/ODataHttpClient/ODataHttpClient.nuspec | 4 +++- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/ODataHttpClient/ODataClient.cs b/src/ODataHttpClient/ODataClient.cs index 32cc6b0..f149840 100644 --- a/src/ODataHttpClient/ODataClient.cs +++ b/src/ODataHttpClient/ODataClient.cs @@ -59,7 +59,7 @@ protected async Task ParseAsync(HttpStatusCode status, HttpContent con } - protected async Task> ParseMultiAsync(MultipartMemoryStreamProvider multipart, HttpResponseHeaders headers = null, CancellationToken cancellationToken = default) + protected async Task> ParseMultiAsync(MultipartMemoryStreamProvider multipart, HttpResponseHeaders headers = null, CancellationToken cancellationToken = default, bool? notfoundIsSuccess = null) { var result = new List(); foreach (var content in multipart.Contents) @@ -77,32 +77,32 @@ protected async Task> ParseMultiAsync(MultipartMemoryStr part.Headers.Add("Content-ID", contentId); } - result.Add(await ParseAsync(part.StatusCode, part.Content, part.Headers, NotFoundIsSuccess)); + result.Add(await ParseAsync(part.StatusCode, part.Content, part.Headers, notfoundIsSuccess ?? NotFoundIsSuccess)); } else if (content.IsMimeMultipartContent()) { var children = await content.ReadAsMultipartAsync(cancellationToken); - result.AddRange(await ParseMultiAsync(children, headers, cancellationToken)); + result.AddRange(await ParseMultiAsync(children, headers, cancellationToken, notfoundIsSuccess)); } } return result; } - public async Task SendAsync(IRequest request, CancellationToken cancellationToken = default) + public async Task SendAsync(IRequest request, CancellationToken cancellationToken = default, bool? notfoundIsSuccess = null) { var message = request.CreateMessage(); _credentialBuilder?.Build(_httpClient, message); var response = await _httpClient.SendAsync(message, cancellationToken); - return await ParseAsync(response.StatusCode, response.Content, response.Headers, NotFoundIsSuccess); + return await ParseAsync(response.StatusCode, response.Content, response.Headers, notfoundIsSuccess ?? NotFoundIsSuccess); } - public Task> SendAsync(IBatchRequest batchRequest, CancellationToken cancellationToken = default) + public Task> SendAsync(IBatchRequest batchRequest, CancellationToken cancellationToken = default, bool? notfoundIsSuccess = null) { - return BatchAsync(batchRequest, cancellationToken); + return BatchAsync(batchRequest, cancellationToken, notfoundIsSuccess); } - public async Task> BatchAsync(IBatchRequest request, CancellationToken cancellationToken = default) + public async Task> BatchAsync(IBatchRequest request, CancellationToken cancellationToken = default, bool? notfoundIsSuccess = null) { var message = request.CreateMessage(); _credentialBuilder?.Build(_httpClient, message); @@ -110,11 +110,11 @@ public async Task> BatchAsync(IBatchRequest request, Can var response = await _httpClient.SendAsync(message, cancellationToken); if (!response.Content.IsMimeMultipartContent()) - return new[] { await ParseAsync(response.StatusCode, response.Content, response.Headers, NotFoundIsSuccess) }; + return new[] { await ParseAsync(response.StatusCode, response.Content, response.Headers, notfoundIsSuccess ?? NotFoundIsSuccess) }; var multipart = await response.Content.ReadAsMultipartAsync(cancellationToken); - return await ParseMultiAsync(multipart, response.Headers, cancellationToken); + return await ParseMultiAsync(multipart, response.Headers, cancellationToken, notfoundIsSuccess); } public static void UseV4Global() { diff --git a/src/ODataHttpClient/ODataHttpClient.csproj b/src/ODataHttpClient/ODataHttpClient.csproj index 608267b..680756f 100644 --- a/src/ODataHttpClient/ODataHttpClient.csproj +++ b/src/ODataHttpClient/ODataHttpClient.csproj @@ -2,7 +2,7 @@ ODataHttpClient - 1.6.10 + 1.6.11 netstandard2.0 ODataHttpClient.nuspec diff --git a/src/ODataHttpClient/ODataHttpClient.nuspec b/src/ODataHttpClient/ODataHttpClient.nuspec index 813fdf9..97cd222 100644 --- a/src/ODataHttpClient/ODataHttpClient.nuspec +++ b/src/ODataHttpClient/ODataHttpClient.nuspec @@ -11,7 +11,9 @@ https://github.com/iwate/ODataHttpClient/blob/master/LICENSE https://iwate.github.io/ODataHttpClient The simplest implementation of OData client. - +v1.6.10 + +v1.6.11 + - Add feature switch: notfound is success/error flag on request level. ++v1.6.10 - Add feature switch: notfound is success/error flag. + v1.6.9 - Change BatchAsync return type from IEnumeable to IReadOnlyList From d4e1f219f6a257e5446b94386fc955704c0d2381 Mon Sep 17 00:00:00 2001 From: Yoshiyuki Taniguchi Date: Thu, 30 Jul 2020 11:40:36 +0900 Subject: [PATCH 29/35] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 58a97c8..2ab249f 100644 --- a/README.md +++ b/README.md @@ -143,3 +143,6 @@ In default, ODataHttpClient decide 404 response code to success. If you change t var odata = new ODataHttpClient(httpClient) { NotFoundIsSuccess = false }; +### 3. Request level settings + + var response = await odata.SendAsync(request, notfoundIsSuccess: false); From 066f2cbfba92660a323bff7de79a61e2050669ec Mon Sep 17 00:00:00 2001 From: yoshiyuki taniguchi Date: Wed, 11 Nov 2020 22:34:52 +0900 Subject: [PATCH 30/35] override null when no content. close #18 --- src/ODataHttpClient.Tests/SenarioTest.cs | 3 ++- src/ODataHttpClient.Tests/SenarioV4Test.cs | 4 +++- src/ODataHttpClient/ODataClient.cs | 5 ++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/ODataHttpClient.Tests/SenarioTest.cs b/src/ODataHttpClient.Tests/SenarioTest.cs index f4d958f..367272d 100644 --- a/src/ODataHttpClient.Tests/SenarioTest.cs +++ b/src/ODataHttpClient.Tests/SenarioTest.cs @@ -89,7 +89,8 @@ public async Task ChangeProductName() var changed = await odata.SendAsync(Request.Patch(uri, patch, type: "ODataDemo.Product")); Assert.True(changed.Success); - + Assert.Null(changed.ReadAs()); + var lookuped = await odata.SendAsync(Request.Get($"{uri}/Name/$value")); Assert.True(lookuped.Success); diff --git a/src/ODataHttpClient.Tests/SenarioV4Test.cs b/src/ODataHttpClient.Tests/SenarioV4Test.cs index 38842f3..283644b 100644 --- a/src/ODataHttpClient.Tests/SenarioV4Test.cs +++ b/src/ODataHttpClient.Tests/SenarioV4Test.cs @@ -88,7 +88,8 @@ public async Task ChangeProductName() var changed = await odata.SendAsync(Request.Patch(uri, patch, type: "ODataDemo.Product", typeKey: "@odata.type")); Assert.True(changed.Success); - + Assert.Null(changed.ReadAs()); + var lookuped = await odata.SendAsync(Request.Get($"{uri}/Name/$value")); Assert.True(lookuped.Success); @@ -97,6 +98,7 @@ public async Task ChangeProductName() Assert.NotEqual(name, replacedName); Assert.Equal(patch.Name, replacedName); + } [Fact] public async Task CreateProductWithCategory() diff --git a/src/ODataHttpClient/ODataClient.cs b/src/ODataHttpClient/ODataClient.cs index f149840..0916921 100644 --- a/src/ODataHttpClient/ODataClient.cs +++ b/src/ODataHttpClient/ODataClient.cs @@ -54,7 +54,10 @@ protected async Task ParseAsync(HttpStatusCode status, HttpContent con if (code >= 400) return Response.CreateError(status, body, headers); - + + if (code == 204) + body = null; + return Response.CreateSuccess(status, mime, body, headers); } From 66e926cde1ea326340d75192ee35fc63c8a0f788 Mon Sep 17 00:00:00 2001 From: yoshiyuki taniguchi Date: Wed, 11 Nov 2020 22:41:08 +0900 Subject: [PATCH 31/35] versionup --- src/ODataHttpClient/ODataHttpClient.csproj | 2 +- src/ODataHttpClient/ODataHttpClient.nuspec | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ODataHttpClient/ODataHttpClient.csproj b/src/ODataHttpClient/ODataHttpClient.csproj index 680756f..7e5b26c 100644 --- a/src/ODataHttpClient/ODataHttpClient.csproj +++ b/src/ODataHttpClient/ODataHttpClient.csproj @@ -2,7 +2,7 @@ ODataHttpClient - 1.6.11 + 1.7.0 netstandard2.0 ODataHttpClient.nuspec diff --git a/src/ODataHttpClient/ODataHttpClient.nuspec b/src/ODataHttpClient/ODataHttpClient.nuspec index 97cd222..96e3673 100644 --- a/src/ODataHttpClient/ODataHttpClient.nuspec +++ b/src/ODataHttpClient/ODataHttpClient.nuspec @@ -11,7 +11,9 @@ https://github.com/iwate/ODataHttpClient/blob/master/LICENSE https://iwate.github.io/ODataHttpClient The simplest implementation of OData client. - +v1.6.11 + +v1.7.0 + - [Breaking Change] Override body null when 204(No Content). ++v1.6.11 - Add feature switch: notfound is success/error flag on request level. +v1.6.10 - Add feature switch: notfound is success/error flag. From 4b6d5ec42747ae5e1cddc35845bdb4a6dda4d717 Mon Sep 17 00:00:00 2001 From: yoshiyuki taniguchi Date: Thu, 5 Aug 2021 15:40:16 +0900 Subject: [PATCH 32/35] add test for parametalizer v4 --- .../ParameterizeV4Test.cs | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 src/ODataHttpClient.Tests/ParameterizeV4Test.cs diff --git a/src/ODataHttpClient.Tests/ParameterizeV4Test.cs b/src/ODataHttpClient.Tests/ParameterizeV4Test.cs new file mode 100644 index 0000000..803b9db --- /dev/null +++ b/src/ODataHttpClient.Tests/ParameterizeV4Test.cs @@ -0,0 +1,140 @@ +using System; +using ODataHttpClient.Parameterizers; +using Xunit; + +namespace ODataHttpClient.Tests +{ + public class ParameterizeV4Test + { + [Fact] + public void LongParam() + { + var odata = new ODataV4Parameterizer(); + var query = odata.Parameterize("$filter=Value eq @Value", new { Value = 123L }); + + Assert.Equal("$filter=Value eq 123L", query); + } + + [Fact] + public void FloatParam() + { + var odata = new ODataParameterizer(); + var query = odata.Parameterize("$filter=Value eq @Value", new { Value = 1.23f }); + + Assert.Equal("$filter=Value eq 1.23f", query); + } + + [Fact] + public void DoubleParam() + { + var odata = new ODataV4Parameterizer(); + var query = odata.Parameterize("$filter=Value eq @Value", new { Value = 1.23d }); + + Assert.Equal("$filter=Value eq 1.23d", query); + } + + [Fact] + public void DecimalParam() + { + var odata = new ODataV4Parameterizer(); + var query = odata.Parameterize("$filter=Value eq @Value", new { Value = 1.23m }); + + Assert.Equal("$filter=Value eq 1.23M", query); + } + + [Fact] + public void BinaryParam() + { + var odata = new ODataV4Parameterizer(); + var query = odata.Parameterize("$filter=Value eq @Value", new { Value = new byte[] { 0x0a, 0x01, 0xff } }); + + Assert.Equal("$filter=Value eq binary'0A01FF'", query); + } + + [Fact] + public void StringParam() + { + var odata = new ODataV4Parameterizer(); + var query = odata.Parameterize("$filter=Value eq @Value", new { Value = "Hello, World!"}); + + Assert.Equal("$filter=Value eq 'Hello, World!'", query); + } + + [Fact] + public void GuidParam() + { + var odata = new ODataV4Parameterizer(); + var query = odata.Parameterize("$filter=Value eq @Value", new { Value = Guid.Empty }); + + Assert.Equal("$filter=Value eq guid'00000000-0000-0000-0000-000000000000'", query); + } + + [Fact] + public void TimeSpanParam() + { + var odata = new ODataV4Parameterizer(); + + Assert.Equal("$filter=Value eq time'P30D'", odata.Parameterize("$filter=Value eq @Value", new { Value = TimeSpan.FromDays(30) })); + Assert.Equal("$filter=Value eq time'PT1H'", odata.Parameterize("$filter=Value eq @Value", new { Value = TimeSpan.FromHours(1) })); + Assert.Equal("$filter=Value eq time'PT15M'", odata.Parameterize("$filter=Value eq @Value", new { Value = TimeSpan.FromMinutes(15) })); + Assert.Equal("$filter=Value eq time'PT1S'", odata.Parameterize("$filter=Value eq @Value", new { Value = TimeSpan.FromSeconds(1) })); + Assert.Equal("$filter=Value eq time'PT0.5S'", odata.Parameterize("$filter=Value eq @Value", new { Value = TimeSpan.FromMilliseconds(500) })); + Assert.Equal("$filter=Value eq time'PT1.5S'", odata.Parameterize("$filter=Value eq @Value", new { Value = TimeSpan.FromMilliseconds(1500) })); + Assert.Equal("$filter=Value eq time'PT0S'", odata.Parameterize("$filter=Value eq @Value", new { Value = default(TimeSpan) })); + } + + [Fact] + public void DateTimeParam() + { + var odata = new ODataV4Parameterizer(); + var query = odata.Parameterize("$filter=Value eq @Value", new { Value = DateTime.MaxValue }); + + Assert.Equal("$filter=Value eq 9999-12-31T23:59:59.9999999", query); + } + + [Fact] + public void DateTimeOffsetParam() + { + var odata = new ODataV4Parameterizer(); + var query = odata.Parameterize("$filter=Value eq @Value", new { Value = DateTimeOffset.MaxValue }); + + Assert.Equal("$filter=Value eq 9999-12-31T23:59:59.9999999%2B00:00", query); + } + + [Fact] + public void All() + { + var odata = new ODataV4Parameterizer(); + var query = odata.Parameterize("$filter=Value1 eq @Value and Value2 eq @Value and Value3 eq @Value", new { Value = 123 }); + + Assert.Equal("$filter=Value1 eq 123 and Value2 eq 123 and Value3 eq 123", query); + } + + [Fact] + public void Complex() + { + var odata = new ODataV4Parameterizer(); + var query = odata.Parameterize("$filter=Value1 eq @Value1 and Value2 eq @Value2 and Value3 eq @Value3", new { Value1 = 123L, Value2 = 1.23d, Value3 = 1.23m }); + + Assert.Equal("$filter=Value1 eq 123L and Value2 eq 1.23d and Value3 eq 1.23M", query); + } + + [Fact] + public void NullableParam() + { + var odata = new ODataV4Parameterizer(); + var query = odata.Parameterize("$filter=Value1 eq @Value1 and Value2 eq @Value2", new { Value1 = (int?)123, Value2 = (int?)null }); + + Assert.Equal("$filter=Value1 eq 123 and Value2 eq null", query); + } + + [Fact] + public void Email() + { + var odata = new ODataV4Parameterizer(); + var query = odata.Parameterize("$filter=Value1 eq @Value1 and Value2 eq @Value2", new { Value1 = "email@Value2.com", Value2 = 123 }); + + Assert.Equal("$filter=Value1 eq 'email@Value2.com' and Value2 eq 123", query); + } + } +} \ No newline at end of file From 6c92cf674b72e4bcd2de90c2667ec31149f3fe92 Mon Sep 17 00:00:00 2001 From: yoshiyuki taniguchi Date: Thu, 5 Aug 2021 15:41:53 +0900 Subject: [PATCH 33/35] add red tests for bool --- src/ODataHttpClient.Tests/ParameterizeTest.cs | 19 ++++ .../ParameterizeV4Test.cs | 19 ++++ .../UseCultureAttribute.cs | 92 +++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 src/ODataHttpClient.Tests/UseCultureAttribute.cs diff --git a/src/ODataHttpClient.Tests/ParameterizeTest.cs b/src/ODataHttpClient.Tests/ParameterizeTest.cs index 1b3bd3f..42a234b 100644 --- a/src/ODataHttpClient.Tests/ParameterizeTest.cs +++ b/src/ODataHttpClient.Tests/ParameterizeTest.cs @@ -6,6 +6,25 @@ namespace ODataHttpClient.Tests { public class ParameterizeTest { + [Fact] + public void BoolParam() + { + var odata = new ODataParameterizer(); + var query = odata.Parameterize("$filter=True eq @True and False eq @False", new { True = true, False = false }); + + Assert.Equal("$filter=True eq true and False eq false", query); + } + + [Fact] + [UseCulture("de-DE")] + public void BoolParamGeDE() + { + var odata = new ODataParameterizer(); + var query = odata.Parameterize("$filter=True eq @True and False eq @False", new { True = true, False = false }); + + Assert.Equal("$filter=True eq true and False eq false", query); + } + [Fact] public void LongParam() { diff --git a/src/ODataHttpClient.Tests/ParameterizeV4Test.cs b/src/ODataHttpClient.Tests/ParameterizeV4Test.cs index 803b9db..761cb46 100644 --- a/src/ODataHttpClient.Tests/ParameterizeV4Test.cs +++ b/src/ODataHttpClient.Tests/ParameterizeV4Test.cs @@ -6,6 +6,25 @@ namespace ODataHttpClient.Tests { public class ParameterizeV4Test { + [Fact] + public void BoolParam() + { + var odata = new ODataParameterizer(); + var query = odata.Parameterize("$filter=True eq @True and False eq @False", new { True = true, False = false }); + + Assert.Equal("$filter=True eq true and False eq false", query); + } + + [Fact] + [UseCulture("de-DE")] + public void BoolParamGeDE() + { + var odata = new ODataParameterizer(); + var query = odata.Parameterize("$filter=True eq @True and False eq @False", new { True = true, False = false }); + + Assert.Equal("$filter=True eq true and False eq false", query); + } + [Fact] public void LongParam() { diff --git a/src/ODataHttpClient.Tests/UseCultureAttribute.cs b/src/ODataHttpClient.Tests/UseCultureAttribute.cs new file mode 100644 index 0000000..5ec1951 --- /dev/null +++ b/src/ODataHttpClient.Tests/UseCultureAttribute.cs @@ -0,0 +1,92 @@ +// https://github.com/xunit/samples.xunit/blob/main/UseCulture/UseCultureAttribute.cs +using System; +using System.Globalization; +using System.Reflection; +using System.Threading; +using Xunit.Sdk; + +namespace ODataHttpClient.Tests +{ + /// + /// Apply this attribute to your test method to replace the + /// and + /// with another culture. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public class UseCultureAttribute : BeforeAfterTestAttribute + { + readonly Lazy culture; + readonly Lazy uiCulture; + + CultureInfo originalCulture; + CultureInfo originalUICulture; + + /// + /// Replaces the culture and UI culture of the current thread with + /// + /// + /// The name of the culture. + /// + /// + /// This constructor overload uses for both + /// and . + /// + /// + public UseCultureAttribute(string culture) + : this(culture, culture) { } + + /// + /// Replaces the culture and UI culture of the current thread with + /// and + /// + /// The name of the culture. + /// The name of the UI culture. + public UseCultureAttribute(string culture, string uiCulture) + { + this.culture = new Lazy(() => new CultureInfo(culture, false)); + this.uiCulture = new Lazy(() => new CultureInfo(uiCulture, false)); + } + + /// + /// Gets the culture. + /// + public CultureInfo Culture { get { return culture.Value; } } + + /// + /// Gets the UI culture. + /// + public CultureInfo UICulture { get { return uiCulture.Value; } } + + /// + /// Stores the current + /// and + /// and replaces them with the new cultures defined in the constructor. + /// + /// The method under test + public override void Before(MethodInfo methodUnderTest) + { + originalCulture = Thread.CurrentThread.CurrentCulture; + originalUICulture = Thread.CurrentThread.CurrentUICulture; + + Thread.CurrentThread.CurrentCulture = Culture; + Thread.CurrentThread.CurrentUICulture = UICulture; + + CultureInfo.CurrentCulture.ClearCachedData(); + CultureInfo.CurrentUICulture.ClearCachedData(); + } + + /// + /// Restores the original and + /// to + /// + /// The method under test + public override void After(MethodInfo methodUnderTest) + { + Thread.CurrentThread.CurrentCulture = originalCulture; + Thread.CurrentThread.CurrentUICulture = originalUICulture; + + CultureInfo.CurrentCulture.ClearCachedData(); + CultureInfo.CurrentUICulture.ClearCachedData(); + } + } +} From cac9dae5033dd8b106cadf0d160cc795e571479d Mon Sep 17 00:00:00 2001 From: yoshiyuki taniguchi Date: Thu, 5 Aug 2021 15:43:12 +0900 Subject: [PATCH 34/35] resolve red tests for bool --- src/ODataHttpClient/Parameterizers/ODataParameterizer.cs | 3 +++ src/ODataHttpClient/Parameterizers/ODataV4Parameterizer.cs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/ODataHttpClient/Parameterizers/ODataParameterizer.cs b/src/ODataHttpClient/Parameterizers/ODataParameterizer.cs index b4e24ac..5262d38 100644 --- a/src/ODataHttpClient/Parameterizers/ODataParameterizer.cs +++ b/src/ODataHttpClient/Parameterizers/ODataParameterizer.cs @@ -30,6 +30,7 @@ private string Literal(object value) switch (value) { + case bool val: return Literal(val); case long val: return Literal(val); case float val: return Literal(val); case double val: return Literal(val); @@ -44,6 +45,8 @@ private string Literal(object value) } } + private string Literal(bool value) => value ? "true" : "false"; + private string Literal(long value) => $"{value}L"; private string Literal(float value) => $"{value}f"; diff --git a/src/ODataHttpClient/Parameterizers/ODataV4Parameterizer.cs b/src/ODataHttpClient/Parameterizers/ODataV4Parameterizer.cs index 280b845..b75cb20 100644 --- a/src/ODataHttpClient/Parameterizers/ODataV4Parameterizer.cs +++ b/src/ODataHttpClient/Parameterizers/ODataV4Parameterizer.cs @@ -30,6 +30,7 @@ private string Literal(object value) switch (value) { + case bool val: return Literal(val); case long val: return Literal(val); case float val: return Literal(val); case double val: return Literal(val); @@ -44,6 +45,8 @@ private string Literal(object value) } } + private string Literal(bool value) => value ? "true" : "false"; + private string Literal(long value) => $"{value}L"; private string Literal(float value) => $"{value}f"; From 597337a80d4b00be997eca4198f390be2e9b9e9e Mon Sep 17 00:00:00 2001 From: yoshiyuki taniguchi Date: Thu, 5 Aug 2021 16:21:21 +0900 Subject: [PATCH 35/35] add red test #7 --- src/ODataHttpClient.Tests/ParameterizeTest.cs | 15 ++++++ .../ParameterizeV4Test.cs | 47 ++++++++++++++++++- src/ODataHttpClient.Tests/RequestTest.cs | 47 +++++++++++++++++++ src/ODataHttpClient.Tests/ResponseTest.cs | 35 ++++++++++++++ src/ODataHttpClient.Tests/SerliazerTest.cs | 26 ++++++++++ 5 files changed, 169 insertions(+), 1 deletion(-) diff --git a/src/ODataHttpClient.Tests/ParameterizeTest.cs b/src/ODataHttpClient.Tests/ParameterizeTest.cs index 42a234b..e6ca1d6 100644 --- a/src/ODataHttpClient.Tests/ParameterizeTest.cs +++ b/src/ODataHttpClient.Tests/ParameterizeTest.cs @@ -102,6 +102,21 @@ public void TimeSpanParam() Assert.Equal("$filter=Value eq time'PT0S'", odata.Parameterize("$filter=Value eq @Value", new { Value = default(TimeSpan) })); } + [Fact] + [UseCulture("it-IT")] + public void TimeSpanParamItIT() + { + var odata = new ODataParameterizer(); + + Assert.Equal("$filter=Value eq time'P30D'", odata.Parameterize("$filter=Value eq @Value", new { Value = TimeSpan.FromDays(30) })); + Assert.Equal("$filter=Value eq time'PT1H'", odata.Parameterize("$filter=Value eq @Value", new { Value = TimeSpan.FromHours(1) })); + Assert.Equal("$filter=Value eq time'PT15M'", odata.Parameterize("$filter=Value eq @Value", new { Value = TimeSpan.FromMinutes(15) })); + Assert.Equal("$filter=Value eq time'PT1S'", odata.Parameterize("$filter=Value eq @Value", new { Value = TimeSpan.FromSeconds(1) })); + Assert.Equal("$filter=Value eq time'PT0.5S'", odata.Parameterize("$filter=Value eq @Value", new { Value = TimeSpan.FromMilliseconds(500) })); + Assert.Equal("$filter=Value eq time'PT1.5S'", odata.Parameterize("$filter=Value eq @Value", new { Value = TimeSpan.FromMilliseconds(1500) })); + Assert.Equal("$filter=Value eq time'PT0S'", odata.Parameterize("$filter=Value eq @Value", new { Value = default(TimeSpan) })); + } + [Fact] public void DateTimeParam() { diff --git a/src/ODataHttpClient.Tests/ParameterizeV4Test.cs b/src/ODataHttpClient.Tests/ParameterizeV4Test.cs index 761cb46..7cac4bc 100644 --- a/src/ODataHttpClient.Tests/ParameterizeV4Test.cs +++ b/src/ODataHttpClient.Tests/ParameterizeV4Test.cs @@ -60,7 +60,37 @@ public void DecimalParam() Assert.Equal("$filter=Value eq 1.23M", query); } - + + [Fact] + [UseCulture("it-IT")] + public void FloatParamItIT() + { + var odata = new ODataParameterizer(); + var query = odata.Parameterize("$filter=Value eq @Value", new { Value = 1.23f }); + + Assert.Equal("$filter=Value eq 1.23f", query); + } + + [Fact] + [UseCulture("it-IT")] + public void DoubleParamItIT() + { + var odata = new ODataV4Parameterizer(); + var query = odata.Parameterize("$filter=Value eq @Value", new { Value = 1.23d }); + + Assert.Equal("$filter=Value eq 1.23d", query); + } + + [Fact] + [UseCulture("it-IT")] + public void DecimalParamItIT() + { + var odata = new ODataV4Parameterizer(); + var query = odata.Parameterize("$filter=Value eq @Value", new { Value = 1.23m }); + + Assert.Equal("$filter=Value eq 1.23M", query); + } + [Fact] public void BinaryParam() { @@ -102,6 +132,21 @@ public void TimeSpanParam() Assert.Equal("$filter=Value eq time'PT0S'", odata.Parameterize("$filter=Value eq @Value", new { Value = default(TimeSpan) })); } + [Fact] + [UseCulture("it-IT")] + public void TimeSpanParamItIT() + { + var odata = new ODataV4Parameterizer(); + + Assert.Equal("$filter=Value eq time'P30D'", odata.Parameterize("$filter=Value eq @Value", new { Value = TimeSpan.FromDays(30) })); + Assert.Equal("$filter=Value eq time'PT1H'", odata.Parameterize("$filter=Value eq @Value", new { Value = TimeSpan.FromHours(1) })); + Assert.Equal("$filter=Value eq time'PT15M'", odata.Parameterize("$filter=Value eq @Value", new { Value = TimeSpan.FromMinutes(15) })); + Assert.Equal("$filter=Value eq time'PT1S'", odata.Parameterize("$filter=Value eq @Value", new { Value = TimeSpan.FromSeconds(1) })); + Assert.Equal("$filter=Value eq time'PT0.5S'", odata.Parameterize("$filter=Value eq @Value", new { Value = TimeSpan.FromMilliseconds(500) })); + Assert.Equal("$filter=Value eq time'PT1.5S'", odata.Parameterize("$filter=Value eq @Value", new { Value = TimeSpan.FromMilliseconds(1500) })); + Assert.Equal("$filter=Value eq time'PT0S'", odata.Parameterize("$filter=Value eq @Value", new { Value = default(TimeSpan) })); + } + [Fact] public void DateTimeParam() { diff --git a/src/ODataHttpClient.Tests/RequestTest.cs b/src/ODataHttpClient.Tests/RequestTest.cs index 96a44d1..dff2f29 100644 --- a/src/ODataHttpClient.Tests/RequestTest.cs +++ b/src/ODataHttpClient.Tests/RequestTest.cs @@ -45,6 +45,53 @@ public void ContentTypeJson() Assert.True(message.Content.Headers.ContentType.MediaType == "application/json"); } [Fact] + public void ContentTypePlainText() + { + var message = Request.Create(HttpMethod.Post, uri, "Hello, World!").CreateMessage(); + Assert.Equal("text/plain", message.Content.Headers.ContentType.MediaType); + Assert.Equal("Hello, World!", message.Content.ReadAsStringAsync().Result); + + message = Request.Create(HttpMethod.Post, uri, 100).CreateMessage(); + Assert.Equal("text/plain", message.Content.Headers.ContentType.MediaType); + Assert.Equal("100", message.Content.ReadAsStringAsync().Result); + + message = Request.Create(HttpMethod.Post, uri, 1.23f).CreateMessage(); + Assert.Equal("text/plain", message.Content.Headers.ContentType.MediaType); + Assert.Equal("1.23", message.Content.ReadAsStringAsync().Result); + + message = Request.Create(HttpMethod.Post, uri, 1.23d).CreateMessage(); + Assert.Equal("text/plain", message.Content.Headers.ContentType.MediaType); + Assert.Equal("1.23", message.Content.ReadAsStringAsync().Result); + + message = Request.Create(HttpMethod.Post, uri, 1.23m).CreateMessage(); + Assert.Equal("text/plain", message.Content.Headers.ContentType.MediaType); + Assert.Equal("1.23", message.Content.ReadAsStringAsync().Result); + } + [Fact] + [UseCulture("it-IT")] + public void ContentTypePlainTextItIT() + { + var message = Request.Create(HttpMethod.Post, uri, "Hello, World!").CreateMessage(); + Assert.Equal("text/plain", message.Content.Headers.ContentType.MediaType); + Assert.Equal("Hello, World!", message.Content.ReadAsStringAsync().Result); + + message = Request.Create(HttpMethod.Post, uri, 100).CreateMessage(); + Assert.Equal("text/plain", message.Content.Headers.ContentType.MediaType); + Assert.Equal("100", message.Content.ReadAsStringAsync().Result); + + message = Request.Create(HttpMethod.Post, uri, 1.23f).CreateMessage(); + Assert.Equal("text/plain", message.Content.Headers.ContentType.MediaType); + Assert.Equal("1.23", message.Content.ReadAsStringAsync().Result); + + message = Request.Create(HttpMethod.Post, uri, 1.23d).CreateMessage(); + Assert.Equal("text/plain", message.Content.Headers.ContentType.MediaType); + Assert.Equal("1.23", message.Content.ReadAsStringAsync().Result); + + message = Request.Create(HttpMethod.Post, uri, 1.23m).CreateMessage(); + Assert.Equal("text/plain", message.Content.Headers.ContentType.MediaType); + Assert.Equal("1.23", message.Content.ReadAsStringAsync().Result); + } + [Fact] public void CreateGetRequest() { var request = Request.Get(uri); diff --git a/src/ODataHttpClient.Tests/ResponseTest.cs b/src/ODataHttpClient.Tests/ResponseTest.cs index d152a57..3278398 100644 --- a/src/ODataHttpClient.Tests/ResponseTest.cs +++ b/src/ODataHttpClient.Tests/ResponseTest.cs @@ -75,6 +75,14 @@ public void ReadTextAsLong() Assert.Equal(100L, response.ReadAs()); } [Fact] + public void ReadTextAsFloat() + { + var response = Response.CreateSuccess(HttpStatusCode.OK, "text/plain", "100.0"); + + Assert.Equal(100f, response.ReadAs()); + Assert.Equal(100f, response.ReadAs()); + } + [Fact] public void ReadTextAsDouble() { var response = Response.CreateSuccess(HttpStatusCode.OK, "text/plain", "100.0"); @@ -91,6 +99,33 @@ public void ReadTextAsDecimal() Assert.Equal(100m, response.ReadAs()); } [Fact] + [UseCulture("it-IT")] + public void ReadTextAsFloatItIT() + { + var response = Response.CreateSuccess(HttpStatusCode.OK, "text/plain", "100.0"); + + Assert.Equal(100f, response.ReadAs()); + Assert.Equal(100f, response.ReadAs()); + } + [Fact] + [UseCulture("it-IT")] + public void ReadTextAsDoubleItIT() + { + var response = Response.CreateSuccess(HttpStatusCode.OK, "text/plain", "100.0"); + + Assert.Equal(100d, response.ReadAs()); + Assert.Equal(100d, response.ReadAs()); + } + [Fact] + [UseCulture("it-IT")] + public void ReadTextAsDecimalItIT() + { + var response = Response.CreateSuccess(HttpStatusCode.OK, "text/plain", "100.0"); + + Assert.Equal(100m, response.ReadAs()); + Assert.Equal(100m, response.ReadAs()); + } + [Fact] public void ReadTextAsDateTime() { var response = Response.CreateSuccess(HttpStatusCode.OK, "text/plain", "2018-01-01T00:00:00.000"); diff --git a/src/ODataHttpClient.Tests/SerliazerTest.cs b/src/ODataHttpClient.Tests/SerliazerTest.cs index 605eba7..bd24882 100644 --- a/src/ODataHttpClient.Tests/SerliazerTest.cs +++ b/src/ODataHttpClient.Tests/SerliazerTest.cs @@ -23,6 +23,19 @@ public void SerializeAsHistorical() Assert.Null(Record.Exception(() => Response.CreateSuccess(HttpStatusCode.OK, "application/json", "\"100.5\"").ReadAs())); } [Fact] + [UseCulture("it-IT")] + public void SerializeAsHistoricalItIT() + { + var odata = new ODataClient(new HttpClient(), JsonSerializer.Historical); + Assert.Equal("{\"a\":\"100\"}", odata.RequestFactory.Post("", new { a = 100L }).Body); + Assert.Equal("{\"a\":\"100.5\"}", odata.RequestFactory.Post("", new { a = 100.5d }).Body); + Assert.Equal("{\"a\":\"100.5\"}", odata.RequestFactory.Post("", new { a = 100.5m }).Body); + + Assert.Null(Record.Exception(() => Response.CreateSuccess(HttpStatusCode.OK, "application/json", "\"100\"").ReadAs())); + Assert.Null(Record.Exception(() => Response.CreateSuccess(HttpStatusCode.OK, "application/json", "\"100.5\"").ReadAs())); + Assert.Null(Record.Exception(() => Response.CreateSuccess(HttpStatusCode.OK, "application/json", "\"100.5\"").ReadAs())); + } + [Fact] public void SerializeAsGeneral() { var odata = new ODataClient(new HttpClient(), JsonSerializer.General); @@ -35,6 +48,19 @@ public void SerializeAsGeneral() Assert.Null(Record.Exception(() => Response.CreateSuccess(HttpStatusCode.OK, "application/json", "100.5").ReadAs())); } [Fact] + [UseCulture("it-IT")] + public void SerializeAsGeneralItIT() + { + var odata = new ODataClient(new HttpClient(), JsonSerializer.General); + Assert.Equal("100", odata.RequestFactory.Post("", 100L).Body); + Assert.Equal("100.5", odata.RequestFactory.Post("", 100.5d).Body); + Assert.Equal("100.5", odata.RequestFactory.Post("", 100.5m).Body); + + Assert.Null(Record.Exception(() => Response.CreateSuccess(HttpStatusCode.OK, "application/json", "100").ReadAs())); + Assert.Null(Record.Exception(() => Response.CreateSuccess(HttpStatusCode.OK, "application/json", "100.5").ReadAs())); + Assert.Null(Record.Exception(() => Response.CreateSuccess(HttpStatusCode.OK, "application/json", "100.5").ReadAs())); + } + [Fact] public void SerliazeByteArrayToBase64ByHistorical() { var json = JsonSerializer.Historical.Serialize(new byte[] { 0, 0, 0, 0, 0, 2, 74, 26 });