diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 0000000..393d187 --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,13 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "csharpier": { + "version": "0.30.6", + "commands": [ + "dotnet-csharpier" + ], + "rollForward": false + } + } +} \ No newline at end of file diff --git a/.github/workflows/dependabot-automerge.yml b/.github/workflows/dependabot-automerge.yml index 68d80b7..d6831ee 100644 --- a/.github/workflows/dependabot-automerge.yml +++ b/.github/workflows/dependabot-automerge.yml @@ -12,7 +12,18 @@ jobs: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} if: ${{ github.actor == 'dependabot[bot]' }} steps: + - uses: actions/checkout@v4 + - name: Verify commit signature. + run: | + curl -s https://github.com/web-flow.gpg | gpg --import + echo "Imported GitHub keys." + + echo "Verifying signature of commit: $GITHUB_SHA" + if ! git verify-commit "$GITHUB_SHA"; then + echo "Commit signature verification failed." + exit 1 + fi - name: Approve a PR run: gh pr review --approve "$PR_URL" - name: Enable auto-merge for Dependabot PRs - run: gh pr merge --auto --squash "$PR_URL" + run: gh pr merge --auto --squash "$PR_URL" \ No newline at end of file diff --git a/.github/workflows/formatter.yml b/.github/workflows/formatter.yml index 884bc67..63be6de 100644 --- a/.github/workflows/formatter.yml +++ b/.github/workflows/formatter.yml @@ -1,4 +1,4 @@ -name: dotnet-format +name: csharpier on: [push, pull_request] @@ -7,13 +7,11 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Setup .NET + - name: Setup .NET 8 uses: actions/setup-dotnet@v4 with: dotnet-version: 8.0.100 - - name: Install dotnet-format - run: | - dotnet tool install -g dotnet-format - - name: Run dotnet-format - working-directory: ./TransformerBeeClient - run: dotnet-format TransformerBeeClient.sln --check + - name: Restore .NET tools + run: dotnet tool restore + - name: Run CSharpier + run: dotnet csharpier . --check diff --git a/.github/workflows/integrationtests.yml b/.github/workflows/integrationtests.yml index 9d8ac8d..400cd7c 100644 --- a/.github/workflows/integrationtests.yml +++ b/.github/workflows/integrationtests.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - dotnet-version: ["6.0.201", "7.0.100", "8.0.100"] + dotnet-version: ["9"] runs-on: ${{ matrix.os }} steps: - name: Checkout code @@ -25,13 +25,13 @@ jobs: - name: Log into registry # GHCR_PAT is a personal access token for the Github Container Registry; You can create it using the following steps: # 1) Go to https://github.com/settings/tokens - # 2) Create a new token (classic as of 2024-01-31) + # 2) Create a new token (classic as of 2025-04-02) # 3) Select the following scopes: read:packages # GHCR_USR is the username for the Github Container Registry; it has to match the PAT and is the username of the Github account that created the PAT # You can update the tokens in the repository settings: # https://github.com/Hochfrequenz/transformer.bee_client.net/settings/secrets/actions/GHCR_PAT # https://github.com/Hochfrequenz/transformer.bee_client.net/settings/secrets/actions/GHCR_USR - # Tokens will expire 2025-01-31 + # Tokens will expire 2026-04-01 run: echo "${{ secrets.GHCR_PAT }}" | docker login ghcr.io -u ${{ secrets.GHCR_USR }} --password-stdin - name: Start containers run: docker compose -f "TransformerBeeClient/TransformerBeeClient.IntegrationTest/docker-compose.yml" up -d diff --git a/.github/workflows/release_nuget.yml b/.github/workflows/release_nuget.yml index 4548c54..130a169 100644 --- a/.github/workflows/release_nuget.yml +++ b/.github/workflows/release_nuget.yml @@ -12,20 +12,20 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v4 with: - dotnet-version: 8.0.100 + dotnet-version: 9 - name: Build/Check for compile errors (dotnet build) working-directory: "TransformerBeeClient" run: dotnet build --configuration Release - name: Log into registry # GHCR_PAT is a personal access token for the Github Container Registry; You can create it using the following steps: # 1) Go to https://github.com/settings/tokens - # 2) Create a new token (classic as of 2024-01-31) + # 2) Create a new token (classic as of 2025-04-02) # 3) Select the following scopes: read:packages # GHCR_USR is the username for the Github Container Registry; it has to match the PAT and is the username of the Github account that created the PAT # You can update the tokens in the repository settings: # https://github.com/Hochfrequenz/transformer.bee_client.net/settings/secrets/actions/GHCR_PAT # https://github.com/Hochfrequenz/transformer.bee_client.net/settings/secrets/actions/GHCR_USR - # Tokens will expire 2025-01-31 + # Tokens will expire 2026-04-01 run: echo "${{ secrets.GHCR_PAT }}" | docker login ghcr.io -u ${{ secrets.GHCR_USR }} --password-stdin - name: Start containers run: docker compose -f "TransformerBeeClient/TransformerBeeClient.IntegrationTest/docker-compose.yml" up -d diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index 0eee283..5336143 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -10,7 +10,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - dotnet-version: ["6.0.201", "7.0.100", "8.0.100"] + dotnet-version: ["9"] runs-on: ${{ matrix.os }} steps: - name: Checkout code diff --git a/TransformerBeeClient/ExampleAspNetCoreApplication.Test/ApplicationTest.cs b/TransformerBeeClient/ExampleAspNetCoreApplication.Test/ApplicationTest.cs index df0bb78..4e03b8a 100644 --- a/TransformerBeeClient/ExampleAspNetCoreApplication.Test/ApplicationTest.cs +++ b/TransformerBeeClient/ExampleAspNetCoreApplication.Test/ApplicationTest.cs @@ -1,4 +1,4 @@ -using System.Net; +using System.Net.Http.Json; using System.Text.Json; using System.Text.Json.Serialization; using FluentAssertions; @@ -20,10 +20,10 @@ public ApplicationTest(WebApplicationFactory factory) public async Task Test_That_Setup_Works_As_Designed() { var client = Factory.CreateDefaultClient(); - var response = await client.GetAsync("/talkToTransformerBee"); - response.StatusCode.Should().Be(HttpStatusCode.OK); - var content = await response.Content.ReadAsStringAsync(); - var bo4e = JsonSerializer.Deserialize(content, new JsonSerializerOptions { Converters = { new JsonStringEnumConverter() } }); + var bo4e = await client.GetFromJsonAsync( + "/talkToTransformerBee", + new JsonSerializerOptions { Converters = { new JsonStringEnumConverter() } } + ); bo4e.Should().NotBeNull(); } } diff --git a/TransformerBeeClient/ExampleAspNetCoreApplication.Test/ExampleAspNetCoreApplication.Test.csproj b/TransformerBeeClient/ExampleAspNetCoreApplication.Test/ExampleAspNetCoreApplication.Test.csproj index 9c19814..d52398c 100644 --- a/TransformerBeeClient/ExampleAspNetCoreApplication.Test/ExampleAspNetCoreApplication.Test.csproj +++ b/TransformerBeeClient/ExampleAspNetCoreApplication.Test/ExampleAspNetCoreApplication.Test.csproj @@ -1,12 +1,13 @@ - net8.0 + net9.0 enable enable false true + latest diff --git a/TransformerBeeClient/ExampleAspNetCoreApplication.Test/GlobalUsings.cs b/TransformerBeeClient/ExampleAspNetCoreApplication.Test/GlobalUsings.cs index 8c927eb..c802f44 100644 --- a/TransformerBeeClient/ExampleAspNetCoreApplication.Test/GlobalUsings.cs +++ b/TransformerBeeClient/ExampleAspNetCoreApplication.Test/GlobalUsings.cs @@ -1 +1 @@ -global using Xunit; \ No newline at end of file +global using Xunit; diff --git a/TransformerBeeClient/ExampleAspNetCoreApplication/ExampleAspNetCoreApplication.csproj b/TransformerBeeClient/ExampleAspNetCoreApplication/ExampleAspNetCoreApplication.csproj index 0bc8314..2ee7839 100644 --- a/TransformerBeeClient/ExampleAspNetCoreApplication/ExampleAspNetCoreApplication.csproj +++ b/TransformerBeeClient/ExampleAspNetCoreApplication/ExampleAspNetCoreApplication.csproj @@ -1,10 +1,11 @@ - net8.0 enable enable true + net8.0;net9.0 + latest diff --git a/TransformerBeeClient/ExampleAspNetCoreApplication/Program.cs b/TransformerBeeClient/ExampleAspNetCoreApplication/Program.cs index aedc283..75d163f 100644 --- a/TransformerBeeClient/ExampleAspNetCoreApplication/Program.cs +++ b/TransformerBeeClient/ExampleAspNetCoreApplication/Program.cs @@ -1,3 +1,5 @@ +using System.Text.Json; +using System.Text.Json.Serialization; using EDILibrary; using TransformerBeeClient; @@ -5,25 +7,36 @@ builder.Services.AddHttpClient(); builder.Services.AddTransient(); // Or you could use ClientIdClientSecretAuthenticator -builder.Services.AddHttpClient("TransformerBee", client => -{ - client.BaseAddress = new Uri("http://localhost:5021/"); // or https://transformerstage.utilibee.io -}); +builder.Services.AddHttpClient( + "TransformerBee", + client => + { + client.BaseAddress = new Uri("http://localhost:5021/"); // or https://transformerstage.utilibee.io + } +); builder.Services.AddTransient(); builder.Services.AddTransient(); var app = builder.Build(); app.MapGet("/", () => "I ❤ BO4E"); -app.MapGet("/talkToTransformerBee", async (ICanConvertToBo4e transformerBeeRestClient) => -{ - var bo4e = await transformerBeeRestClient.ConvertToBo4e( - "UNA:+,? 'UNB+UNOC:3+9912345789012:500+9909876543210:500+230703:1059+ASDFHGJ'UNH+11223344556678+UTILMD:D:11A:UN:S1.1'BGM+E01+918273746512345678901'DTM+137:202306300558?+00:303'NAD+MS+9912345789012::293'NAD+MR+9909876543210::293'IDE+24+918273746512345678901'IMD++Z36+Z13'DTM+92:202212312300?+00:303'STS+7++E01'LOC+Z16+78889918283'LOC+Z17+DE0000111122223333444455556667778'RFF+Z13:55001'SEQ+Z01'CCI+Z30++Z07'CCI+Z19++11X0-0000-0116-J'CCI+++Z15'CCI+++Z88'CAV+Z74:::Z09'CAV+Z73:::Z11'SEQ+Z12'QTY+Z16:0:P1'SEQ+Z03'CCI+++E13'CAV+Z30:::788811123'SEQ+Z75'CCI+Z61++ZG1'NAD+Z09+++Schaefer:Ulrike:::Frau:Z01'NAD+Z04+++Schaefer:Ulrike:::Frau:Z01+Flughafenstrasse::64+Vilseck++92247+DE'NAD+DP++++Flughafenstrasse::64+Vilseck++92247+DE'NAD+Z05+++Schaefer:Ulrike:::Frau:Z01+Flughafenstrasse::64+Vilseck++92247+DE'UNT+31+11223344556678'UNZ+1+ASDFHGJ'", - EdifactFormatVersion.FV2310); - return bo4e.Single().Transaktionen.Single(); -}); +app.MapGet( + "/talkToTransformerBee", + async (HttpContext context, ICanConvertToBo4e transformerBeeRestClient) => + { + var bo4e = await transformerBeeRestClient.ConvertToBo4e( + "UNA:+,? 'UNB+UNOC:3+9912345789012:500+9909876543210:500+230703:1059+ASDFHGJ'UNH+11223344556678+UTILMD:D:11A:UN:S1.1'BGM+E01+918273746512345678901'DTM+137:202306300558?+00:303'NAD+MS+9912345789012::293'NAD+MR+9909876543210::293'IDE+24+918273746512345678901'IMD++Z36+Z13'DTM+92:202212312300?+00:303'STS+7++E01'LOC+Z16+78889918283'LOC+Z17+DE0000111122223333444455556667778'RFF+Z13:55001'SEQ+Z01'CCI+Z30++Z07'CCI+Z19++11X0-0000-0116-J'CCI+++Z15'CCI+++Z88'CAV+Z74:::Z09'CAV+Z73:::Z11'SEQ+Z12'QTY+Z16:0:P1'SEQ+Z03'CCI+++E13'CAV+Z30:::788811123'SEQ+Z75'CCI+Z61++ZG1'NAD+Z09+++Schaefer:Ulrike:::Frau:Z01'NAD+Z04+++Schaefer:Ulrike:::Frau:Z01+Flughafenstrasse::64+Vilseck++92247+DE'NAD+DP++++Flughafenstrasse::64+Vilseck++92247+DE'NAD+Z05+++Schaefer:Ulrike:::Frau:Z01+Flughafenstrasse::64+Vilseck++92247+DE'UNT+31+11223344556678'UNZ+1+ASDFHGJ'", + EdifactFormatVersion.FV2310 + ); + context.Response.ContentType = System.Net.Mime.MediaTypeNames.Application.Json; + var result = bo4e.Single().Transaktionen.Single(); + var json = JsonSerializer.Serialize( + result, + new JsonSerializerOptions() { Converters = { new JsonStringEnumConverter() } } + ); + await context.Response.WriteAsync(json); + } +); app.Run(); -public partial class Program -{ -} // required for integration testing; If you miss this the test will complain, that it cannot find a 'testhost.deps.json' +public partial class Program { } // required for integration testing; If you miss this the test will complain, that it cannot find a 'testhost.deps.json' diff --git a/TransformerBeeClient/TransformerBeeClient.IntegrationTest/Bo4eToEdifactTests.cs b/TransformerBeeClient/TransformerBeeClient.IntegrationTest/Bo4eToEdifactTests.cs index deb5f23..b271e16 100644 --- a/TransformerBeeClient/TransformerBeeClient.IntegrationTest/Bo4eToEdifactTests.cs +++ b/TransformerBeeClient/TransformerBeeClient.IntegrationTest/Bo4eToEdifactTests.cs @@ -25,16 +25,19 @@ public Bo4eToEdifactTests(ClientFixture clientFixture) public async Task BOneyComb_Can_Be_Converted_To_Edifact() { var httpClientFactory = _client.HttpClientFactory; - ICanConvertToEdifact client = new TransformerBeeRestClient(httpClientFactory, _authenticator); + ICanConvertToEdifact client = new TransformerBeeRestClient( + httpClientFactory, + _authenticator + ); var boneyCombString = await File.ReadAllTextAsync("TestEdifacts/FV2310/55001.json"); var deserializerOptions = new JsonSerializerOptions { - Converters = - { - new JsonStringEnumConverter() - } + Converters = { new JsonStringEnumConverter() }, }; - var boneyComb = System.Text.Json.JsonSerializer.Deserialize(boneyCombString, deserializerOptions); + var boneyComb = System.Text.Json.JsonSerializer.Deserialize( + boneyCombString, + deserializerOptions + ); boneyComb.Should().NotBeNull(); var result = await client.ConvertToEdifact(boneyComb, EdifactFormatVersion.FV2310); result.Should().BeOfType().And.StartWith("UNB+UNOC"); diff --git a/TransformerBeeClient/TransformerBeeClient.IntegrationTest/ClientFixture.cs b/TransformerBeeClient/TransformerBeeClient.IntegrationTest/ClientFixture.cs index 1dec46b..5753154 100644 --- a/TransformerBeeClient/TransformerBeeClient.IntegrationTest/ClientFixture.cs +++ b/TransformerBeeClient/TransformerBeeClient.IntegrationTest/ClientFixture.cs @@ -17,10 +17,13 @@ public class ClientFixture : IClassFixture public ClientFixture() { var services = new ServiceCollection(); - services.AddHttpClient("TransformerBee", client => - { - client.BaseAddress = new Uri("http://localhost:5021"); // Check docker-compose.yml - }); + services.AddHttpClient( + "TransformerBee", + client => + { + client.BaseAddress = new Uri("http://localhost:5021"); // Check docker-compose.yml + } + ); var serviceProvider = services.BuildServiceProvider(); ServiceCollection = services; HttpClientFactory = serviceProvider.GetService(); diff --git a/TransformerBeeClient/TransformerBeeClient.IntegrationTest/ConnectionTests.cs b/TransformerBeeClient/TransformerBeeClient.IntegrationTest/ConnectionTests.cs index bdc0f28..00e1e3d 100644 --- a/TransformerBeeClient/TransformerBeeClient.IntegrationTest/ConnectionTests.cs +++ b/TransformerBeeClient/TransformerBeeClient.IntegrationTest/ConnectionTests.cs @@ -9,7 +9,6 @@ namespace TransformerBeeClient.IntegrationTest; /// public class ConnectionTests : IClassFixture { - private readonly ClientFixture _client; private readonly ITransformerBeeAuthenticator _authenticator; @@ -32,12 +31,18 @@ public async Task IsAvailable_Returns_True_If_Service_Is_Available() public async Task IsAvailable_Throws_Exception_If_Host_Is_Unavailable() { var services = new ServiceCollection(); - services.AddHttpClient("TransformerBee", client => - { - client.BaseAddress = new Uri("http://localhost:1234"); // <-- no service running under this address - }); + services.AddHttpClient( + "TransformerBee", + client => + { + client.BaseAddress = new Uri("http://localhost:1234"); // <-- no service running under this address + } + ); var serviceProvider = services.BuildServiceProvider(); - var client = new TransformerBeeRestClient(serviceProvider.GetService(), _authenticator); + var client = new TransformerBeeRestClient( + serviceProvider.GetService(), + _authenticator + ); var checkIfIsAvailable = async () => await client.IsAvailable(); await checkIfIsAvailable.Should().ThrowAsync(); } diff --git a/TransformerBeeClient/TransformerBeeClient.IntegrationTest/EdifactToBo4eTests.cs b/TransformerBeeClient/TransformerBeeClient.IntegrationTest/EdifactToBo4eTests.cs index 690cb96..8ced5cb 100644 --- a/TransformerBeeClient/TransformerBeeClient.IntegrationTest/EdifactToBo4eTests.cs +++ b/TransformerBeeClient/TransformerBeeClient.IntegrationTest/EdifactToBo4eTests.cs @@ -45,7 +45,10 @@ public class EdifactToBo4eTestsWithAuthentication : IClassFixture>(); diff --git a/TransformerBeeClient/TransformerBeeClient.IntegrationTest/GithubActionClientFixture.cs b/TransformerBeeClient/TransformerBeeClient.IntegrationTest/GithubActionClientFixture.cs index 0f8fb79..f70d8f1 100644 --- a/TransformerBeeClient/TransformerBeeClient.IntegrationTest/GithubActionClientFixture.cs +++ b/TransformerBeeClient/TransformerBeeClient.IntegrationTest/GithubActionClientFixture.cs @@ -24,10 +24,19 @@ public GithubActionClientFixture() return; } var services = new ServiceCollection(); - services.AddHttpClient("TransformerBee", client => { client.BaseAddress = new Uri("http://transformerstage.utilibee.io"); }); + services.AddHttpClient( + "TransformerBee", + client => + { + client.BaseAddress = new Uri("http://transformerstage.utilibee.io"); + } + ); var serviceProvider = services.BuildServiceProvider(); ServiceCollection = services; HttpClientFactory = serviceProvider.GetService(); - AuthenticationProvider = new ClientIdClientSecretAuthenticator(clientId: clientId, clientSecret: clientSecret); + AuthenticationProvider = new ClientIdClientSecretAuthenticator( + clientId: clientId, + clientSecret: clientSecret + ); } } diff --git a/TransformerBeeClient/TransformerBeeClient.IntegrationTest/MweWithoutAspNetTest.cs b/TransformerBeeClient/TransformerBeeClient.IntegrationTest/MweWithoutAspNetTest.cs index 7b00456..306777b 100644 --- a/TransformerBeeClient/TransformerBeeClient.IntegrationTest/MweWithoutAspNetTest.cs +++ b/TransformerBeeClient/TransformerBeeClient.IntegrationTest/MweWithoutAspNetTest.cs @@ -15,10 +15,7 @@ internal class MyHttpClientFactory : IHttpClientFactory { public HttpClient CreateClient(string name) { - return new HttpClient - { - BaseAddress = new Uri("http://localhost:5021") - }; + return new HttpClient { BaseAddress = new Uri("http://localhost:5021") }; } } @@ -28,6 +25,9 @@ public async Task Test_Transformer_Bee_Communication() IHttpClientFactory myFactory = new MyHttpClientFactory(); ITransformerBeeAuthenticator myAuthenticator = new NoAuthenticator(); // or use ClientIdClientSecretAuthenticator var client = new TransformerBeeRestClient(myFactory, myAuthenticator); - await client.ConvertToBo4e("UNA:+,? 'UNB+UNOC:3+9912345789012:500+9909876543210:500+230703:1059+ASDFHGJ'UNH+11223344556678+UTILMD:D:11A:UN:S1.1'BGM+E01+918273746512345678901'DTM+137:202306300558?+00:303'NAD+MS+9912345789012::293'NAD+MR+9909876543210::293'IDE+24+918273746512345678901'IMD++Z36+Z13'DTM+92:202212312300?+00:303'STS+7++E01'LOC+Z16+78889918283'LOC+Z17+DE0000111122223333444455556667778'RFF+Z13:55001'SEQ+Z01'CCI+Z30++Z07'CCI+Z19++11X0-0000-0116-J'CCI+++Z15'CCI+++Z88'CAV+Z74:::Z09'CAV+Z73:::Z11'SEQ+Z12'QTY+Z16:0:P1'SEQ+Z03'CCI+++E13'CAV+Z30:::788811123'SEQ+Z75'CCI+Z61++ZG1'NAD+Z09+++Schaefer:Ulrike:::Frau:Z01'NAD+Z04+++Schaefer:Ulrike:::Frau:Z01+Flughafenstrasse::64+Vilseck++92247+DE'NAD+DP++++Flughafenstrasse::64+Vilseck++92247+DE'NAD+Z05+++Schaefer:Ulrike:::Frau:Z01+Flughafenstrasse::64+Vilseck++92247+DE'UNT+31+11223344556678'UNZ+1+ASDFHGJ'", EdifactFormatVersion.FV2310); + await client.ConvertToBo4e( + "UNA:+,? 'UNB+UNOC:3+9912345789012:500+9909876543210:500+230703:1059+ASDFHGJ'UNH+11223344556678+UTILMD:D:11A:UN:S1.1'BGM+E01+918273746512345678901'DTM+137:202306300558?+00:303'NAD+MS+9912345789012::293'NAD+MR+9909876543210::293'IDE+24+918273746512345678901'IMD++Z36+Z13'DTM+92:202212312300?+00:303'STS+7++E01'LOC+Z16+78889918283'LOC+Z17+DE0000111122223333444455556667778'RFF+Z13:55001'SEQ+Z01'CCI+Z30++Z07'CCI+Z19++11X0-0000-0116-J'CCI+++Z15'CCI+++Z88'CAV+Z74:::Z09'CAV+Z73:::Z11'SEQ+Z12'QTY+Z16:0:P1'SEQ+Z03'CCI+++E13'CAV+Z30:::788811123'SEQ+Z75'CCI+Z61++ZG1'NAD+Z09+++Schaefer:Ulrike:::Frau:Z01'NAD+Z04+++Schaefer:Ulrike:::Frau:Z01+Flughafenstrasse::64+Vilseck++92247+DE'NAD+DP++++Flughafenstrasse::64+Vilseck++92247+DE'NAD+Z05+++Schaefer:Ulrike:::Frau:Z01+Flughafenstrasse::64+Vilseck++92247+DE'UNT+31+11223344556678'UNZ+1+ASDFHGJ'", + EdifactFormatVersion.FV2310 + ); } } diff --git a/TransformerBeeClient/TransformerBeeClient.IntegrationTest/TransformerBeeClient.IntegrationTest.csproj b/TransformerBeeClient/TransformerBeeClient.IntegrationTest/TransformerBeeClient.IntegrationTest.csproj index a2959af..25825ac 100644 --- a/TransformerBeeClient/TransformerBeeClient.IntegrationTest/TransformerBeeClient.IntegrationTest.csproj +++ b/TransformerBeeClient/TransformerBeeClient.IntegrationTest/TransformerBeeClient.IntegrationTest.csproj @@ -6,7 +6,8 @@ false true - net8.0;net6.0;net7.0 + net9.0 + latest diff --git a/TransformerBeeClient/TransformerBeeClient.UnitTest/ConnectionTests.cs b/TransformerBeeClient/TransformerBeeClient.UnitTest/ConnectionTests.cs index ae92893..59c3be9 100644 --- a/TransformerBeeClient/TransformerBeeClient.UnitTest/ConnectionTests.cs +++ b/TransformerBeeClient/TransformerBeeClient.UnitTest/ConnectionTests.cs @@ -10,12 +10,19 @@ public class ConnectionTests public void IsAvailable_Throws_ArgumentNullException_If_BaseAddress_Is_Not_Configured() { var services = new ServiceCollection(); - services.AddHttpClient("TransformerBee", client => - { - client.BaseAddress = null; - }); + services.AddHttpClient( + "TransformerBee", + client => + { + client.BaseAddress = null; + } + ); var serviceProvider = services.BuildServiceProvider(); - var instantiateClient = () => new TransformerBeeRestClient(serviceProvider.GetService(), new NoAuthenticator()); + var instantiateClient = () => + new TransformerBeeRestClient( + serviceProvider.GetService(), + new NoAuthenticator() + ); instantiateClient.Should().Throw(); } } diff --git a/TransformerBeeClient/TransformerBeeClient.UnitTest/TransformerBeeClient.UnitTest.csproj b/TransformerBeeClient/TransformerBeeClient.UnitTest/TransformerBeeClient.UnitTest.csproj index 87b814f..5b7e680 100644 --- a/TransformerBeeClient/TransformerBeeClient.UnitTest/TransformerBeeClient.UnitTest.csproj +++ b/TransformerBeeClient/TransformerBeeClient.UnitTest/TransformerBeeClient.UnitTest.csproj @@ -6,7 +6,8 @@ false true - net8.0;net6.0;net7.0 + net9.0 + latest diff --git a/TransformerBeeClient/TransformerBeeClient.sln.DotSettings.user b/TransformerBeeClient/TransformerBeeClient.sln.DotSettings.user index 40c3a5d..bcc3853 100644 --- a/TransformerBeeClient/TransformerBeeClient.sln.DotSettings.user +++ b/TransformerBeeClient/TransformerBeeClient.sln.DotSettings.user @@ -1,4 +1,7 @@ + ForceIncluded + ForceIncluded + ForceIncluded <SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from Solution #2" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> <Solution /> diff --git a/TransformerBeeClient/TransformerBeeClient/ClientIdClientSecretAuthenticator.cs b/TransformerBeeClient/TransformerBeeClient/ClientIdClientSecretAuthenticator.cs index 43845dd..7a465c9 100644 --- a/TransformerBeeClient/TransformerBeeClient/ClientIdClientSecretAuthenticator.cs +++ b/TransformerBeeClient/TransformerBeeClient/ClientIdClientSecretAuthenticator.cs @@ -1,8 +1,8 @@ namespace TransformerBeeClient; +using System.IdentityModel.Tokens.Jwt; using System.Security.Authentication; using IdentityModel.Client; -using System.IdentityModel.Tokens.Jwt; /// /// a that is based on a client secret and a client id @@ -43,15 +43,22 @@ public ClientIdClientSecretAuthenticator(string? clientId, string? clientSecret) { if (!string.IsNullOrWhiteSpace(clientId) && string.IsNullOrWhiteSpace(clientSecret)) { - throw new ArgumentNullException(nameof(clientSecret), $"If you provide a {nameof(clientId)} you must also provide a {nameof(clientSecret)}"); + throw new ArgumentNullException( + nameof(clientSecret), + $"If you provide a {nameof(clientId)} you must also provide a {nameof(clientSecret)}" + ); } if (!string.IsNullOrWhiteSpace(clientSecret) && string.IsNullOrWhiteSpace(clientId)) { - throw new ArgumentNullException(nameof(clientId), $"If you provide a {nameof(clientSecret)} you must also provide a {nameof(clientId)}"); + throw new ArgumentNullException( + nameof(clientId), + $"If you provide a {nameof(clientSecret)} you must also provide a {nameof(clientId)}" + ); } - _useAuthentication = !string.IsNullOrWhiteSpace(clientId) && !string.IsNullOrWhiteSpace(clientSecret); + _useAuthentication = + !string.IsNullOrWhiteSpace(clientId) && !string.IsNullOrWhiteSpace(clientSecret); if (_useAuthentication) { _clientId = clientId; @@ -69,7 +76,8 @@ private static bool TokenNeedsToBeRefreshed(string token) ArgumentNullException.ThrowIfNull(token); var handler = new JwtSecurityTokenHandler(); var jwtToken = handler.ReadToken(token) as JwtSecurityToken; - if (jwtToken == null) return true; // Assume renewal if token cannot be read + if (jwtToken == null) + return true; // Assume renewal if token cannot be read var expiry = jwtToken.ValidTo; // Consider a buffer to renew the token a bit before it actually expires var buffer = TimeSpan.FromMinutes(5); @@ -86,7 +94,9 @@ private static async Task GetDiscoveryDocument(HttpCl var discoveryDocument = await client.GetDiscoveryDocumentAsync(Auth0Domain); if (discoveryDocument.IsError) { - throw new AuthenticationException($"Could not get discovery document from auth0: {discoveryDocument.Error}"); + throw new AuthenticationException( + $"Could not get discovery document from auth0: {discoveryDocument.Error}" + ); } return discoveryDocument; @@ -103,7 +113,9 @@ public async Task Authenticate(HttpClient client) { if (!UseAuthentication()) { - throw new AuthenticationException("You must provide a client id and a client secret to the constructor to authenticate with the transformer bee"); + throw new AuthenticationException( + "You must provide a client id and a client secret to the constructor to authenticate with the transformer bee" + ); } if (!string.IsNullOrWhiteSpace(_token) && !TokenNeedsToBeRefreshed(_token)) @@ -125,7 +137,9 @@ public async Task Authenticate(HttpClient client) var tokenResponse = await client.RequestClientCredentialsTokenAsync(tokenRequest); if (tokenResponse.IsError) { - throw new AuthenticationException($"Could not get token from auth0: {tokenResponse.Error}"); + throw new AuthenticationException( + $"Could not get token from auth0: {tokenResponse.Error}" + ); } _token = tokenResponse.AccessToken!; diff --git a/TransformerBeeClient/TransformerBeeClient/Interfaces.cs b/TransformerBeeClient/TransformerBeeClient/Interfaces.cs index 1dd9eaf..b9f5984 100644 --- a/TransformerBeeClient/TransformerBeeClient/Interfaces.cs +++ b/TransformerBeeClient/TransformerBeeClient/Interfaces.cs @@ -15,7 +15,10 @@ public interface ICanConvertToBo4e /// edifact message as string /// /// - public Task> ConvertToBo4e(string edifact, EdifactFormatVersion formatVersion); + public Task> ConvertToBo4e( + string edifact, + EdifactFormatVersion formatVersion + ); } /// diff --git a/TransformerBeeClient/TransformerBeeClient/Model/Bo4eTransactionToEdifactRequest.cs b/TransformerBeeClient/TransformerBeeClient/Model/Bo4eTransactionToEdifactRequest.cs index ade7c34..765cdb8 100644 --- a/TransformerBeeClient/TransformerBeeClient/Model/Bo4eTransactionToEdifactRequest.cs +++ b/TransformerBeeClient/TransformerBeeClient/Model/Bo4eTransactionToEdifactRequest.cs @@ -10,7 +10,7 @@ internal class Bo4eTransactionToEdifactRequest // internally we only use system.text, no newtonsoft /// - /// the BOneyComb as json string + /// the BOneyComb as json string /// [System.Text.Json.Serialization.JsonPropertyName("BO4E")] public string? Bo4eJsonString { get; set; } diff --git a/TransformerBeeClient/TransformerBeeClient/Model/Marktnachricht.cs b/TransformerBeeClient/TransformerBeeClient/Model/Marktnachricht.cs index fb288df..cd535b5 100644 --- a/TransformerBeeClient/TransformerBeeClient/Model/Marktnachricht.cs +++ b/TransformerBeeClient/TransformerBeeClient/Model/Marktnachricht.cs @@ -19,7 +19,7 @@ public class Marktnachricht /// /// One marktnachricht contains at least 1 transaction aka BOneyComb /// - [JsonPropertyName("transaktionen")]// we want to support both System.Text and Newtonsoft as long as BO4E.net does so + [JsonPropertyName("transaktionen")] // we want to support both System.Text and Newtonsoft as long as BO4E.net does so [JsonProperty(PropertyName = "transaktionen")] public List? Transaktionen { get; set; } diff --git a/TransformerBeeClient/TransformerBeeClient/NoAutenticator.cs b/TransformerBeeClient/TransformerBeeClient/NoAutenticator.cs index fdf0e02..ed53dd8 100644 --- a/TransformerBeeClient/TransformerBeeClient/NoAutenticator.cs +++ b/TransformerBeeClient/TransformerBeeClient/NoAutenticator.cs @@ -9,6 +9,8 @@ public class NoAuthenticator : ITransformerBeeAuthenticator public Task Authenticate(HttpClient client) { - throw new NotImplementedException("This must never be called, because we don't use authentication."); + throw new NotImplementedException( + "This must never be called, because we don't use authentication." + ); } } diff --git a/TransformerBeeClient/TransformerBeeClient/RestClient.cs b/TransformerBeeClient/TransformerBeeClient/RestClient.cs index 4978ecc..25ad719 100644 --- a/TransformerBeeClient/TransformerBeeClient/RestClient.cs +++ b/TransformerBeeClient/TransformerBeeClient/RestClient.cs @@ -1,11 +1,11 @@ +using System.Net; +using System.Net.Http.Headers; using System.Security.Authentication; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; using EDILibrary; using TransformerBeeClient.Model; -using System.Net; -using System.Net.Http.Headers; namespace TransformerBeeClient; @@ -20,7 +20,7 @@ public class TransformerBeeRestClient : ICanConvertToBo4e, ICanConvertToEdifact private readonly JsonSerializerOptions _jsonSerializerOptions = new() { PropertyNameCaseInsensitive = true, - Converters = { new JsonStringEnumConverter() } + Converters = { new JsonStringEnumConverter() }, }; /// @@ -31,12 +31,19 @@ public class TransformerBeeRestClient : ICanConvertToBo4e, ICanConvertToEdifact /// something that tells you whether and how you need to authenticate yourself at transformer.bee /// name used to create the client /// Find the OpenAPI Spec here: https://transformerstage.utilibee.io/swagger/index.html - public TransformerBeeRestClient(IHttpClientFactory httpClientFactory, ITransformerBeeAuthenticator authenticator, string httpClientName = "TransformerBee") + public TransformerBeeRestClient( + IHttpClientFactory httpClientFactory, + ITransformerBeeAuthenticator authenticator, + string httpClientName = "TransformerBee" + ) { _httpClient = httpClientFactory.CreateClient(httpClientName); if (_httpClient.BaseAddress == null) { - throw new ArgumentNullException(nameof(httpClientFactory), $"The http client factory must provide a base address for the client with name '{httpClientName}'"); + throw new ArgumentNullException( + nameof(httpClientFactory), + $"The http client factory must provide a base address for the client with name '{httpClientName}'" + ); } _authenticator = authenticator ?? throw new ArgumentNullException(nameof(authenticator)); @@ -50,7 +57,10 @@ private async Task EnsureAuthentication() if (_authenticator.UseAuthentication()) { var token = await _authenticator.Authenticate(_httpClient); - _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); + _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( + "Bearer", + token + ); } } @@ -66,10 +76,7 @@ private async Task EnsureAuthentication() /// public async Task IsAvailable() { - var uriBuilder = new UriBuilder(_httpClient.BaseAddress!) - { - Path = "/version" - }; + var uriBuilder = new UriBuilder(_httpClient.BaseAddress!) { Path = "/version" }; var versionUrl = uriBuilder.Uri.AbsoluteUri; var response = await _httpClient.GetAsync(versionUrl); @@ -85,7 +92,10 @@ public async Task IsAvailable() /// /// /// - public async Task> ConvertToBo4e(string edifact, EdifactFormatVersion formatVersion) + public async Task> ConvertToBo4e( + string edifact, + EdifactFormatVersion formatVersion + ) { if (string.IsNullOrWhiteSpace(edifact)) { @@ -94,39 +104,54 @@ public async Task> ConvertToBo4e(string edifact, EdifactFor var uriBuilder = new UriBuilder(_httpClient!.BaseAddress!) { - Path = "/v1/transformer/EdiToBo4E" + Path = "/v1/transformer/EdiToBo4E", }; var convertUrl = uriBuilder.Uri.AbsoluteUri; - var request = new EdifactToBo4eRequest - { - Edifact = edifact, - FormatVersion = formatVersion, - }; + var request = new EdifactToBo4eRequest { Edifact = edifact, FormatVersion = formatVersion }; var requestJson = JsonSerializer.Serialize(request, _jsonSerializerOptions); await EnsureAuthentication(); - var httpResponse = await _httpClient.PostAsync(convertUrl, new StringContent(requestJson, Encoding.UTF8, "application/json")); + var httpResponse = await _httpClient.PostAsync( + convertUrl, + new StringContent(requestJson, Encoding.UTF8, "application/json") + ); if (!httpResponse.IsSuccessStatusCode) { var errorContent = await httpResponse.Content.ReadAsStringAsync(); - if (httpResponse.StatusCode == HttpStatusCode.Unauthorized && !_authenticator.UseAuthentication()) + if ( + httpResponse.StatusCode == HttpStatusCode.Unauthorized + && !_authenticator.UseAuthentication() + ) { - throw new AuthenticationException($"Did you correctly set up the {nameof(ITransformerBeeAuthenticator)}?"); + throw new AuthenticationException( + $"Did you correctly set up the {nameof(ITransformerBeeAuthenticator)}?" + ); } - throw new HttpRequestException($"Could not convert {edifact} to BO4E. Status code: {httpResponse.StatusCode} / {errorContent}"); + throw new HttpRequestException( + $"Could not convert {edifact} to BO4E. Status code: {httpResponse.StatusCode} / {errorContent}" + ); } var responseContent = await httpResponse.Content.ReadAsStringAsync(); - var bo4eResponse = JsonSerializer.Deserialize(responseContent, _jsonSerializerOptions); + var bo4eResponse = JsonSerializer.Deserialize( + responseContent, + _jsonSerializerOptions + ); // todo: handle the case that the deserialization fails and bo4eResponse is null var unescapedJson = bo4eResponse!.Bo4eJsonString!.Unescape(); - var result = JsonSerializer.Deserialize>(unescapedJson!, _jsonSerializerOptions); + var result = JsonSerializer.Deserialize>( + unescapedJson!, + _jsonSerializerOptions + ); // todo: handle the case that the deserialization fails and result is null return result!; } - public async Task ConvertToEdifact(BOneyComb boneyComb, EdifactFormatVersion formatVersion) + public async Task ConvertToEdifact( + BOneyComb boneyComb, + EdifactFormatVersion formatVersion + ) { if (boneyComb is null) { @@ -135,7 +160,7 @@ public async Task ConvertToEdifact(BOneyComb boneyComb, EdifactFormatVer var uriBuilder = new UriBuilder(_httpClient!.BaseAddress!) { - Path = "/v1/transformer/Bo4ETransactionToEdi" + Path = "/v1/transformer/Bo4ETransactionToEdi", }; var convertUrl = uriBuilder.Uri.AbsoluteUri; @@ -147,21 +172,34 @@ public async Task ConvertToEdifact(BOneyComb boneyComb, EdifactFormatVer }; var requestJson = JsonSerializer.Serialize(request, _jsonSerializerOptions); await EnsureAuthentication(); - var httpResponse = await _httpClient.PostAsync(convertUrl, new StringContent(requestJson, Encoding.UTF8, "application/json")); + var httpResponse = await _httpClient.PostAsync( + convertUrl, + new StringContent(requestJson, Encoding.UTF8, "application/json") + ); if (!httpResponse.IsSuccessStatusCode) { var errorContent = await httpResponse.Content.ReadAsStringAsync(); - if (httpResponse.StatusCode == HttpStatusCode.Unauthorized && !_authenticator.UseAuthentication()) + if ( + httpResponse.StatusCode == HttpStatusCode.Unauthorized + && !_authenticator.UseAuthentication() + ) { - throw new AuthenticationException($"Did you correctly set up the {nameof(ITransformerBeeAuthenticator)}?"); + throw new AuthenticationException( + $"Did you correctly set up the {nameof(ITransformerBeeAuthenticator)}?" + ); } - throw new HttpRequestException($"Could not convert to EDIFACT; Status code: {httpResponse.StatusCode} / {errorContent}"); + throw new HttpRequestException( + $"Could not convert to EDIFACT; Status code: {httpResponse.StatusCode} / {errorContent}" + ); } var responseContent = await httpResponse.Content.ReadAsStringAsync(); // todo: ensure that the deserialization does not fail and the response is not empty - var responseBody = JsonSerializer.Deserialize(responseContent!, _jsonSerializerOptions); + var responseBody = JsonSerializer.Deserialize( + responseContent!, + _jsonSerializerOptions + ); // todo: handle case that deserialization fails and responseBody is null return responseBody!.Edifact!; } diff --git a/TransformerBeeClient/TransformerBeeClient/TransformerBeeClient.csproj b/TransformerBeeClient/TransformerBeeClient/TransformerBeeClient.csproj index e34985c..45ffeab 100644 --- a/TransformerBeeClient/TransformerBeeClient/TransformerBeeClient.csproj +++ b/TransformerBeeClient/TransformerBeeClient/TransformerBeeClient.csproj @@ -3,7 +3,7 @@ enable enable - net8.0;net6.0;net7.0 + net8.0;net9.0 https://github.com/Hochfrequenz/TransformerBeeClient.NET MIT diff --git a/TransformerBeeClient/global.json b/TransformerBeeClient/global.json index 6fbe9d0..a27a2b8 100644 --- a/TransformerBeeClient/global.json +++ b/TransformerBeeClient/global.json @@ -1,7 +1,7 @@ { "sdk": { - "version": "6.0.0", + "version": "9.0.0", "rollForward": "latestMajor", - "allowPrerelease": true + "allowPrerelease": false } -} +} \ No newline at end of file