diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 245c5a6..1c81619 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -10,10 +10,10 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup .NET - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v5 with: dotnet-version: '10.0.x' @@ -27,7 +27,7 @@ jobs: run: dotnet build ./*/Infra.Http.Api.slnx --no-restore -c Release - name: Test Infra.Http.Api - run: dotnet test ./*/Infra.Http.Api.slnx --no-restore -c Release + run: dotnet test ./*/Infra.Http.Api.slnx --no-build --no-restore -c Release - name: Pack Infra.Http.Api run: dotnet pack ./*/Infra.Http.Api.slnx --no-build -o ~/nuget -c Release diff --git a/src/Api.Contract/Api.Contract.csproj b/src/Api.Contract/Api.Contract.csproj index 299b65c..df34c70 100644 --- a/src/Api.Contract/Api.Contract.csproj +++ b/src/Api.Contract/Api.Contract.csproj @@ -9,15 +9,15 @@ $(NoWarn);IDE0130;CA1859 GarageGroup.Infra GarageGroup.Infra.Http.Api.Contract - 1.0.0 + 1.1.0 - + - + \ No newline at end of file diff --git a/src/Api.Test/Api.Test.csproj b/src/Api.Test/Api.Test.csproj index af40a5f..38979a3 100644 --- a/src/Api.Test/Api.Test.csproj +++ b/src/Api.Test/Api.Test.csproj @@ -17,13 +17,13 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/src/Api.Test/Test.HttpApi/HttpApiTest.cs b/src/Api.Test/Test.HttpApi/HttpApiTest.cs index bfff8c2..f20ec78 100644 --- a/src/Api.Test/Test.HttpApi/HttpApiTest.cs +++ b/src/Api.Test/Test.HttpApi/HttpApiTest.cs @@ -84,4 +84,22 @@ private static HttpResponseMessage CreateResponse( return response; } -} + + private static bool ContainsHeader(FlatArray> headers, string key, string value) + { + foreach (var header in headers) + { + if (string.Equals(header.Key, key, StringComparison.InvariantCultureIgnoreCase) is false) + { + continue; + } + + if (string.Equals(header.Value, value, StringComparison.InvariantCultureIgnoreCase)) + { + return true; + } + } + + return false; + } +} \ No newline at end of file diff --git a/src/Api.Test/Test.HttpApi/Test.Send.cs b/src/Api.Test/Test.HttpApi/Test.Send.cs index 9f5aec8..14e3899 100644 --- a/src/Api.Test/Test.HttpApi/Test.Send.cs +++ b/src/Api.Test/Test.HttpApi/Test.Send.cs @@ -12,11 +12,7 @@ partial class HttpApiTest [Theory] [MemberData(nameof(SuccessCaseTestData))] public static async Task SendAsync_ResponseIsSuccess_ExpectMappedSuccess( - HttpSuccessType successType, - int statusCode, - string? reasonPhrase, - bool hasHeaders, - bool hasBody) + HttpSuccessType successType, int statusCode, string? reasonPhrase, bool hasHeaders, bool hasBody) { var source = CreateApi( sendAsync: (_, _) => @@ -44,9 +40,8 @@ public static async Task SendAsync_ResponseIsSuccess_ExpectMappedSuccess( if (hasHeaders) { - Assert.Equal(1, success.Headers.Length); - Assert.True(string.Equals(success.Headers[0].Key, "x-request-id", StringComparison.InvariantCultureIgnoreCase)); - Assert.Equal("abc", success.Headers[0].Value); + Assert.True(ContainsHeader(success.Headers, "x-request-id", "abc")); + Assert.True(ContainsHeader(success.Headers, "Content-Type", "application/json; charset=utf-8")); } else { @@ -97,9 +92,7 @@ public static async Task SendAsync_ResponseIsFailure_ExpectMappedFailure( Assert.Equal((HttpFailureCode)statusCode, failure.StatusCode); Assert.Equal(reasonPhrase, failure.ReasonPhrase); - Assert.Equal(1, failure.Headers.Length); - Assert.True(string.Equals(failure.Headers[0].Key, "x-request-id", StringComparison.InvariantCultureIgnoreCase)); - Assert.Equal("abc", failure.Headers[0].Value); + Assert.True(ContainsHeader(failure.Headers, "x-request-id", "abc")); if (body is null) { @@ -107,6 +100,11 @@ public static async Task SendAsync_ResponseIsFailure_ExpectMappedFailure( return; } + if (string.IsNullOrWhiteSpace(mediaType) is false) + { + Assert.True(ContainsHeader(failure.Headers, "Content-Type", $"{mediaType}; charset={charSet}")); + } + Assert.Equal(mediaType, failure.Body.Type.MediaType); Assert.Equal(charSet, failure.Body.Type.CharSet); Assert.Equal(body, failure.Body.Content?.ToString()); @@ -206,4 +204,4 @@ public static async Task SendAsync_InputBodyIsEmpty_ExpectRequestWithoutContent( Assert.False(hasContent); } -} +} \ No newline at end of file diff --git a/src/Api/Api.csproj b/src/Api/Api.csproj index fe3f522..b090fff 100644 --- a/src/Api/Api.csproj +++ b/src/Api/Api.csproj @@ -9,7 +9,7 @@ $(NoWarn);IDE0130;CA1859 GarageGroup.Infra GarageGroup.Infra.Http.Api - 1.0.0 + 1.1.0 @@ -23,8 +23,8 @@ - - + + \ No newline at end of file diff --git a/src/Api/Api/HttpApi.cs b/src/Api/Api/HttpApi.cs index 109c245..7b3bdf1 100644 --- a/src/Api/Api/HttpApi.cs +++ b/src/Api/Api/HttpApi.cs @@ -74,16 +74,29 @@ private static void SetBody(HttpRequestMessage httpRequest, HttpBody body) } } - private static IEnumerable> GetHeaders(HttpResponseMessage httpResponse) - { - foreach (var header in httpResponse.Headers) - { - foreach (var value in header.Value) + private static IEnumerable> GetHeaders(HttpResponseMessage httpResponse) + { + foreach (var header in httpResponse.Headers) + { + foreach (var value in header.Value) { - yield return new(header.Key, value); - } - } - } + yield return new(header.Key, value); + } + } + + if (httpResponse.Content is null) + { + yield break; + } + + foreach (var header in httpResponse.Content.Headers) + { + foreach (var value in header.Value) + { + yield return new(header.Key, value); + } + } + } private static async Task ReadBodyAsync(HttpContent httpContent, CancellationToken cancellationToken) {