From a0d29631fc4ae20e826294a985eea9e035cfacbc Mon Sep 17 00:00:00 2001 From: CDR-AidenJ Date: Wed, 7 Oct 2026 16:43:56 +1100 Subject: [PATCH 1/2] v5.0.0 release (#96)z Co-authored-by: CDR Open Source Co-authored-by: AidenJahani --- .azuredevops/pipelines/build-v2.yml | 10 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/sonarcloud-analysis.yml | 2 +- CHANGELOG.md | 11 + Help/debugging/HELP.md | 4 +- Help/testing/HELP.md | 4 +- README.md | 26 +- SECURITY.md | 3 +- ...lder.Banking.Resource.API.UnitTests.csproj | 2 +- .../Data/seed-data.json | 24 +- .../Fixtures/SeedDataFixture.cs | 2 +- ...CDR.DataHolder.Banking.Resource.API.csproj | 1 - .../Controllers/ResourceController.cs | 8 +- .../Startup.cs | 42 ++- .../BaseTest.cs | 7 +- ...lder.Banking.Tests.IntegrationTests.csproj | 3 +- .../US12973_MDH_CommonAPI_GetCustomer.cs | 2 +- .../US12975_MDH_BankingAPI_GetAccounts.cs | 2 +- .../US15350_MDH_BankingAPI_GetTransactions.cs | 11 +- .../XUnit/Orderers/AlphabeticalOrderer.cs | 22 +- .../appsettings.Development.json | 2 +- .../appsettings.Release.json | 2 +- .../Controllers/CommonController.cs | 6 +- .../ServiceCollectionExtension.cs | 16 +- .../CDR.DataHolder.Common.API/Program.cs | 31 +-- Source/DataHolder.sln | 248 ----------------- Source/DataHolder.slnx | 95 +++++++ Source/DataHolder_Shared.sln | 263 ------------------ Source/DataHolder_Shared.slnx | 101 +++++++ Source/Directory.Build.props | 4 +- Source/Directory.Packages.props | 67 ++--- Source/Dockerfile | 34 +-- Source/Dockerfile.integration-tests | 5 +- Source/Dockerfile.unit-tests | 8 +- ...older.Energy.Resource.API.UnitTests.csproj | 2 +- .../Fixtures/SeedDataFixture.cs | 2 +- .../Business/MappingProfile.cs | 9 - .../Business/Models/EnergyAccount.cs | 3 + .../Business/Models/EnergyAccountV2.cs | 10 - .../CDR.DataHolder.Energy.Resource.API.csproj | 1 - .../Controllers/ResourceController.cs | 32 +-- .../Startup.cs | 29 +- .../BaseTest.cs | 7 +- ...older.Energy.Tests.IntegrationTests.csproj | 3 +- .../US27571_MDH_EnergyAPI_GetAccounts.cs | 38 +-- ...USX00001_MDH_InfosecProfileAPI_PAR_FAPI.cs | 4 +- .../XUnit/Orderers/AlphabeticalOrderer.cs | 22 +- .../appsettings.Development.json | 2 +- .../appsettings.Release.json | 2 +- .../CDR.DataHolder.Admin.API.csproj | 1 - .../Controllers/AdminController.cs | 23 +- .../CDR.DataHolder.Admin.API/Startup.cs | 23 +- .../CDR.DataHolder.Admin.API/appsettings.json | 2 - .../CDR.DataHolder.Manage.API.csproj | 1 - .../ServiceCollectionExtension.cs | 7 +- .../CDR.DataHolder.Manage.API/Startup.cs | 13 +- .../CDR.DataHolder.Public.API.csproj | 3 +- .../Controllers/DiscoveryController.cs | 8 +- .../CDR.DataHolder.Public.API/Startup.cs | 21 +- .../Certificates/CertificateValidator.cs | 2 +- ...Shared.API.Infrastructure.UnitTests.csproj | 2 +- .../HttpClientHandlerExtensionsTests.cs | 33 ++- .../Authorisation/PolicyAuthorizeAttribute.cs | 2 +- ...ataHolder.Shared.API.Infrastructure.csproj | 3 +- .../Constants.cs | 5 + .../CdrSwaggerMiddlewareExtensions.cs | 54 ++++ .../Extensions/ConfigExtensions.cs | 2 +- .../Extensions/HttpContextExtensions.cs | 2 +- .../NameValueCollectionExtensions.cs | 6 +- .../Filters/CheckXVAttribute.cs | 62 ----- .../Filters/SetVersionResponseAttribute.cs | 24 ++ .../IdPermanence/IdPermanenceHelper.cs | 2 +- .../Middleware/ApiExceptionHandler.cs | 2 +- .../Middleware/InteractionIdMiddleware.cs | 4 +- .../Models/CdrApiEndpointVersionOptions.cs | 52 ++++ .../Models/CdrApiOptions.cs | 62 +++++ .../Models/ErrorResponseVersion.cs | 58 ---- .../Versioning/ApiVersionSelector.cs | 133 --------- .../Versioning/CdrApiVersioning.cs | 34 +++ .../Versioning/CdrVersionReader.cs | 97 +++++++ .../RequestResponseLoggingMiddleware.cs | 6 +- .../Extensions.cs | 2 +- ...esourceAuthoriseErrorHandlingMiddleware.cs | 4 +- .../Infrastructure/Extensions.cs | 2 +- Source/supervisord.conf | 10 +- 85 files changed, 845 insertions(+), 1158 deletions(-) delete mode 100644 Source/DataHolder.sln create mode 100644 Source/DataHolder.slnx delete mode 100644 Source/DataHolder_Shared.sln create mode 100644 Source/DataHolder_Shared.slnx delete mode 100644 Source/Energy/CDR.DataHolder.Energy.Resource.API/Business/Models/EnergyAccountV2.cs create mode 100644 Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Extensions/CdrSwaggerMiddlewareExtensions.cs delete mode 100644 Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Filters/CheckXVAttribute.cs create mode 100644 Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Filters/SetVersionResponseAttribute.cs create mode 100644 Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Models/CdrApiEndpointVersionOptions.cs create mode 100644 Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Models/CdrApiOptions.cs delete mode 100644 Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Models/ErrorResponseVersion.cs delete mode 100644 Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Versioning/ApiVersionSelector.cs create mode 100644 Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Versioning/CdrApiVersioning.cs create mode 100644 Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Versioning/CdrVersionReader.cs diff --git a/.azuredevops/pipelines/build-v2.yml b/.azuredevops/pipelines/build-v2.yml index 2465774..2540ab9 100644 --- a/.azuredevops/pipelines/build-v2.yml +++ b/.azuredevops/pipelines/build-v2.yml @@ -424,18 +424,18 @@ jobs: ################################################################################################### - task: UseDotNet@2 - displayName: 'Use .NET 8 sdk' + displayName: 'Use .NET 10 sdk' condition: always() inputs: packageType: sdk - version: '8.0.x' + version: '10.0.x' performMultiLevelLookup: true - task: CmdLine@2 displayName: 'Install dotnet-ef' condition: always() inputs: - script: 'dotnet tool install --version 8.0.4 --global dotnet-ef' + script: 'dotnet tool install --version 10.0.11 --global dotnet-ef' - task: CmdLine@2 displayName: 'Check dotnet-ef version' @@ -447,6 +447,7 @@ jobs: # MDH Banking - script: | cd $(baseSourceDirectory)/Banking/CDR.DataHolder.Banking.Repository + dotnet restore dotnet ef migrations bundle --context BankingDataHolderDatabaseContext --verbose --self-contained ls displayName: 'Run EF Migrations bundle (Banking)' @@ -460,6 +461,7 @@ jobs: # MDH Energy - script: | cd $(baseSourceDirectory)/Energy/CDR.DataHolder.Energy.Repository + dotnet restore dotnet ef migrations bundle --context EnergyDataHolderDatabaseContext --verbose --self-contained ls displayName: 'Run EF Migrations bundle (Energy)' @@ -473,7 +475,7 @@ jobs: # CdrAuthServer - script: | cd $(Build.SourcesDirectory)/sb-mock-data-holder/Source/cdr-auth-server/Source/CdrAuthServer.Repository - + dotnet restore dotnet ef migrations bundle --context CdrAuthServerDatabaseContext --verbose --self-contained ls displayName: 'Run EF Migrations bundle (CdrAuthServer)' diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 425388f..eebb754 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -73,7 +73,7 @@ jobs: - name: Build solution run: | - dotnet build ./Source/DataHolder.sln --configuration 'Release' + dotnet build ./Source/DataHolder.slnx --configuration 'Release' - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/sonarcloud-analysis.yml b/.github/workflows/sonarcloud-analysis.yml index e92d51e..dbff1ea 100644 --- a/.github/workflows/sonarcloud-analysis.yml +++ b/.github/workflows/sonarcloud-analysis.yml @@ -74,5 +74,5 @@ jobs: shell: powershell run: | .\.sonar\scanner\dotnet-sonarscanner begin /k:"ConsumerDataRight_mock-data-holder" /o:"consumerdataright" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" - dotnet build .\source\DataHolder.sln + dotnet build .\source\DataHolder.slnx .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}" diff --git a/CHANGELOG.md b/CHANGELOG.md index 01f1112..e2c48cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +## [5.0.0] - 2026-09-30 +### Changed +- Migrated from .NET 8 to .NET 10 +- Migrated xUnit from v2 to v3 +- Updated Swashbuckle and swagger pages +- Removed obsolete Get Energy Accounts V1 and Get Metrics V4 APIs +- Updated to use .NET 10 version of ConsumerDataRight.ParticipantTooling.MockSolution.TestAutomation +- Updated NuGet packages +- Migrate slnx files to slnx + ## [4.0.5] - 2026-07-08 ### Changed - Updated NuGet packages diff --git a/Help/debugging/HELP.md b/Help/debugging/HELP.md index 29d40d6..178fed3 100644 --- a/Help/debugging/HELP.md +++ b/Help/debugging/HELP.md @@ -42,8 +42,8 @@ An output window will be launched for the Authorisation Server project showing t ## Run solution using MS Visual Studio There are two Visual Studio solution files that are available for use: -- DataHolder.sln - This is the default solution file that is used primarily for running and debugging the Mock Data Holder projects. -- DataHolder_Shared.sln - In addition to the Mock Data Holder projects, this solution file also opens the [Mock Solutions Test Automation](https://github.com/ConsumerDataRight/mock-solution-test-automation) project. This is useful when wanting to debug or step through source code used in Mock Solution Test Automation project. Further information can be found in [Mock Data Holder Test Automation Execution Guide](../testing/HELP.md) +- DataHolder.slnx - This is the default solution file that is used primarily for running and debugging the Mock Data Holder projects. +- DataHolder_Shared.slnx - In addition to the Mock Data Holder projects, this solution file also opens the [Mock Solutions Test Automation](https://github.com/ConsumerDataRight/mock-solution-test-automation) project. This is useful when wanting to debug or step through source code used in Mock Solution Test Automation project. Further information can be found in [Mock Data Holder Test Automation Execution Guide](../testing/HELP.md) ### Start the Mock Data Holder Banking diff --git a/Help/testing/HELP.md b/Help/testing/HELP.md index fe9877a..c167d11 100644 --- a/Help/testing/HELP.md +++ b/Help/testing/HELP.md @@ -153,7 +153,7 @@ Tests can now be run using Microsoft Visual Studio. The following steps detail the process of running tests using Microsoft Visual Studio's Test Explorer: -1. Open the [DataHolder.sln](../../Source/DataHolder.sln) solution file in Microsoft Visual Studio. +1. Open the [DataHolder.slnx](../../Source/DataHolder.slnx) solution file in Microsoft Visual Studio. 2. Build the solution. 3. Open the Test Explorer. If Test Explorer is not visible, choose 'Test' on the Visual Studio menu and then choose 'Test Explorer'. @@ -175,7 +175,7 @@ This repository can be cloned using following command: git clone https://github.com/ConsumerDataRight/mock-solution-test-automation.git ``` -The [DataHolder_Shared.sln](../../Source/DataHolder_Shared.sln) solution has been created to allow for debugging and stepping through the source code used in Mock Solution Test Automation project. +The [DataHolder_Shared.slnx](../../Source/DataHolder_Shared.slnx) solution has been created to allow for debugging and stepping through the source code used in Mock Solution Test Automation project. [Data Holder Shared Solution in Microsoft Visual Studio](./images/MS-Visual-Studio-View-Data-Holder-Shared-Solution.png) diff --git a/README.md b/README.md index 7d3966e..411e272 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ![Consumer Data Right Logo](./Assets/cdr-logo.png?raw=true) -[![Consumer Data Standards v1.34.0](https://img.shields.io/badge/Consumer%20Data%20Standards-v1.34.0-blue.svg)](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.34.0/#introduction) -[![Conformance Test Suite Data Holders 5.2.0](https://img.shields.io/badge/Conformance%20Test%20Suite%20Data%20Holders-v5.2.0-darkblue.svg)](https://www.cdr.gov.au/for-providers/conformance-test-suite-data-holders) +[![Consumer Data Standards v1.36.0](https://img.shields.io/badge/Consumer%20Data%20Standards-v1.34.0-blue.svg)](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.36.0/#introduction) +[![Conformance Test Suite Data Holders 5.3.0](https://img.shields.io/badge/Conformance%20Test%20Suite%20Data%20Holders-v5.3.0-darkblue.svg)](https://www.cdr.gov.au/for-providers/conformance-test-suite-data-holders) [![FAPI 1.0 Advanced Profile](https://img.shields.io/badge/FAPI%201.0-orange.svg)](https://openid.net/specs/openid-financial-api-part-2-1_0.html) [![made-with-dotnet](https://img.shields.io/badge/Made%20with-.NET-1f425Ff.svg)](https://dotnet.microsoft.com/) [![made-with-csharp](https://img.shields.io/badge/Made%20with-C%23-1f425Ff.svg)](https://docs.microsoft.com/en-us/dotnet/csharp/) @@ -17,8 +17,8 @@ The Mock Data Holder solution can be configured for Banking or Energy industries ## Mock Data Holder - Alignment The Mock Data Holder: -* aligns to [v1.34.0](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.34.0/#introduction) of the [Consumer Data Standards](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.34.0/#introduction) in particular [FAPI 1.0 Migration Phase 3](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.34.0/#introduction) with backwards compatibility to Migration Phase 2; -* has passed v5.2.0 of the [Conformance Test Suite for Data Holders](https://www.cdr.gov.au/for-providers/conformance-test-suite-data-holders); and +* aligns to [v1.36.0](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.36.0/#introduction) of the [Consumer Data Standards](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.36.0/#introduction) in particular [FAPI 1.0 Migration Phase 3](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.36.0/#introduction) with backwards compatibility to Migration Phase 2; +* has passed v5.3.0 of the [Conformance Test Suite for Data Holders](https://www.cdr.gov.au/for-providers/conformance-test-suite-data-holders); and * is compliant with the [FAPI 1.0 Advanced Profile](https://openid.net/specs/openid-financial-api-part-2-1_0.html). ## Getting Started @@ -138,16 +138,16 @@ The [docker compose file](./Source/DockerCompose/docker-compose.yml) can be used To get help on launching and debugging the solutions as containers and switching out your solution(s), see the [help guide](./Help/container/HELP.md). ## Mock Data Holder - Requirements -Data Holders require these core functions defined in the [Consumer Data Standards](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.34.0/#introduction) to operate in the [Consumer Data Right](https://www.cdr.gov.au/): -- Identity Provider for [authentication and authorisation](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.34.0/#security-profile). Compliant with OAuth and [FAPI 1.0 Advanced Profile](https://openid.net/specs/openid-financial-api-part-2-1_0.html). -- [Dynamic Client Registration](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.34.0/#dcr-apis) to allow clients to register their Software Products. -- Data Recipient and Software Product metadata updates using the [Register APIs](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.34.0/#register-apis). +Data Holders require these core functions defined in the [Consumer Data Standards](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.36.0/#introduction) to operate in the [Consumer Data Right](https://www.cdr.gov.au/): +- Identity Provider for [authentication and authorisation](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.36.0/#security-profile). Compliant with OAuth and [FAPI 1.0 Advanced Profile](https://openid.net/specs/openid-financial-api-part-2-1_0.html). +- [Dynamic Client Registration](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.36.0/#dcr-apis) to allow clients to register their Software Products. +- Data Recipient and Software Product metadata updates using the [Register APIs](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.36.0/#register-apis). - Industry specific data (one of) - - [Banking APIs](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.34.0/#banking-apis). - - [Energy APIs](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.34.0/#energy-apis) + - [Banking APIs](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.36.0/#banking-apis). + - [Energy APIs](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.36.0/#energy-apis) - Industry agnostic data - - [Common APIs](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.34.0/#common-apis). -- [Metrics and metadata update requests](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.34.0/#admin-apis). + - [Common APIs](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.36.0/#common-apis). +- [Metrics and metadata update requests](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.36.0/#admin-apis). The Mock Data Holder combined with the [Authorisation Server](https://github.com/ConsumerDataRight/authorisation-server) provides all of these functions for the Banking and Energy industries. The below diagram provides a view of the Mock Data Holder and and Authorisation Server when opened in an integrated development environment. @@ -225,7 +225,7 @@ The Mock Data Holder contains the following components: ## Technology Stack The following technologies have been used to build the Mock Data Holder: -- The source code has been written in `C#` using the `.Net 8` framework. +- The source code has been written in `C#` using the `.Net 10` framework. - The Identity Provider is implemented using the [Authorisation Server](https://github.com/ConsumerDataRight/authorisation-server). - The mTLS Gateway has been implemented using `Ocelot`. - The Repository utilises a `SQL` instance. diff --git a/SECURITY.md b/SECURITY.md index 8295801..f6a7eb2 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -11,7 +11,8 @@ Visit our [Responsible disclosure of security vulnerabilities policy](https://ww | Version | Supported | | ------- | ------------------ | -| 4.0.x | :white_check_mark: | +| 5.x.x | :white_check_mark: | +| 4.x.x | :x: | | 3.x.x | :x: | | 2.x.x | :x: | | 1.x.x | :x: | diff --git a/Source/Banking/CDR.DataHolder.Banking.Resource.API.UnitTests/CDR.DataHolder.Banking.Resource.API.UnitTests.csproj b/Source/Banking/CDR.DataHolder.Banking.Resource.API.UnitTests/CDR.DataHolder.Banking.Resource.API.UnitTests.csproj index 79f8e95..3d4341e 100644 --- a/Source/Banking/CDR.DataHolder.Banking.Resource.API.UnitTests/CDR.DataHolder.Banking.Resource.API.UnitTests.csproj +++ b/Source/Banking/CDR.DataHolder.Banking.Resource.API.UnitTests/CDR.DataHolder.Banking.Resource.API.UnitTests.csproj @@ -39,7 +39,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Source/Banking/CDR.DataHolder.Banking.Resource.API.UnitTests/Data/seed-data.json b/Source/Banking/CDR.DataHolder.Banking.Resource.API.UnitTests/Data/seed-data.json index 6000b1b..4a3404e 100644 --- a/Source/Banking/CDR.DataHolder.Banking.Resource.API.UnitTests/Data/seed-data.json +++ b/Source/Banking/CDR.DataHolder.Banking.Resource.API.UnitTests/Data/seed-data.json @@ -2,7 +2,7 @@ "Customers": [ { "CustomerID": "4ee1a8db-13af-44d7-b54b-e94dff3df548", - "CustomerUType": "PERSON", + "CustomerUType": "person", "LoginId" : "jsmith", "Person": { "PersonID": "be36d5b8-8d92-4076-81c1-2260ba7e7272", @@ -133,7 +133,7 @@ }, { "CustomerID": "bfb689fb-7745-45b9-bbaa-b21e00072447", - "CustomerUType": "PERSON", + "CustomerUType": "person", "LoginId": "jwilson", "Person": { "PersonID": "3f0b4a8a-4f0a-49ac-b561-11903a072d22", @@ -722,7 +722,7 @@ }, { "CustomerID": "f0a87c57-9a98-401f-9012-b6ac0c882bf7", - "CustomerUType": "PERSON", + "CustomerUType": "person", "LoginId": "lbj", "Person": { "PersonID": "b4715700-aab1-42ad-a171-517a02738365", @@ -758,7 +758,7 @@ }, { "CustomerID": "aa649633-eed2-4e56-b97d-7df150360942", - "CustomerUType": "PERSON", + "CustomerUType": "person", "LoginId": "ksmith", "Person": { "PersonID": "3bf33bd5-a838-4a23-9fc1-a32ab92cf694", @@ -1142,7 +1142,7 @@ }, { "CustomerID": "dcb72d59-73e9-4807-9b1e-f3e2654190f4", - "CustomerUType": "PERSON", + "CustomerUType": "person", "LoginId": "ssmith", "Person": { "PersonID": "bfc3a55a-81c1-427a-8a30-7eeb85560f2f", @@ -1178,7 +1178,7 @@ }, { "CustomerID": "390b6e62-db5e-40b9-a0b8-dfb158b1326b", - "CustomerUType": "PERSON", + "CustomerUType": "person", "LoginId": "rray", "Person": { "PersonID": "c674766c-371d-41f2-a3a0-5681ea96c9a2", @@ -1230,7 +1230,7 @@ }, { "CustomerID": "1cdedda0-1669-4590-842a-fd5a4021dd30", - "CustomerUType": "PERSON", + "CustomerUType": "person", "LoginId": "pjay", "Person": { "PersonID": "3ff40f07-1798-4577-ae42-1c5d7329bce9", @@ -1266,7 +1266,7 @@ }, { "CustomerID": "3b7715c5-b7a6-4d4b-888e-fc2dadf3e91e", - "CustomerUType": "PERSON", + "CustomerUType": "person", "LoginId": "olee", "Person": { "PersonID": "045da794-b5f4-43e7-92f9-6b7f5c36abdf", @@ -1302,7 +1302,7 @@ }, { "CustomerID": "75455a64-d1d6-44b9-845c-8a9330e55937", - "CustomerUType": "PERSON", + "CustomerUType": "person", "LoginId": "ldame", "Person": { "PersonID": "0fe698a5-34a1-482b-93c7-55e5a47a8064", @@ -1338,7 +1338,7 @@ }, { "CustomerID": "6a1aaf2f-379c-45b7-ad54-f8104896c683", - "CustomerUType": "PERSON", + "CustomerUType": "person", "LoginId": "mmia", "Person": { "PersonID": "88041dea-f480-43d2-80be-555339fbac3d", @@ -1374,7 +1374,7 @@ }, { "CustomerID": "688e36cf-bfc7-46bb-855b-c70893daa800", - "CustomerUType": "PERSON", + "CustomerUType": "person", "LoginId": "dsteve", "Person": { "PersonID": "070e0ca0-cb17-41a4-ae05-937e70e0cb89", @@ -1453,7 +1453,7 @@ }, { "CustomerID": "4705eba7-daae-4dca-a1f9-12aa785a702f", - "CustomerUType": "PERSON", + "CustomerUType": "person", "LoginId": "sken", "Person": { "PersonID": "9090793f-f366-48d3-99ae-c9ab4aefd0f1", diff --git a/Source/Banking/CDR.DataHolder.Banking.Resource.API.UnitTests/Fixtures/SeedDataFixture.cs b/Source/Banking/CDR.DataHolder.Banking.Resource.API.UnitTests/Fixtures/SeedDataFixture.cs index 9a7b3e4..346fb51 100644 --- a/Source/Banking/CDR.DataHolder.Banking.Resource.API.UnitTests/Fixtures/SeedDataFixture.cs +++ b/Source/Banking/CDR.DataHolder.Banking.Resource.API.UnitTests/Fixtures/SeedDataFixture.cs @@ -41,7 +41,7 @@ public SeedDataFixture() services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(dispose: true)); - services.AddAutoMapper(typeof(Startup), typeof(BankingDataHolderDatabaseContext)); + services.AddAutoMapper(cfg => { }, typeof(Startup).Assembly, typeof(BankingDataHolderDatabaseContext).Assembly); services.AddScoped(c => configuration); services.AddScoped(); diff --git a/Source/Banking/CDR.DataHolder.Banking.Resource.API/CDR.DataHolder.Banking.Resource.API.csproj b/Source/Banking/CDR.DataHolder.Banking.Resource.API/CDR.DataHolder.Banking.Resource.API.csproj index 06c907a..cdcc532 100644 --- a/Source/Banking/CDR.DataHolder.Banking.Resource.API/CDR.DataHolder.Banking.Resource.API.csproj +++ b/Source/Banking/CDR.DataHolder.Banking.Resource.API/CDR.DataHolder.Banking.Resource.API.csproj @@ -29,7 +29,6 @@ - diff --git a/Source/Banking/CDR.DataHolder.Banking.Resource.API/Controllers/ResourceController.cs b/Source/Banking/CDR.DataHolder.Banking.Resource.API/Controllers/ResourceController.cs index a18dea9..2159cb4 100644 --- a/Source/Banking/CDR.DataHolder.Banking.Resource.API/Controllers/ResourceController.cs +++ b/Source/Banking/CDR.DataHolder.Banking.Resource.API/Controllers/ResourceController.cs @@ -1,4 +1,5 @@ -using AutoMapper; +using Asp.Versioning; +using AutoMapper; using CDR.DataHolder.Banking.Domain.Repositories; using CDR.DataHolder.Banking.Resource.API.Business.Filters; using CDR.DataHolder.Banking.Resource.API.Business.Models; @@ -13,7 +14,6 @@ using CDR.DataHolder.Shared.Domain.Models; using CDR.DataHolder.Shared.Domain.ValueObjects; using CDR.DataHolder.Shared.Resource.API.Business.Filters; -using CDR.DataHolder.Shared.Resource.API.Infrastructure.Filters; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; @@ -57,8 +57,8 @@ public ResourceController( [PolicyAuthorize(AuthorisationPolicy.GetAccountsApi)] [HttpGet("v1/banking/accounts", Name = nameof(GetAccountsV2))] [CheckScope(ApiScopes.Banking.AccountsBasicRead)] - [CheckXV(2, 2)] [CheckAuthDate] + [SetVersionResponse(2)] [ApiVersion("2")] [ServiceFilter(typeof(LogActionEntryAttribute))] public async Task GetAccountsV2( @@ -113,8 +113,8 @@ public async Task GetAccountsV2( [PolicyAuthorize(AuthorisationPolicy.GetTransactionsApi)] [HttpGet("v1/banking/accounts/{accountId}/transactions", Name = nameof(GetTransactions))] [CheckScope(ApiScopes.Banking.TransactionsRead)] - [CheckXV(1, 1)] [CheckAuthDate] + [SetVersionResponse(1)] [ApiVersion("1")] [ServiceFilter(typeof(LogActionEntryAttribute))] public async Task GetTransactions([FromQuery] RequestAccountTransactions request) diff --git a/Source/Banking/CDR.DataHolder.Banking.Resource.API/Startup.cs b/Source/Banking/CDR.DataHolder.Banking.Resource.API/Startup.cs index 1dded76..d0bac2e 100644 --- a/Source/Banking/CDR.DataHolder.Banking.Resource.API/Startup.cs +++ b/Source/Banking/CDR.DataHolder.Banking.Resource.API/Startup.cs @@ -1,4 +1,7 @@ -using CDR.DataHolder.Banking.Domain.Repositories; +using System; +using System.Collections.Generic; +using System.Net.Http; +using CDR.DataHolder.Banking.Domain.Repositories; using CDR.DataHolder.Banking.Repository; using CDR.DataHolder.Banking.Repository.Infrastructure; using CDR.DataHolder.Banking.Resource.API.Business.Services; @@ -9,6 +12,7 @@ using CDR.DataHolder.Shared.API.Infrastructure.IdPermanence; using CDR.DataHolder.Shared.API.Infrastructure.Middleware; using CDR.DataHolder.Shared.API.Infrastructure.Models; +using CDR.DataHolder.Shared.API.Infrastructure.Versioning; using CDR.DataHolder.Shared.API.Logger; using CDR.DataHolder.Shared.Business; using CDR.DataHolder.Shared.Business.Middleware; @@ -20,20 +24,15 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Versioning; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.IdentityModel.Tokens; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Newtonsoft.Json.Converters; using Serilog; -using System; -using System.Collections.Generic; -using System.Net.Http; using static CDR.DataHolder.Shared.API.Infrastructure.Constants; namespace CDR.DataHolder.Banking.Resource.API @@ -59,6 +58,7 @@ public void ConfigureServices(IServiceCollection services) services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "Mock Data Holder Discovery API", Version = "v1" }); + c.SwaggerDoc("v2", new OpenApiInfo { Title = "Mock Data Holder Discovery API", Version = "v2" }); }); services.AddSwaggerGenNewtonsoftSupport(); @@ -74,13 +74,7 @@ public void ConfigureServices(IServiceCollection services) options.InvalidModelStateResponseFactory = ModelStateErrorMiddleware.ExecuteResult; }); - services.AddApiVersioning(options => - { - options.DefaultApiVersion = new ApiVersion(1, 0); - options.AssumeDefaultVersionWhenUnspecified = false; - options.ApiVersionReader = new HeaderApiVersionReader("x-v"); - options.ErrorResponses = new ErrorResponseVersion(); - }); + services.AddCdrApiVersioning(); // This is to manage the EF database context through the web API DI. // If this is to be done inside the repository project itself, we need to manage the context life-cycle explicitly. @@ -89,7 +83,7 @@ public void ConfigureServices(IServiceCollection services) // Enable authentication and authorisation AddAuthenticationAuthorization(services, Configuration); - services.AddAutoMapper(typeof(Startup), typeof(BankingDataHolderDatabaseContext)); + services.AddAutoMapper(cfg => { }, typeof(Startup).Assembly, typeof(BankingDataHolderDatabaseContext).Assembly); services.AddScoped(); @@ -172,15 +166,9 @@ private static void AddAuthenticationAuthorization(IServiceCollection services, Type = SecuritySchemeType.ApiKey, BearerFormat = "JWT", }); - c.AddSecurityRequirement(new OpenApiSecurityRequirement + c.AddSecurityRequirement(document => new OpenApiSecurityRequirement { - { - new OpenApiSecurityScheme - { - Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }, - }, - new List() - }, + [new OpenApiSecuritySchemeReference("Bearer", document)] = [], }); }); } @@ -200,8 +188,10 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger< // ExceptionHandlingMiddleware must be first in the line, so it will catch all unhandled exceptions. app.UseMiddleware(); - app.UseSwagger(); - app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Mock Data Holder Discovery API v1")); + app.UseExceptionHandler(exceptionHandlerApp => + { + exceptionHandlerApp.Run(async context => await ApiExceptionHandler.Handle(context)); + }); app.UseHttpsRedirection(); @@ -213,6 +203,8 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger< // Add custom middleware app.UseInteractionId(); + app.UseCdrSwagger(); + app.UseEndpoints(endpoints => { endpoints.MapControllers(); diff --git a/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/BaseTest.cs b/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/BaseTest.cs index 5b7ef03..2085c24 100644 --- a/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/BaseTest.cs +++ b/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/BaseTest.cs @@ -1,4 +1,5 @@ -using ConsumerDataRight.ParticipantTooling.MockSolution.TestAutomation; +using CDR.DataHolder.Banking.Tests.IntegrationTests.XUnit.Orderers; +using ConsumerDataRight.ParticipantTooling.MockSolution.TestAutomation; using Microsoft.Extensions.Configuration; using Xunit; using Xunit.DependencyInjection; @@ -7,11 +8,11 @@ namespace CDR.DataHolder.Banking.Tests.IntegrationTests { // Put all tests in same collection because we need them to run sequentially since some tests are mutating DB. [Collection("IntegrationTests")] - [TestCaseOrderer("CDR.DataHolder.Banking.Tests.IntegrationTests.XUnit.Orderers.AlphabeticalOrderer", "CDR.DataHolder.Banking.Tests.IntegrationTests")] + [TestCaseOrderer(typeof(AlphabeticalOrderer))] public abstract class BaseTest : SharedBaseTest { protected BaseTest(ITestOutputHelperAccessor testOutputHelperAccessor, IConfiguration config) - : base(testOutputHelperAccessor, config) + : base(config) { } } diff --git a/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/CDR.DataHolder.Banking.Tests.IntegrationTests.csproj b/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/CDR.DataHolder.Banking.Tests.IntegrationTests.csproj index 9ad1c05..6ff5f3f 100644 --- a/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/CDR.DataHolder.Banking.Tests.IntegrationTests.csproj +++ b/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/CDR.DataHolder.Banking.Tests.IntegrationTests.csproj @@ -46,9 +46,10 @@ true - + true + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/US12973_MDH_CommonAPI_GetCustomer.cs b/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/US12973_MDH_CommonAPI_GetCustomer.cs index c2539ca..52dbe16 100644 --- a/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/US12973_MDH_CommonAPI_GetCustomer.cs +++ b/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/US12973_MDH_CommonAPI_GetCustomer.cs @@ -305,7 +305,7 @@ public async Task AC03c_Get_WithMissingXV_ShouldRespondWith_400BadRequest(string // Arrange var accessToken = await _dataHolderAccessTokenCache.GetAccessToken(TokenType.JaneWilson); - CdrException expectedError = new MissingRequiredHeaderException("x-v"); + CdrException expectedError = new MissingRequiredHeaderException("An API version x-v header is required, but was not specified."); var expectedContent = JsonConvert.SerializeObject(new ResponseErrorListV2(expectedError, string.Empty)); // Act diff --git a/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/US12975_MDH_BankingAPI_GetAccounts.cs b/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/US12975_MDH_BankingAPI_GetAccounts.cs index aafe028..9088e35 100644 --- a/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/US12975_MDH_BankingAPI_GetAccounts.cs +++ b/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/US12975_MDH_BankingAPI_GetAccounts.cs @@ -279,7 +279,7 @@ public async Task AC17_Get_WithMissingXV_ShouldRespondWith_400BadRequest(string { Log.Information("Running test with Params: {P1}={V1}.", nameof(xv), xv); - await Test_AC15_AC16_AC17(xv, new MissingRequiredHeaderException("x-v")); + await Test_AC15_AC16_AC17(xv, new MissingRequiredHeaderException("An API version x-v header is required, but was not specified.")); } // [InlineData("DateTime.Now.RFC1123", HttpStatusCode.OK)] diff --git a/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/US15350_MDH_BankingAPI_GetTransactions.cs b/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/US15350_MDH_BankingAPI_GetTransactions.cs index 7e1fc7b..bea6e64 100644 --- a/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/US15350_MDH_BankingAPI_GetTransactions.cs +++ b/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/US15350_MDH_BankingAPI_GetTransactions.cs @@ -362,7 +362,7 @@ public async Task AC26_WithMissingXV_ShouldRespondWith_400BadRequest(string xv) { Log.Information("Running test with Params: {P1}={V1}.", nameof(xv), xv); - await TestForError(TokenType.JaneWilson, Constants.Accounts.Banking.AccountIdJaneWilson, new MissingRequiredHeaderException("x-v"), new TransactionFilterParameters(), xv: xv); + await TestForError(TokenType.JaneWilson, Constants.Accounts.Banking.AccountIdJaneWilson, new MissingRequiredHeaderException("An API version x-v header is required, but was not specified."), new TransactionFilterParameters(), xv: xv); } [Fact] @@ -717,7 +717,7 @@ private async Task TestForSuccess( var xFapiAuthDate = DateTime.Now.ToUniversalTime().ToString("r"); var baseUrl = $"{_options.DH_MTLS_GATEWAY_URL}/cds-au/v1/banking/accounts/{encryptedAccountId}/transactions"; - var url = GetUrl(baseUrl, filterParams); + var url = GetUrl(baseUrl, filterParams, true); // Act var api = _apiServiceDirector.BuildDataHolderBankingGetTransactionsAPI(accessToken, xFapiAuthDate: xFapiAuthDate, xv: "1", xFapiInteractionId: xFapiInteractionId, url: url); @@ -819,9 +819,14 @@ private async Task TestForError( // Assert - Check ContentType (if response has content) if (!string.IsNullOrEmpty(await response.Content.ReadAsStringAsync())) { + response.Content.Should().NotBeNull(); response.Content?.Headers.Should().NotBeNull(); response.Content?.Headers?.ContentType.Should().NotBeNull(); - response.Content?.Headers?.ContentType?.ToString().Should().Be("application/json; charset=utf-8"); + + // Assert - Check content type +#pragma warning disable CS8604 // Possible null reference argument. + Assertions.AssertHasContentTypeApplicationJson(response.Content); +#pragma warning restore CS8604 // Possible null reference argument. } // Assert - Check WWWAutheticate header diff --git a/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/XUnit/Orderers/AlphabeticalOrderer.cs b/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/XUnit/Orderers/AlphabeticalOrderer.cs index b6e3633..40e59fd 100644 --- a/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/XUnit/Orderers/AlphabeticalOrderer.cs +++ b/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/XUnit/Orderers/AlphabeticalOrderer.cs @@ -1,11 +1,25 @@ -using Xunit.Abstractions; -using Xunit.Sdk; +using Xunit.Sdk; +using Xunit.v3; namespace CDR.DataHolder.Banking.Tests.IntegrationTests.XUnit.Orderers { public class AlphabeticalOrderer : ITestCaseOrderer { - public IEnumerable OrderTestCases(IEnumerable testCases) - where TTestCase : ITestCase => testCases.OrderBy(testCase => testCase.TestMethod.Method.Name); + IReadOnlyCollection ITestCaseOrderer.OrderTestCases( + IReadOnlyCollection testCases) + { + return testCases.OrderBy(tc => ExtractTestName(tc)).ToList().AsReadOnly(); + } + + private static string ExtractTestName(ITestCase testCase) + { + var testMethod = testCase?.TestMethod; + if (testMethod is ITestMethodMetadata testMethodMetadata) + { + return testMethodMetadata.MethodName ?? string.Empty; + } + + return string.Empty; + } } } diff --git a/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/appsettings.Development.json b/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/appsettings.Development.json index fbd402b..3aa732b 100644 --- a/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/appsettings.Development.json +++ b/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/appsettings.Development.json @@ -1,6 +1,6 @@ { "Serilog": { - "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Sinks.XUnit", "Serilog.Sinks.Async" ], + "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Sinks.XUnit3", "Serilog.Sinks.Async" ], "MinimumLevel": { "Default": "Debug" }, diff --git a/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/appsettings.Release.json b/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/appsettings.Release.json index e6fd0c3..01f5548 100644 --- a/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/appsettings.Release.json +++ b/Source/Banking/CDR.DataHolder.Banking.Tests.IntegrationTests/appsettings.Release.json @@ -1,6 +1,6 @@ { "Serilog": { - "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Sinks.XUnit", "Serilog.Sinks.Async" ], + "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Sinks.XUnit3", "Serilog.Sinks.Async" ], "MinimumLevel": { "Default": "Information" }, diff --git a/Source/Common/CDR.DataHolder.Common.API/Controllers/CommonController.cs b/Source/Common/CDR.DataHolder.Common.API/Controllers/CommonController.cs index bb007fc..11f9059 100644 --- a/Source/Common/CDR.DataHolder.Common.API/Controllers/CommonController.cs +++ b/Source/Common/CDR.DataHolder.Common.API/Controllers/CommonController.cs @@ -1,4 +1,5 @@ -using AutoMapper; +using Asp.Versioning; +using AutoMapper; using CDR.DataHolder.Common.API.Infrastructure; using CDR.DataHolder.Common.Resource.API.Business.Responses; using CDR.DataHolder.Shared.API.Infrastructure.Authorization; @@ -7,7 +8,6 @@ using CDR.DataHolder.Shared.API.Infrastructure.Models; using CDR.DataHolder.Shared.Business; using CDR.DataHolder.Shared.Resource.API.Business.Filters; -using CDR.DataHolder.Shared.Resource.API.Infrastructure.Filters; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using static CDR.DataHolder.Shared.Domain.Constants; @@ -38,8 +38,8 @@ public CommonController( [PolicyAuthorize(AuthorisationPolicy.GetCustomersApi)] [HttpGet("v1/common/customer", Name = "GetCustomer")] [CheckScope(CDR.DataHolder.Shared.API.Infrastructure.Constants.ApiScopes.Common.CustomerBasicRead)] - [CheckXV(1, 1)] [CheckAuthDate] + [SetVersionResponse(1)] [ApiVersion("1")] [ServiceFilter(typeof(LogActionEntryAttribute))] public async Task GetCustomer() diff --git a/Source/Common/CDR.DataHolder.Common.API/Infrastructure/ServiceCollectionExtension.cs b/Source/Common/CDR.DataHolder.Common.API/Infrastructure/ServiceCollectionExtension.cs index ea65b72..36c15e1 100644 --- a/Source/Common/CDR.DataHolder.Common.API/Infrastructure/ServiceCollectionExtension.cs +++ b/Source/Common/CDR.DataHolder.Common.API/Infrastructure/ServiceCollectionExtension.cs @@ -19,7 +19,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using static CDR.DataHolder.Shared.API.Infrastructure.Constants; using static CDR.DataHolder.Shared.Domain.Constants; @@ -38,14 +38,14 @@ public static void AddIndustryDBContext(this IServiceCollection services, IConfi services.AddScoped(); services.AddScoped(); services.AddDbContext(options => options.UseSqlServer(defaultConnectionString)); - services.AddAutoMapper(typeof(Program), typeof(BankingDataHolderDatabaseContext)); + services.AddAutoMapper(cfg => { }, typeof(Program).Assembly, typeof(BankingDataHolderDatabaseContext).Assembly); } else if (industry.IsEnergy()) { services.AddScoped(); services.AddDbContext(options => options.UseSqlServer(defaultConnectionString)); services.AddScoped(); - services.AddAutoMapper(typeof(Program), typeof(EnergyDataHolderDatabaseContext)); + services.AddAutoMapper(cfg => { }, typeof(Program).Assembly, typeof(EnergyDataHolderDatabaseContext).Assembly); } } @@ -134,15 +134,9 @@ public static void AddAuthenticationAuthorization(this IServiceCollection servic Type = SecuritySchemeType.ApiKey, BearerFormat = "JWT", }); - c.AddSecurityRequirement(new OpenApiSecurityRequirement + c.AddSecurityRequirement(document => new OpenApiSecurityRequirement { - { - new OpenApiSecurityScheme - { - Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }, - }, - new List() - }, + [new OpenApiSecuritySchemeReference("Bearer", document)] = [], }); }); } diff --git a/Source/Common/CDR.DataHolder.Common.API/Program.cs b/Source/Common/CDR.DataHolder.Common.API/Program.cs index 4411428..cb08ee2 100644 --- a/Source/Common/CDR.DataHolder.Common.API/Program.cs +++ b/Source/Common/CDR.DataHolder.Common.API/Program.cs @@ -1,13 +1,12 @@ -using AutoMapper; +using System.Text.Json.Serialization; +using AutoMapper; using CDR.DataHolder.Common.API.Infrastructure; using CDR.DataHolder.Shared.API.Infrastructure.Extensions; using CDR.DataHolder.Shared.API.Infrastructure.Filters; -using CDR.DataHolder.Shared.API.Infrastructure.Models; +using CDR.DataHolder.Shared.API.Infrastructure.Middleware; +using CDR.DataHolder.Shared.API.Infrastructure.Versioning; using CDR.DataHolder.Shared.Business; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Versioning; using Serilog; -using System.Text.Json.Serialization; using static CDR.DataHolder.Shared.Domain.Constants; var builder = WebApplication.CreateBuilder(args); @@ -56,27 +55,22 @@ .AddControllers() .AddJsonOptions(options => options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull); -builder.Services.AddApiVersioning(options => -{ - options.DefaultApiVersion = new ApiVersion(1, 0); - options.AssumeDefaultVersionWhenUnspecified = false; - options.ApiVersionReader = new HeaderApiVersionReader("x-v"); - options.ErrorResponses = new ErrorResponseVersion(); -}); +builder.Services.AddCdrApiVersioning(); builder.Services.AddAuthenticationAuthorization(builder.Configuration); var app = builder.Build(); // Configure the HTTP request pipeline. -if (app.Environment.IsDevelopment()) +app.UseExceptionHandler(exceptionHandlerApp => { - app.UseSwagger(); - app.UseSwaggerUI(); -} + exceptionHandlerApp.Run(async context => await ApiExceptionHandler.Handle(context)); +}); app.UseHttpsRedirection(); +app.UseRouting(); + app.UseAuthentication(); app.UseAuthorization(); @@ -86,6 +80,11 @@ // assert Automapper configuration is valid. app.Services.GetService()?.ConfigurationProvider.AssertConfigurationIsValid(); +if (app.Environment.IsDevelopment()) +{ + app.UseCdrSwagger(); +} + app.MapControllers(); await app.RunAsync(); diff --git a/Source/DataHolder.sln b/Source/DataHolder.sln deleted file mode 100644 index 95886f5..0000000 --- a/Source/DataHolder.sln +++ /dev/null @@ -1,248 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32112.339 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A958A8EB-FC1A-49BC-ABA0-7DB3DB56CADB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Public.API", "Shared\CDR.DataHolder.Public.API\CDR.DataHolder.Public.API.csproj", "{ACCF8355-24EA-4C43-9862-6F75DBF56304}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "API", "API", "{0BD4EE79-7F77-4CE6-B0F9-A2CE2F17F0BE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Manage.API", "Shared\CDR.DataHolder.Manage.API\CDR.DataHolder.Manage.API.csproj", "{7A3D76A9-4259-4AD4-95DF-F5416165DA1E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Admin.API", "Shared\CDR.DataHolder.Admin.API\CDR.DataHolder.Admin.API.csproj", "{E6CFE76E-03A9-445B-A6C9-B0B3BAF58A63}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "API Infrastructure", "API Infrastructure", "{1140FEF6-AF92-42B2-A670-B77354A0B4C1}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Shared.Domain", "Shared\CDR.DataHolder.Shared.Domain\CDR.DataHolder.Shared.Domain.csproj", "{BDC6661A-D2B2-43EE-A4C6-029815DA10A1}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Shared.Repository", "Shared\CDR.DataHolder.Shared.Repository\CDR.DataHolder.Shared.Repository.csproj", "{671E3693-2F79-4251-A70E-F2527D6F471B}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Banking", "Banking", "{AC72555E-198B-4542-9993-6CA067FD5EE4}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Banking.Repository", "Banking\CDR.DataHolder.Banking.Repository\CDR.DataHolder.Banking.Repository.csproj", "{07A67EEB-3191-4FC2-9503-9400E4B63D5A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Banking.Resource.API", "Banking\CDR.DataHolder.Banking.Resource.API\CDR.DataHolder.Banking.Resource.API.csproj", "{D191C5D3-0C74-41E9-B6C7-F3619E12FE44}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Banking.Domain", "Banking\CDR.DataHolder.Banking.Domain\CDR.DataHolder.Banking.Domain.csproj", "{DB9F8EC2-0C34-4E0F-8426-EDE609D6D6F8}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "API", "API", "{56C71FCA-4FA8-43BC-8D42-57652064BE10}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{5956ED95-4FBD-4D6B-9A0C-040865FF31A2}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Energy", "Energy", "{69CA9C9F-6D5F-40F9-A036-760F2090BBF7}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "API", "API", "{C40E2889-D45F-4507-AC0C-684BFA20DF0F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Energy.Resource.API", "Energy\CDR.DataHolder.Energy.Resource.API\CDR.DataHolder.Energy.Resource.API.csproj", "{ACC0AFE5-EE84-441C-9849-18D2D37B77E0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Energy.Domain", "Energy\CDR.DataHolder.Energy.Domain\CDR.DataHolder.Energy.Domain.csproj", "{D5ED10BC-A1A2-485B-92D0-4679BA1C60CB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Energy.Repository", "Energy\CDR.DataHolder.Energy.Repository\CDR.DataHolder.Energy.Repository.csproj", "{7E44240D-2328-4F0B-8738-5E54245FC598}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Common.API", "Common\CDR.DataHolder.Common.API\CDR.DataHolder.Common.API.csproj", "{94EC3FB8-41D2-4371-9245-651D6496F9BE}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{40CAD81A-9D02-45C5-B341-AF9C7E018895}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Banking.Resource.API.UnitTests", "Banking\CDR.DataHolder.Banking.Resource.API.UnitTests\CDR.DataHolder.Banking.Resource.API.UnitTests.csproj", "{2AD6346B-4B2D-4C3A-A021-1D0FCB118294}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{BC8E1101-5DC8-4763-8CEC-78E3D3D9D7E6}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Energy.Resource.API.UnitTests", "Energy\CDR.DataHolder.Energy.Resource.API.UnitTests\CDR.DataHolder.Energy.Resource.API.UnitTests.csproj", "{C839CB68-DFA8-4487-9153-46FE9508137A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Shared.Business", "Shared\CDR.DataHolder.Shared.Business\CDR.DataHolder.Shared.Business.csproj", "{BFF889CE-0CF2-4710-9C09-811CA7BDB500}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Banking.Tests.IntegrationTests", "Banking\CDR.DataHolder.Banking.Tests.IntegrationTests\CDR.DataHolder.Banking.Tests.IntegrationTests.csproj", "{61A9BABD-C707-4D54-9545-6223B461D80E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Shared.API.Gateway.mTLS", "Shared\CDR.DataHolder.Shared.API.Gateway.mTLS\CDR.DataHolder.Shared.API.Gateway.mTLS.csproj", "{2241458A-8632-4E22-AF14-BF606C1FC208}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Shared.API.Infrastructure", "Shared\CDR.DataHolder.Shared.API.Infrastructure\CDR.DataHolder.Shared.API.Infrastructure.csproj", "{62147441-A558-48E2-B698-221EF020CA02}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Shared.API.Infrastructure.UnitTests", "Shared\CDR.DataHolder.Shared.API.Infrastructure.UnitTests\CDR.DataHolder.Shared.API.Infrastructure.UnitTests.csproj", "{38A9F7B5-0319-481A-A04D-9D527EBE8861}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Shared.API.Logger", "Shared\CDR.DataHolder.Shared.API.Logger\CDR.DataHolder.Shared.API.Logger.csproj", "{41AEC50F-D4CB-4C70-999C-AC466465AADF}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Energy.Tests.IntegrationTests", "Energy\CDR.DataHolder.Energy.Tests.IntegrationTests\CDR.DataHolder.Energy.Tests.IntegrationTests.csproj", "{343715C2-5B41-47B7-8D33-DE064C26C722}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{225FCADA-5149-45F8-A05C-4AAC25ABB287}" - ProjectSection(SolutionItems) = preProject - .dockerignore = .dockerignore - .editorconfig = .editorconfig - Directory.Build.props = Directory.Build.props - Directory.Packages.props = Directory.Packages.props - Dockerfile = Dockerfile - Dockerfile.integration-tests = Dockerfile.integration-tests - Dockerfile.unit-tests = Dockerfile.unit-tests - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - Shared|Any CPU = Shared|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {ACCF8355-24EA-4C43-9862-6F75DBF56304}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ACCF8355-24EA-4C43-9862-6F75DBF56304}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ACCF8355-24EA-4C43-9862-6F75DBF56304}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ACCF8355-24EA-4C43-9862-6F75DBF56304}.Release|Any CPU.Build.0 = Release|Any CPU - {ACCF8355-24EA-4C43-9862-6F75DBF56304}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {ACCF8355-24EA-4C43-9862-6F75DBF56304}.Shared|Any CPU.Build.0 = Release|Any CPU - {7A3D76A9-4259-4AD4-95DF-F5416165DA1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7A3D76A9-4259-4AD4-95DF-F5416165DA1E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7A3D76A9-4259-4AD4-95DF-F5416165DA1E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7A3D76A9-4259-4AD4-95DF-F5416165DA1E}.Release|Any CPU.Build.0 = Release|Any CPU - {7A3D76A9-4259-4AD4-95DF-F5416165DA1E}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {7A3D76A9-4259-4AD4-95DF-F5416165DA1E}.Shared|Any CPU.Build.0 = Release|Any CPU - {E6CFE76E-03A9-445B-A6C9-B0B3BAF58A63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E6CFE76E-03A9-445B-A6C9-B0B3BAF58A63}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E6CFE76E-03A9-445B-A6C9-B0B3BAF58A63}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E6CFE76E-03A9-445B-A6C9-B0B3BAF58A63}.Release|Any CPU.Build.0 = Release|Any CPU - {E6CFE76E-03A9-445B-A6C9-B0B3BAF58A63}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {E6CFE76E-03A9-445B-A6C9-B0B3BAF58A63}.Shared|Any CPU.Build.0 = Release|Any CPU - {BDC6661A-D2B2-43EE-A4C6-029815DA10A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BDC6661A-D2B2-43EE-A4C6-029815DA10A1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BDC6661A-D2B2-43EE-A4C6-029815DA10A1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BDC6661A-D2B2-43EE-A4C6-029815DA10A1}.Release|Any CPU.Build.0 = Release|Any CPU - {BDC6661A-D2B2-43EE-A4C6-029815DA10A1}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {BDC6661A-D2B2-43EE-A4C6-029815DA10A1}.Shared|Any CPU.Build.0 = Release|Any CPU - {671E3693-2F79-4251-A70E-F2527D6F471B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {671E3693-2F79-4251-A70E-F2527D6F471B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {671E3693-2F79-4251-A70E-F2527D6F471B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {671E3693-2F79-4251-A70E-F2527D6F471B}.Release|Any CPU.Build.0 = Release|Any CPU - {671E3693-2F79-4251-A70E-F2527D6F471B}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {671E3693-2F79-4251-A70E-F2527D6F471B}.Shared|Any CPU.Build.0 = Release|Any CPU - {07A67EEB-3191-4FC2-9503-9400E4B63D5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {07A67EEB-3191-4FC2-9503-9400E4B63D5A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {07A67EEB-3191-4FC2-9503-9400E4B63D5A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {07A67EEB-3191-4FC2-9503-9400E4B63D5A}.Release|Any CPU.Build.0 = Release|Any CPU - {07A67EEB-3191-4FC2-9503-9400E4B63D5A}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {07A67EEB-3191-4FC2-9503-9400E4B63D5A}.Shared|Any CPU.Build.0 = Release|Any CPU - {D191C5D3-0C74-41E9-B6C7-F3619E12FE44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D191C5D3-0C74-41E9-B6C7-F3619E12FE44}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D191C5D3-0C74-41E9-B6C7-F3619E12FE44}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D191C5D3-0C74-41E9-B6C7-F3619E12FE44}.Release|Any CPU.Build.0 = Release|Any CPU - {D191C5D3-0C74-41E9-B6C7-F3619E12FE44}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {D191C5D3-0C74-41E9-B6C7-F3619E12FE44}.Shared|Any CPU.Build.0 = Release|Any CPU - {DB9F8EC2-0C34-4E0F-8426-EDE609D6D6F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DB9F8EC2-0C34-4E0F-8426-EDE609D6D6F8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DB9F8EC2-0C34-4E0F-8426-EDE609D6D6F8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DB9F8EC2-0C34-4E0F-8426-EDE609D6D6F8}.Release|Any CPU.Build.0 = Release|Any CPU - {DB9F8EC2-0C34-4E0F-8426-EDE609D6D6F8}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {DB9F8EC2-0C34-4E0F-8426-EDE609D6D6F8}.Shared|Any CPU.Build.0 = Release|Any CPU - {ACC0AFE5-EE84-441C-9849-18D2D37B77E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ACC0AFE5-EE84-441C-9849-18D2D37B77E0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ACC0AFE5-EE84-441C-9849-18D2D37B77E0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ACC0AFE5-EE84-441C-9849-18D2D37B77E0}.Release|Any CPU.Build.0 = Release|Any CPU - {ACC0AFE5-EE84-441C-9849-18D2D37B77E0}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {ACC0AFE5-EE84-441C-9849-18D2D37B77E0}.Shared|Any CPU.Build.0 = Release|Any CPU - {D5ED10BC-A1A2-485B-92D0-4679BA1C60CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D5ED10BC-A1A2-485B-92D0-4679BA1C60CB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D5ED10BC-A1A2-485B-92D0-4679BA1C60CB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D5ED10BC-A1A2-485B-92D0-4679BA1C60CB}.Release|Any CPU.Build.0 = Release|Any CPU - {D5ED10BC-A1A2-485B-92D0-4679BA1C60CB}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {D5ED10BC-A1A2-485B-92D0-4679BA1C60CB}.Shared|Any CPU.Build.0 = Release|Any CPU - {7E44240D-2328-4F0B-8738-5E54245FC598}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7E44240D-2328-4F0B-8738-5E54245FC598}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7E44240D-2328-4F0B-8738-5E54245FC598}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7E44240D-2328-4F0B-8738-5E54245FC598}.Release|Any CPU.Build.0 = Release|Any CPU - {7E44240D-2328-4F0B-8738-5E54245FC598}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {7E44240D-2328-4F0B-8738-5E54245FC598}.Shared|Any CPU.Build.0 = Release|Any CPU - {94EC3FB8-41D2-4371-9245-651D6496F9BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {94EC3FB8-41D2-4371-9245-651D6496F9BE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {94EC3FB8-41D2-4371-9245-651D6496F9BE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {94EC3FB8-41D2-4371-9245-651D6496F9BE}.Release|Any CPU.Build.0 = Release|Any CPU - {94EC3FB8-41D2-4371-9245-651D6496F9BE}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {94EC3FB8-41D2-4371-9245-651D6496F9BE}.Shared|Any CPU.Build.0 = Release|Any CPU - {2AD6346B-4B2D-4C3A-A021-1D0FCB118294}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2AD6346B-4B2D-4C3A-A021-1D0FCB118294}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2AD6346B-4B2D-4C3A-A021-1D0FCB118294}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2AD6346B-4B2D-4C3A-A021-1D0FCB118294}.Release|Any CPU.Build.0 = Release|Any CPU - {2AD6346B-4B2D-4C3A-A021-1D0FCB118294}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {2AD6346B-4B2D-4C3A-A021-1D0FCB118294}.Shared|Any CPU.Build.0 = Release|Any CPU - {C839CB68-DFA8-4487-9153-46FE9508137A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C839CB68-DFA8-4487-9153-46FE9508137A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C839CB68-DFA8-4487-9153-46FE9508137A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C839CB68-DFA8-4487-9153-46FE9508137A}.Release|Any CPU.Build.0 = Release|Any CPU - {C839CB68-DFA8-4487-9153-46FE9508137A}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {C839CB68-DFA8-4487-9153-46FE9508137A}.Shared|Any CPU.Build.0 = Release|Any CPU - {BFF889CE-0CF2-4710-9C09-811CA7BDB500}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BFF889CE-0CF2-4710-9C09-811CA7BDB500}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BFF889CE-0CF2-4710-9C09-811CA7BDB500}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BFF889CE-0CF2-4710-9C09-811CA7BDB500}.Release|Any CPU.Build.0 = Release|Any CPU - {BFF889CE-0CF2-4710-9C09-811CA7BDB500}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {BFF889CE-0CF2-4710-9C09-811CA7BDB500}.Shared|Any CPU.Build.0 = Release|Any CPU - {61A9BABD-C707-4D54-9545-6223B461D80E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {61A9BABD-C707-4D54-9545-6223B461D80E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {61A9BABD-C707-4D54-9545-6223B461D80E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {61A9BABD-C707-4D54-9545-6223B461D80E}.Release|Any CPU.Build.0 = Release|Any CPU - {61A9BABD-C707-4D54-9545-6223B461D80E}.Shared|Any CPU.ActiveCfg = Shared|Any CPU - {61A9BABD-C707-4D54-9545-6223B461D80E}.Shared|Any CPU.Build.0 = Shared|Any CPU - {2241458A-8632-4E22-AF14-BF606C1FC208}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2241458A-8632-4E22-AF14-BF606C1FC208}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2241458A-8632-4E22-AF14-BF606C1FC208}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2241458A-8632-4E22-AF14-BF606C1FC208}.Release|Any CPU.Build.0 = Release|Any CPU - {2241458A-8632-4E22-AF14-BF606C1FC208}.Shared|Any CPU.ActiveCfg = Debug|Any CPU - {2241458A-8632-4E22-AF14-BF606C1FC208}.Shared|Any CPU.Build.0 = Debug|Any CPU - {62147441-A558-48E2-B698-221EF020CA02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {62147441-A558-48E2-B698-221EF020CA02}.Debug|Any CPU.Build.0 = Debug|Any CPU - {62147441-A558-48E2-B698-221EF020CA02}.Release|Any CPU.ActiveCfg = Release|Any CPU - {62147441-A558-48E2-B698-221EF020CA02}.Release|Any CPU.Build.0 = Release|Any CPU - {62147441-A558-48E2-B698-221EF020CA02}.Shared|Any CPU.ActiveCfg = Debug|Any CPU - {62147441-A558-48E2-B698-221EF020CA02}.Shared|Any CPU.Build.0 = Debug|Any CPU - {38A9F7B5-0319-481A-A04D-9D527EBE8861}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {38A9F7B5-0319-481A-A04D-9D527EBE8861}.Debug|Any CPU.Build.0 = Debug|Any CPU - {38A9F7B5-0319-481A-A04D-9D527EBE8861}.Release|Any CPU.ActiveCfg = Release|Any CPU - {38A9F7B5-0319-481A-A04D-9D527EBE8861}.Release|Any CPU.Build.0 = Release|Any CPU - {38A9F7B5-0319-481A-A04D-9D527EBE8861}.Shared|Any CPU.ActiveCfg = Debug|Any CPU - {38A9F7B5-0319-481A-A04D-9D527EBE8861}.Shared|Any CPU.Build.0 = Debug|Any CPU - {41AEC50F-D4CB-4C70-999C-AC466465AADF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {41AEC50F-D4CB-4C70-999C-AC466465AADF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {41AEC50F-D4CB-4C70-999C-AC466465AADF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {41AEC50F-D4CB-4C70-999C-AC466465AADF}.Release|Any CPU.Build.0 = Release|Any CPU - {41AEC50F-D4CB-4C70-999C-AC466465AADF}.Shared|Any CPU.ActiveCfg = Debug|Any CPU - {41AEC50F-D4CB-4C70-999C-AC466465AADF}.Shared|Any CPU.Build.0 = Debug|Any CPU - {343715C2-5B41-47B7-8D33-DE064C26C722}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {343715C2-5B41-47B7-8D33-DE064C26C722}.Debug|Any CPU.Build.0 = Debug|Any CPU - {343715C2-5B41-47B7-8D33-DE064C26C722}.Release|Any CPU.ActiveCfg = Release|Any CPU - {343715C2-5B41-47B7-8D33-DE064C26C722}.Release|Any CPU.Build.0 = Release|Any CPU - {343715C2-5B41-47B7-8D33-DE064C26C722}.Shared|Any CPU.ActiveCfg = Shared|Any CPU - {343715C2-5B41-47B7-8D33-DE064C26C722}.Shared|Any CPU.Build.0 = Shared|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {ACCF8355-24EA-4C43-9862-6F75DBF56304} = {0BD4EE79-7F77-4CE6-B0F9-A2CE2F17F0BE} - {0BD4EE79-7F77-4CE6-B0F9-A2CE2F17F0BE} = {A958A8EB-FC1A-49BC-ABA0-7DB3DB56CADB} - {7A3D76A9-4259-4AD4-95DF-F5416165DA1E} = {0BD4EE79-7F77-4CE6-B0F9-A2CE2F17F0BE} - {E6CFE76E-03A9-445B-A6C9-B0B3BAF58A63} = {0BD4EE79-7F77-4CE6-B0F9-A2CE2F17F0BE} - {1140FEF6-AF92-42B2-A670-B77354A0B4C1} = {A958A8EB-FC1A-49BC-ABA0-7DB3DB56CADB} - {BDC6661A-D2B2-43EE-A4C6-029815DA10A1} = {A958A8EB-FC1A-49BC-ABA0-7DB3DB56CADB} - {671E3693-2F79-4251-A70E-F2527D6F471B} = {A958A8EB-FC1A-49BC-ABA0-7DB3DB56CADB} - {07A67EEB-3191-4FC2-9503-9400E4B63D5A} = {AC72555E-198B-4542-9993-6CA067FD5EE4} - {D191C5D3-0C74-41E9-B6C7-F3619E12FE44} = {56C71FCA-4FA8-43BC-8D42-57652064BE10} - {DB9F8EC2-0C34-4E0F-8426-EDE609D6D6F8} = {AC72555E-198B-4542-9993-6CA067FD5EE4} - {56C71FCA-4FA8-43BC-8D42-57652064BE10} = {AC72555E-198B-4542-9993-6CA067FD5EE4} - {C40E2889-D45F-4507-AC0C-684BFA20DF0F} = {69CA9C9F-6D5F-40F9-A036-760F2090BBF7} - {ACC0AFE5-EE84-441C-9849-18D2D37B77E0} = {C40E2889-D45F-4507-AC0C-684BFA20DF0F} - {D5ED10BC-A1A2-485B-92D0-4679BA1C60CB} = {69CA9C9F-6D5F-40F9-A036-760F2090BBF7} - {7E44240D-2328-4F0B-8738-5E54245FC598} = {69CA9C9F-6D5F-40F9-A036-760F2090BBF7} - {94EC3FB8-41D2-4371-9245-651D6496F9BE} = {5956ED95-4FBD-4D6B-9A0C-040865FF31A2} - {40CAD81A-9D02-45C5-B341-AF9C7E018895} = {AC72555E-198B-4542-9993-6CA067FD5EE4} - {2AD6346B-4B2D-4C3A-A021-1D0FCB118294} = {40CAD81A-9D02-45C5-B341-AF9C7E018895} - {BC8E1101-5DC8-4763-8CEC-78E3D3D9D7E6} = {69CA9C9F-6D5F-40F9-A036-760F2090BBF7} - {C839CB68-DFA8-4487-9153-46FE9508137A} = {BC8E1101-5DC8-4763-8CEC-78E3D3D9D7E6} - {BFF889CE-0CF2-4710-9C09-811CA7BDB500} = {A958A8EB-FC1A-49BC-ABA0-7DB3DB56CADB} - {61A9BABD-C707-4D54-9545-6223B461D80E} = {40CAD81A-9D02-45C5-B341-AF9C7E018895} - {2241458A-8632-4E22-AF14-BF606C1FC208} = {1140FEF6-AF92-42B2-A670-B77354A0B4C1} - {62147441-A558-48E2-B698-221EF020CA02} = {1140FEF6-AF92-42B2-A670-B77354A0B4C1} - {38A9F7B5-0319-481A-A04D-9D527EBE8861} = {1140FEF6-AF92-42B2-A670-B77354A0B4C1} - {41AEC50F-D4CB-4C70-999C-AC466465AADF} = {1140FEF6-AF92-42B2-A670-B77354A0B4C1} - {343715C2-5B41-47B7-8D33-DE064C26C722} = {BC8E1101-5DC8-4763-8CEC-78E3D3D9D7E6} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {AE8E874B-11F7-494D-9902-AD374F1EC3B3} - EndGlobalSection -EndGlobal diff --git a/Source/DataHolder.slnx b/Source/DataHolder.slnx new file mode 100644 index 0000000..97e59fe --- /dev/null +++ b/Source/DataHolder.slnx @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/DataHolder_Shared.sln b/Source/DataHolder_Shared.sln deleted file mode 100644 index 58c7839..0000000 --- a/Source/DataHolder_Shared.sln +++ /dev/null @@ -1,263 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32112.339 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A958A8EB-FC1A-49BC-ABA0-7DB3DB56CADB}" - ProjectSection(SolutionItems) = preProject - docker-compose.E2ETests.yml = docker-compose.E2ETests.yml - docker-compose.IntegrationTests.CdrAuthServer.yml = docker-compose.IntegrationTests.CdrAuthServer.yml - docker-compose.IntegrationTests.yml = docker-compose.IntegrationTests.yml - docker-compose.UnitTests.yml = docker-compose.UnitTests.yml - Dockerfile = Dockerfile - Dockerfile.integration-tests = Dockerfile.integration-tests - Dockerfile.unit-tests = Dockerfile.unit-tests - integration.runsettings = integration.runsettings - run-integration-tests.ps1 = run-integration-tests.ps1 - run-unit-tests.ps1 = run-unit-tests.ps1 - supervisord.conf = supervisord.conf - wait-until-manage-healthy-then-start.sh = wait-until-manage-healthy-then-start.sh - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Public.API", "Shared\CDR.DataHolder.Public.API\CDR.DataHolder.Public.API.csproj", "{ACCF8355-24EA-4C43-9862-6F75DBF56304}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "API", "API", "{0BD4EE79-7F77-4CE6-B0F9-A2CE2F17F0BE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Manage.API", "Shared\CDR.DataHolder.Manage.API\CDR.DataHolder.Manage.API.csproj", "{7A3D76A9-4259-4AD4-95DF-F5416165DA1E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Admin.API", "Shared\CDR.DataHolder.Admin.API\CDR.DataHolder.Admin.API.csproj", "{E6CFE76E-03A9-445B-A6C9-B0B3BAF58A63}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "API Infrastructure", "API Infrastructure", "{1140FEF6-AF92-42B2-A670-B77354A0B4C1}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Shared.Domain", "Shared\CDR.DataHolder.Shared.Domain\CDR.DataHolder.Shared.Domain.csproj", "{BDC6661A-D2B2-43EE-A4C6-029815DA10A1}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Shared.Repository", "Shared\CDR.DataHolder.Shared.Repository\CDR.DataHolder.Shared.Repository.csproj", "{671E3693-2F79-4251-A70E-F2527D6F471B}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Banking", "Banking", "{AC72555E-198B-4542-9993-6CA067FD5EE4}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Banking.Repository", "Banking\CDR.DataHolder.Banking.Repository\CDR.DataHolder.Banking.Repository.csproj", "{07A67EEB-3191-4FC2-9503-9400E4B63D5A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Banking.Resource.API", "Banking\CDR.DataHolder.Banking.Resource.API\CDR.DataHolder.Banking.Resource.API.csproj", "{D191C5D3-0C74-41E9-B6C7-F3619E12FE44}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Banking.Domain", "Banking\CDR.DataHolder.Banking.Domain\CDR.DataHolder.Banking.Domain.csproj", "{DB9F8EC2-0C34-4E0F-8426-EDE609D6D6F8}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "API", "API", "{56C71FCA-4FA8-43BC-8D42-57652064BE10}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{5956ED95-4FBD-4D6B-9A0C-040865FF31A2}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Energy", "Energy", "{69CA9C9F-6D5F-40F9-A036-760F2090BBF7}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "API", "API", "{C40E2889-D45F-4507-AC0C-684BFA20DF0F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Energy.Resource.API", "Energy\CDR.DataHolder.Energy.Resource.API\CDR.DataHolder.Energy.Resource.API.csproj", "{ACC0AFE5-EE84-441C-9849-18D2D37B77E0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Energy.Domain", "Energy\CDR.DataHolder.Energy.Domain\CDR.DataHolder.Energy.Domain.csproj", "{D5ED10BC-A1A2-485B-92D0-4679BA1C60CB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Energy.Repository", "Energy\CDR.DataHolder.Energy.Repository\CDR.DataHolder.Energy.Repository.csproj", "{7E44240D-2328-4F0B-8738-5E54245FC598}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Common.API", "Common\CDR.DataHolder.Common.API\CDR.DataHolder.Common.API.csproj", "{94EC3FB8-41D2-4371-9245-651D6496F9BE}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{40CAD81A-9D02-45C5-B341-AF9C7E018895}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Banking.Resource.API.UnitTests", "Banking\CDR.DataHolder.Banking.Resource.API.UnitTests\CDR.DataHolder.Banking.Resource.API.UnitTests.csproj", "{2AD6346B-4B2D-4C3A-A021-1D0FCB118294}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{BC8E1101-5DC8-4763-8CEC-78E3D3D9D7E6}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Energy.Resource.API.UnitTests", "Energy\CDR.DataHolder.Energy.Resource.API.UnitTests\CDR.DataHolder.Energy.Resource.API.UnitTests.csproj", "{C839CB68-DFA8-4487-9153-46FE9508137A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Shared.Business", "Shared\CDR.DataHolder.Shared.Business\CDR.DataHolder.Shared.Business.csproj", "{BFF889CE-0CF2-4710-9C09-811CA7BDB500}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestAutomation", "TestAutomation", "{0A71F4D0-129F-44C0-A7FC-3954A65B3570}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Shared.API.Gateway.mTLS", "Shared\CDR.DataHolder.Shared.API.Gateway.mTLS\CDR.DataHolder.Shared.API.Gateway.mTLS.csproj", "{241D4AD3-A8BF-4977-802F-FE663C763CA9}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Shared.API.Infrastructure", "Shared\CDR.DataHolder.Shared.API.Infrastructure\CDR.DataHolder.Shared.API.Infrastructure.csproj", "{90B46AD5-63DC-4827-8156-2BC1A52494D0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Shared.API.Infrastructure.UnitTests", "Shared\CDR.DataHolder.Shared.API.Infrastructure.UnitTests\CDR.DataHolder.Shared.API.Infrastructure.UnitTests.csproj", "{78D70D97-1C02-410A-B6A8-DE76BFD2A832}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Shared.API.Logger", "Shared\CDR.DataHolder.Shared.API.Logger\CDR.DataHolder.Shared.API.Logger.csproj", "{3302A9E2-0E06-4CE3-9965-B11AD7579332}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Banking.Tests.IntegrationTests", "Banking\CDR.DataHolder.Banking.Tests.IntegrationTests\CDR.DataHolder.Banking.Tests.IntegrationTests.csproj", "{D4D6300C-04C8-4863-BABD-83372640BE63}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataHolder.Energy.Tests.IntegrationTests", "Energy\CDR.DataHolder.Energy.Tests.IntegrationTests\CDR.DataHolder.Energy.Tests.IntegrationTests.csproj", "{D94F990E-8A1F-4055-BC55-26BA704784C8}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsumerDataRight.ParticipantTooling.MockSolution.TestAutomation", "..\..\sb-mock-solution-test-automation\Source\ConsumerDataRight.ParticipantTooling.MockSolution.TestAutomation\ConsumerDataRight.ParticipantTooling.MockSolution.TestAutomation.csproj", "{1D629650-FF20-4959-A43E-3322E1766090}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - Shared|Any CPU = Shared|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {ACCF8355-24EA-4C43-9862-6F75DBF56304}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ACCF8355-24EA-4C43-9862-6F75DBF56304}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ACCF8355-24EA-4C43-9862-6F75DBF56304}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ACCF8355-24EA-4C43-9862-6F75DBF56304}.Release|Any CPU.Build.0 = Release|Any CPU - {ACCF8355-24EA-4C43-9862-6F75DBF56304}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {ACCF8355-24EA-4C43-9862-6F75DBF56304}.Shared|Any CPU.Build.0 = Release|Any CPU - {7A3D76A9-4259-4AD4-95DF-F5416165DA1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7A3D76A9-4259-4AD4-95DF-F5416165DA1E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7A3D76A9-4259-4AD4-95DF-F5416165DA1E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7A3D76A9-4259-4AD4-95DF-F5416165DA1E}.Release|Any CPU.Build.0 = Release|Any CPU - {7A3D76A9-4259-4AD4-95DF-F5416165DA1E}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {7A3D76A9-4259-4AD4-95DF-F5416165DA1E}.Shared|Any CPU.Build.0 = Release|Any CPU - {E6CFE76E-03A9-445B-A6C9-B0B3BAF58A63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E6CFE76E-03A9-445B-A6C9-B0B3BAF58A63}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E6CFE76E-03A9-445B-A6C9-B0B3BAF58A63}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E6CFE76E-03A9-445B-A6C9-B0B3BAF58A63}.Release|Any CPU.Build.0 = Release|Any CPU - {E6CFE76E-03A9-445B-A6C9-B0B3BAF58A63}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {E6CFE76E-03A9-445B-A6C9-B0B3BAF58A63}.Shared|Any CPU.Build.0 = Release|Any CPU - {BDC6661A-D2B2-43EE-A4C6-029815DA10A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BDC6661A-D2B2-43EE-A4C6-029815DA10A1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BDC6661A-D2B2-43EE-A4C6-029815DA10A1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BDC6661A-D2B2-43EE-A4C6-029815DA10A1}.Release|Any CPU.Build.0 = Release|Any CPU - {BDC6661A-D2B2-43EE-A4C6-029815DA10A1}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {BDC6661A-D2B2-43EE-A4C6-029815DA10A1}.Shared|Any CPU.Build.0 = Release|Any CPU - {671E3693-2F79-4251-A70E-F2527D6F471B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {671E3693-2F79-4251-A70E-F2527D6F471B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {671E3693-2F79-4251-A70E-F2527D6F471B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {671E3693-2F79-4251-A70E-F2527D6F471B}.Release|Any CPU.Build.0 = Release|Any CPU - {671E3693-2F79-4251-A70E-F2527D6F471B}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {671E3693-2F79-4251-A70E-F2527D6F471B}.Shared|Any CPU.Build.0 = Release|Any CPU - {07A67EEB-3191-4FC2-9503-9400E4B63D5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {07A67EEB-3191-4FC2-9503-9400E4B63D5A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {07A67EEB-3191-4FC2-9503-9400E4B63D5A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {07A67EEB-3191-4FC2-9503-9400E4B63D5A}.Release|Any CPU.Build.0 = Release|Any CPU - {07A67EEB-3191-4FC2-9503-9400E4B63D5A}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {07A67EEB-3191-4FC2-9503-9400E4B63D5A}.Shared|Any CPU.Build.0 = Release|Any CPU - {D191C5D3-0C74-41E9-B6C7-F3619E12FE44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D191C5D3-0C74-41E9-B6C7-F3619E12FE44}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D191C5D3-0C74-41E9-B6C7-F3619E12FE44}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D191C5D3-0C74-41E9-B6C7-F3619E12FE44}.Release|Any CPU.Build.0 = Release|Any CPU - {D191C5D3-0C74-41E9-B6C7-F3619E12FE44}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {D191C5D3-0C74-41E9-B6C7-F3619E12FE44}.Shared|Any CPU.Build.0 = Release|Any CPU - {DB9F8EC2-0C34-4E0F-8426-EDE609D6D6F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DB9F8EC2-0C34-4E0F-8426-EDE609D6D6F8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DB9F8EC2-0C34-4E0F-8426-EDE609D6D6F8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DB9F8EC2-0C34-4E0F-8426-EDE609D6D6F8}.Release|Any CPU.Build.0 = Release|Any CPU - {DB9F8EC2-0C34-4E0F-8426-EDE609D6D6F8}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {DB9F8EC2-0C34-4E0F-8426-EDE609D6D6F8}.Shared|Any CPU.Build.0 = Release|Any CPU - {ACC0AFE5-EE84-441C-9849-18D2D37B77E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ACC0AFE5-EE84-441C-9849-18D2D37B77E0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ACC0AFE5-EE84-441C-9849-18D2D37B77E0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ACC0AFE5-EE84-441C-9849-18D2D37B77E0}.Release|Any CPU.Build.0 = Release|Any CPU - {ACC0AFE5-EE84-441C-9849-18D2D37B77E0}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {ACC0AFE5-EE84-441C-9849-18D2D37B77E0}.Shared|Any CPU.Build.0 = Release|Any CPU - {D5ED10BC-A1A2-485B-92D0-4679BA1C60CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D5ED10BC-A1A2-485B-92D0-4679BA1C60CB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D5ED10BC-A1A2-485B-92D0-4679BA1C60CB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D5ED10BC-A1A2-485B-92D0-4679BA1C60CB}.Release|Any CPU.Build.0 = Release|Any CPU - {D5ED10BC-A1A2-485B-92D0-4679BA1C60CB}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {D5ED10BC-A1A2-485B-92D0-4679BA1C60CB}.Shared|Any CPU.Build.0 = Release|Any CPU - {7E44240D-2328-4F0B-8738-5E54245FC598}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7E44240D-2328-4F0B-8738-5E54245FC598}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7E44240D-2328-4F0B-8738-5E54245FC598}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7E44240D-2328-4F0B-8738-5E54245FC598}.Release|Any CPU.Build.0 = Release|Any CPU - {7E44240D-2328-4F0B-8738-5E54245FC598}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {7E44240D-2328-4F0B-8738-5E54245FC598}.Shared|Any CPU.Build.0 = Release|Any CPU - {94EC3FB8-41D2-4371-9245-651D6496F9BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {94EC3FB8-41D2-4371-9245-651D6496F9BE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {94EC3FB8-41D2-4371-9245-651D6496F9BE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {94EC3FB8-41D2-4371-9245-651D6496F9BE}.Release|Any CPU.Build.0 = Release|Any CPU - {94EC3FB8-41D2-4371-9245-651D6496F9BE}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {94EC3FB8-41D2-4371-9245-651D6496F9BE}.Shared|Any CPU.Build.0 = Release|Any CPU - {2AD6346B-4B2D-4C3A-A021-1D0FCB118294}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2AD6346B-4B2D-4C3A-A021-1D0FCB118294}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2AD6346B-4B2D-4C3A-A021-1D0FCB118294}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2AD6346B-4B2D-4C3A-A021-1D0FCB118294}.Release|Any CPU.Build.0 = Release|Any CPU - {2AD6346B-4B2D-4C3A-A021-1D0FCB118294}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {2AD6346B-4B2D-4C3A-A021-1D0FCB118294}.Shared|Any CPU.Build.0 = Release|Any CPU - {C839CB68-DFA8-4487-9153-46FE9508137A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C839CB68-DFA8-4487-9153-46FE9508137A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C839CB68-DFA8-4487-9153-46FE9508137A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C839CB68-DFA8-4487-9153-46FE9508137A}.Release|Any CPU.Build.0 = Release|Any CPU - {C839CB68-DFA8-4487-9153-46FE9508137A}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {C839CB68-DFA8-4487-9153-46FE9508137A}.Shared|Any CPU.Build.0 = Release|Any CPU - {BFF889CE-0CF2-4710-9C09-811CA7BDB500}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BFF889CE-0CF2-4710-9C09-811CA7BDB500}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BFF889CE-0CF2-4710-9C09-811CA7BDB500}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BFF889CE-0CF2-4710-9C09-811CA7BDB500}.Release|Any CPU.Build.0 = Release|Any CPU - {BFF889CE-0CF2-4710-9C09-811CA7BDB500}.Shared|Any CPU.ActiveCfg = Release|Any CPU - {BFF889CE-0CF2-4710-9C09-811CA7BDB500}.Shared|Any CPU.Build.0 = Release|Any CPU - {241D4AD3-A8BF-4977-802F-FE663C763CA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {241D4AD3-A8BF-4977-802F-FE663C763CA9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {241D4AD3-A8BF-4977-802F-FE663C763CA9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {241D4AD3-A8BF-4977-802F-FE663C763CA9}.Release|Any CPU.Build.0 = Release|Any CPU - {241D4AD3-A8BF-4977-802F-FE663C763CA9}.Shared|Any CPU.ActiveCfg = Debug|Any CPU - {241D4AD3-A8BF-4977-802F-FE663C763CA9}.Shared|Any CPU.Build.0 = Debug|Any CPU - {90B46AD5-63DC-4827-8156-2BC1A52494D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {90B46AD5-63DC-4827-8156-2BC1A52494D0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {90B46AD5-63DC-4827-8156-2BC1A52494D0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {90B46AD5-63DC-4827-8156-2BC1A52494D0}.Release|Any CPU.Build.0 = Release|Any CPU - {90B46AD5-63DC-4827-8156-2BC1A52494D0}.Shared|Any CPU.ActiveCfg = Debug|Any CPU - {90B46AD5-63DC-4827-8156-2BC1A52494D0}.Shared|Any CPU.Build.0 = Debug|Any CPU - {78D70D97-1C02-410A-B6A8-DE76BFD2A832}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {78D70D97-1C02-410A-B6A8-DE76BFD2A832}.Debug|Any CPU.Build.0 = Debug|Any CPU - {78D70D97-1C02-410A-B6A8-DE76BFD2A832}.Release|Any CPU.ActiveCfg = Release|Any CPU - {78D70D97-1C02-410A-B6A8-DE76BFD2A832}.Release|Any CPU.Build.0 = Release|Any CPU - {78D70D97-1C02-410A-B6A8-DE76BFD2A832}.Shared|Any CPU.ActiveCfg = Debug|Any CPU - {78D70D97-1C02-410A-B6A8-DE76BFD2A832}.Shared|Any CPU.Build.0 = Debug|Any CPU - {3302A9E2-0E06-4CE3-9965-B11AD7579332}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3302A9E2-0E06-4CE3-9965-B11AD7579332}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3302A9E2-0E06-4CE3-9965-B11AD7579332}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3302A9E2-0E06-4CE3-9965-B11AD7579332}.Release|Any CPU.Build.0 = Release|Any CPU - {3302A9E2-0E06-4CE3-9965-B11AD7579332}.Shared|Any CPU.ActiveCfg = Debug|Any CPU - {3302A9E2-0E06-4CE3-9965-B11AD7579332}.Shared|Any CPU.Build.0 = Debug|Any CPU - {D4D6300C-04C8-4863-BABD-83372640BE63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D4D6300C-04C8-4863-BABD-83372640BE63}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D4D6300C-04C8-4863-BABD-83372640BE63}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D4D6300C-04C8-4863-BABD-83372640BE63}.Release|Any CPU.Build.0 = Release|Any CPU - {D4D6300C-04C8-4863-BABD-83372640BE63}.Shared|Any CPU.ActiveCfg = Shared|Any CPU - {D4D6300C-04C8-4863-BABD-83372640BE63}.Shared|Any CPU.Build.0 = Shared|Any CPU - {D94F990E-8A1F-4055-BC55-26BA704784C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D94F990E-8A1F-4055-BC55-26BA704784C8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D94F990E-8A1F-4055-BC55-26BA704784C8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D94F990E-8A1F-4055-BC55-26BA704784C8}.Release|Any CPU.Build.0 = Release|Any CPU - {D94F990E-8A1F-4055-BC55-26BA704784C8}.Shared|Any CPU.ActiveCfg = Shared|Any CPU - {D94F990E-8A1F-4055-BC55-26BA704784C8}.Shared|Any CPU.Build.0 = Shared|Any CPU - {1D629650-FF20-4959-A43E-3322E1766090}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1D629650-FF20-4959-A43E-3322E1766090}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1D629650-FF20-4959-A43E-3322E1766090}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1D629650-FF20-4959-A43E-3322E1766090}.Release|Any CPU.Build.0 = Release|Any CPU - {1D629650-FF20-4959-A43E-3322E1766090}.Shared|Any CPU.ActiveCfg = Shared|Any CPU - {1D629650-FF20-4959-A43E-3322E1766090}.Shared|Any CPU.Build.0 = Shared|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {ACCF8355-24EA-4C43-9862-6F75DBF56304} = {0BD4EE79-7F77-4CE6-B0F9-A2CE2F17F0BE} - {0BD4EE79-7F77-4CE6-B0F9-A2CE2F17F0BE} = {A958A8EB-FC1A-49BC-ABA0-7DB3DB56CADB} - {7A3D76A9-4259-4AD4-95DF-F5416165DA1E} = {0BD4EE79-7F77-4CE6-B0F9-A2CE2F17F0BE} - {E6CFE76E-03A9-445B-A6C9-B0B3BAF58A63} = {0BD4EE79-7F77-4CE6-B0F9-A2CE2F17F0BE} - {1140FEF6-AF92-42B2-A670-B77354A0B4C1} = {A958A8EB-FC1A-49BC-ABA0-7DB3DB56CADB} - {BDC6661A-D2B2-43EE-A4C6-029815DA10A1} = {A958A8EB-FC1A-49BC-ABA0-7DB3DB56CADB} - {671E3693-2F79-4251-A70E-F2527D6F471B} = {A958A8EB-FC1A-49BC-ABA0-7DB3DB56CADB} - {07A67EEB-3191-4FC2-9503-9400E4B63D5A} = {AC72555E-198B-4542-9993-6CA067FD5EE4} - {D191C5D3-0C74-41E9-B6C7-F3619E12FE44} = {56C71FCA-4FA8-43BC-8D42-57652064BE10} - {DB9F8EC2-0C34-4E0F-8426-EDE609D6D6F8} = {AC72555E-198B-4542-9993-6CA067FD5EE4} - {56C71FCA-4FA8-43BC-8D42-57652064BE10} = {AC72555E-198B-4542-9993-6CA067FD5EE4} - {C40E2889-D45F-4507-AC0C-684BFA20DF0F} = {69CA9C9F-6D5F-40F9-A036-760F2090BBF7} - {ACC0AFE5-EE84-441C-9849-18D2D37B77E0} = {C40E2889-D45F-4507-AC0C-684BFA20DF0F} - {D5ED10BC-A1A2-485B-92D0-4679BA1C60CB} = {69CA9C9F-6D5F-40F9-A036-760F2090BBF7} - {7E44240D-2328-4F0B-8738-5E54245FC598} = {69CA9C9F-6D5F-40F9-A036-760F2090BBF7} - {94EC3FB8-41D2-4371-9245-651D6496F9BE} = {5956ED95-4FBD-4D6B-9A0C-040865FF31A2} - {40CAD81A-9D02-45C5-B341-AF9C7E018895} = {AC72555E-198B-4542-9993-6CA067FD5EE4} - {2AD6346B-4B2D-4C3A-A021-1D0FCB118294} = {40CAD81A-9D02-45C5-B341-AF9C7E018895} - {BC8E1101-5DC8-4763-8CEC-78E3D3D9D7E6} = {69CA9C9F-6D5F-40F9-A036-760F2090BBF7} - {C839CB68-DFA8-4487-9153-46FE9508137A} = {BC8E1101-5DC8-4763-8CEC-78E3D3D9D7E6} - {BFF889CE-0CF2-4710-9C09-811CA7BDB500} = {A958A8EB-FC1A-49BC-ABA0-7DB3DB56CADB} - {0A71F4D0-129F-44C0-A7FC-3954A65B3570} = {A958A8EB-FC1A-49BC-ABA0-7DB3DB56CADB} - {241D4AD3-A8BF-4977-802F-FE663C763CA9} = {1140FEF6-AF92-42B2-A670-B77354A0B4C1} - {90B46AD5-63DC-4827-8156-2BC1A52494D0} = {1140FEF6-AF92-42B2-A670-B77354A0B4C1} - {78D70D97-1C02-410A-B6A8-DE76BFD2A832} = {1140FEF6-AF92-42B2-A670-B77354A0B4C1} - {3302A9E2-0E06-4CE3-9965-B11AD7579332} = {1140FEF6-AF92-42B2-A670-B77354A0B4C1} - {D4D6300C-04C8-4863-BABD-83372640BE63} = {40CAD81A-9D02-45C5-B341-AF9C7E018895} - {D94F990E-8A1F-4055-BC55-26BA704784C8} = {BC8E1101-5DC8-4763-8CEC-78E3D3D9D7E6} - {1D629650-FF20-4959-A43E-3322E1766090} = {0A71F4D0-129F-44C0-A7FC-3954A65B3570} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {AE8E874B-11F7-494D-9902-AD374F1EC3B3} - EndGlobalSection -EndGlobal diff --git a/Source/DataHolder_Shared.slnx b/Source/DataHolder_Shared.slnx new file mode 100644 index 0000000..50e2bfb --- /dev/null +++ b/Source/DataHolder_Shared.slnx @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/Directory.Build.props b/Source/Directory.Build.props index 15af89e..3958577 100644 --- a/Source/Directory.Build.props +++ b/Source/Directory.Build.props @@ -1,7 +1,7 @@ - net8.0 - 4.0.5 + net10.0 + 5.0.0 true true true diff --git a/Source/Directory.Packages.props b/Source/Directory.Packages.props index bd885c0..0c37f2a 100644 --- a/Source/Directory.Packages.props +++ b/Source/Directory.Packages.props @@ -4,51 +4,54 @@ true - - + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + - - + + - + - - + + - - - - + + + + + \ No newline at end of file diff --git a/Source/Dockerfile b/Source/Dockerfile index bd60a9f..47c79ec 100644 --- a/Source/Dockerfile +++ b/Source/Dockerfile @@ -2,7 +2,7 @@ ############################################################################### # Build base layer ############################################################################### -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base # Install nodejs, npm and live-server, which are needed by the auth UI RUN apt-get update && apt-get install -y --no-install-recommends \ @@ -11,6 +11,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ nginx \ && rm -rf /var/lib/apt/lists/* +# install now so it will be immediately available for supervisord +RUN npm install -g react-inject-env + WORKDIR /app EXPOSE 8001 EXPOSE 8002 @@ -45,7 +48,7 @@ COPY ./cdr-auth-server/Source/CdrAuthServer.UI/nginx/ssl/authserver-ui.key /etc/ ############################################################################### # Build CdrAuthServer API layer ############################################################################### -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /src COPY . ./ @@ -150,21 +153,20 @@ RUN sudo cp ./gateway-mtls/Certificates/ca.crt /usr/local/share/ca-certificates/ USER 0 RUN setcap cap_net_bind_service=+ep /usr/sbin/nginx -RUN addgroup --group appgroup --gid 2000 \ - && adduser --uid 1000 --gid 2000 "appuser" \ - && chown -R appuser:appgroup /app \ - && chown -R appuser:appgroup /usr/bin \ - && chown -R appuser:appgroup /usr/local \ - && chown -R appuser:appgroup /tmp \ - && chown -R appuser:appgroup /var/log/nginx \ - && chown -R appuser:appgroup /var/lib/nginx +RUN chown -R app:app /app \ + && chown -R app:app /app \ + && chown -R app:app /usr/bin \ + && chown -R app:app /usr/local \ + && chown -R app:app /tmp \ + && chown -R app:app /var/log/nginx \ + && chown -R app:app /var/lib/nginx RUN touch /run/nginx.pid \ - && chown -R appuser:appgroup /run/nginx.pid + && chown -R app:app /run/nginx.pid RUN touch /usr/share/nginx/html/ui/env.js \ - && chown -R appuser:appgroup /usr/share/nginx/html/ui/env.js + && chown -R app:app /usr/share/nginx/html/ui/env.js -USER appuser:appgroup +USER $APP_UID ENV ASPNETCORE_URLS=https://+:8001;https://+:8002 @@ -220,7 +222,7 @@ ENV ResourceBaseUri=https://mock-data-holder-energy:8102 # Entry point ################################################################# -ENTRYPOINT ["/usr/bin/supervisord", "-c", "/app/supervisord.conf", "-u", "1000"] +ENTRYPOINT ["/usr/bin/supervisord", "-c", "/app/supervisord.conf"] FROM final AS Banking @@ -271,9 +273,9 @@ ENV IdentityServerUrl=https://mock-data-holder:8001 ENV ResourceBaseUri=https://mock-data-holder:8002 # Entry point ################################################################# -ENTRYPOINT ["/usr/bin/supervisord", "-c", "/app/supervisord.conf", "-u", "1000"] +ENTRYPOINT ["/usr/bin/supervisord", "-c", "/app/supervisord.conf"] FROM final AS NoIndustry # Entry point ################################################################# -ENTRYPOINT ["/usr/bin/supervisord", "-c", "/app/supervisord.conf", "-u", "1000"] \ No newline at end of file +ENTRYPOINT ["/usr/bin/supervisord", "-c", "/app/supervisord.conf"] \ No newline at end of file diff --git a/Source/Dockerfile.integration-tests b/Source/Dockerfile.integration-tests index 837f935..87d9669 100644 --- a/Source/Dockerfile.integration-tests +++ b/Source/Dockerfile.integration-tests @@ -1,8 +1,9 @@ # Dockerfile for running integration tests -# playwright jammy for .Net 8 +# playwright noble for .Net 10 # the image tag version should be the same as the Playwright package # which is a transitive dependency from ConsumerDataRight.ParticipantTooling.MockSolution.TestAutomation -FROM mcr.microsoft.com/playwright/dotnet:v1.43.0-jammy as build + +FROM mcr.microsoft.com/playwright/dotnet:v1.62.0-noble as build ARG INTEGRATION_TESTS_LOCATION diff --git a/Source/Dockerfile.unit-tests b/Source/Dockerfile.unit-tests index 0d6e8e9..4f2963e 100644 --- a/Source/Dockerfile.unit-tests +++ b/Source/Dockerfile.unit-tests @@ -1,6 +1,6 @@ # Dockerfile for running unit tests -FROM mcr.microsoft.com/dotnet/sdk:8.0-noble AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0-noble AS build WORKDIR /src EXPOSE 9999 EXPOSE 9998 @@ -26,8 +26,8 @@ ARG FEED_ACCESSTOKEN ARG FEED_URI ENV VSS_NUGET_EXTERNAL_FEED_ENDPOINTS="{\"endpointCredentials\": [{\"endpoint\":\"${FEED_URI}\", \"username\":\"docker\", \"password\":\"${FEED_ACCESSTOKEN}\"}]}" RUN echo $VSS_NUGET_EXTERNAL_FEED_ENDPOINTS -RUN dotnet restore DataHolder.sln -RUN dotnet build DataHolder.sln --configuration Release +RUN dotnet restore DataHolder.slnx +RUN dotnet build DataHolder.slnx --configuration Release # Run tests -ENTRYPOINT ["dotnet", "test", "DataHolder.sln", "--configuration", "Release", "--filter", "Category=UnitTests", "--no-build", "--logger", "trx;verbosity=detailed", "--results-directory", "/testresults"] +ENTRYPOINT ["dotnet", "test", "DataHolder.slnx", "--configuration", "Release", "--filter", "Category=UnitTests", "--no-build", "--logger", "trx;verbosity=detailed", "--results-directory", "/testresults"] diff --git a/Source/Energy/CDR.DataHolder.Energy.Resource.API.UnitTests/CDR.DataHolder.Energy.Resource.API.UnitTests.csproj b/Source/Energy/CDR.DataHolder.Energy.Resource.API.UnitTests/CDR.DataHolder.Energy.Resource.API.UnitTests.csproj index eb0b586..9ac28c5 100644 --- a/Source/Energy/CDR.DataHolder.Energy.Resource.API.UnitTests/CDR.DataHolder.Energy.Resource.API.UnitTests.csproj +++ b/Source/Energy/CDR.DataHolder.Energy.Resource.API.UnitTests/CDR.DataHolder.Energy.Resource.API.UnitTests.csproj @@ -40,7 +40,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Source/Energy/CDR.DataHolder.Energy.Resource.API.UnitTests/Fixtures/SeedDataFixture.cs b/Source/Energy/CDR.DataHolder.Energy.Resource.API.UnitTests/Fixtures/SeedDataFixture.cs index 7bbb03c..8c9a799 100644 --- a/Source/Energy/CDR.DataHolder.Energy.Resource.API.UnitTests/Fixtures/SeedDataFixture.cs +++ b/Source/Energy/CDR.DataHolder.Energy.Resource.API.UnitTests/Fixtures/SeedDataFixture.cs @@ -40,7 +40,7 @@ public SeedDataFixture() services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(dispose: true)); - services.AddAutoMapper(typeof(Startup), typeof(EnergyDataHolderDatabaseContext)); + services.AddAutoMapper(cfg => { }, typeof(Startup).Assembly, typeof(EnergyDataHolderDatabaseContext).Assembly); services.AddScoped(); services.AddScoped(); diff --git a/Source/Energy/CDR.DataHolder.Energy.Resource.API/Business/MappingProfile.cs b/Source/Energy/CDR.DataHolder.Energy.Resource.API/Business/MappingProfile.cs index 582e0c4..a7854d4 100644 --- a/Source/Energy/CDR.DataHolder.Energy.Resource.API/Business/MappingProfile.cs +++ b/Source/Energy/CDR.DataHolder.Energy.Resource.API/Business/MappingProfile.cs @@ -34,10 +34,6 @@ public MappingProfile() .ForMember(dest => dest.CreationDate, source => source.MapFrom(source => source.CreationDate == null ? string.Empty : source.CreationDate.Value.ToString("yyyy-MM-dd"))) .ForMember(dest => dest.Plans, source => source.MapFrom(source => source.Plans)) - .ReverseMap() - .MaxDepth(AutoMapperMaxDepth); - CreateMap() - .IncludeBase() .ForMember(dest => dest.OpenStatus, source => source.MapFrom(source => source.OpenStatus)) .ReverseMap() .MaxDepth(AutoMapperMaxDepth); @@ -46,11 +42,6 @@ public MappingProfile() .ForMember(dest => dest.Meta, source => source.MapFrom(source => source)) .ReverseMap() .MaxDepth(AutoMapperMaxDepth); - CreateMap, EnergyAccountListResponse>() - .ForPath(dest => dest.Data.Accounts, source => source.MapFrom(source => source.Data)) - .ForMember(dest => dest.Meta, source => source.MapFrom(source => source)) - .ReverseMap() - .MaxDepth(AutoMapperMaxDepth); CreateMap() .ForPath(dest => dest.Data.Concessions, source => source.MapFrom(source => source)); diff --git a/Source/Energy/CDR.DataHolder.Energy.Resource.API/Business/Models/EnergyAccount.cs b/Source/Energy/CDR.DataHolder.Energy.Resource.API/Business/Models/EnergyAccount.cs index 9b0cc6f..95dc0c2 100644 --- a/Source/Energy/CDR.DataHolder.Energy.Resource.API/Business/Models/EnergyAccount.cs +++ b/Source/Energy/CDR.DataHolder.Energy.Resource.API/Business/Models/EnergyAccount.cs @@ -14,6 +14,9 @@ public class EnergyAccount [JsonProperty(Order = 3)] public string? DisplayName { get; set; } + [JsonProperty(Order = 4)] + public string OpenStatus { get; set; } = string.Empty; + [JsonProperty(Order = 5)] public string CreationDate { get; set; } = string.Empty; diff --git a/Source/Energy/CDR.DataHolder.Energy.Resource.API/Business/Models/EnergyAccountV2.cs b/Source/Energy/CDR.DataHolder.Energy.Resource.API/Business/Models/EnergyAccountV2.cs deleted file mode 100644 index a441258..0000000 --- a/Source/Energy/CDR.DataHolder.Energy.Resource.API/Business/Models/EnergyAccountV2.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace CDR.DataHolder.Energy.Resource.API.Business.Models -{ - public class EnergyAccountV2 : EnergyAccount - { - [JsonProperty(Order = 4)] - public string OpenStatus { get; set; } = string.Empty; - } -} diff --git a/Source/Energy/CDR.DataHolder.Energy.Resource.API/CDR.DataHolder.Energy.Resource.API.csproj b/Source/Energy/CDR.DataHolder.Energy.Resource.API/CDR.DataHolder.Energy.Resource.API.csproj index 7e25a5f..f3e399d 100644 --- a/Source/Energy/CDR.DataHolder.Energy.Resource.API/CDR.DataHolder.Energy.Resource.API.csproj +++ b/Source/Energy/CDR.DataHolder.Energy.Resource.API/CDR.DataHolder.Energy.Resource.API.csproj @@ -33,7 +33,6 @@ - diff --git a/Source/Energy/CDR.DataHolder.Energy.Resource.API/Controllers/ResourceController.cs b/Source/Energy/CDR.DataHolder.Energy.Resource.API/Controllers/ResourceController.cs index 1e276be..4929c64 100644 --- a/Source/Energy/CDR.DataHolder.Energy.Resource.API/Controllers/ResourceController.cs +++ b/Source/Energy/CDR.DataHolder.Energy.Resource.API/Controllers/ResourceController.cs @@ -1,4 +1,5 @@ -using AutoMapper; +using Asp.Versioning; +using AutoMapper; using CDR.DataHolder.Energy.Domain.Repositories; using CDR.DataHolder.Energy.Domain.ValueObjects; using CDR.DataHolder.Energy.Resource.API.Business.Models; @@ -12,7 +13,6 @@ using CDR.DataHolder.Shared.Domain.Models; using CDR.DataHolder.Shared.Domain.ValueObjects; using CDR.DataHolder.Shared.Resource.API.Business.Filters; -using CDR.DataHolder.Shared.Resource.API.Infrastructure.Filters; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; @@ -51,24 +51,6 @@ public ResourceController( _idPermanenceManager = idPermanenceManager; } - [PolicyAuthorize(AuthorisationPolicy.GetAccountsApi)] - [HttpGet("v1/energy/accounts", Name = nameof(GetEnergyAccountsXV1))] - [CheckScope(CDR.DataHolder.Shared.API.Infrastructure.Constants.ApiScopes.Energy.AccountsBasicRead)] - [CheckXV(1, 1)] - [CheckAuthDate] - [ApiVersion("1")] - [ServiceFilter(typeof(LogActionEntryAttribute))] - public async Task GetEnergyAccountsXV1( - [FromQuery(Name = "page"), CheckPage] string? page, - [FromQuery(Name = "page-size"), CheckPageSize] string? pageSize) - { - // Create the filter - var accountIds = User.GetAccountIds(); - var accountFilter = new AccountFilter(accountIds); - - return await GetPagedEnergyAccountsForFilter(page, pageSize, accountFilter); - } - private async Task GetPagedEnergyAccountsForFilter(string? page, string? pageSize, AccountFilter accountFilter) where T : EnergyAccount { @@ -109,13 +91,13 @@ private async Task GetPagedEnergyAccountsForFilter(string? pag } [PolicyAuthorize(AuthorisationPolicy.GetAccountsApi)] - [HttpGet("v1/energy/accounts", Name = nameof(GetEnergyAccountsXV2))] + [HttpGet("v1/energy/accounts", Name = nameof(GetEnergyAccounts))] [CheckScope(Shared.API.Infrastructure.Constants.ApiScopes.Energy.AccountsBasicRead)] - [CheckXV(2, 2)] [CheckAuthDate] + [SetVersionResponse(2)] [ApiVersion("2")] [ServiceFilter(typeof(LogActionEntryAttribute))] - public async Task GetEnergyAccountsXV2( + public async Task GetEnergyAccounts( [FromQuery(Name = "open-status"), CheckOpenStatus] string? openStatus, [FromQuery(Name = "page"), CheckPage] string? page, [FromQuery(Name = "page-size"), CheckPageSize] string? pageSize) @@ -127,14 +109,14 @@ public async Task GetEnergyAccountsXV2( OpenStatus = (openStatus != null && openStatus.Equals(OpenStatus.All.ToString(), StringComparison.OrdinalIgnoreCase)) ? null : openStatus, }; - return await GetPagedEnergyAccountsForFilter(page, pageSize, accountFilter); + return await GetPagedEnergyAccountsForFilter(page, pageSize, accountFilter); } [PolicyAuthorize(AuthorisationPolicy.GetConcessionsApi)] [HttpGet("v1/energy/accounts/{accountId}/concessions", Name = nameof(GetConcessions))] [CheckScope(Shared.API.Infrastructure.Constants.ApiScopes.Energy.ConcessionsRead)] - [CheckXV(1, 1)] [CheckAuthDate] + [SetVersionResponse(1)] [ApiVersion("1")] [ServiceFilter(typeof(LogActionEntryAttribute))] public async Task GetConcessions([FromRoute] string accountId) diff --git a/Source/Energy/CDR.DataHolder.Energy.Resource.API/Startup.cs b/Source/Energy/CDR.DataHolder.Energy.Resource.API/Startup.cs index 296c015..24a4097 100644 --- a/Source/Energy/CDR.DataHolder.Energy.Resource.API/Startup.cs +++ b/Source/Energy/CDR.DataHolder.Energy.Resource.API/Startup.cs @@ -19,13 +19,12 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.IdentityModel.Tokens; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Newtonsoft.Json.Converters; using Serilog; using System; @@ -56,6 +55,7 @@ public void ConfigureServices(IServiceCollection services) services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "Mock Data Holder Discovery API", Version = "v1" }); + c.SwaggerDoc("v2", new OpenApiInfo { Title = "Mock Data Holder Discovery API", Version = "v2" }); }); services.AddSwaggerGenNewtonsoftSupport(); @@ -71,13 +71,7 @@ public void ConfigureServices(IServiceCollection services) options.InvalidModelStateResponseFactory = ModelStateErrorMiddleware.ExecuteResult; }); - services.AddApiVersioning(options => - { - options.DefaultApiVersion = new ApiVersion(1, 0); - options.AssumeDefaultVersionWhenUnspecified = true; - options.ApiVersionSelector = new ApiVersionSelector(options); - options.ErrorResponses = new ErrorResponseVersion(); - }); + services.AddCdrApiVersioning(); // This is to manage the EF database context through the web API DI. // If this is to be done inside the repository project itself, we need to manage the context life-cycle explicitly. @@ -86,7 +80,7 @@ public void ConfigureServices(IServiceCollection services) // Enable authentication and authorisation AddAuthenticationAuthorization(services, Configuration); - services.AddAutoMapper(typeof(Startup), typeof(EnergyDataHolderDatabaseContext)); + services.AddAutoMapper(cfg => { }, typeof(Startup).Assembly, typeof(EnergyDataHolderDatabaseContext).Assembly); services.AddScoped(); if (Configuration.GetSection("SerilogRequestResponseLogger") != null) @@ -168,15 +162,9 @@ private static void AddAuthenticationAuthorization(IServiceCollection services, Type = SecuritySchemeType.ApiKey, BearerFormat = "JWT", }); - c.AddSecurityRequirement(new OpenApiSecurityRequirement + c.AddSecurityRequirement(document => new OpenApiSecurityRequirement { - { - new OpenApiSecurityScheme - { - Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }, - }, - new List() - }, + [new OpenApiSecuritySchemeReference("Bearer", document)] = [], }); }); } @@ -200,9 +188,6 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) exceptionHandlerApp.Run(async context => await ApiExceptionHandler.Handle(context)); }); - app.UseSwagger(); - app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Mock Data Holder Discovery API v1")); - app.UseHttpsRedirection(); app.UseRouting(); @@ -213,6 +198,8 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) // Add custom middleware app.UseInteractionId(); + app.UseCdrSwagger(); + app.UseEndpoints(endpoints => { endpoints.MapControllers(); diff --git a/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/BaseTest.cs b/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/BaseTest.cs index e7094ce..e1ac9ca 100644 --- a/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/BaseTest.cs +++ b/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/BaseTest.cs @@ -1,4 +1,5 @@ -using ConsumerDataRight.ParticipantTooling.MockSolution.TestAutomation; +using CDR.DataHolder.Energy.Tests.IntegrationTests.XUnit.Orderers; +using ConsumerDataRight.ParticipantTooling.MockSolution.TestAutomation; using Microsoft.Extensions.Configuration; using Xunit; using Xunit.DependencyInjection; @@ -7,11 +8,11 @@ namespace CDR.DataHolder.Energy.Tests.IntegrationTests { // Put all tests in same collection because we need them to run sequentially since some tests are mutating DB. [Collection("IntegrationTests")] - [TestCaseOrderer("CDR.DataHolder.Energy.Tests.IntegrationTests.XUnit.Orderers.AlphabeticalOrderer", "CDR.DataHolder.Energy.Tests.IntegrationTests")] + [TestCaseOrderer(typeof(AlphabeticalOrderer))] public abstract class BaseTest : SharedBaseTest { protected BaseTest(ITestOutputHelperAccessor testOutputHelperAccessor, IConfiguration config) - : base(testOutputHelperAccessor, config) + : base(config) { } } diff --git a/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/CDR.DataHolder.Energy.Tests.IntegrationTests.csproj b/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/CDR.DataHolder.Energy.Tests.IntegrationTests.csproj index 2b36b07..b775dcd 100644 --- a/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/CDR.DataHolder.Energy.Tests.IntegrationTests.csproj +++ b/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/CDR.DataHolder.Energy.Tests.IntegrationTests.csproj @@ -39,9 +39,10 @@ true - + true + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/US27571_MDH_EnergyAPI_GetAccounts.cs b/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/US27571_MDH_EnergyAPI_GetAccounts.cs index 92bbf9c..31102e3 100644 --- a/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/US27571_MDH_EnergyAPI_GetAccounts.cs +++ b/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/US27571_MDH_EnergyAPI_GetAccounts.cs @@ -59,15 +59,6 @@ public US27571_Mdh_EnergyApi_GetAccounts( energy_Get_Accounts_Base_Url = $"{_options.DH_MTLS_GATEWAY_URL}/cds-au/v1/energy/accounts"; } - [Theory] - [InlineData(TokenType.MaryMoss, "1")] - public async Task AC01_GetAccounts_ShouldRespondWith_200OK_Accounts(TokenType tokenType, string apiVersion) - { - Log.Information("Running test with Params: {P1}={V1}, {P2}={V2}.", nameof(tokenType), tokenType, nameof(apiVersion), apiVersion); - - await Test_ValidGetAccountsScenario(tokenType, apiVersion: apiVersion); - } - // Note: Covers US45029-AC01a, US45029-AC01b, US45029-AC01c and US45029-AC01d [Theory] [InlineData(TokenType.MaryMoss, "ALL", "2")] @@ -82,7 +73,6 @@ public async Task AC01_GetAccountsV2_ShouldRespondWith_200OK_Accounts(TokenType } [Theory] - [InlineData("DateTime.Now.RFC1123", "1")] [InlineData("DateTime.Now.RFC1123", "2")] public async Task AC02_AC09_Get_WithValidXFAPIAuthDate_Success( string xFapiAuthDate, @@ -109,11 +99,6 @@ public async Task AC02_AC09_Get_WithValidXFAPIAuthDate_Success( } [Theory] - [InlineData("000", "1", CdsError.InvalidHeader)] - [InlineData("foo", "1", CdsError.InvalidHeader)] - [InlineData("", "1", CdsError.InvalidHeader)] - [InlineData(null, "1", CdsError.MissingRequiredHeader)] - [InlineData("DateTime.UtcNow", "1", CdsError.InvalidHeader)] [InlineData("000", "2", CdsError.InvalidHeader)] [InlineData("foo", "2", CdsError.InvalidHeader)] [InlineData("", "2", CdsError.InvalidHeader)] @@ -164,9 +149,6 @@ public async Task AC02_AC09_Get_WithInvalidXFAPIAuthDate_ShouldRespondWith_400Ba } [Theory] - [InlineData(null, 1001, CdsError.InvalidPageSize, "1")] - [InlineData(100, null, CdsError.InvalidPage, "1")] - [InlineData(0, null, CdsError.InvalidField, "1")] [InlineData(null, 1001, CdsError.InvalidPageSize, "2")] [InlineData(100, null, CdsError.InvalidPage, "2")] [InlineData(0, null, CdsError.InvalidField, "2")] @@ -210,8 +192,9 @@ public async Task AC03_AC06_AC07_Get_WithInvalidPageSizeOrInvalidPageOrInvalidFi [Theory] [InlineData("foo", CdsError.InvalidVersion)] [InlineData("-1", CdsError.InvalidVersion)] + [InlineData("1", CdsError.UnsupportedVersion)] [InlineData("3", CdsError.UnsupportedVersion)] - [InlineData("", CdsError.InvalidVersion)] + [InlineData("", CdsError.MissingRequiredHeader)] [InlineData(null, CdsError.MissingRequiredHeader)] public async Task AC04_AC05_AC08_Get_WithInvalidXV_Failure( string apiVersion, @@ -278,7 +261,6 @@ public async Task ACX03_Get_WithPageSize5_AndPage5_ShouldRespondWith_200OK_Page5 } [Theory] - [InlineData(SCOPE_ACCOUNTS_BASIC_READ, "1")] [InlineData(SCOPE_ACCOUNTS_BASIC_READ, "2")] public async Task ACX04_Get_Success(string scope, string apiVersion) { @@ -299,7 +281,6 @@ public async Task ACX04_Get_Success(string scope, string apiVersion) } [Theory] - [InlineData(SCOPE_WITHOUT_ACCOUNTS_BASIC_READ, "1")] [InlineData(SCOPE_WITHOUT_ACCOUNTS_BASIC_READ, "2")] public async Task ACX04_Get_WithoutEnergyAccountsReadScope_ShouldRespondWith_403Forbidden(string scope, string apiVersion) { @@ -328,8 +309,6 @@ public async Task ACX04_Get_WithoutEnergyAccountsReadScope_ShouldRespondWith_403 } [Theory] - [InlineData(TokenType.MaryMoss, HttpStatusCode.OK, "1")] - [InlineData(TokenType.InvalidFoo, HttpStatusCode.Unauthorized, "1")] [InlineData(TokenType.MaryMoss, HttpStatusCode.OK, "2")] [InlineData(TokenType.InvalidFoo, HttpStatusCode.Unauthorized, "2")] public async Task ACX05_Get_WithInvalidAccessToken_ShouldRespondWith_401Unauthorized(TokenType tokenType, HttpStatusCode expectedStatusCode, string apiVersion) @@ -411,7 +390,6 @@ public async Task ACX07_Get_WithExpiredAccessToken_ShouldRespondWith_401Unauthor } [Theory] - [InlineData("123", HttpStatusCode.OK, "1")] [InlineData("123", HttpStatusCode.OK, "2")] public async Task ACX10_Get_WithXFAPIInteractionId123_ShouldRespondWith_200OK_Accounts_AndXFapiInteractionIDis123(string xFapiInteractionId, HttpStatusCode expectedStatusCode, string apiVersion) { @@ -445,7 +423,7 @@ public async Task ACX11_Get_Success(string certificateFilename, string certifica var accessToken = await _dataHolderAccessTokenCache.GetAccessToken(TokenType.MaryMoss); // Act - var api = _apiServiceDirector.BuildDataHolderEnergyGetAccountsAPI(accessToken, DateTime.Now.ToUniversalTime().ToString("r"), certFileName: certificateFilename, certPassword: certificatePassword); + var api = _apiServiceDirector.BuildDataHolderEnergyGetAccountsAPI(accessToken, DateTime.Now.ToUniversalTime().ToString("r"), xv: "2", certFileName: certificateFilename, certPassword: certificatePassword); var response = await api.SendAsync(); // Assert @@ -469,7 +447,7 @@ public async Task ACX11_Get_WithDifferentHolderOfKey_401Unauthorized(string cert var expectedContent = JsonConvert.SerializeObject(new ResponseErrorListV2(expectedError, string.Empty)); // Act - var api = _apiServiceDirector.BuildDataHolderEnergyGetAccountsAPI(accessToken, DateTime.Now.ToUniversalTime().ToString("r"), certFileName: certificateFilename, certPassword: certificatePassword); + var api = _apiServiceDirector.BuildDataHolderEnergyGetAccountsAPI(accessToken, DateTime.Now.ToUniversalTime().ToString("r"), xv: "2", certFileName: certificateFilename, certPassword: certificatePassword); var response = await api.SendAsync(); // Assert @@ -539,7 +517,7 @@ public async Task ACX13_GetAccountsMultipleTimes_ShouldRespondWith_SameEncrypted { async Task GetAccounts(string? accessToken) { - var api = _apiServiceDirector.BuildDataHolderEnergyGetAccountsAPI(accessToken, DateTime.Now.ToUniversalTime().ToString("r")); + var api = _apiServiceDirector.BuildDataHolderEnergyGetAccountsAPI(accessToken, DateTime.Now.ToUniversalTime().ToString("r"), xv: "2"); var response = await api.SendAsync(); if (response.StatusCode != HttpStatusCode.OK) @@ -592,8 +570,6 @@ public async Task ACX13_GetAccountsMultipleTimes_ShouldRespondWith_SameEncrypted } [Theory] - [InlineData("1", "1", "1")] // Valid. Should return v1 - [InlineData("1", "2", "1")] // Valid. Should return v1 - x-min-v is ignored when > x-v [InlineData("2", "1", "2")] // Valid. Should return v2 - x-v is supported and higher than x-min-v [InlineData("2", "2", "2")] // Valid. Should return v2 - x-v is supported equal to x-min-v [InlineData("3", "2", "2")] // Valid. Should return v2 - x-v is NOT supported and x-min-v is supported @@ -653,7 +629,7 @@ public async Task ACX14_ApiVersionAndMinimumSupportedVersionScenarios_406NotAcce } } - private async Task GetAccounts(string? accessToken, string url, string? apiVersion = "1") + private async Task GetAccounts(string? accessToken, string url, string? apiVersion = "2") { var api = _apiServiceDirector.BuildDataHolderEnergyGetAccountsAPI(accessToken, DateTime.Now.ToUniversalTime().ToString("r"), xv: apiVersion, url: url); return await api.SendAsync(); @@ -667,7 +643,7 @@ private async Task Test_ValidGetAccountsScenario( int? queryPage = null, int? queryPageSize = null, int? expectedRecordCount = null, - string apiVersion = "1") + string apiVersion = "2") { // Arrange var accessToken = await _dataHolderAccessTokenCache.GetAccessToken(tokenType, scope: SCOPE_ACCOUNTS_BASIC_READ); diff --git a/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/USX00001_MDH_InfosecProfileAPI_PAR_FAPI.cs b/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/USX00001_MDH_InfosecProfileAPI_PAR_FAPI.cs index cca2ade..aac85fe 100644 --- a/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/USX00001_MDH_InfosecProfileAPI_PAR_FAPI.cs +++ b/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/USX00001_MDH_InfosecProfileAPI_PAR_FAPI.cs @@ -230,7 +230,7 @@ public async Task ACX12_FAPI_AuthorizeWithNoRequestOrRequestUri_ShouldRespondWit using var client = ConsumerDataRight.ParticipantTooling.MockSolution.TestAutomation.Helpers.Web.CreateHttpClient(); // Act - var response = await client.GetAsync(url); + var response = await client.GetAsync(url, TestContext.Current.CancellationToken); // Assert using (new AssertionScope(BaseTestAssertionStrategy)) @@ -242,7 +242,7 @@ public async Task ACX12_FAPI_AuthorizeWithNoRequestOrRequestUri_ShouldRespondWit response?.RequestMessage?.RequestUri?.PathAndQuery.Should().StartWith("/connect/authorize"); var expectedErrorResponse = "ERR-AUTH-008: request_uri is missing"; - var actualResponseContent = response?.Content != null ? await response.Content.ReadAsStringAsync() : null; + var actualResponseContent = response?.Content != null ? await response.Content.ReadAsStringAsync(TestContext.Current.CancellationToken) : null; actualResponseContent.Should().Contain(expectedErrorResponse); } } diff --git a/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/XUnit/Orderers/AlphabeticalOrderer.cs b/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/XUnit/Orderers/AlphabeticalOrderer.cs index da998f8..73f8484 100644 --- a/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/XUnit/Orderers/AlphabeticalOrderer.cs +++ b/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/XUnit/Orderers/AlphabeticalOrderer.cs @@ -1,11 +1,25 @@ -using Xunit.Abstractions; -using Xunit.Sdk; +using Xunit.Sdk; +using Xunit.v3; namespace CDR.DataHolder.Energy.Tests.IntegrationTests.XUnit.Orderers { public class AlphabeticalOrderer : ITestCaseOrderer { - public IEnumerable OrderTestCases(IEnumerable testCases) - where TTestCase : ITestCase => testCases.OrderBy(testCase => testCase.TestMethod.Method.Name); + IReadOnlyCollection ITestCaseOrderer.OrderTestCases( + IReadOnlyCollection testCases) + { + return testCases.OrderBy(tc => ExtractTestName(tc)).ToList().AsReadOnly(); + } + + private static string ExtractTestName(ITestCase testCase) + { + var testMethod = testCase?.TestMethod; + if (testMethod is ITestMethodMetadata testMethodMetadata) + { + return testMethodMetadata.MethodName ?? string.Empty; + } + + return string.Empty; + } } } diff --git a/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/appsettings.Development.json b/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/appsettings.Development.json index c9ca394..2e59260 100644 --- a/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/appsettings.Development.json +++ b/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/appsettings.Development.json @@ -1,6 +1,6 @@ { "Serilog": { - "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Sinks.XUnit", "Serilog.Sinks.Async" ], + "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Sinks.XUnit3", "Serilog.Sinks.Async" ], "MinimumLevel": { "Default": "Debug" }, diff --git a/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/appsettings.Release.json b/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/appsettings.Release.json index 8cc7978..d9ced05 100644 --- a/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/appsettings.Release.json +++ b/Source/Energy/CDR.DataHolder.Energy.Tests.IntegrationTests/appsettings.Release.json @@ -1,6 +1,6 @@ { "Serilog": { - "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Sinks.XUnit", "Serilog.Sinks.Async" ], + "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Sinks.XUnit3", "Serilog.Sinks.Async" ], "MinimumLevel": { "Default": "Information" }, diff --git a/Source/Shared/CDR.DataHolder.Admin.API/CDR.DataHolder.Admin.API.csproj b/Source/Shared/CDR.DataHolder.Admin.API/CDR.DataHolder.Admin.API.csproj index 5b405a8..13c8f72 100644 --- a/Source/Shared/CDR.DataHolder.Admin.API/CDR.DataHolder.Admin.API.csproj +++ b/Source/Shared/CDR.DataHolder.Admin.API/CDR.DataHolder.Admin.API.csproj @@ -17,7 +17,6 @@ - diff --git a/Source/Shared/CDR.DataHolder.Admin.API/Controllers/AdminController.cs b/Source/Shared/CDR.DataHolder.Admin.API/Controllers/AdminController.cs index d69b760..13e6502 100644 --- a/Source/Shared/CDR.DataHolder.Admin.API/Controllers/AdminController.cs +++ b/Source/Shared/CDR.DataHolder.Admin.API/Controllers/AdminController.cs @@ -1,4 +1,5 @@ -using CDR.DataHolder.Admin.API.Models; +using Asp.Versioning; +using CDR.DataHolder.Admin.API.Models; using CDR.DataHolder.Shared.API.Infrastructure; using CDR.DataHolder.Shared.API.Infrastructure.Extensions; using CDR.DataHolder.Shared.API.Infrastructure.Filters; @@ -31,29 +32,11 @@ public AdminController( _configuration = configuration; } - [HttpGet("v1/admin/metrics")] - [ApiVersion("4")] - [HttpGet] - [ServiceFilter(typeof(LogActionEntryAttribute))] - public async Task GetMetricsV4() - { - var authorizationResult = await Authorize(); - if (!authorizationResult.IsAuthorized) - { - return authorizationResult.SendError(Response); - } - - // Read in the v4 data from the json file. - var jsonFileContents = await GetFileContents(_configuration.GetValue("Data:MetricsV4FileLocation") ?? string.Empty); - Response.Headers[Constants.CustomHeaders.ApiVersionHeaderKey] = "4"; - return Content(ReplacePlaceholders(jsonFileContents), "application/json"); - } - [HttpGet("v1/admin/metrics")] [ApiVersion("5")] [HttpGet] [ServiceFilter(typeof(LogActionEntryAttribute))] - public async Task GetMetricsV5() + public async Task GetMetrics() { var authorizationResult = await Authorize(); if (!authorizationResult.IsAuthorized) diff --git a/Source/Shared/CDR.DataHolder.Admin.API/Startup.cs b/Source/Shared/CDR.DataHolder.Admin.API/Startup.cs index 6391156..f633517 100644 --- a/Source/Shared/CDR.DataHolder.Admin.API/Startup.cs +++ b/Source/Shared/CDR.DataHolder.Admin.API/Startup.cs @@ -3,14 +3,10 @@ using CDR.DataHolder.Shared.API.Infrastructure.Versioning; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Serilog; -using System; -using System.Collections.Generic; -using System.Linq; namespace CDR.DataHolder.Admin.API { @@ -28,24 +24,7 @@ public void ConfigureServices(IServiceCollection services) { services.AddControllers(); - var getMetricsSupportVersion = Configuration.GetValue("GetMetricsSupportedVersions", "4,5") ?? string.Empty; - var overrideMetricsVersions = new Dictionary - { - { - @"\/cds-au\/v1\/admin\/metrics", - getMetricsSupportVersion - .Split(',') - .Select(x => Convert.ToInt32(x)) - .ToArray() - }, - }; - - services.AddApiVersioning(options => - { - options.DefaultApiVersion = new ApiVersion(4, 0); - options.AssumeDefaultVersionWhenUnspecified = true; - options.ApiVersionSelector = new ApiVersionSelector(options, overrideMetricsVersions); - }); + services.AddCdrApiVersioning(); services.AddScoped(); } diff --git a/Source/Shared/CDR.DataHolder.Admin.API/appsettings.json b/Source/Shared/CDR.DataHolder.Admin.API/appsettings.json index 1a74e68..b4b0c72 100644 --- a/Source/Shared/CDR.DataHolder.Admin.API/appsettings.json +++ b/Source/Shared/CDR.DataHolder.Admin.API/appsettings.json @@ -16,9 +16,7 @@ "Password": "" }, "Data": { - "MetricsV4FileLocation": "Data/metrics-v4.json", "MetricsV5FileLocation": "Data/metrics-v5.json" }, - "GetMetricsSupportedVersions": "4,5", "EnableServerCertificateValidation": false } \ No newline at end of file diff --git a/Source/Shared/CDR.DataHolder.Manage.API/CDR.DataHolder.Manage.API.csproj b/Source/Shared/CDR.DataHolder.Manage.API/CDR.DataHolder.Manage.API.csproj index 05d35b0..9f300f9 100644 --- a/Source/Shared/CDR.DataHolder.Manage.API/CDR.DataHolder.Manage.API.csproj +++ b/Source/Shared/CDR.DataHolder.Manage.API/CDR.DataHolder.Manage.API.csproj @@ -15,7 +15,6 @@ - all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Source/Shared/CDR.DataHolder.Manage.API/Infrastructure/ServiceCollectionExtension.cs b/Source/Shared/CDR.DataHolder.Manage.API/Infrastructure/ServiceCollectionExtension.cs index 179f396..e14d975 100644 --- a/Source/Shared/CDR.DataHolder.Manage.API/Infrastructure/ServiceCollectionExtension.cs +++ b/Source/Shared/CDR.DataHolder.Manage.API/Infrastructure/ServiceCollectionExtension.cs @@ -1,5 +1,4 @@ -using System.Configuration; -using CDR.DataHolder.Banking.Repository.Infrastructure; +using CDR.DataHolder.Banking.Repository.Infrastructure; using CDR.DataHolder.Energy.Repository.Infrastructure; using CDR.DataHolder.Shared.Domain.Extensions; using CDR.DataHolder.Shared.Repository; @@ -20,14 +19,14 @@ public static void AddIndustryDBContext(this IServiceCollection services, IConfi { services.AddScoped(); services.AddDbContext(options => options.UseSqlServer(configuration.GetConnectionString(DbConstants.ConnectionStringNames.Resource.Default))); - services.AddAutoMapper(typeof(Startup), typeof(BankingDataHolderDatabaseContext)); + services.AddAutoMapper(cfg => { }, typeof(Startup).Assembly, typeof(BankingDataHolderDatabaseContext).Assembly); } if (industry.IsEnergy()) { services.AddDbContext(options => options.UseSqlServer(configuration.GetConnectionString(DbConstants.ConnectionStringNames.Resource.Default))); services.AddScoped(); - services.AddAutoMapper(typeof(Startup), typeof(EnergyDataHolderDatabaseContext)); + services.AddAutoMapper(cfg => { }, typeof(Startup).Assembly, typeof(EnergyDataHolderDatabaseContext).Assembly); } } } diff --git a/Source/Shared/CDR.DataHolder.Manage.API/Startup.cs b/Source/Shared/CDR.DataHolder.Manage.API/Startup.cs index 211d1dc..602f091 100644 --- a/Source/Shared/CDR.DataHolder.Manage.API/Startup.cs +++ b/Source/Shared/CDR.DataHolder.Manage.API/Startup.cs @@ -89,7 +89,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger< }); // Ensure the database exists and is up to the latest version. - EnsureDatabase(app, logger, healthStatuses, webHostEnvironment).Wait(); + EnsureDatabase(app, logger, healthStatuses, webHostEnvironment).Wait(applicationLifetime.ApplicationStopping); } private async Task EnsureDatabase(IApplicationBuilder app, ILogger logger, HealthCheckStatuses healthCheckStatuses, IWebHostEnvironment webHostEnvironment) @@ -104,7 +104,14 @@ private async Task EnsureDatabase(IApplicationBuilder app, ILogger logg IIndustryDbContext industryMigrationDbContext = dbContextFactory.Create(_industry, DbConstants.ConnectionStringType.Migrations); logger.LogInformation("Running migrations"); var dbContext = industryMigrationDbContext as DbContext; - await dbContext!.Database.MigrateAsync().ConfigureAwait(false); + if (dbContext != null) + { + await dbContext.Database.MigrateAsync().ConfigureAwait(false); + } + else + { + logger.LogError("dbContext is null. Database connectivity could not be established"); + } } // Configure logger with the DB @@ -153,7 +160,7 @@ private static Task CustomResponseWriter(HttpContext context, HealthReport healt description = e.Value.Description, }), }); - return context.Response.WriteAsync(result); + return context.Response.WriteAsync(result, context.RequestAborted); } } } diff --git a/Source/Shared/CDR.DataHolder.Public.API/CDR.DataHolder.Public.API.csproj b/Source/Shared/CDR.DataHolder.Public.API/CDR.DataHolder.Public.API.csproj index b8f0011..1e0bc8d 100644 --- a/Source/Shared/CDR.DataHolder.Public.API/CDR.DataHolder.Public.API.csproj +++ b/Source/Shared/CDR.DataHolder.Public.API/CDR.DataHolder.Public.API.csproj @@ -1,6 +1,6 @@  - net8.0 + $(TargetFrameworkVersion) win-x64;linux-x64 $(TargetFrameworkVersion) $(Version) @@ -18,7 +18,6 @@ - diff --git a/Source/Shared/CDR.DataHolder.Public.API/Controllers/DiscoveryController.cs b/Source/Shared/CDR.DataHolder.Public.API/Controllers/DiscoveryController.cs index 8319bc7..e7f66db 100644 --- a/Source/Shared/CDR.DataHolder.Public.API/Controllers/DiscoveryController.cs +++ b/Source/Shared/CDR.DataHolder.Public.API/Controllers/DiscoveryController.cs @@ -1,5 +1,5 @@ -using CDR.DataHolder.Shared.API.Infrastructure.Filters; -using CDR.DataHolder.Shared.Resource.API.Infrastructure.Filters; +using Asp.Versioning; +using CDR.DataHolder.Shared.API.Infrastructure.Filters; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using System.Threading.Tasks; @@ -19,7 +19,7 @@ public DiscoveryController( } [HttpGet("v1/discovery/status")] - [CheckXV(1, 1)] + [SetVersionResponse(1)] [ApiVersion("1")] [ServiceFilter(typeof(LogActionEntryAttribute))] public async Task GetStatus() @@ -29,7 +29,7 @@ public async Task GetStatus() } [HttpGet("v1/discovery/outages")] - [CheckXV(1, 1)] + [SetVersionResponse(1)] [ApiVersion("1")] [ServiceFilter(typeof(LogActionEntryAttribute))] public async Task GetOutages() diff --git a/Source/Shared/CDR.DataHolder.Public.API/Startup.cs b/Source/Shared/CDR.DataHolder.Public.API/Startup.cs index 352926a..4567cee 100644 --- a/Source/Shared/CDR.DataHolder.Public.API/Startup.cs +++ b/Source/Shared/CDR.DataHolder.Public.API/Startup.cs @@ -1,10 +1,8 @@ -using System; -using CDR.DataHolder.Shared.API.Infrastructure.Filters; -using CDR.DataHolder.Shared.API.Infrastructure.Models; +using CDR.DataHolder.Shared.API.Infrastructure.Filters; +using CDR.DataHolder.Shared.API.Infrastructure.Middleware; +using CDR.DataHolder.Shared.API.Infrastructure.Versioning; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Versioning; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -26,13 +24,7 @@ public void ConfigureServices(IServiceCollection services) { services.AddControllers(); - services.AddApiVersioning(options => - { - options.DefaultApiVersion = new ApiVersion(1, 0); - options.AssumeDefaultVersionWhenUnspecified = false; - options.ApiVersionReader = new HeaderApiVersionReader("x-v"); - options.ErrorResponses = new ErrorResponseVersion(); - }); + services.AddCdrApiVersioning(); services.AddScoped(); } @@ -47,6 +39,11 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseSerilogRequestLogging(); + app.UseExceptionHandler(exceptionHandlerApp => + { + exceptionHandlerApp.Run(async context => await ApiExceptionHandler.Handle(context)); + }); + app.UseHttpsRedirection(); app.UseRouting(); diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Gateway.mTLS/Certificates/CertificateValidator.cs b/Source/Shared/CDR.DataHolder.Shared.API.Gateway.mTLS/Certificates/CertificateValidator.cs index 0be2412..aaf486d 100644 --- a/Source/Shared/CDR.DataHolder.Shared.API.Gateway.mTLS/Certificates/CertificateValidator.cs +++ b/Source/Shared/CDR.DataHolder.Shared.API.Gateway.mTLS/Certificates/CertificateValidator.cs @@ -31,7 +31,7 @@ public void ValidateClientCertificate(X509Certificate2 clientCert) } // Validate that the certificate has been issued by the Mock CDR CA. - var rootCACertificate = new X509Certificate2(_config.GetValue("RootCACertificate:Path") ?? string.Empty); + var rootCACertificate = X509CertificateLoader.LoadCertificateFromFile(_config.GetValue("RootCACertificate:Path") ?? string.Empty); var ch = new X509Chain(); ch.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; ch.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag; diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure.UnitTests/CDR.DataHolder.Shared.API.Infrastructure.UnitTests.csproj b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure.UnitTests/CDR.DataHolder.Shared.API.Infrastructure.UnitTests.csproj index 4f89ae2..c75de2d 100644 --- a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure.UnitTests/CDR.DataHolder.Shared.API.Infrastructure.UnitTests.csproj +++ b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure.UnitTests/CDR.DataHolder.Shared.API.Infrastructure.UnitTests.csproj @@ -26,7 +26,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure.UnitTests/Extensions/HttpClientHandlerExtensionsTests.cs b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure.UnitTests/Extensions/HttpClientHandlerExtensionsTests.cs index 3b7bd08..2166d80 100644 --- a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure.UnitTests/Extensions/HttpClientHandlerExtensionsTests.cs +++ b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure.UnitTests/Extensions/HttpClientHandlerExtensionsTests.cs @@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Serilog; using Xunit; @@ -52,12 +53,12 @@ public async Task ServerCertificates_ValidationEnabled_ShouldValidateSslConnecti var client = new HttpClient(_handler); if (expected) { - var result = await client.GetAsync("https://localhost:9990"); + var result = await client.GetAsync("https://localhost:9990", TestContext.Current.CancellationToken); Assert.NotNull(result); } else { - await Assert.ThrowsAsync(async () => await client.GetAsync("https://localhost:9990")); + await Assert.ThrowsAsync(async () => await client.GetAsync("https://localhost:9990", TestContext.Current.CancellationToken)); } await mockEndpoint.Stop(); @@ -85,22 +86,26 @@ public MockEndpoint(string url, string certificatePath, string certificatePasswo public string CertificatePassword { get; init; } - private IWebHost? _host; + private IHost? _host; public void Start() { Log.Information("Calling {FUNCTION} in {ClassName}.", nameof(Start), nameof(MockEndpoint)); - _host = new WebHostBuilder() - .UseKestrel(opts => + var builder = Host.CreateDefaultBuilder() + .ConfigureWebHostDefaults(webBuilder => { - opts.ListenAnyIP( - UrlPort, - opts => opts.UseHttps(new X509Certificate2(CertificatePath, CertificatePassword, X509KeyStorageFlags.Exportable))); - }) - .UseStartup(_ => new MockEndpointStartup()) - .Build(); - + webBuilder.UseKestrel(opts => + { + opts.ListenAnyIP( + UrlPort, + opts => opts.UseHttps(X509CertificateLoader.LoadPkcs12FromFile(CertificatePath, CertificatePassword, X509KeyStorageFlags.Exportable))); + }) + .ConfigureServices(services => MockEndpointStartup.ConfigureServices(services)) + .Configure(app => MockEndpointStartup.Configure(app)); + }); + + _host = builder.Build(); _host.RunAsync(); } @@ -129,9 +134,9 @@ public async ValueTask DisposeAsync() GC.SuppressFinalize(this); } - private class MockEndpointStartup + private static class MockEndpointStartup { - public void Configure(IApplicationBuilder app) + public static void Configure(IApplicationBuilder app) { app.UseHttpsRedirection(); app.UseRouting(); diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Authorisation/PolicyAuthorizeAttribute.cs b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Authorisation/PolicyAuthorizeAttribute.cs index 244635d..664f2fc 100644 --- a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Authorisation/PolicyAuthorizeAttribute.cs +++ b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Authorisation/PolicyAuthorizeAttribute.cs @@ -45,7 +45,7 @@ public async Task OnAuthorizationAsync(AuthorizationFilterContext context) return; } - if (authorizationResult.Failure!.FailedRequirements.Any(r => r.GetType() == typeof(MtlsRequirement))) + if (authorizationResult.Failure.FailedRequirements.Any(r => r.GetType() == typeof(MtlsRequirement))) { context.Result = new DataHolderUnauthorizedResult(new ResponseErrorList(StatusCodes.Status401Unauthorized.ToString(), HttpStatusCode.Unauthorized.ToString(), "invalid_token")); return; diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/CDR.DataHolder.Shared.API.Infrastructure.csproj b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/CDR.DataHolder.Shared.API.Infrastructure.csproj index f9447c3..46a010a 100644 --- a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/CDR.DataHolder.Shared.API.Infrastructure.csproj +++ b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/CDR.DataHolder.Shared.API.Infrastructure.csproj @@ -8,14 +8,15 @@ True + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Constants.cs b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Constants.cs index 6eee729..168faba 100644 --- a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Constants.cs +++ b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Constants.cs @@ -97,5 +97,10 @@ public static class ConfigurationKeys { public const string IsServerCertificateValidationEnabled = "EnableServerCertificateValidation"; } + + public static class Versioning + { + public const string GroupNameFormat = "'v'VVV"; + } } } diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Extensions/CdrSwaggerMiddlewareExtensions.cs b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Extensions/CdrSwaggerMiddlewareExtensions.cs new file mode 100644 index 0000000..84f75ad --- /dev/null +++ b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Extensions/CdrSwaggerMiddlewareExtensions.cs @@ -0,0 +1,54 @@ +using System.Linq; +using Asp.Versioning.ApiExplorer; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; + +namespace CDR.DataHolder.Shared.API.Infrastructure.Extensions +{ + public static class CdrSwaggerMiddlewareExtensions + { + public static IApplicationBuilder UseCdrSwagger(this IApplicationBuilder builder, IApiVersionDescriptionProvider? provider = null) + { + if (provider == null) + { + provider = builder.ApplicationServices.GetRequiredService(); + } + + builder.UseSwagger(); + + builder.UseSwaggerUI( + options => + { + // Configure swagger Ui for multiple versions of the API + string swaggerJsonBasePath = string.IsNullOrWhiteSpace(options.RoutePrefix) ? "." : ".."; + + foreach (var groupName in provider.ApiVersionDescriptions.Select(d => d.GroupName)) + { + options.SwaggerEndpoint( + $"{swaggerJsonBasePath}/swagger/{groupName}/swagger.json", + groupName.ToUpperInvariant()); + } + }); + + return builder; + } + + public static IApplicationBuilder UseCdrSwagger(this IApplicationBuilder builder, string name) + { + builder.UseSwagger(); + + builder.UseSwaggerUI( + options => + { + // Configure swagger Ui for multiple versions of the API + string swaggerJsonBasePath = string.IsNullOrWhiteSpace(options.RoutePrefix) ? "." : ".."; + + options.SwaggerEndpoint( + $"{swaggerJsonBasePath}/swagger/v1/swagger.json", + name); + }); + + return builder; + } + } +} diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Extensions/ConfigExtensions.cs b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Extensions/ConfigExtensions.cs index e72b7e0..f289950 100644 --- a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Extensions/ConfigExtensions.cs +++ b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Extensions/ConfigExtensions.cs @@ -32,7 +32,7 @@ public static class ConfigExtensions return null; } - var cert = new X509Certificate2(DownloadData(certUrl), certPassword, X509KeyStorageFlags.Exportable); + var cert = X509CertificateLoader.LoadPkcs12(DownloadData(certUrl), certPassword, X509KeyStorageFlags.Exportable); logger.Information("Downloaded certificate: {Thumbprint}", cert.Thumbprint); return cert; } diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Extensions/HttpContextExtensions.cs b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Extensions/HttpContextExtensions.cs index d6554b1..4713376 100644 --- a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Extensions/HttpContextExtensions.cs +++ b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Extensions/HttpContextExtensions.cs @@ -30,7 +30,7 @@ public static class HttpContextExtensions return string.Empty; } - var pathValues = httpContext.Request.Path!.Value.Split('/'); + var pathValues = httpContext.Request.Path.Value.Split('/'); return pathValues[pathValues.Length - 1]; } diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Extensions/NameValueCollectionExtensions.cs b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Extensions/NameValueCollectionExtensions.cs index d34eb92..f80a7b9 100644 --- a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Extensions/NameValueCollectionExtensions.cs +++ b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Extensions/NameValueCollectionExtensions.cs @@ -9,7 +9,7 @@ namespace CDR.DataHolder.Shared.API.Infrastructure.Extensions { public static class NameValueCollectionExtensions { - public static string ToQueryString(this NameValueCollection collection) + public static string ToQueryString(this NameValueCollection collection, bool urlEncode) { if (collection.Count == 0) { @@ -23,13 +23,13 @@ public static string ToQueryString(this NameValueCollection collection) var values = collection.GetValues(name); if (values == null || values.Length == 0) { - first = AppendNameValuePair(builder, first, true, name, string.Empty); + first = AppendNameValuePair(builder, first, urlEncode, name, string.Empty); } else { foreach (var value in values) { - first = AppendNameValuePair(builder, first, true, name, value); + first = AppendNameValuePair(builder, first, urlEncode, name, value); } } } diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Filters/CheckXVAttribute.cs b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Filters/CheckXVAttribute.cs deleted file mode 100644 index b062b13..0000000 --- a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Filters/CheckXVAttribute.cs +++ /dev/null @@ -1,62 +0,0 @@ -using CDR.DataHolder.Shared.Domain.Models; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Filters; -using System; -using System.Net; - -namespace CDR.DataHolder.Shared.Resource.API.Infrastructure.Filters -{ - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)] - public class CheckXVAttribute : ActionFilterAttribute - { - private readonly int _minVersion; - private readonly int _maxVersion; - - public CheckXVAttribute(int minVersion, int maxVersion) - { - _minVersion = minVersion; - _maxVersion = maxVersion; - } - - public override void OnActionExecuting(ActionExecutingContext context) - { - // Get x-v from request header - var versionHeaderValue = context.HttpContext.Request.Headers["x-v"]; - - if (string.IsNullOrEmpty(versionHeaderValue)) - { - context.Result = new BadRequestObjectResult(new ResponseErrorList().AddMissingRequiredHeader("x-v")); - } - else - { - // If the x-v is set, check that it is a postive integer. - if (int.TryParse(versionHeaderValue, out int version) && version > 0) - { - if (version < _minVersion) - { - // return a 406 Not Accepted as the version is not supported. - context.Result = new ObjectResult(new ResponseErrorList().AddInvalidXVUnsupportedVersion()) - { - StatusCode = (int)HttpStatusCode.NotAcceptable, - }; - } - } - else - { - // Return a 400 bad request. - context.Result = new BadRequestObjectResult(new ResponseErrorList().AddInvalidXVInvalidVersion()); - } - } - - base.OnActionExecuting(context); - } - - public override void OnActionExecuted(ActionExecutedContext context) - { - // Set version (x-v) we are responding with in the response header - context.HttpContext.Response.Headers["x-v"] = _maxVersion.ToString(); - - base.OnActionExecuted(context); - } - } -} diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Filters/SetVersionResponseAttribute.cs b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Filters/SetVersionResponseAttribute.cs new file mode 100644 index 0000000..65c4df5 --- /dev/null +++ b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Filters/SetVersionResponseAttribute.cs @@ -0,0 +1,24 @@ +using System; +using Microsoft.AspNetCore.Mvc.Filters; + +namespace CDR.DataHolder.Shared.API.Infrastructure.Filters +{ + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)] + public class SetVersionResponseAttribute : ActionFilterAttribute + { + private readonly int _version; + + public SetVersionResponseAttribute(int version) + { + _version = version; + } + + public override void OnActionExecuted(ActionExecutedContext context) + { + // Set version (x-v) we are responding with in the response header + context.HttpContext.Response.Headers["x-v"] = _version.ToString(); + + base.OnActionExecuted(context); + } + } +} diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/IdPermanence/IdPermanenceHelper.cs b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/IdPermanence/IdPermanenceHelper.cs index cf24ce3..ef617bc 100644 --- a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/IdPermanence/IdPermanenceHelper.cs +++ b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/IdPermanence/IdPermanenceHelper.cs @@ -210,7 +210,7 @@ public static string GetPrivateKey(IConfiguration config) throw new ConfigurationErrorsException($"The private key was not found in configuration. Either set the \"IdPermanence:PrivateKey\" configuration item or the \"IdPermanence:Certificate:Path\" and \"IdPermanence:Certificate:Password\" configuration items to load the private key."); } - var cert = new X509Certificate2(path, pwd, X509KeyStorageFlags.Exportable); + var cert = X509CertificateLoader.LoadPkcs12FromFile(path, pwd, X509KeyStorageFlags.Exportable); return new string(cert.GetRSAPrivateKey()?.ExportPkcs8PrivateKey().Select(b => Convert.ToChar(b)).ToArray()); } } diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Middleware/ApiExceptionHandler.cs b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Middleware/ApiExceptionHandler.cs index a6ec957..4f09e77 100644 --- a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Middleware/ApiExceptionHandler.cs +++ b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Middleware/ApiExceptionHandler.cs @@ -43,7 +43,7 @@ public static async Task Handle(HttpContext context) { context.Response.StatusCode = statusCode; context.Response.ContentType = "application/json"; - await context.Response.WriteAsync(handledError).ConfigureAwait(false); + await context.Response.WriteAsync(handledError, context.RequestAborted).ConfigureAwait(false); } } } diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Middleware/InteractionIdMiddleware.cs b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Middleware/InteractionIdMiddleware.cs index 1d4101a..51193e1 100644 --- a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Middleware/InteractionIdMiddleware.cs +++ b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Middleware/InteractionIdMiddleware.cs @@ -17,10 +17,10 @@ public InteractionIdMiddleware(RequestDelegate next) public Task Invoke(HttpContext context) { - string interactionId = Guid.NewGuid().ToString(); + string? interactionId = Guid.NewGuid().ToString(); if (context.Request.Headers.TryGetValue(HEADER_NAME, out StringValues existingInteractionId)) { - interactionId = existingInteractionId!; + interactionId = existingInteractionId; } // Apply the interaction ID to the response header for client side tracking diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Models/CdrApiEndpointVersionOptions.cs b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Models/CdrApiEndpointVersionOptions.cs new file mode 100644 index 0000000..65306e2 --- /dev/null +++ b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Models/CdrApiEndpointVersionOptions.cs @@ -0,0 +1,52 @@ +namespace CDR.DataHolder.Shared.API.Infrastructure.Models +{ + public class CdrApiEndpointVersionOptions + { + /// + /// Initializes a new instance of the class. + /// Constructs an option set where multiple versions of the endpoint are supported. + /// + public CdrApiEndpointVersionOptions(string path, bool isXvMandatory, int minVersion, int maxVersion) + { + this.Path = path; + this.IsVersioned = true; + this.IsXVHeaderMandatory = isXvMandatory; + this.CurrentMinVersion = minVersion; + this.CurrentMaxVersion = maxVersion; + } + + /// + /// Initializes a new instance of the class. + /// Constructs an option set where only one version of the endpoint is supported. + /// + public CdrApiEndpointVersionOptions(string path, bool isXvMandatory, int version) + { + this.Path = path; + this.IsVersioned = true; + this.IsXVHeaderMandatory = isXvMandatory; + this.CurrentMinVersion = version; + this.CurrentMaxVersion = version; + } + + /// + /// Initializes a new instance of the class. + /// Constructs an option set where the endpoint is unversioned. + /// + public CdrApiEndpointVersionOptions(string path) + { + this.Path = path; + this.IsVersioned = false; + this.IsXVHeaderMandatory = false; + } + + public string Path { get; } + + public bool IsVersioned { get; } + + public bool IsXVHeaderMandatory { get; } + + public int? CurrentMinVersion { get; } + + public int? CurrentMaxVersion { get; } + } +} diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Models/CdrApiOptions.cs b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Models/CdrApiOptions.cs new file mode 100644 index 0000000..f43250b --- /dev/null +++ b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Models/CdrApiOptions.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Http; + +namespace CDR.DataHolder.Shared.API.Infrastructure.Models +{ + public class CdrApiOptions + { + private const string Id = @"[^\/]+"; // any value other than a / + private const string BasePathAdmin = @"\/cds-au\/v1\/admin"; + private const string BasePathCommon = @"\/cds-au\/v1\/common"; + private const string BasePathEnergy = @"\/cds-au\/v1\/energy"; + private const string BasePathBanking = @"\/cds-au\/v1\/banking"; + + private static readonly CdrApiEndpointVersionOptions[] _supportedApiVersionsAdmin = + [ + new CdrApiEndpointVersionOptions(@$"{BasePathAdmin}\/metrics", true, 5), + ]; + + private static readonly CdrApiEndpointVersionOptions[] _supportedApiVersionsCommon = + [ + new CdrApiEndpointVersionOptions(@$"{BasePathCommon}\/customer", true, 1), + ]; + + private static readonly CdrApiEndpointVersionOptions[] _supportedApiVersionsBanking = + [ + new CdrApiEndpointVersionOptions(@$"{BasePathBanking}\/accounts", true, 2), + new CdrApiEndpointVersionOptions(@$"{BasePathBanking}\/accounts\/{Id}\/transactions", true, 1), + ]; + + private static readonly CdrApiEndpointVersionOptions[] _supportedApiVersionsEnergy = + [ + new CdrApiEndpointVersionOptions(@$"{BasePathEnergy}\/accounts", true, 2), + new CdrApiEndpointVersionOptions(@$"{BasePathEnergy}\/accounts\/{Id}\/concessions", true, 1), + ]; + + public List EndpointVersionOptions { get; } = + [ + .. _supportedApiVersionsAdmin, + .. _supportedApiVersionsCommon, + .. _supportedApiVersionsBanking, + .. _supportedApiVersionsEnergy + ]; + + public string DefaultVersion { get; set; } = "1"; + + public CdrApiEndpointVersionOptions? GetApiEndpointVersionOption(PathString path) + { + foreach (var supportedApi in this.EndpointVersionOptions.OrderByDescending(v => v.Path.Length)) + { + var regEx = new System.Text.RegularExpressions.Regex(supportedApi.Path, System.Text.RegularExpressions.RegexOptions.IgnoreCase, TimeSpan.FromSeconds(2)); + if (regEx.IsMatch(path)) + { + return supportedApi; + } + } + + return null; + } + } +} diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Models/ErrorResponseVersion.cs b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Models/ErrorResponseVersion.cs deleted file mode 100644 index 534627a..0000000 --- a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Models/ErrorResponseVersion.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System.Net; -using CDR.DataHolder.Shared.Domain.Models; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Versioning; - -namespace CDR.DataHolder.Shared.API.Infrastructure.Models -{ - public class ErrorResponseVersion : DefaultErrorResponseProvider - { - public override IActionResult CreateResponse(ErrorResponseContext context) - { - // The version was not specified. - if (context.ErrorCode == "ApiVersionUnspecified") - { - return new ObjectResult(new ResponseErrorList().AddMissingRequiredHeader("x-v")) // Note: This isn't consistent with the new PT behaviour (or RAAP) - { - StatusCode = (int)HttpStatusCode.BadRequest, - }; - } - - // Get x-v from request header - var versionHeaderValue = context.Request.Headers["x-v"]; - var invalid_XV_Version = true; - - // If the x-v is set, check that it is a postive integer. - if (int.TryParse(versionHeaderValue, out int version)) - { - invalid_XV_Version = version < 1; - } - - if (invalid_XV_Version) - { - return new ObjectResult(new ResponseErrorList().AddInvalidXVInvalidVersion()) - { - StatusCode = (int)HttpStatusCode.BadRequest, - }; - } - - if (context.ErrorCode == "InvalidApiVersion") - { - return new ObjectResult(new ResponseErrorList().AddInvalidXVInvalidVersion()) - { - StatusCode = (int)HttpStatusCode.BadRequest, - }; - } - - if (context.ErrorCode == "UnsupportedApiVersion") - { - return new ObjectResult(new ResponseErrorList().AddInvalidXVUnsupportedVersion()) - { - StatusCode = (int)HttpStatusCode.NotAcceptable, - }; - } - - return base.CreateResponse(context); - } - } -} diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Versioning/ApiVersionSelector.cs b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Versioning/ApiVersionSelector.cs deleted file mode 100644 index 048cfdb..0000000 --- a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Versioning/ApiVersionSelector.cs +++ /dev/null @@ -1,133 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Versioning; -using System; -using System.Collections.Generic; -using System.Linq; -using static CDR.DataHolder.Shared.API.Infrastructure.Constants; - -namespace CDR.DataHolder.Shared.API.Infrastructure.Versioning -{ - public class ApiVersionSelector : IApiVersionSelector - { - private readonly ApiVersion _defaultVersion; - private readonly Dictionary _supportedApiVersions = new Dictionary() - { - { @"\/cds-au\/v1\/admin\/metrics", new int[] { 4, 5 } }, - { @"\/cds-au\/v1\/common\/customer", new int[] { 1 } }, - { @"\/cds-au\/v1\/energy\/accounts", new int[] { 1, 2 } }, - { @"\/cds-au\/v1\/energy\/accounts\/[A-Za-z0-9\-]*\/concessions", new int[] { 1 } }, - }; - - public ApiVersionSelector(ApiVersioningOptions options, Dictionary? overrideDefaultVersions = null) - { - _defaultVersion = options.DefaultApiVersion; - - if (overrideDefaultVersions != null) - { - foreach (var kvp in overrideDefaultVersions) - { - if (_supportedApiVersions.ContainsKey(kvp.Key)) - { - // Update the value in _supportedApiVersions with the value from overrideDefaultVersions - _supportedApiVersions[kvp.Key] = kvp.Value; - } - else - { - // If the key doesn't exist in overrideDefaultVersions, add it with the value from overrideDefaultVersions - _supportedApiVersions.Add(kvp.Key, kvp.Value); - } - } - } - } - - public ApiVersion SelectVersion(HttpRequest request, ApiVersionModel model) - { - // Try and get x-v value from request header - if (!request.Headers.TryGetValue(CustomHeaders.ApiVersionHeaderKey, out var x_v)) - { - // Raise an error - throw new MissingRequiredHeaderException(CustomHeaders.ApiVersionHeaderKey); - } - - // x-v must be a positive integer. - if (!int.TryParse(x_v, out int xvVersion) || xvVersion < 1) - { - // Raise an error. - throw new InvalidVersionException(CustomHeaders.ApiVersionHeaderKey); - } - - // If requested version is 1, then just return. - if (xvVersion == 1) - { - return _defaultVersion; - } - - // Check if the requested version is supported by the API. - var apiVersions = GetApiVersions(request.Path); - - // Matching api was not found. - if (!apiVersions.Any()) - { - return _defaultVersion; - } - - // Version match. - if (apiVersions.Contains(xvVersion)) - { - return new ApiVersion(xvVersion, 0); - } - - // No matching version, so check if a x-min-v header has been provided. - if (!request.Headers.ContainsKey(CustomHeaders.ApiMinVersionHeaderKey)) - { - // For not supported higher version of x-v; without x-min-v below exception is thrown - // x-min-v has not been provided, so throw an unsupported version error. - throw new UnsupportedVersionException(apiVersions.Min(), apiVersions.Max()); - } - - // Check if the x-min-v is a positive integer. - var x_min_v = request.Headers[CustomHeaders.ApiMinVersionHeaderKey]; - - // x-min-v must be a positive integer. - if (!int.TryParse(x_min_v, out int xvMinVersion) || xvMinVersion < 1) - { - // Raise an invalid error. - throw new InvalidVersionException(CustomHeaders.ApiMinVersionHeaderKey); - } - - // If x-min-v is greater than x-v then ignore it. - if (xvMinVersion > xvVersion) - { - xvMinVersion = xvVersion; - } - - // Find the largest supported version between x-min-v and x-v. - var supportedVersions = apiVersions - .Where(v => (v >= xvMinVersion && v <= xvVersion)); - - // No supported versions were found. - if (!supportedVersions.Any()) - { - throw new UnsupportedVersionException(apiVersions.Min(), apiVersions.Max()); - } - - // Return the highest support version. - return new ApiVersion(supportedVersions.OrderByDescending(v => v).Take(1).Single(), 0); - } - - private IEnumerable GetApiVersions(PathString path) - { - foreach (var supportedApi in _supportedApiVersions.OrderByDescending(v => v.Key.Length)) - { - var regEx = new System.Text.RegularExpressions.Regex(supportedApi.Key); - if (regEx.IsMatch(path)) - { - return supportedApi.Value; - } - } - - return Array.Empty(); - } - } -} diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Versioning/CdrApiVersioning.cs b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Versioning/CdrApiVersioning.cs new file mode 100644 index 0000000..6d1b1e4 --- /dev/null +++ b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Versioning/CdrApiVersioning.cs @@ -0,0 +1,34 @@ +using System; +using Asp.Versioning; +using Asp.Versioning.ApiExplorer; +using CDR.DataHolder.Shared.API.Infrastructure.Models; + +using Microsoft.Extensions.DependencyInjection; + +namespace CDR.DataHolder.Shared.API.Infrastructure.Versioning +{ + public static class CdrApiVersioning + { + /// + /// Add CDR-specific API versioning and API explorer. + /// + /// The services. + /// Additional setup actions to configure beyond the default settings. + /// Additional setup actions to configure beyond the default settings. + /// The versioning builder. + public static IApiVersioningBuilder AddCdrApiVersioning(this IServiceCollection services, Action? setupVersioningAction = null, Action? setupExplorerAction = null) + { + return services + .AddApiVersioning(options => + { + options.ApiVersionReader = new CdrVersionReader(new CdrApiOptions()); // uses default options atm + setupVersioningAction?.Invoke(options); + }) + .AddApiExplorer(options => + { + options.GroupNameFormat = Constants.Versioning.GroupNameFormat; + setupExplorerAction?.Invoke(options); + }); + } + } +} diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Versioning/CdrVersionReader.cs b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Versioning/CdrVersionReader.cs new file mode 100644 index 0000000..9af5c37 --- /dev/null +++ b/Source/Shared/CDR.DataHolder.Shared.API.Infrastructure/Versioning/CdrVersionReader.cs @@ -0,0 +1,97 @@ +using System.Collections.Generic; +using Asp.Versioning; +using CDR.DataHolder.Shared.API.Infrastructure.Models; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; +using static CDR.DataHolder.Shared.API.Infrastructure.Constants; + +namespace CDR.DataHolder.Shared.API.Infrastructure.Versioning +{ + /// + /// The purpose of the reader is to check what the client has put in and return what we want from that. We return an error string if it is no good and we are able to handle changing min version. + /// + public class CdrVersionReader : IApiVersionReader + { + private readonly CdrApiOptions _options; + + public CdrVersionReader(CdrApiOptions options) + { + this._options = options; + } + + public void AddParameters(IApiVersionParameterDescriptionContext context) + { + context.AddParameter(CustomHeaders.ApiVersionHeaderKey, ApiVersionParameterLocation.Header); + context.AddParameter(CustomHeaders.ApiMinVersionHeaderKey, ApiVersionParameterLocation.Header); + } + + public IReadOnlyList Read(HttpRequest request) + { + var endpointOption = this._options.GetApiEndpointVersionOption(request.Path); + + if (endpointOption == null) + { + // handle any endpoint that hasn't been defined in options + endpointOption = new CdrApiEndpointVersionOptions(string.Empty, false, int.Parse(this._options.DefaultVersion)); + } + else if (!endpointOption.IsVersioned) + { + return [this._options.DefaultVersion]; + } + + // If x-min-v is passed in, we expect it to be a Positive Integer, the x-v value is parsed out of the header and will be validated by the Package itself + // Refer to Standards here - https://consumerdatastandardsaustralia.github.io/standards/#http-headers + // When there is error in x-min-v, we return custom String x-min-v '' this is then manipulated in ApiVersionErrorResponse for a user friendly error message. + if (!request.Headers.TryGetValue(CustomHeaders.ApiVersionHeaderKey, out var xvValue) || string.IsNullOrWhiteSpace(xvValue)) + { + if (endpointOption.IsXVHeaderMandatory) + { + throw new MissingRequiredHeaderException(CustomHeaders.ApiVersionHeaderKey); + } + + xvValue = endpointOption.CurrentMinVersion.ToString(); + request.Headers.Remove(CustomHeaders.ApiVersionHeaderKey); // Added this to handle both the missing header (just add) and the header with a blank value (update) + request.Headers.Append(CustomHeaders.ApiVersionHeaderKey, xvValue); + } + + if (int.TryParse(xvValue, out int xvInt) && xvInt > 0) + { + request.Headers.TryGetValue(CustomHeaders.ApiMinVersionHeaderKey, out var xvMinValue); + + xvValue = CalculateVersion(xvInt, xvMinValue, endpointOption); + + return xvValue; + } + + throw new InvalidVersionException(CustomHeaders.ApiVersionHeaderKey); + } + + private static string? CalculateVersion(int xvInt, string? xvMinString, CdrApiEndpointVersionOptions endpointOption) + { + if (!string.IsNullOrEmpty(xvMinString)) + { + if (!int.TryParse(xvMinString, out int xvMinInt) || xvMinInt < 1) + { + throw new InvalidVersionException(CustomHeaders.ApiMinVersionHeaderKey); + } + + if (xvMinInt < xvInt) + { + if (xvMinInt > endpointOption.CurrentMaxVersion || xvInt < endpointOption.CurrentMinVersion) + { + throw new UnsupportedVersionException(); + } + + return xvInt > endpointOption.CurrentMaxVersion ? endpointOption.CurrentMaxVersion.ToString() : xvInt.ToString(); + } + } + + if (xvInt < endpointOption.CurrentMinVersion || xvInt > endpointOption.CurrentMaxVersion) + { + throw new UnsupportedVersionException(); + } + + return xvInt.ToString(); + } + } +} diff --git a/Source/Shared/CDR.DataHolder.Shared.API.Logger/RequestResponseLoggingMiddleware.cs b/Source/Shared/CDR.DataHolder.Shared.API.Logger/RequestResponseLoggingMiddleware.cs index f843b7b..15609e3 100644 --- a/Source/Shared/CDR.DataHolder.Shared.API.Logger/RequestResponseLoggingMiddleware.cs +++ b/Source/Shared/CDR.DataHolder.Shared.API.Logger/RequestResponseLoggingMiddleware.cs @@ -101,7 +101,7 @@ private async Task ExtractRequestProperties(HttpContext context) { context.Request.EnableBuffering(); await using var requestStream = _recyclableMemoryStreamManager.GetStream(); - await context.Request.Body.CopyToAsync(requestStream); + await context.Request.Body.CopyToAsync(requestStream, context.RequestAborted); _requestBody = ReadStreamInChunks(requestStream); context.Request.Body.Position = 0; @@ -292,7 +292,7 @@ private async Task ExtractResponseProperties(HttpContext httpContext) _elapsedTime = sw.ElapsedMilliseconds.ToString(); responseBody.Seek(0, SeekOrigin.Begin); - _responseBody = await new StreamReader(responseBody).ReadToEndAsync(); + _responseBody = await new StreamReader(responseBody).ReadToEndAsync(httpContext.RequestAborted); responseBody.Seek(0, SeekOrigin.Begin); IEnumerable keyValues = httpContext.Response.Headers.Keys.Select(key => key + ": " + string.Join(",", httpContext.Response.Headers[key].ToArray())); @@ -304,7 +304,7 @@ private async Task ExtractResponseProperties(HttpContext httpContext) // This is for middleware hooked before us to see our changes. // Otherwise the original stream would be seen which cannot be read again. - await responseBody.CopyToAsync(originalBodyStream); + await responseBody.CopyToAsync(originalBodyStream, httpContext.RequestAborted); } } diff --git a/Source/Shared/CDR.DataHolder.Shared.Business/Extensions.cs b/Source/Shared/CDR.DataHolder.Shared.Business/Extensions.cs index e3c5a35..d6a69bc 100644 --- a/Source/Shared/CDR.DataHolder.Shared.Business/Extensions.cs +++ b/Source/Shared/CDR.DataHolder.Shared.Business/Extensions.cs @@ -93,7 +93,7 @@ public static Uri GetPageUri(this ControllerBase controller, Uri selfLink, int? query.AddOrUpdate("page-size", pageSize.Value.ToString()); } - return new Uri(string.Format("{0}?{1}", selfLink.ToString().Split('?')[0], query.ToQueryString())); + return new Uri(string.Format("{0}?{1}", selfLink.ToString().Split('?')[0], query.ToQueryString(false))); } private static Uri ReplaceUriHost(string url, string? newHost = null) diff --git a/Source/Shared/CDR.DataHolder.Shared.Business/Middleware/ResourceAuthoriseErrorHandlingMiddleware.cs b/Source/Shared/CDR.DataHolder.Shared.Business/Middleware/ResourceAuthoriseErrorHandlingMiddleware.cs index 6ce0781..acc04c6 100644 --- a/Source/Shared/CDR.DataHolder.Shared.Business/Middleware/ResourceAuthoriseErrorHandlingMiddleware.cs +++ b/Source/Shared/CDR.DataHolder.Shared.Business/Middleware/ResourceAuthoriseErrorHandlingMiddleware.cs @@ -62,10 +62,10 @@ private static async Task SetUnauthorisedErrorResponseAsync(HttpContext httpCont var memoryStreamModified = new MemoryStream(); var sw = new StreamWriter(memoryStreamModified); await sw.WriteAsync(responseBody); - await sw.FlushAsync(); + await sw.FlushAsync(httpContext.RequestAborted); memoryStreamModified.Position = 0; - await memoryStreamModified.CopyToAsync(originBody).ConfigureAwait(false); + await memoryStreamModified.CopyToAsync(originBody, httpContext.RequestAborted).ConfigureAwait(false); } } } diff --git a/Source/Shared/CDR.DataHolder.Shared.Repository/Infrastructure/Extensions.cs b/Source/Shared/CDR.DataHolder.Shared.Repository/Infrastructure/Extensions.cs index d5c1f14..9d6610e 100644 --- a/Source/Shared/CDR.DataHolder.Shared.Repository/Infrastructure/Extensions.cs +++ b/Source/Shared/CDR.DataHolder.Shared.Repository/Infrastructure/Extensions.cs @@ -9,7 +9,7 @@ namespace CDR.DataHolder.Shared.Repository.Infrastructure { public static class Extensions { - private static readonly Regex DatetimeMatchRegex = new Regex("[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z", RegexOptions.Compiled); + private static readonly Regex DatetimeMatchRegex = new Regex("[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z", RegexOptions.Compiled, TimeSpan.FromSeconds(10)); /// /// This is the initial database seed. If there are records in the database, this will not re-seed the database. diff --git a/Source/supervisord.conf b/Source/supervisord.conf index e781c54..5ce7065 100644 --- a/Source/supervisord.conf +++ b/Source/supervisord.conf @@ -74,20 +74,12 @@ command=bash /app/wait-until-manage-healthy-then-start.sh /app/cdrauthserver/Cdr ;username=user ;password=123 -# Inject REACT_APP_* environment variables into env.js -[program:CdrAuthServer-UI-InjectReactEnvironment] -priority=1 -stdout_logfile=/dev/stdout -stdout_logfile_maxbytes=0 -directory=/usr/share/nginx/html/ui -command=npx --yes react-inject-env set -d /usr/share/nginx/html/ui - [program:CdrAuthServer-UI] priority=5 stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 directory=/usr/share/nginx/html/ui -command=nginx -g "daemon off;" +command=bash -c "react-inject-env set -d /usr/share/nginx/html/ui && exec nginx -g 'daemon off;'" autostart=true autorestart=true startretries=5 From a8b3123dd0580d1fb4373cf61bc424cdfbb9fe44 Mon Sep 17 00:00:00 2001 From: CDR-AidenJ Date: Thu, 15 Oct 2026 11:49:14 +1100 Subject: [PATCH 2/2] v5.0.0 patch (#98) --- Source/Directory.Build.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Directory.Build.props b/Source/Directory.Build.props index 3958577..c4201f8 100644 --- a/Source/Directory.Build.props +++ b/Source/Directory.Build.props @@ -4,7 +4,7 @@ 5.0.0 true true - true + false NU1901;NU1902 - \ No newline at end of file +