diff --git a/README.md b/README.md index 39b2a87f4..e211e6ba3 100644 --- a/README.md +++ b/README.md @@ -30,15 +30,8 @@ Dev branch contains the latest "stable" code, and their images are tagged with ` **NEWS / ANNOUNCEMENTS** Do you want to be up-to-date on .NET Architecture guidance and reference apps like eShopOnContainers? --> Subscribe by "WATCHING" this new GitHub repo: https://github.com/dotnet-architecture/News -## Update to .NET Core 3 - -> There's currently an update to .NET Core 3 going on in the branch [features/migration-dotnet3](https://github.com/dotnet-architecture/eShopOnContainers/tree/features/migration-dotnet3). -> -> You can monitor this branch, but it's being changed frequently, community contributions will be accepted once it's officially released. - -## Updated for .NET Core 2.2 "wave" of technologies - -eShopOnContainers is updated to .NET Core 2.x (currently updated to 2.2) "wave" of technologies. Not just compilation but also new recommended code in EF Core, ASP.NET Core, and other new related versions. +## Updated for .NET Core 3.0 +eShopOnContainers is updated to .NET Core 3.0 "wave" of technologies. Not just compilation but also new recommended code in EF Core, ASP.NET Core, and other new related versions. The **dockerfiles** in the solution have also been updated and now support [**Docker Multi-Stage**](https://blogs.msdn.microsoft.com/stevelasker/2017/09/11/net-and-multistage-dockerfiles/) since mid-December 2017. diff --git a/build/acr-build/queue-all.ps1 b/build/acr-build/queue-all.ps1 index aacffea95..69448f9a2 100644 --- a/build/acr-build/queue-all.ps1 +++ b/build/acr-build/queue-all.ps1 @@ -13,7 +13,7 @@ $services = @( @{ Name="eshopcatalog"; Image="eshop/catalog.api"; File="src/Services/Catalog/Catalog.API/Dockerfile" }, @{ Name="eshopidentity"; Image="eshop/identity.api"; File="src/Services/Identity/Identity.API/Dockerfile" }, @{ Name="eshopordering"; Image="eshop/ordering.api"; File="src/Services/Ordering/Ordering.API/Dockerfile" }, - @{ Name="eshoporderingbg"; Image="eshop/ordering.backgroundtasks"; File="src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile" }, + @{ Name="eshoporderingbg"; Image="eshop/ordering.backgroundtasks"; File="src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile" }, @{ Name="eshopmarketing"; Image="eshop/marketing.api"; File="src/Services/Marketing/Marketing.API/Dockerfile" }, @{ Name="eshopwebspa"; Image="eshop/webspa"; File="src/Web/WebSPA/Dockerfile" }, @{ Name="eshopwebmvc"; Image="eshop/webmvc"; File="src/Web/WebMVC/Dockerfile" }, diff --git a/build/azure-devops/buildimages.yaml b/build/azure-devops/buildimages.yaml index da40a7054..cf6457513 100644 --- a/build/azure-devops/buildimages.yaml +++ b/build/azure-devops/buildimages.yaml @@ -36,7 +36,7 @@ jobs: dockerComposeCommand: 'build ${{ parameters.services }}' containerregistrytype: Container Registry dockerRegistryEndpoint: ${{ parameters.registryEndpoint }} - dockerComposeFile: docker-compose.yml + dockerComposeFile: src/docker-compose.yml qualifyImageNames: true projectName: "" dockerComposeFileArgs: | @@ -47,7 +47,7 @@ jobs: dockerComposeCommand: 'push ${{ parameters.services }}' containerregistrytype: Container Registry dockerRegistryEndpoint: ${{ parameters.registryEndpoint }} - dockerComposeFile: docker-compose.yml + dockerComposeFile: src/docker-compose.yml qualifyImageNames: true projectName: "" dockerComposeFileArgs: | @@ -71,7 +71,7 @@ jobs: dockerComposeCommand: 'build ${{ parameters.services }}' containerregistrytype: Container Registry dockerRegistryEndpoint: ${{ parameters.registryEndpoint }} - dockerComposeFile: docker-compose.yml + dockerComposeFile: src/docker-compose.yml qualifyImageNames: true projectName: "" dockerComposeFileArgs: | @@ -84,7 +84,7 @@ jobs: dockerComposeCommand: 'push ${{ parameters.services }}' containerregistrytype: Container Registry dockerRegistryEndpoint: ${{ parameters.registryEndpoint }} - dockerComposeFile: docker-compose.yml + dockerComposeFile: src/docker-compose.yml qualifyImageNames: true projectName: "" dockerComposeFileArgs: | diff --git a/docker-compose-external.override.yml b/docker-compose-external.override.yml deleted file mode 100644 index 4637385a1..000000000 --- a/docker-compose-external.override.yml +++ /dev/null @@ -1,14 +0,0 @@ -version: '3.4' - -services: - sql.data: - environment: - - MSSQL_SA_PASSWORD=Pass@word - - ACCEPT_EULA=Y - - MSSQL_PID=Developer - ports: - - "5433:1433" - - nosql.data: - ports: - - "27017:27017" \ No newline at end of file diff --git a/docker-compose-external.yml b/docker-compose-external.yml deleted file mode 100644 index 22fe4ce89..000000000 --- a/docker-compose-external.yml +++ /dev/null @@ -1,18 +0,0 @@ -version: '3.4' - -services: - sql.data: - image: microsoft/mssql-server-linux:2017-latest - - basket.data: - image: redis - ports: - - "6379:6379" - - rabbitmq: - image: rabbitmq - ports: - - "5672:5672" - - nosql.data: - image: mongo diff --git a/docker-compose.nobuild.yml b/docker-compose.nobuild.yml deleted file mode 100644 index b2ebcf903..000000000 --- a/docker-compose.nobuild.yml +++ /dev/null @@ -1,83 +0,0 @@ -version: '3.4' - -services: - basket.api: - image: eshop/basket.api - depends_on: - - basket.data - - identity.api - - rabbitmq - - catalog.api: - image: eshop/catalog.api - depends_on: - - sql.data - - rabbitmq - - identity.api: - image: eshop/identity.api - depends_on: - - sql.data - - ordering.api: - image: eshop/ordering.api - depends_on: - - sql.data - - rabbitmq - - marketing.api: - image: eshop/marketing.api - depends_on: - - sql.data - - nosql.data - - identity.api - - rabbitmq - - webspa: - image: eshop/webspa - depends_on: - - catalog.api - - ordering.api - - identity.api - - basket.api - - marketing.api - - webmvc: - image: eshop/webmvc - depends_on: - - catalog.api - - ordering.api - - identity.api - - basket.api - - marketing.api - - webstatus: - image: eshop/webstatus - - payment.api: - image: eshop/payment.api - depends_on: - - rabbitmq - - locations.api: - image: eshop/locations.api - depends_on: - - nosql.data - - rabbitmq - - sql.data: - image: microsoft/mssql-server-linux:2017-latest - - nosql.data: - image: mongo - - basket.data: - image: redis - ports: - - "6379:6379" - - rabbitmq: - image: rabbitmq:3-management - ports: - - "5672:5672" - diff --git a/eShopOnContainers.sln b/eShopOnContainers.sln index c3e63925d..658eb26d7 100644 --- a/eShopOnContainers.sln +++ b/eShopOnContainers.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27130.2024 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29123.88 MinimumVisualStudioVersion = 10.0.40219.1 Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FEA0C318-FFED-4D39-8781-265718CA43DD}" EndProject @@ -99,8 +99,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eShopOnContainers.TestRunne EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eShopOnContainers.TestRunner.Windows", "src\Mobile\eShopOnContainers\eShopOnContainers.TestRunner.Windows\eShopOnContainers.TestRunner.Windows.csproj", "{A7337243-33B8-463A-87AD-944B75EFD820}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.BackgroundTasks", "src\Services\Ordering\Ordering.BackgroundTasks\Ordering.BackgroundTasks.csproj", "{16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Basket.FunctionalTests", "src\Services\Basket\Basket.FunctionalTests\Basket.FunctionalTests.csproj", "{9F00E62F-E180-4A9C-8794-98A72AFAC2DB}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Basket.UnitTests", "src\Services\Basket\Basket.UnitTests\Basket.UnitTests.csproj", "{63417272-1E6A-406A-AD11-C738558D89C0}" @@ -165,6 +163,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Devspaces.Support", "Devspa EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Devspaces.Support", "src\BuildingBlocks\Devspaces.Support\Devspaces.Support.csproj", "{CB6D01A4-E597-4348-9570-FC8DB03B4267}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Clients", "Clients", "{8449B293-5949-4832-8612-6BCE2962BCB1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Clients.Grpc.Caller", "src\Clients\Clients.Grpc.Caller\Clients.Grpc.Caller.csproj", "{7C8FA264-ED49-4ACA-9629-FCE5462B30AB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Ad-Hoc|Any CPU = Ad-Hoc|Any CPU @@ -1371,54 +1373,6 @@ Global {A7337243-33B8-463A-87AD-944B75EFD820}.Release|x86.ActiveCfg = Release|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Release|x86.Build.0 = Release|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Release|x86.Deploy.0 = Release|x86 - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.AppStore|ARM.Build.0 = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.AppStore|iPhone.Build.0 = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.AppStore|x64.ActiveCfg = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.AppStore|x64.Build.0 = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.AppStore|x86.ActiveCfg = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.AppStore|x86.Build.0 = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Debug|Any CPU.Build.0 = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Debug|ARM.ActiveCfg = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Debug|ARM.Build.0 = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Debug|iPhone.Build.0 = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Debug|x64.ActiveCfg = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Debug|x64.Build.0 = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Debug|x86.ActiveCfg = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Debug|x86.Build.0 = Debug|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Release|Any CPU.ActiveCfg = Release|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Release|Any CPU.Build.0 = Release|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Release|ARM.ActiveCfg = Release|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Release|ARM.Build.0 = Release|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Release|iPhone.ActiveCfg = Release|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Release|iPhone.Build.0 = Release|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Release|x64.ActiveCfg = Release|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Release|x64.Build.0 = Release|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Release|x86.ActiveCfg = Release|Any CPU - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480}.Release|x86.Build.0 = Release|Any CPU {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {9F00E62F-E180-4A9C-8794-98A72AFAC2DB}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU @@ -2091,6 +2045,54 @@ Global {CB6D01A4-E597-4348-9570-FC8DB03B4267}.Release|x64.Build.0 = Release|Any CPU {CB6D01A4-E597-4348-9570-FC8DB03B4267}.Release|x86.ActiveCfg = Release|Any CPU {CB6D01A4-E597-4348-9570-FC8DB03B4267}.Release|x86.Build.0 = Release|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.AppStore|ARM.Build.0 = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.AppStore|iPhone.Build.0 = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.AppStore|x64.ActiveCfg = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.AppStore|x64.Build.0 = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.AppStore|x86.ActiveCfg = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.AppStore|x86.Build.0 = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Debug|ARM.ActiveCfg = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Debug|ARM.Build.0 = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Debug|iPhone.Build.0 = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Debug|x64.ActiveCfg = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Debug|x64.Build.0 = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Debug|x86.ActiveCfg = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Debug|x86.Build.0 = Debug|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Release|Any CPU.Build.0 = Release|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Release|ARM.ActiveCfg = Release|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Release|ARM.Build.0 = Release|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Release|iPhone.ActiveCfg = Release|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Release|iPhone.Build.0 = Release|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Release|x64.ActiveCfg = Release|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Release|x64.Build.0 = Release|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Release|x86.ActiveCfg = Release|Any CPU + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2138,7 +2140,6 @@ Global {A289A7F0-ACD8-42AE-87B6-AB1AFD310BF1} = {0AAED9FF-3260-43BB-B586-9AAF1E010A90} {B68C2B56-7581-46AE-B55D-D25DDFD3BFE3} = {0AAED9FF-3260-43BB-B586-9AAF1E010A90} {A7337243-33B8-463A-87AD-944B75EFD820} = {0AAED9FF-3260-43BB-B586-9AAF1E010A90} - {16CDE5D2-2DDE-4AF2-B902-AD9CC42DE480} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B} {9F00E62F-E180-4A9C-8794-98A72AFAC2DB} = {7BA332A2-189D-4D03-9935-FDFF81C42496} {63417272-1E6A-406A-AD11-C738558D89C0} = {7BA332A2-189D-4D03-9935-FDFF81C42496} {56E0E455-731E-41CB-AF46-C1A70F8A140B} = {2F0DEF71-84AC-4212-86D4-E36E8896BDBF} @@ -2165,6 +2166,8 @@ Global {E39BD762-BC86-459D-B818-B6BF2D9F1352} = {424BC53E-17EA-4E12-BC07-64BAA927ABCB} {ABBA561B-499B-48C0-8299-85D41E6E9E98} = {DB0EFB20-B024-4E5E-A75C-52143C131D25} {CB6D01A4-E597-4348-9570-FC8DB03B4267} = {ABBA561B-499B-48C0-8299-85D41E6E9E98} + {8449B293-5949-4832-8612-6BCE2962BCB1} = {932D8224-11F6-4D07-B109-DA28AD288A63} + {7C8FA264-ED49-4ACA-9629-FCE5462B30AB} = {8449B293-5949-4832-8612-6BCE2962BCB1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {25728519-5F0F-4973-8A64-0A81EB4EA8D9} diff --git a/k8s/basket-data.yaml b/k8s/basket-data.yaml deleted file mode 100644 index b48e73fed..000000000 --- a/k8s/basket-data.yaml +++ /dev/null @@ -1,29 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: basket-data - name: basket-data -spec: - ports: - - port: 6379 - selector: - app: eshop - component: basket-data ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: basket-data -spec: - template: - metadata: - labels: - app: eshop - component: basket-data - spec: - containers: - - name: basket-data - image: redis - diff --git a/k8s/deploy.ps1 b/k8s/deploy.ps1 index abeb12aed..6a44a4b12 100644 --- a/k8s/deploy.ps1 +++ b/k8s/deploy.ps1 @@ -133,8 +133,8 @@ ExecKube -cmd 'create -f services.yaml' ExecKube -cmd 'create -f internalurls.yaml' ExecKube -cmd 'create configmap urls ` - --from-literal=PicBaseUrl=http://$($externalDns)/webshoppingapigw/api/v1/c/catalog/items/[0]/pic/ ` - --from-literal=Marketing_PicBaseUrl=http://$($externalDns)/webmarketingapigw/api/v1/m/campaigns/[0]/pic/ ` + --from-literal=PicBaseUrl=http://$($externalDns)/webshoppingapigw/c/api/v1/catalog/items/[0]/pic/ ` + --from-literal=Marketing_PicBaseUrl=http://$($externalDns)/webmarketingapigw/m/api/v1/campaigns/[0]/pic/ ` --from-literal=mvc_e=http://$($externalDns)/webmvc ` --from-literal=marketingapigw_e=http://$($externalDns)/webmarketingapigw ` --from-literal=webshoppingapigw_e=http://$($externalDns)/webshoppingapigw ` diff --git a/k8s/deployments.yaml b/k8s/deployments.yaml deleted file mode 100644 index f362c319c..000000000 --- a/k8s/deployments.yaml +++ /dev/null @@ -1,928 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: basket -spec: - paused: true - template: - metadata: - labels: - app: eshop - component: basket - spec: - containers: - - name: basket - image: eshop/basket.api - imagePullPolicy: Always - env: - - name: PATH_BASE - value: /basket-api - - name: ConnectionString - valueFrom: - configMapKeyRef: - name: externalcfg - key: basket__ConnectionString - - name: EventBusConnection - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__EventBusConnection - - name: AzureServiceBusEnabled - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__UseAzureServiceBus - - name: ApplicationInsights__InstrumentationKey - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__InstrumentationKey - - name: IdentityUrl - valueFrom: - configMapKeyRef: - name: urls - key: identity_e - - name: UseLoadTest - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__EnableLoadTest - - name: OrchestratorType - value: 'K8S' - ports: - - containerPort: 80 - - imagePullSecrets: - - name: registry-key ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: catalog -spec: - paused: true - template: - metadata: - labels: - app: eshop - component: catalog - spec: - containers: - - name: catalog - image: eshop/catalog.api - imagePullPolicy: Always - env: - - name: PATH_BASE - value: /catalog-api - - name: ConnectionString - valueFrom: - configMapKeyRef: - name: externalcfg - key: catalog__ConnectionString - - name: PicBaseUrl - valueFrom: - configMapKeyRef: - name: urls - key: PicBaseUrl - - name: AzureStorageEnabled - valueFrom: - configMapKeyRef: - name: externalcfg - key: catalog__AzureStorageEnabled - - name: EventBusConnection - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__EventBusConnection - - name: ApplicationInsights__InstrumentationKey - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__InstrumentationKey - - name: OrchestratorType - value: 'K8S' - ports: - - containerPort: 80 - - imagePullSecrets: - - name: registry-key ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: identity -spec: - paused: true - template: - metadata: - labels: - app: eshop - component: identity - spec: - containers: - - name: identity - image: eshop/identity.api - imagePullPolicy: Always - env: - - name: PATH_BASE - value: /identity - - name: ConnectionString - valueFrom: - configMapKeyRef: - name: externalcfg - key: identity__ConnectionString - - name: DPConnectionString - valueFrom: - configMapKeyRef: - name: externalcfg - key: keystore - - name: IsClusterEnv - value: 'True' - - name: MvcClient - valueFrom: - configMapKeyRef: - name: urls - key: mvc_e - - name: SpaClient - valueFrom: - configMapKeyRef: - name: urls - key: spa_e - - name: LocationApiClient - valueFrom: - configMapKeyRef: - name: urls - key: locations_e - - name: MarketingApiClient - valueFrom: - configMapKeyRef: - name: urls - key: marketing_e - - name: BasketApiClient - valueFrom: - configMapKeyRef: - name: urls - key: basket_e - - name: OrderingApiClient - valueFrom: - configMapKeyRef: - name: urls - key: ordering_e - - name: MobileShoppingAggClient - valueFrom: - configMapKeyRef: - name: urls - key: mobileshoppingagg_e - - name: WebShoppingAggClient - valueFrom: - configMapKeyRef: - name: urls - key: webshoppingagg_e - - name: XamarinCallback - valueFrom: - configMapKeyRef: - name: urls - key: xamarin_callback_e - - name: ApplicationInsights__InstrumentationKey - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__InstrumentationKey - - name: OrchestratorType - value: 'K8S' - ports: - - containerPort: 80 - - imagePullSecrets: - - name: registry-key ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: ordering -spec: - paused: true - template: - metadata: - labels: - app: eshop - component: ordering - spec: - containers: - - name: ordering - image: eshop/ordering.api - imagePullPolicy: Always - env: - - name: PATH_BASE - value: /ordering-api - - name: ConnectionString - valueFrom: - configMapKeyRef: - name: externalcfg - key: ordering__ConnectionString - - name: EventBusConnection - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__EventBusConnection - - name: AzureServiceBusEnabled - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__UseAzureServiceBus - - name: IdentityUrl - valueFrom: - configMapKeyRef: - name: urls - key: identity_e - - name: CheckUpdateTime - valueFrom: - configMapKeyRef: - name: externalcfg - key: GracePeriodManager__CheckUpdateTime - - name: GracePeriodTime - valueFrom: - configMapKeyRef: - name: externalcfg - key: GracePeriodManager__GracePeriodTime - - name: ApplicationInsights__InstrumentationKey - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__InstrumentationKey - - name: UseLoadTest - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__EnableLoadTest - - name: OrchestratorType - value: 'K8S' - ports: - - containerPort: 80 - - imagePullSecrets: - - name: registry-key ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: ordering-backgroundtasks -spec: - paused: true - template: - metadata: - labels: - app: eshop - component: ordering-backgroundtasks - spec: - containers: - - name: ordering-backgroundtasks - image: eshop/ordering.backgroundtasks - imagePullPolicy: Always - env: - - name: ConnectionString - valueFrom: - configMapKeyRef: - name: externalcfg - key: ordering__ConnectionString - - name: EventBusConnection - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__EventBusConnection - - name: AzureServiceBusEnabled - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__UseAzureServiceBus - - name: CheckUpdateTime - valueFrom: - configMapKeyRef: - name: externalcfg - key: GracePeriodManager__CheckUpdateTime - - name: GracePeriodTime - valueFrom: - configMapKeyRef: - name: externalcfg - key: GracePeriodManager__GracePeriodTime - - name: ApplicationInsights__InstrumentationKey - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__InstrumentationKey - - name: UseLoadTest - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__EnableLoadTest - - name: OrchestratorType - value: 'K8S' - ports: - - containerPort: 80 - imagePullSecrets: - - name: registry-key ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: ordering-signalrhub -spec: - paused: true - template: - metadata: - labels: - app: eshop - component: ordering-signalrhub - spec: - containers: - - name: ordering-signalrhub - image: eshop/ordering.signalrhub - imagePullPolicy: Always - env: - - name: EventBusConnection - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__EventBusConnection - - name: IdentityUrl - valueFrom: - configMapKeyRef: - name: urls - key: identity_e - - name: AzureServiceBusEnabled - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__UseAzureServiceBus - - name: ApplicationInsights__InstrumentationKey - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__InstrumentationKey - - name: OrchestratorType - value: 'K8S' - - name: IsClusterEnv - value: 'True' - - name: SignalrStoreConnectionString - valueFrom: - configMapKeyRef: - name: externalcfg - key: keystore - ports: - - containerPort: 80 - imagePullSecrets: - - name: registry-key ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: locations -spec: - paused: true - template: - metadata: - labels: - app: eshop - component: locations - spec: - containers: - - name: locations - image: eshop/locations.api - imagePullPolicy: Always - env: - - name: PATH_BASE - value: /locations-api - - name: ConnectionString - valueFrom: - configMapKeyRef: - name: externalcfg - key: locations__ConnectionString - - name: Database - valueFrom: - configMapKeyRef: - name: externalcfg - key: locations__Database - - name: AzureServiceBusEnabled - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__UseAzureServiceBus - - name: EventBusConnection - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__EventBusConnection - - name: IdentityUrl - valueFrom: - configMapKeyRef: - name: internalurls - key: identity - - name: IdentityUrlExternal - valueFrom: - configMapKeyRef: - name: urls - key: identity_e - - name: ApplicationInsights__InstrumentationKey - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__InstrumentationKey - - name: UseLoadTest - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__EnableLoadTest - - name: OrchestratorType - value: 'K8S' - ports: - - containerPort: 80 - - imagePullSecrets: - - name: registry-key ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: marketing -spec: - paused: true - template: - metadata: - labels: - app: eshop - component: marketing - spec: - containers: - - name: marketing - image: eshop/marketing.api - imagePullPolicy: Always - env: - - name: PATH_BASE - value: /marketing-api - - name: ConnectionString - valueFrom: - configMapKeyRef: - name: externalcfg - key: marketing__ConnectionString - - name: MongoConnectionString - valueFrom: - configMapKeyRef: - name: externalcfg - key: marketing__MongoConnectionString - - name: MongoDatabase - valueFrom: - configMapKeyRef: - name: externalcfg - key: marketing__MongoDatabase - - name: AzureServiceBusEnabled - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__UseAzureServiceBus - - name: EventBusConnection - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__EventBusConnection - - name: IdentityUrl - valueFrom: - configMapKeyRef: - name: internalurls - key: identity - - name: IdentityUrlExternal - valueFrom: - configMapKeyRef: - name: urls - key: identity_e - - name: PicBaseUrl - valueFrom: - configMapKeyRef: - name: urls - key: Marketing_PicBaseUrl - - name: ApplicationInsights__InstrumentationKey - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__InstrumentationKey - - name: UseLoadTest - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__EnableLoadTest - - name: OrchestratorType - value: 'K8S' - ports: - - containerPort: 80 - - imagePullSecrets: - - name: registry-key ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: payment -spec: - paused: true - template: - metadata: - labels: - app: eshop - component: payment - spec: - containers: - - name: payment - image: eshop/payment.api - imagePullPolicy: Always - env: - - name: PATH_BASE - value: /payment-api - - name: AzureServiceBusEnabled - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__UseAzureServiceBus - - name: EventBusConnection - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__EventBusConnection - - name: ApplicationInsights__InstrumentationKey - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__InstrumentationKey - - name: OrchestratorType - value: 'K8S' - ports: - - containerPort: 80 - - imagePullSecrets: - - name: registry-key ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: webmvc -spec: - paused: true - template: - metadata: - labels: - app: eshop - component: webmvc - spec: - containers: - - name: webmvc - image: eshop/webmvc - imagePullPolicy: Always - env: - - name: PATH_BASE - value: /webmvc - - name: DPConnectionString - valueFrom: - configMapKeyRef: - name: externalcfg - key: keystore - - name: IsClusterEnv - value: 'True' - - name: PurchaseUrl - valueFrom: - configMapKeyRef: - name: internalurls - key: apigwws - - name: ExternalPurchaseUrl - valueFrom: - configMapKeyRef: - name: urls - key: webshoppingapigw_e - - name: CallBackUrl - valueFrom: - configMapKeyRef: - name: urls - key: mvc_e - - name: IdentityUrl - valueFrom: - configMapKeyRef: - name: urls - key: identity_e - - name: MarketingUrl - valueFrom: - configMapKeyRef: - name: internalurls - key: apigwwm - - name: BasketUrlHC - valueFrom: - configMapKeyRef: - name: internalurls - key: basket__hc - - name: CatalogUrlHC - valueFrom: - configMapKeyRef: - name: internalurls - key: catalog__hc - - name: IdentityUrlHC - valueFrom: - configMapKeyRef: - name: internalurls - key: identity__hc - - name: OrderingUrlHC - valueFrom: - configMapKeyRef: - name: internalurls - key: ordering__hc - - name: MarketingUrlHC - valueFrom: - configMapKeyRef: - name: internalurls - key: marketing__hc - - name: PaymentUrlHC - valueFrom: - configMapKeyRef: - name: internalurls - key: payment__hc - - name: ApplicationInsights__InstrumentationKey - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__InstrumentationKey - - name: UseLoadTest - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__EnableLoadTest - - name: OrchestratorType - value: 'K8S' - - name: SignalrHubUrl - valueFrom: - configMapKeyRef: - name: urls - key: webshoppingapigw_e - ports: - - containerPort: 80 - - imagePullSecrets: - - name: registry-key ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: webstatus -spec: - paused: true - template: - metadata: - labels: - app: eshop - component: webstatus - spec: - containers: - - name: webstatus - image: eshop/webstatus - imagePullPolicy: Always - env: - - name: PATH_BASE - value: /webstatus - - name: BasketUrl - valueFrom: - configMapKeyRef: - name: internalurls - key: basket__hc - - name: CatalogUrl - valueFrom: - configMapKeyRef: - name: internalurls - key: catalog__hc - - name: IdentityUrl - valueFrom: - configMapKeyRef: - name: internalurls - key: identity__hc - - name: OrderingUrl - valueFrom: - configMapKeyRef: - name: internalurls - key: ordering__hc - - name: OrderingBackgroundTasksUrl - valueFrom: - configMapKeyRef: - name: internalurls - key: ordering-background__hc - - name: LocationsUrl - valueFrom: - configMapKeyRef: - name: internalurls - key: locations__hc - - name: MarketingUrl - valueFrom: - configMapKeyRef: - name: internalurls - key: marketing__hc - - name: mvc - valueFrom: - configMapKeyRef: - name: internalurls - key: mvc__hc - - name: spa - valueFrom: - configMapKeyRef: - name: internalurls - key: spa__hc - - name: PaymentUrl - valueFrom: - configMapKeyRef: - name: internalurls - key: payment__hc - - name: ApplicationInsights__InstrumentationKey - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__InstrumentationKey - - name: OrchestratorType - value: 'K8S' - ports: - - containerPort: 80 - imagePullSecrets: - - name: registry-key ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: webspa -spec: - paused: true - template: - metadata: - labels: - app: eshop - component: webspa - spec: - containers: - - name: webspa - image: eshop/webspa - imagePullPolicy: Always - env: - - name: ASPNETCORE_URLS - value: http://0.0.0.0:80 - - name: DPConnectionString - valueFrom: - configMapKeyRef: - name: externalcfg - key: keystore - - name: IsClusterEnv - value: 'True' - - name: PurchaseUrl - valueFrom: - configMapKeyRef: - name: urls - key: webshoppingapigw_e - - name: CallBackUrl - valueFrom: - configMapKeyRef: - name: urls - key: spa_e - - name: IdentityUrl - valueFrom: - configMapKeyRef: - name: urls - key: identity_e - - name: MarketingUrl - valueFrom: - configMapKeyRef: - name: urls - key: marketingapigw_e - - name: BasketUrlHC - valueFrom: - configMapKeyRef: - name: internalurls - key: basket__hc - - name: CatalogUrlHC - valueFrom: - configMapKeyRef: - name: internalurls - key: catalog__hc - - name: IdentityUrlHC - valueFrom: - configMapKeyRef: - name: internalurls - key: identity__hc - - name: OrderingUrlHC - valueFrom: - configMapKeyRef: - name: internalurls - key: ordering__hc - - name: MarketingUrlHC - valueFrom: - configMapKeyRef: - name: internalurls - key: marketing__hc - - name: PaymentUrlHC - valueFrom: - configMapKeyRef: - name: internalurls - key: payment__hc - - name: ApplicationInsights__InstrumentationKey - valueFrom: - configMapKeyRef: - name: externalcfg - key: all__InstrumentationKey - - name: OrchestratorType - value: 'K8S' - - name: SignalrHubUrl - valueFrom: - configMapKeyRef: - name: urls - key: webshoppingapigw_e - ports: - - containerPort: 80 - - imagePullSecrets: - - name: registry-key ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: webshoppingagg -spec: - paused: true - template: - metadata: - labels: - app: eshop - component: webshoppingagg - spec: - containers: - - name: webshoppingagg - image: eshop/webshoppingagg - imagePullPolicy: Always - env: - - name: ASPNETCORE_URLS - value: http://0.0.0.0:80 - - name: urls__basket - valueFrom: - configMapKeyRef: - name: internalurls - key: basket - - name: urls__catalog - valueFrom: - configMapKeyRef: - name: internalurls - key: catalog - - name: urls__orders - valueFrom: - configMapKeyRef: - name: internalurls - key: ordering - - name: urls__identity - valueFrom: - configMapKeyRef: - name: internalurls - key: identity - ports: - - containerPort: 80 - imagePullSecrets: - - name: registry-key ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: mobileshoppingagg -spec: - paused: true - template: - metadata: - labels: - app: eshop - component: mobileshoppingagg - spec: - containers: - - name: mobileshoppingagg - image: eshop/mobileshoppingagg - imagePullPolicy: Always - env: - - name: ASPNETCORE_URLS - value: http://0.0.0.0:80 - - name: urls__basket - valueFrom: - configMapKeyRef: - name: internalurls - key: basket - - name: urls__catalog - valueFrom: - configMapKeyRef: - name: internalurls - key: catalog - - name: urls__orders - valueFrom: - configMapKeyRef: - name: internalurls - key: ordering - - name: urls__identity - valueFrom: - configMapKeyRef: - name: internalurls - key: identity - ports: - - containerPort: 80 - imagePullSecrets: - - name: registry-key ---- diff --git a/k8s/eshop-namespace.yaml b/k8s/eshop-namespace.yaml deleted file mode 100644 index c7eebb7a0..000000000 --- a/k8s/eshop-namespace.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: eshop - \ No newline at end of file diff --git a/k8s/gen-k8s-env-aks.ps1 b/k8s/gen-k8s-env-aks.ps1 index 727a9ca53..327f5fd6b 100644 --- a/k8s/gen-k8s-env-aks.ps1 +++ b/k8s/gen-k8s-env-aks.ps1 @@ -4,9 +4,12 @@ [parameter(Mandatory=$true)][string]$serviceName, [parameter(Mandatory=$true)][string]$dnsNamePrefix, [parameter(Mandatory=$false)][string]$registryName, - [parameter(Mandatory=$true)][string]$createAcr=$true, + [parameter(Mandatory=$true)][bool]$createAcr=$true, [parameter(Mandatory=$false)][int]$nodeCount=3, - [parameter(Mandatory=$false)][string]$nodeVMSize="Standard_D2_v2" + [parameter(Mandatory=$false)][string]$nodeVMSize="Standard_D2_v2", + [parameter(Mandatory=$false)][bool]$enableHttpApplicationAddon=$true, + [parameter(Mandatory=$false)][bool]$enableAzureMonitoring=$false, + [parameter(Mandatory=$false)][ValidateSet("VirtualMachineScaleSets","AvailabilitySet",IgnoreCase=$true)]$vmSetType="VirtualMachineScaleSets" ) # Create resource group @@ -15,13 +18,26 @@ az group create --name=$resourceGroupName --location=$location if ($createAcr -eq $true) { # Create Azure Container Registry - Write-Host "Creating Azure Container Registry..." -ForegroundColor Yellow + if ([string]::IsNullOrEmpty($registryName)) { + $registryName=$serviceName + } + Write-Host "Creating Azure Container Registry named $registryName" -ForegroundColor Yellow az acr create -n $registryName -g $resourceGroupName -l $location --admin-enabled true --sku Basic } # Create kubernetes cluster in AKS -Write-Host "Creating Kubernetes cluster in AKS..." -ForegroundColor Yellow -az aks create --resource-group=$resourceGroupName --name=$serviceName --dns-name-prefix=$dnsNamePrefix --generate-ssh-keys --node-count=$nodeCount --node-vm-size=$nodeVMSize +Write-Host "Creating AKS $resourceGroupName/$serviceName" -ForegroundColor Yellow +az aks create --resource-group=$resourceGroupName --name=$serviceName --dns-name-prefix=$dnsNamePrefix --generate-ssh-keys --node-count=$nodeCount --node-vm-size=$nodeVMSize --vm-set-type $vmSetType + +if ($enableHttpApplicationAddon) { + Write-Host "Enabling Http Applciation Routing in AKS $serviceName" -ForegroundColor Yellow + az aks enable-addons --resource-group $resourceGroupName --name $serviceName --addons http_application_routing +} + +if ($enableAzureMonitoring) { + Write-Host "Enabling Azure Monitoring in AKS $serviceName" -ForegroundColor Yellow + az aks enable-addons --resource-group $resourceGroupName --name $serviceName --addons monitoring +} # Retrieve kubernetes cluster configuration and save it under ~/.kube/config Write-Host "Getting Kubernetes config..." -ForegroundColor Yellow @@ -29,6 +45,6 @@ az aks get-credentials --resource-group=$resourceGroupName --name=$serviceName if ($createAcr -eq $true) { # Show ACR credentials - Write-Host "ACR credentials" -ForegroundColor Yellow + Write-Host "ACR $registryName credentials:" -ForegroundColor Yellow az acr credential show -n $registryName } diff --git a/k8s/gen-k8s-env.ps1 b/k8s/gen-k8s-env.ps1 deleted file mode 100644 index fffe1546f..000000000 --- a/k8s/gen-k8s-env.ps1 +++ /dev/null @@ -1,33 +0,0 @@ -Param( - [parameter(Mandatory=$true)][string]$resourceGroupName, - [parameter(Mandatory=$true)][string]$location, - [parameter(Mandatory=$false)][string]$registryName, - [parameter(Mandatory=$true)][string]$orchestratorName, - [parameter(Mandatory=$true)][string]$dnsName, - [parameter(Mandatory=$true)][string]$createAcr=$true, - [parameter(Mandatory=$false)][int]$agentCount=2, - [parameter(Mandatory=$false)][string]$agentVMSize="Standard_D2_v2", - [parameter(Mandatory=$false)][int]$masterCount=1 -) - -# Create resource group -Write-Host "Creating resource group..." -ForegroundColor Yellow -az group create --name=$resourceGroupName --location=$location - -if ($createAcr -eq $true) { - # Create Azure Container Registry - Write-Host "Creating Azure Container Registry..." -ForegroundColor Yellow - az acr create -n $registryName -g $resourceGroupName -l $location --admin-enabled true --sku Basic -} - -# Create kubernetes orchestrator -Write-Host "Creating kubernetes orchestrator..." -ForegroundColor Yellow -az acs create --orchestrator-type=kubernetes --resource-group $resourceGroupName --name=$orchestratorName --dns-prefix=$dnsName --generate-ssh-keys --agent-count=$agentCount --agent-vm-size=$agentVMSize --master-count=$masterCount - -# Retrieve kubernetes cluster configuration and save it under ~/.kube/config -az acs kubernetes get-credentials --resource-group=$resourceGroupName --name=$orchestratorName - -if ($createAcr -eq $true) { - # Show ACR credentials - az acr credential show -n $registryName -} \ No newline at end of file diff --git a/k8s/helm/apigwmm/configuration-mobile-marketing.json b/k8s/helm/apigwmm/configuration-mobile-marketing.json deleted file mode 100644 index 666df1633..000000000 --- a/k8s/helm/apigwmm/configuration-mobile-marketing.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "ReRoutes": [ - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "marketing", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/m/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "locations", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/l/{everything}", - "UpstreamHttpMethod": [] - } - - ], - "GlobalConfiguration": { - "RequestIdKey": "OcRequestId", - "AdministrationPath": "/administration" - } -} - \ No newline at end of file diff --git a/k8s/helm/apigwmm/envoy.yaml b/k8s/helm/apigwmm/envoy.yaml new file mode 100644 index 000000000..54b1afa06 --- /dev/null +++ b/k8s/helm/apigwmm/envoy.yaml @@ -0,0 +1,75 @@ +admin: + access_log_path: "/dev/null" + address: + socket_address: + address: 0.0.0.0 + port_value: 8001 +static_resources: + listeners: + - address: + socket_address: + address: 0.0.0.0 + port_value: 80 + filter_chains: + - filters: + - name: envoy.http_connection_manager + config: + codec_type: auto + stat_prefix: ingress_http + route_config: + name: eshop_backend_route + virtual_hosts: + - name: eshop_backend + domains: + - "*" + routes: + - name: "m-short" + match: + prefix: "/m/" + route: + auto_host_rewrite: true + prefix_rewrite: "/marketing-api/" + cluster: marketing + - name: "m-long" + match: + prefix: "/marketing-api/" + route: + auto_host_rewrite: true + cluster: marketing + http_filters: + - name: envoy.router + access_log: + - name: envoy.file_access_log + filter: + not_health_check_filter: {} + config: + json_format: + time: "%START_TIME%" + protocol: "%PROTOCOL%" + duration: "%DURATION%" + request_method: "%REQ(:METHOD)%" + request_host: "%REQ(HOST)%" + path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%" + response_flags: "%RESPONSE_FLAGS%" + route_name: "%ROUTE_NAME%" + upstream_host: "%UPSTREAM_HOST%" + upstream_cluster: "%UPSTREAM_CLUSTER%" + upstream_local_address: "%UPSTREAM_LOCAL_ADDRESS%" + path: "/tmp/access.log" + clusters: + - name: marketing + connect_timeout: 0.25s + type: logical_dns + lb_policy: round_robin + hosts: + - socket_address: + address: marketing-api + port_value: 80 + - name: locations + connect_timeout: 0.25s + type: logical_dns + lb_policy: round_robin + hosts: + - socket_address: + address: locations-api + port_value: 80 diff --git a/k8s/helm/apigwmm/templates/configmap.yaml b/k8s/helm/apigwmm/templates/configmap.yaml deleted file mode 100644 index fbffcd339..000000000 --- a/k8s/helm/apigwmm/templates/configmap.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- $name := include "apigwmm.fullname" . -}} - -apiVersion: v1 -kind: ConfigMap -metadata: - name: "cfg-{{ $name }}" - labels: - app: {{ template "apigwmm.name" . }} - chart: {{ template "apigwmm.chart" .}} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -data: - internalurls__identity: http://{{ .Values.app.svc.identity }} - internalurls__basket__hc: http://{{ .Values.app.svc.basket }}/hc - internalurls__catalog__hc: http://{{ .Values.app.svc.catalog }}/hc - internalurls__identity__hc: http://{{ .Values.app.svc.identity }}/hc - internalurls__ordering__hc: http://{{ .Values.app.svc.ordering }}/hc - internalurls__marketing__hc: http://{{ .Values.app.svc.marketing }}/hc - internalurls__payment__hc: http://{{ .Values.app.svc.payment }}/hc - internalurls__location__hc: http://{{ .Values.app.svc.locations }}/hc - diff --git a/k8s/helm/apigwmm/templates/deployment.yaml b/k8s/helm/apigwmm/templates/deployment.yaml index c9abb0b62..f93706bb9 100644 --- a/k8s/helm/apigwmm/templates/deployment.yaml +++ b/k8s/helm/apigwmm/templates/deployment.yaml @@ -1,6 +1,6 @@ {{- $name := include "apigwmm.fullname" . -}} {{- $cfgname := printf "%s-%s" "cfg" $name -}} -{{- $ocelotcfgname := printf "%s-%s" "ocelot" $name -}} +{{- $envoycfgname := printf "%s-%s" "envoy" $name -}} apiVersion: apps/v1beta2 kind: Deployment metadata: @@ -22,6 +22,10 @@ spec: labels: app: {{ template "apigwmm.name" . }} release: {{ .Release.Name }} + {{ if .Values.inf.mesh.enabled -}} + annotations: + linkerd.io/inject: enabled + {{- end }} spec: {{ if .Values.inf.registry -}} imagePullSecrets: @@ -30,10 +34,10 @@ spec: volumes: - name: config configMap: - name: {{ $ocelotcfgname }} + name: {{ $envoycfgname }} items: - - key: configuration-mobile-marketing.json - path: configuration.json + - key: envoy.yaml + path: envoy.yaml containers: - name: {{ .Chart.Name }} {{ if .Values.probes -}} @@ -58,10 +62,10 @@ spec: {{- end -}} {{- end }} image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} + imagePullPolicy: IfNotPresent volumeMounts: - name: config - mountPath: {{ .Values.ocelot.configPath }} + mountPath: {{ .Values.envoy.configPath }} env: - name: PATH_BASE value: {{ include "pathBase" . }} @@ -86,6 +90,9 @@ spec: - name: http containerPort: 80 protocol: TCP + - name: admin + containerPort: 8001 + protocol: TCP resources: {{ toYaml .Values.resources | indent 12 }} {{- with .Values.nodeSelector }} diff --git a/k8s/helm/apigwmm/templates/ocelot-cm.yaml b/k8s/helm/apigwmm/templates/envoy-cm.yaml similarity index 70% rename from k8s/helm/apigwmm/templates/ocelot-cm.yaml rename to k8s/helm/apigwmm/templates/envoy-cm.yaml index c7c20ce06..71728d084 100644 --- a/k8s/helm/apigwmm/templates/ocelot-cm.yaml +++ b/k8s/helm/apigwmm/templates/envoy-cm.yaml @@ -3,12 +3,12 @@ apiVersion: v1 kind: ConfigMap metadata: - name: "ocelot-{{ $name }}" + name: "envoy-{{ $name }}" labels: app: {{ template "apigwmm.name" . }} chart: {{ template "apigwmm.chart" .}} release: {{ .Release.Name }} heritage: {{ .Release.Service }} data: - {{ (.Files.Glob "configuration-mobile-marketing.json").AsConfig | indent 2 }} + {{ (.Files.Glob "envoy.yaml").AsConfig | indent 2 }} diff --git a/k8s/helm/apigwmm/templates/ingress.yaml b/k8s/helm/apigwmm/templates/ingress.yaml index 290aac0b3..932252400 100644 --- a/k8s/helm/apigwmm/templates/ingress.yaml +++ b/k8s/helm/apigwmm/templates/ingress.yaml @@ -14,6 +14,11 @@ metadata: annotations: {{ toYaml . | indent 4 }} {{- end }} +{{- if .Values.inf.mesh.enabled }} +{{- with .Values.ingress.mesh.annotations }} +{{ toYaml . | indent 4 }} +{{- end }} +{{- end }} spec: {{- if .Values.ingress.tls }} tls: diff --git a/k8s/helm/apigwmm/templates/service.yaml b/k8s/helm/apigwmm/templates/service.yaml index dac59b23a..286277c7d 100644 --- a/k8s/helm/apigwmm/templates/service.yaml +++ b/k8s/helm/apigwmm/templates/service.yaml @@ -14,6 +14,10 @@ spec: targetPort: http protocol: TCP name: http + - port: {{ .Values.service.adminPort }} + targetPort: admin + protocol: TCP + name: admin selector: app: {{ template "apigwmm.name" . }} release: {{ .Release.Name }} diff --git a/k8s/helm/apigwmm/values.yaml b/k8s/helm/apigwmm/values.yaml index ea87a6c05..21f12f27a 100644 --- a/k8s/helm/apigwmm/values.yaml +++ b/k8s/helm/apigwmm/values.yaml @@ -3,17 +3,19 @@ clusterName: eshop-aks pathBase: /mobilemarketingapigw image: - repository: eshop/ocelotapigw - tag: latest - pullPolicy: IfNotPresent + repository: envoyproxy/envoy + tag: v1.11.1 service: type: ClusterIP port: 80 + adminPort: 8001 ingress: enabled: true - annotations: {} + annotations: + nginx.ingress.kubernetes.io/rewrite-target: "/" + ingress.kubernetes.io/rewrite-target: "/" tls: [] resources: {} @@ -25,42 +27,19 @@ tolerations: [] affinity: {} -# env defines the environment variables that will be declared in the pod -env: - urls: - # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). - configmap: - - name: IdentityUrl - key: internalurls__identity - - name: CatalogUrlHC - key: internalurls__catalog__hc - - name: BasketUrlHC - key: internalurls__basket__hc - - name: IdentityUrlHC - key: internalurls__identity__hc - - name: OrderingUrlHC - key: internalurls__ordering__hc - - name: MarketingUrlHC - key: internalurls__marketing__hc - - name: PaymentUrlHC - key: internalurls__payment__hc - - name: LocationUrlHC - key: internalurls__location__hc - # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) - values: - - name: ASPNETCORE_ENVIRONMENT - value: Development +env: {} + +envoy: + configPath: /etc/envoy + probes: liveness: - path: /liveness - initialDelaySeconds: 10 + path: /ready + initialDelaySeconds: 5 periodSeconds: 15 - port: 80 + port: 8001 readiness: - path: /hc - timeoutSeconds: 5 - initialDelaySeconds: 90 + path: /ready + initialDelaySeconds: 5 periodSeconds: 60 - port: 80 -ocelot: - configPath: /app/configuration + port: 8001 \ No newline at end of file diff --git a/k8s/helm/apigwms/configuration-mobile-shopping.json b/k8s/helm/apigwms/configuration-mobile-shopping.json deleted file mode 100644 index cf3a48aff..000000000 --- a/k8s/helm/apigwms/configuration-mobile-shopping.json +++ /dev/null @@ -1,142 +0,0 @@ -{ - "ReRoutes": [ - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "catalog", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/c/{everything}", - "UpstreamHttpMethod": [ "GET" ] - }, - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "basket", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/b/{everything}", - "UpstreamHttpMethod": [], - "AuthenticationOptions": { - "AuthenticationProviderKey": "IdentityApiKey", - "AllowedScopes": [] - } - }, - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "ordering", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/o/{everything}", - "UpstreamHttpMethod": [], - "AuthenticationOptions": { - "AuthenticationProviderKey": "IdentityApiKey", - "AllowedScopes": [] - } - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "mobileshoppingagg", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/{everything}", - "UpstreamHttpMethod": [ "POST", "PUT", "GET" ], - "AuthenticationOptions": { - "AuthenticationProviderKey": "IdentityApiKey", - "AllowedScopes": [] - } - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "ordering", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/orders-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "basket", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/basket-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "catalog", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/catalog-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "marketing", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/marketing-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "payment", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/payment-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "locations.api", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/location-api/{everything}", - "UpstreamHttpMethod": [] - } - - ], - "GlobalConfiguration": { - "RequestIdKey": "OcRequestId", - "AdministrationPath": "/administration" - } - } - \ No newline at end of file diff --git a/k8s/helm/apigwms/envoy.yaml b/k8s/helm/apigwms/envoy.yaml new file mode 100644 index 000000000..373806b06 --- /dev/null +++ b/k8s/helm/apigwms/envoy.yaml @@ -0,0 +1,124 @@ +admin: + access_log_path: "/dev/null" + address: + socket_address: + address: 0.0.0.0 + port_value: 8001 +static_resources: + listeners: + - address: + socket_address: + address: 0.0.0.0 + port_value: 80 + filter_chains: + - filters: + - name: envoy.http_connection_manager + config: + codec_type: auto + stat_prefix: ingress_http + route_config: + name: eshop_backend_route + virtual_hosts: + - name: eshop_backend + domains: + - "*" + routes: + - name: "c-short" + match: + prefix: "/c/" + route: + auto_host_rewrite: true + prefix_rewrite: "/catalog-api/" + cluster: catalog + - name: "c-long" + match: + prefix: "/catalog-api/" + route: + auto_host_rewrite: true + cluster: catalog + - name: "o-short" + match: + prefix: "/o/" + route: + auto_host_rewrite: true + prefix_rewrite: "/ordering-api/" + cluster: ordering + - name: "o-long" + match: + prefix: "/ordering-api/" + route: + auto_host_rewrite: true + cluster: ordering + - name: "b-short" + match: + prefix: "/b/" + route: + auto_host_rewrite: true + prefix_rewrite: "/basket-api/" + cluster: basket + - name: "b-long" + match: + prefix: "/basket-api/" + route: + auto_host_rewrite: true + cluster: basket + - name: "agg" + match: + prefix: "/" + route: + auto_host_rewrite: true + prefix_rewrite: "/" + cluster: shoppingagg + http_filters: + - name: envoy.router + access_log: + - name: envoy.file_access_log + filter: + not_health_check_filter: {} + config: + json_format: + time: "%START_TIME%" + protocol: "%PROTOCOL%" + duration: "%DURATION%" + request_method: "%REQ(:METHOD)%" + request_host: "%REQ(HOST)%" + path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%" + response_flags: "%RESPONSE_FLAGS%" + route_name: "%ROUTE_NAME%" + upstream_host: "%UPSTREAM_HOST%" + upstream_cluster: "%UPSTREAM_CLUSTER%" + upstream_local_address: "%UPSTREAM_LOCAL_ADDRESS%" + path: "/tmp/access.log" + clusters: + - name: shoppingagg + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + hosts: + - socket_address: + address: webshoppingagg + port_value: 80 + - name: catalog + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + hosts: + - socket_address: + address: catalog-api + port_value: 80 + - name: basket + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + hosts: + - socket_address: + address: basket-api + port_value: 80 + - name: ordering + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + hosts: + - socket_address: + address: ordering-api + port_value: 80 \ No newline at end of file diff --git a/k8s/helm/apigwms/templates/configmap.yaml b/k8s/helm/apigwms/templates/configmap.yaml deleted file mode 100644 index f3292ce72..000000000 --- a/k8s/helm/apigwms/templates/configmap.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- $name := include "apigwms.fullname" . -}} - -apiVersion: v1 -kind: ConfigMap -metadata: - name: "cfg-{{ $name }}" - labels: - app: {{ template "apigwms.name" . }} - chart: {{ template "apigwms.chart" .}} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -data: - internalurls__identity: http://{{ .Values.app.svc.identity }} - internalurls__basket__hc: http://{{ .Values.app.svc.basket }}/hc - internalurls__catalog__hc: http://{{ .Values.app.svc.catalog }}/hc - internalurls__identity__hc: http://{{ .Values.app.svc.identity }}/hc - internalurls__ordering__hc: http://{{ .Values.app.svc.ordering }}/hc - internalurls__marketing__hc: http://{{ .Values.app.svc.marketing }}/hc - internalurls__payment__hc: http://{{ .Values.app.svc.payment }}/hc - internalurls__location__hc: http://{{ .Values.app.svc.locations }}/hc - diff --git a/k8s/helm/apigwms/templates/deployment.yaml b/k8s/helm/apigwms/templates/deployment.yaml index b22922f89..2c5703103 100644 --- a/k8s/helm/apigwms/templates/deployment.yaml +++ b/k8s/helm/apigwms/templates/deployment.yaml @@ -1,6 +1,6 @@ {{- $name := include "apigwms.fullname" . -}} {{- $cfgname := printf "%s-%s" "cfg" $name -}} -{{- $ocelotcfgname := printf "%s-%s" "ocelot" $name -}} +{{- $envoycfgname := printf "%s-%s" "envoy" $name -}} apiVersion: apps/v1beta2 kind: Deployment metadata: @@ -22,6 +22,10 @@ spec: labels: app: {{ template "apigwms.name" . }} release: {{ .Release.Name }} + {{ if .Values.inf.mesh.enabled -}} + annotations: + linkerd.io/inject: enabled + {{- end }} spec: {{ if .Values.inf.registry -}} imagePullSecrets: @@ -30,10 +34,10 @@ spec: volumes: - name: config configMap: - name: {{ $ocelotcfgname }} + name: {{ $envoycfgname }} items: - - key: configuration-mobile-shopping.json - path: configuration.json + - key: envoy.yaml + path: envoy.yaml containers: - name: {{ .Chart.Name }} {{ if .Values.probes -}} @@ -58,10 +62,10 @@ spec: {{- end -}} {{- end }} image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} + imagePullPolicy: IfNotPresent volumeMounts: - name: config - mountPath: {{ .Values.ocelot.configPath }} + mountPath: {{ .Values.envoy.configPath }} env: - name: PATH_BASE value: {{ include "pathBase" . }} @@ -86,6 +90,9 @@ spec: - name: http containerPort: 80 protocol: TCP + - name: admin + containerPort: 8001 + protocol: TCP resources: {{ toYaml .Values.resources | indent 12 }} {{- with .Values.nodeSelector }} diff --git a/k8s/helm/apigwms/templates/ocelot-cm.yaml b/k8s/helm/apigwms/templates/envoy-cm.yaml similarity index 70% rename from k8s/helm/apigwms/templates/ocelot-cm.yaml rename to k8s/helm/apigwms/templates/envoy-cm.yaml index 5f92ca409..76da5832b 100644 --- a/k8s/helm/apigwms/templates/ocelot-cm.yaml +++ b/k8s/helm/apigwms/templates/envoy-cm.yaml @@ -3,12 +3,12 @@ apiVersion: v1 kind: ConfigMap metadata: - name: "ocelot-{{ $name }}" + name: "envoy-{{ $name }}" labels: app: {{ template "apigwms.name" . }} chart: {{ template "apigwms.chart" .}} release: {{ .Release.Name }} heritage: {{ .Release.Service }} data: - {{ (.Files.Glob "configuration-mobile-shopping.json").AsConfig | indent 2 }} + {{ (.Files.Glob "envoy.yaml").AsConfig | indent 2 }} diff --git a/k8s/helm/apigwms/templates/ingress.yaml b/k8s/helm/apigwms/templates/ingress.yaml index e93ddc2c6..5efb36868 100644 --- a/k8s/helm/apigwms/templates/ingress.yaml +++ b/k8s/helm/apigwms/templates/ingress.yaml @@ -15,6 +15,11 @@ metadata: annotations: {{ toYaml . | indent 4 }} {{- end }} +{{- if .Values.inf.mesh.enabled }} +{{- with .Values.ingress.mesh.annotations }} +{{ toYaml . | indent 4 }} +{{- end }} +{{- end }} spec: {{- if .Values.ingress.tls }} tls: diff --git a/k8s/helm/apigwms/templates/service.yaml b/k8s/helm/apigwms/templates/service.yaml index 2a37d3c14..aa087d428 100644 --- a/k8s/helm/apigwms/templates/service.yaml +++ b/k8s/helm/apigwms/templates/service.yaml @@ -14,6 +14,10 @@ spec: targetPort: http protocol: TCP name: http + - port: {{ .Values.service.adminPort }} + targetPort: admin + protocol: TCP + name: admin selector: app: {{ template "apigwms.name" . }} release: {{ .Release.Name }} diff --git a/k8s/helm/apigwms/values.yaml b/k8s/helm/apigwms/values.yaml index 650ab6449..4a92d85e9 100644 --- a/k8s/helm/apigwms/values.yaml +++ b/k8s/helm/apigwms/values.yaml @@ -3,17 +3,19 @@ clusterName: eshop-aks pathBase: /mobileshoppingapigw image: - repository: eshop/ocelotapigw - tag: latest - pullPolicy: IfNotPresent + repository: envoyproxy/envoy + tag: v1.11.1 service: type: ClusterIP port: 80 + adminPort: 8001 ingress: enabled: true - annotations: {} + annotations: + nginx.ingress.kubernetes.io/rewrite-target: "/" + ingress.kubernetes.io/rewrite-target: "/" tls: [] resources: {} @@ -25,42 +27,19 @@ tolerations: [] affinity: {} -# env defines the environment variables that will be declared in the pod -env: - urls: - # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). - configmap: - - name: IdentityUrl - key: internalurls__identity - - name: CatalogUrlHC - key: internalurls__catalog__hc - - name: BasketUrlHC - key: internalurls__basket__hc - - name: IdentityUrlHC - key: internalurls__identity__hc - - name: OrderingUrlHC - key: internalurls__ordering__hc - - name: MarketingUrlHC - key: internalurls__marketing__hc - - name: PaymentUrlHC - key: internalurls__payment__hc - - name: LocationUrlHC - key: internalurls__location__hc - # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) - values: - - name: ASPNETCORE_ENVIRONMENT - value: Development +env: {} + +envoy: + configPath: /etc/envoy + probes: liveness: - path: /liveness - initialDelaySeconds: 10 + path: /ready + initialDelaySeconds: 5 periodSeconds: 15 - port: 80 + port: 8001 readiness: - path: /hc - timeoutSeconds: 5 - initialDelaySeconds: 90 + path: /ready + initialDelaySeconds: 5 periodSeconds: 60 - port: 80 -ocelot: - configPath: /app/configuration \ No newline at end of file + port: 8001 \ No newline at end of file diff --git a/k8s/helm/apigwwm/configuration-web-marketing.json b/k8s/helm/apigwwm/configuration-web-marketing.json deleted file mode 100644 index 666df1633..000000000 --- a/k8s/helm/apigwwm/configuration-web-marketing.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "ReRoutes": [ - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "marketing", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/m/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "locations", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/l/{everything}", - "UpstreamHttpMethod": [] - } - - ], - "GlobalConfiguration": { - "RequestIdKey": "OcRequestId", - "AdministrationPath": "/administration" - } -} - \ No newline at end of file diff --git a/k8s/helm/apigwwm/envoy.yaml b/k8s/helm/apigwwm/envoy.yaml new file mode 100644 index 000000000..c6f3421de --- /dev/null +++ b/k8s/helm/apigwwm/envoy.yaml @@ -0,0 +1,75 @@ +admin: + access_log_path: "/dev/null" + address: + socket_address: + address: 0.0.0.0 + port_value: 8001 +static_resources: + listeners: + - address: + socket_address: + address: 0.0.0.0 + port_value: 80 + filter_chains: + - filters: + - name: envoy.http_connection_manager + config: + codec_type: auto + stat_prefix: ingress_http + route_config: + name: eshop_backend_route + virtual_hosts: + - name: eshop_backend + domains: + - "*" + routes: + - name: "m-short" + match: + prefix: "/m/" + route: + auto_host_rewrite: true + prefix_rewrite: "/marketing-api/" + cluster: marketing + - name: "m-long" + match: + prefix: "/marketing-api/" + route: + auto_host_rewrite: true + cluster: marketing + http_filters: + - name: envoy.router + access_log: + - name: envoy.file_access_log + filter: + not_health_check_filter: {} + config: + json_format: + time: "%START_TIME%" + protocol: "%PROTOCOL%" + duration: "%DURATION%" + request_method: "%REQ(:METHOD)%" + request_host: "%REQ(HOST)%" + path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%" + response_flags: "%RESPONSE_FLAGS%" + route_name: "%ROUTE_NAME%" + upstream_host: "%UPSTREAM_HOST%" + upstream_cluster: "%UPSTREAM_CLUSTER%" + upstream_local_address: "%UPSTREAM_LOCAL_ADDRESS%" + path: "/tmp/access.log" + clusters: + - name: marketing + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + hosts: + - socket_address: + address: marketing-api + port_value: 80 + - name: locations + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + hosts: + - socket_address: + address: locations-api + port_value: 80 diff --git a/k8s/helm/apigwwm/templates/configmap.yaml b/k8s/helm/apigwwm/templates/configmap.yaml deleted file mode 100644 index 34c0e6979..000000000 --- a/k8s/helm/apigwwm/templates/configmap.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- $name := include "apigwwm.fullname" . -}} - -apiVersion: v1 -kind: ConfigMap -metadata: - name: "cfg-{{ $name }}" - labels: - app: {{ template "apigwwm.name" . }} - chart: {{ template "apigwwm.chart" .}} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -data: - internalurls__identity: http://{{ .Values.app.svc.identity }} - internalurls__basket__hc: http://{{ .Values.app.svc.basket }}/hc - internalurls__catalog__hc: http://{{ .Values.app.svc.catalog }}/hc - internalurls__identity__hc: http://{{ .Values.app.svc.identity }}/hc - internalurls__ordering__hc: http://{{ .Values.app.svc.ordering }}/hc - internalurls__marketing__hc: http://{{ .Values.app.svc.marketing }}/hc - internalurls__payment__hc: http://{{ .Values.app.svc.payment }}/hc - internalurls__location__hc: http://{{ .Values.app.svc.locations }}/hc - diff --git a/k8s/helm/apigwwm/templates/deployment.yaml b/k8s/helm/apigwwm/templates/deployment.yaml index d1f39ab6c..6ceb1fa1b 100644 --- a/k8s/helm/apigwwm/templates/deployment.yaml +++ b/k8s/helm/apigwwm/templates/deployment.yaml @@ -1,6 +1,6 @@ {{- $name := include "apigwwm.fullname" . -}} {{- $cfgname := printf "%s-%s" "cfg" $name -}} -{{- $ocelotcfgname := printf "%s-%s" "ocelot" $name -}} +{{- $envoycfgname := printf "%s-%s" "envoy" $name -}} apiVersion: apps/v1beta2 kind: Deployment metadata: @@ -22,6 +22,10 @@ spec: labels: app: {{ template "apigwwm.name" . }} release: {{ .Release.Name }} + {{ if .Values.inf.mesh.enabled -}} + annotations: + linkerd.io/inject: enabled + {{- end }} spec: {{ if .Values.inf.registry -}} imagePullSecrets: @@ -30,10 +34,10 @@ spec: volumes: - name: config configMap: - name: {{ $ocelotcfgname }} + name: {{ $envoycfgname }} items: - - key: configuration-web-marketing.json - path: configuration.json + - key: envoy.yaml + path: envoy.yaml containers: - name: {{ .Chart.Name }} {{ if .Values.probes -}} @@ -58,10 +62,10 @@ spec: {{- end -}} {{- end }} image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} + imagePullPolicy: IfNotPresent volumeMounts: - name: config - mountPath: {{ .Values.ocelot.configPath }} + mountPath: {{ .Values.envoy.configPath }} env: - name: PATH_BASE value: {{ include "pathBase" . }} @@ -86,6 +90,9 @@ spec: - name: http containerPort: 80 protocol: TCP + - name: admin + containerPort: 8001 + protocol: TCP resources: {{ toYaml .Values.resources | indent 12 }} {{- with .Values.nodeSelector }} diff --git a/k8s/helm/apigwwm/templates/ocelot-cm.yaml b/k8s/helm/apigwwm/templates/envoy-cm.yaml similarity index 70% rename from k8s/helm/apigwwm/templates/ocelot-cm.yaml rename to k8s/helm/apigwwm/templates/envoy-cm.yaml index 3de28b1a1..4d6307e36 100644 --- a/k8s/helm/apigwwm/templates/ocelot-cm.yaml +++ b/k8s/helm/apigwwm/templates/envoy-cm.yaml @@ -3,12 +3,12 @@ apiVersion: v1 kind: ConfigMap metadata: - name: "ocelot-{{ $name }}" + name: "envoy-{{ $name }}" labels: app: {{ template "apigwwm.name" . }} chart: {{ template "apigwwm.chart" .}} release: {{ .Release.Name }} heritage: {{ .Release.Service }} data: - {{ (.Files.Glob "configuration-web-marketing.json").AsConfig | indent 2 -}} + {{ (.Files.Glob "envoy.yaml").AsConfig | indent 2 -}} diff --git a/k8s/helm/apigwwm/templates/ingress.yaml b/k8s/helm/apigwwm/templates/ingress.yaml index 297fea52b..708488f3c 100644 --- a/k8s/helm/apigwwm/templates/ingress.yaml +++ b/k8s/helm/apigwwm/templates/ingress.yaml @@ -15,6 +15,11 @@ metadata: annotations: {{ toYaml . | indent 4 }} {{- end }} +{{- if .Values.inf.mesh.enabled }} +{{- with .Values.ingress.mesh.annotations }} +{{ toYaml . | indent 4 }} +{{- end }} +{{- end }} spec: {{- if .Values.ingress.tls }} tls: diff --git a/k8s/helm/apigwwm/templates/service.yaml b/k8s/helm/apigwwm/templates/service.yaml index 0ee3c4fb0..cb11cc665 100644 --- a/k8s/helm/apigwwm/templates/service.yaml +++ b/k8s/helm/apigwwm/templates/service.yaml @@ -14,6 +14,10 @@ spec: targetPort: http protocol: TCP name: http + - port: {{ .Values.service.adminPort }} + targetPort: admin + protocol: TCP + name: admin selector: app: {{ template "apigwwm.name" . }} release: {{ .Release.Name }} diff --git a/k8s/helm/apigwwm/values.yaml b/k8s/helm/apigwwm/values.yaml index 63deb5832..d866c2d3c 100644 --- a/k8s/helm/apigwwm/values.yaml +++ b/k8s/helm/apigwwm/values.yaml @@ -3,17 +3,19 @@ clusterName: eshop-aks pathBase: /webmarketingapigw image: - repository: eshop/ocelotapigw - tag: latest - pullPolicy: IfNotPresent + repository: envoyproxy/envoy + tag: v1.11.1 service: type: ClusterIP port: 80 + adminPort: 8001 ingress: enabled: true - annotations: {} + annotations: + nginx.ingress.kubernetes.io/rewrite-target: "/" + ingress.kubernetes.io/rewrite-target: "/" tls: [] resources: {} @@ -26,41 +28,19 @@ tolerations: [] affinity: {} # env defines the environment variables that will be declared in the pod -env: - urls: - # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). - configmap: - - name: IdentityUrl - key: internalurls__identity - - name: CatalogUrlHC - key: internalurls__catalog__hc - - name: BasketUrlHC - key: internalurls__basket__hc - - name: IdentityUrlHC - key: internalurls__identity__hc - - name: OrderingUrlHC - key: internalurls__ordering__hc - - name: MarketingUrlHC - key: internalurls__marketing__hc - - name: PaymentUrlHC - key: internalurls__payment__hc - - name: LocationUrlHC - key: internalurls__location__hc - # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) - values: - - name: ASPNETCORE_ENVIRONMENT - value: Development +env: {} + +envoy: + configPath: /etc/envoy + probes: liveness: - path: /liveness - initialDelaySeconds: 10 + path: /ready + initialDelaySeconds: 5 periodSeconds: 15 - port: 80 + port: 8001 readiness: - path: /hc - timeoutSeconds: 5 - initialDelaySeconds: 90 + path: /ready + initialDelaySeconds: 5 periodSeconds: 60 - port: 80 -ocelot: - configPath: /app/configuration \ No newline at end of file + port: 8001 \ No newline at end of file diff --git a/k8s/helm/apigwws/configuration-web-shopping.json b/k8s/helm/apigwws/configuration-web-shopping.json deleted file mode 100644 index 021056f43..000000000 --- a/k8s/helm/apigwws/configuration-web-shopping.json +++ /dev/null @@ -1,154 +0,0 @@ -{ - "ReRoutes": [ - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "catalog", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/c/{everything}", - "UpstreamHttpMethod": [ "GET" ] - }, - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "basket", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/b/{everything}", - "UpstreamHttpMethod": [], - "AuthenticationOptions": { - "AuthenticationProviderKey": "IdentityApiKey", - "AllowedScopes": [] - } - }, - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "ordering", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/o/{everything}", - "UpstreamHttpMethod": [], - "AuthenticationOptions": { - "AuthenticationProviderKey": "IdentityApiKey", - "AllowedScopes": [] - } - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "webshoppingagg", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/{everything}", - "UpstreamHttpMethod": [ "POST", "PUT", "GET" ], - "AuthenticationOptions": { - "AuthenticationProviderKey": "IdentityApiKey", - "AllowedScopes": [] - } - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "ordering", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/orders-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "ordering-signalrhub", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/hub/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "basket", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/basket-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "catalog", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/catalog-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "marketing", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/marketing-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "payment", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/payment-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "locations.api", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/location-api/{everything}", - "UpstreamHttpMethod": [] - } - - ], - "GlobalConfiguration": { - "RequestIdKey": "OcRequestId", - "AdministrationPath": "/administration" - } - } - \ No newline at end of file diff --git a/k8s/helm/apigwws/envoy.yaml b/k8s/helm/apigwws/envoy.yaml new file mode 100644 index 000000000..1491f37af --- /dev/null +++ b/k8s/helm/apigwws/envoy.yaml @@ -0,0 +1,124 @@ +admin: + access_log_path: "/dev/null" + address: + socket_address: + address: 0.0.0.0 + port_value: 8001 +static_resources: + listeners: + - address: + socket_address: + address: 0.0.0.0 + port_value: 80 + filter_chains: + - filters: + - name: envoy.http_connection_manager + config: + codec_type: auto + stat_prefix: ingress_http + route_config: + name: eshop_backend_route + virtual_hosts: + - name: eshop_backend + domains: + - "*" + routes: + - name: "c-short" + match: + prefix: "/c/" + route: + auto_host_rewrite: true + prefix_rewrite: "/catalog-api/" + cluster: catalog + - name: "c-long" + match: + prefix: "/catalog-api/" + route: + auto_host_rewrite: true + cluster: catalog + - name: "o-short" + match: + prefix: "/o/" + route: + auto_host_rewrite: true + prefix_rewrite: "/ordering-api/" + cluster: ordering + - name: "o-long" + match: + prefix: "/ordering-api/" + route: + auto_host_rewrite: true + cluster: ordering + - name: "b-short" + match: + prefix: "/b/" + route: + auto_host_rewrite: true + prefix_rewrite: "/basket-api/" + cluster: basket + - name: "b-long" + match: + prefix: "/basket-api/" + route: + auto_host_rewrite: true + cluster: basket + - name: "agg" + match: + prefix: "/" + route: + auto_host_rewrite: true + prefix_rewrite: "/" + cluster: shoppingagg + http_filters: + - name: envoy.router + access_log: + - name: envoy.file_access_log + filter: + not_health_check_filter: {} + config: + json_format: + time: "%START_TIME%" + protocol: "%PROTOCOL%" + duration: "%DURATION%" + request_method: "%REQ(:METHOD)%" + request_host: "%REQ(HOST)%" + path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%" + response_flags: "%RESPONSE_FLAGS%" + route_name: "%ROUTE_NAME%" + upstream_host: "%UPSTREAM_HOST%" + upstream_cluster: "%UPSTREAM_CLUSTER%" + upstream_local_address: "%UPSTREAM_LOCAL_ADDRESS%" + path: "/tmp/access.log" + clusters: + - name: shoppingagg + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + hosts: + - socket_address: + address: webshoppingagg + port_value: 80 + - name: catalog + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + hosts: + - socket_address: + address: catalog-api + port_value: 80 + - name: basket + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + hosts: + - socket_address: + address: basket-api + port_value: 80 + - name: ordering + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + hosts: + - socket_address: + address: ordering-api + port_value: 80 \ No newline at end of file diff --git a/k8s/helm/apigwws/templates/configmap.yaml b/k8s/helm/apigwws/templates/configmap.yaml deleted file mode 100644 index dd5530f61..000000000 --- a/k8s/helm/apigwws/templates/configmap.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- $name := include "apigwws.fullname" . -}} - -apiVersion: v1 -kind: ConfigMap -metadata: - name: "cfg-{{ $name }}" - labels: - app: {{ template "apigwws.name" . }} - chart: {{ template "apigwws.chart" .}} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -data: - internalurls__identity: http://{{ .Values.app.svc.identity }} - internalurls__basket__hc: http://{{ .Values.app.svc.basket }}/hc - internalurls__catalog__hc: http://{{ .Values.app.svc.catalog }}/hc - internalurls__identity__hc: http://{{ .Values.app.svc.identity }}/hc - internalurls__ordering__hc: http://{{ .Values.app.svc.ordering }}/hc - internalurls__marketing__hc: http://{{ .Values.app.svc.marketing }}/hc - internalurls__payment__hc: http://{{ .Values.app.svc.payment }}/hc - internalurls__location__hc: http://{{ .Values.app.svc.locations }}/hc - diff --git a/k8s/helm/apigwws/templates/deployment.yaml b/k8s/helm/apigwws/templates/deployment.yaml index 327eb50b7..3aedde6dd 100644 --- a/k8s/helm/apigwws/templates/deployment.yaml +++ b/k8s/helm/apigwws/templates/deployment.yaml @@ -1,6 +1,6 @@ {{- $name := include "apigwws.fullname" . -}} {{- $cfgname := printf "%s-%s" "cfg" $name -}} -{{- $ocelotcfgname := printf "%s-%s" "ocelot" $name -}} +{{- $envoycfgname := printf "%s-%s" "envoy" $name -}} apiVersion: apps/v1beta2 kind: Deployment metadata: @@ -21,6 +21,10 @@ spec: labels: app: {{ template "apigwws.name" . }} release: {{ .Release.Name }} + {{ if .Values.inf.mesh.enabled -}} + annotations: + linkerd.io/inject: enabled + {{- end }} spec: {{ if .Values.inf.registry -}} imagePullSecrets: @@ -29,10 +33,10 @@ spec: volumes: - name: config configMap: - name: {{ $ocelotcfgname }} + name: {{ $envoycfgname }} items: - - key: configuration-web-shopping.json - path: configuration.json + - key: envoy.yaml + path: envoy.yaml containers: - name: {{ .Chart.Name }} {{ if .Values.probes -}} @@ -60,7 +64,7 @@ spec: imagePullPolicy: {{ .Values.image.pullPolicy }} volumeMounts: - name: config - mountPath: {{ .Values.ocelot.configPath }} + mountPath: {{ .Values.envoy.configPath }} env: - name: PATH_BASE value: {{ include "pathBase" . }} @@ -85,6 +89,9 @@ spec: - name: http containerPort: 80 protocol: TCP + - name: admin + containerPort: 8001 + protocol: TCP resources: {{ toYaml .Values.resources | indent 12 }} {{- with .Values.nodeSelector }} diff --git a/k8s/helm/apigwws/templates/ocelot-cm.yaml b/k8s/helm/apigwws/templates/envoy-cm.yaml similarity index 71% rename from k8s/helm/apigwws/templates/ocelot-cm.yaml rename to k8s/helm/apigwws/templates/envoy-cm.yaml index 39b27f29a..6d41bd2e2 100644 --- a/k8s/helm/apigwws/templates/ocelot-cm.yaml +++ b/k8s/helm/apigwws/templates/envoy-cm.yaml @@ -3,12 +3,12 @@ apiVersion: v1 kind: ConfigMap metadata: - name: "ocelot-{{ $name }}" + name: "envoy-{{ $name }}" labels: app: {{ template "apigwws.name" . }} chart: {{ template "apigwws.chart" .}} release: {{ .Release.Name }} heritage: {{ .Release.Service }} data: - {{ (.Files.Glob "configuration-web-shopping.json").AsConfig | indent 2 }} + {{ (.Files.Glob "envoy.yaml").AsConfig | indent 2 }} diff --git a/k8s/helm/apigwws/templates/ingress.yaml b/k8s/helm/apigwws/templates/ingress.yaml index 8bd2cfc6d..b536f2dc9 100644 --- a/k8s/helm/apigwws/templates/ingress.yaml +++ b/k8s/helm/apigwws/templates/ingress.yaml @@ -14,6 +14,11 @@ metadata: annotations: {{ toYaml . | indent 4 }} {{- end }} +{{- if .Values.inf.mesh.enabled }} +{{- with .Values.ingress.mesh.annotations }} +{{ toYaml . | indent 4 }} +{{- end }} +{{- end }} spec: {{- if .Values.ingress.tls }} tls: diff --git a/k8s/helm/apigwws/templates/service.yaml b/k8s/helm/apigwws/templates/service.yaml index 5d74c2ad0..55f6daf3f 100644 --- a/k8s/helm/apigwws/templates/service.yaml +++ b/k8s/helm/apigwws/templates/service.yaml @@ -14,6 +14,10 @@ spec: targetPort: http protocol: TCP name: http + - port: {{ .Values.service.adminPort }} + targetPort: admin + protocol: TCP + name: admin selector: app: {{ template "apigwws.name" . }} release: {{ .Release.Name }} diff --git a/k8s/helm/apigwws/values.yaml b/k8s/helm/apigwws/values.yaml index 2b047de99..fb1182dac 100644 --- a/k8s/helm/apigwws/values.yaml +++ b/k8s/helm/apigwws/values.yaml @@ -3,17 +3,19 @@ clusterName: eshop-aks pathBase: /webshoppingapigw image: - repository: eshop/ocelotapigw - tag: latest - pullPolicy: IfNotPresent + repository: envoyproxy/envoy + tag: v1.11.1 service: type: ClusterIP port: 80 + adminPort: 8001 ingress: enabled: true - annotations: {} + annotations: + nginx.ingress.kubernetes.io/rewrite-target: "/" + ingress.kubernetes.io/rewrite-target: "/" tls: [] resources: {} @@ -26,41 +28,19 @@ tolerations: [] affinity: {} # env defines the environment variables that will be declared in the pod -env: - urls: - # configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap). - configmap: - - name: IdentityUrl - key: internalurls__identity - - name: CatalogUrlHC - key: internalurls__catalog__hc - - name: BasketUrlHC - key: internalurls__basket__hc - - name: IdentityUrlHC - key: internalurls__identity__hc - - name: OrderingUrlHC - key: internalurls__ordering__hc - - name: MarketingUrlHC - key: internalurls__marketing__hc - - name: PaymentUrlHC - key: internalurls__payment__hc - - name: LocationUrlHC - key: internalurls__location__hc - # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) - values: - - name: ASPNETCORE_ENVIRONMENT - value: Development +env: {} + +envoy: + configPath: /etc/envoy + probes: liveness: - path: /liveness - initialDelaySeconds: 10 + path: /ready + initialDelaySeconds: 5 periodSeconds: 15 - port: 80 + port: 8001 readiness: - path: /hc - timeoutSeconds: 5 - initialDelaySeconds: 90 + path: /ready + initialDelaySeconds: 5 periodSeconds: 60 - port: 80 -ocelot: - configPath: /app/configuration \ No newline at end of file + port: 8001 \ No newline at end of file diff --git a/k8s/helm/app.yaml b/k8s/helm/app.yaml index 91e829b27..d57fd8836 100644 --- a/k8s/helm/app.yaml +++ b/k8s/helm/app.yaml @@ -25,12 +25,12 @@ app: # app global settings webhooks: webhooks-api # ingress entry for webhooks api webhooksweb: webhooks-web # ingress entry for webhooks web demo client svc: - basket: basket # service name for basket api - catalog: catalog # service name for catalog api - ordering: ordering # service name for ordering api - orderingbackgroundtasks: orderingbackgroundtasks # service name for orderingbackgroundtasks + basket: basket-api # service name for basket api + catalog: catalog-api # service name for catalog api + ordering: ordering-api # service name for ordering api + orderingbackgroundtasks: ordering-backgroundtasks # service name for orderingbackgroundtasks orderingsignalrhub: ordering-signalrhub # service name for orderingsignalrhub - identity: identity # service name for identity api + identity: identity-api # service name for identity api mvc: webmvc # service name for web mvc spa: webspa # service name for web spa status: webstatus # service name for web status @@ -40,8 +40,8 @@ app: # app global settings mobileshoppingapigw: mobileshoppingapigw # service name for mobile shopping Agw webshoppingagg: webshoppingagg # service name for web shopping aggregator mobileshoppingagg: mobileshoppingagg # service name for mobile shopping aggregator - payment: payment # service name for payment api - locations: locations # service name for locations api - marketing: marketing # service name for marketing ap - webhooks: webhooks # service name for webhooks api - webhooksweb: webhooksweb # service name for webhooks web + payment: payment-api # service name for payment api + locations: locations-api # service name for locations api + marketing: marketing-api # service name for marketing ap + webhooks: webhooks-api # service name for webhooks api + webhooksweb: webhooks-client # service name for webhooks web diff --git a/k8s/helm/basket-api/templates/configmap.yaml b/k8s/helm/basket-api/templates/configmap.yaml index 911318fc1..2de0e28c7 100644 --- a/k8s/helm/basket-api/templates/configmap.yaml +++ b/k8s/helm/basket-api/templates/configmap.yaml @@ -1,5 +1,4 @@ {{- $name := include "basket-api.fullname" . -}} -{{- $identity := include "url-of" (list .Values.app.ingress.entries.identity .) -}} apiVersion: v1 kind: ConfigMap @@ -12,7 +11,7 @@ metadata: heritage: {{ .Release.Service }} data: basket__ConnectionString: {{ .Values.inf.redis.basket.constr }} - urls__IdentityUrl: http://{{ $identity }} + urls__IdentityUrl: http://{{ .Values.app.svc.identity }} basket__EnableLoadTest: "{{ .Values.inf.misc.useLoadTest }}" all__EventBusConnection: {{ .Values.inf.eventbus.constr }} all__InstrumentationKey: "{{ .Values.inf.appinsights.key }}" diff --git a/k8s/helm/basket-api/templates/deployment.yaml b/k8s/helm/basket-api/templates/deployment.yaml index d96c0cacf..dc90666f5 100644 --- a/k8s/helm/basket-api/templates/deployment.yaml +++ b/k8s/helm/basket-api/templates/deployment.yaml @@ -21,6 +21,10 @@ spec: labels: app: {{ template "basket-api.name" . }} release: {{ .Release.Name }} + {{ if .Values.inf.mesh.enabled -}} + annotations: + linkerd.io/inject: enabled + {{- end }} spec: {{ if .Values.inf.registry -}} imagePullSecrets: @@ -75,6 +79,9 @@ spec: - name: http containerPort: 80 protocol: TCP + - name: grpc + containerPort: 81 + protocol: TCP resources: {{ toYaml .Values.resources | indent 12 }} {{- with .Values.nodeSelector }} diff --git a/k8s/helm/basket-api/templates/ingress.yaml b/k8s/helm/basket-api/templates/ingress.yaml index f99bd55a6..83745a1fe 100644 --- a/k8s/helm/basket-api/templates/ingress.yaml +++ b/k8s/helm/basket-api/templates/ingress.yaml @@ -15,6 +15,11 @@ metadata: annotations: {{ toYaml . | indent 4 }} {{- end }} +{{- if .Values.inf.mesh.enabled }} +{{- with .Values.ingress.mesh.annotations }} +{{ toYaml . | indent 4 }} +{{- end }} +{{- end }} spec: {{- if .Values.ingress.tls }} tls: diff --git a/k8s/helm/basket-api/templates/service.yaml b/k8s/helm/basket-api/templates/service.yaml index 20224c3b5..1783c59aa 100644 --- a/k8s/helm/basket-api/templates/service.yaml +++ b/k8s/helm/basket-api/templates/service.yaml @@ -14,6 +14,10 @@ spec: targetPort: http protocol: TCP name: http + - port: {{ .Values.service.grpcPort }} + targetPort: grpc + protocol: TCP + name: grpc selector: app: {{ template "basket-api.name" . }} release: {{ .Release.Name }} diff --git a/k8s/helm/basket-api/values.yaml b/k8s/helm/basket-api/values.yaml index a773700fe..121de02de 100644 --- a/k8s/helm/basket-api/values.yaml +++ b/k8s/helm/basket-api/values.yaml @@ -10,6 +10,7 @@ image: service: type: ClusterIP port: 80 + grpcPort: 81 resources: {} @@ -41,6 +42,10 @@ env: values: - name: OrchestratorType value: 'K8S' + - name: PORT + value: "80" + - name: GRPC_PORT + value: "81" probes: liveness: path: /liveness diff --git a/k8s/helm/catalog-api/templates/configmap.yaml b/k8s/helm/catalog-api/templates/configmap.yaml index 902b65f5c..d85929080 100644 --- a/k8s/helm/catalog-api/templates/configmap.yaml +++ b/k8s/helm/catalog-api/templates/configmap.yaml @@ -13,7 +13,7 @@ metadata: heritage: {{ .Release.Service }} data: catalog__ConnectionString: Server={{ $sqlsrv }};Initial Catalog={{ .Values.inf.sql.catalog.db }};User Id={{ .Values.inf.sql.common.user }};Password={{ .Values.inf.sql.common.pwd }}; - catalog__PicBaseUrl: http://{{ $webshoppingapigw }}/api/v1/c/catalog/items/[0]/pic/ + catalog__PicBaseUrl: http://{{ $webshoppingapigw }}/c/api/v1/catalog/items/[0]/pic/ catalog__AzureStorageEnabled: "{{ .Values.inf.misc.useAzureStorage }}" all__EventBusConnection: {{ .Values.inf.eventbus.constr }} all__InstrumentationKey: "{{ .Values.inf.appinsights.key }}" diff --git a/k8s/helm/catalog-api/templates/deployment.yaml b/k8s/helm/catalog-api/templates/deployment.yaml index d7a424a99..33a0ad5b4 100644 --- a/k8s/helm/catalog-api/templates/deployment.yaml +++ b/k8s/helm/catalog-api/templates/deployment.yaml @@ -21,6 +21,10 @@ spec: labels: app: {{ template "catalog-api.name" . }} release: {{ .Release.Name }} + {{ if .Values.inf.mesh.enabled -}} + annotations: + linkerd.io/inject: enabled + {{- end }} spec: {{ if .Values.inf.registry -}} imagePullSecrets: @@ -75,6 +79,9 @@ spec: - name: http containerPort: 80 protocol: TCP + - name: grpc + containerPort: 81 + protocol: TCP resources: {{ toYaml .Values.resources | indent 12 }} {{- with .Values.nodeSelector }} diff --git a/k8s/helm/catalog-api/templates/ingress.yaml b/k8s/helm/catalog-api/templates/ingress.yaml index 238d7b07e..234be0826 100644 --- a/k8s/helm/catalog-api/templates/ingress.yaml +++ b/k8s/helm/catalog-api/templates/ingress.yaml @@ -15,6 +15,11 @@ metadata: annotations: {{ toYaml . | indent 4 }} {{- end }} +{{- if .Values.inf.mesh.enabled }} +{{- with .Values.ingress.mesh.annotations }} +{{ toYaml . | indent 4 }} +{{- end }} +{{- end }} spec: {{- if .Values.ingress.tls }} tls: diff --git a/k8s/helm/catalog-api/templates/service.yaml b/k8s/helm/catalog-api/templates/service.yaml index e63d4a4fc..f634a7088 100644 --- a/k8s/helm/catalog-api/templates/service.yaml +++ b/k8s/helm/catalog-api/templates/service.yaml @@ -14,6 +14,10 @@ spec: targetPort: http protocol: TCP name: http + - port: {{ .Values.service.grpcPort }} + targetPort: grpc + protocol: TCP + name: grpc selector: app: {{ template "catalog-api.name" . }} release: {{ .Release.Name }} diff --git a/k8s/helm/catalog-api/values.yaml b/k8s/helm/catalog-api/values.yaml index 836db6125..0de49b7f6 100644 --- a/k8s/helm/catalog-api/values.yaml +++ b/k8s/helm/catalog-api/values.yaml @@ -10,7 +10,7 @@ image: service: type: ClusterIP port: 80 - + grpcPort: 81 resources: {} @@ -44,6 +44,10 @@ env: value: Development - name: OrchestratorType value: 'K8S' + - name: PORT + value: "80" + - name: GRPC_PORT + value: "81" probes: liveness: path: /liveness diff --git a/k8s/helm/deploy-all.ps1 b/k8s/helm/deploy-all.ps1 index 9b02ab5fe..ae49de625 100644 --- a/k8s/helm/deploy-all.ps1 +++ b/k8s/helm/deploy-all.ps1 @@ -11,7 +11,10 @@ Param( [parameter(Mandatory=$false)][string]$aksRg="", [parameter(Mandatory=$false)][string]$imageTag="latest", [parameter(Mandatory=$false)][bool]$useLocalk8s=$false, - [parameter(Mandatory=$false)][bool]$useLocalImages=$false + [parameter(Mandatory=$false)][bool]$useMesh=$false, + [parameter(Mandatory=$false)][string][ValidateSet('Always','IfNotPresent','Never', IgnoreCase=$false)]$imagePullPolicy="Always", + [parameter(Mandatory=$false)][string]$chartsToDeploy="*", + [parameter(Mandatory=$false)][string]$ingressMeshAnnotationsFile="ingress_values_linkerd.yaml" ) $dns = $externalDns @@ -23,12 +26,6 @@ if ($useLocalk8s -eq $true) { $dns="localhost" } -$pullPolicy = "Always" - -if ($useLocalImages -eq $true) { - $pullPolicy = "IfNotPresent" -} - if ($externalDns -eq "aks") { if ([string]::IsNullOrEmpty($aksName) -or [string]::IsNullOrEmpty($aksRg)) { Write-Host "Error: When using -dns aks, MUST set -aksName and -aksRg too." -ForegroundColor Red @@ -69,7 +66,8 @@ if (-not [string]::IsNullOrEmpty($registry)) { Write-Host "Begin eShopOnContainers installation using Helm" -ForegroundColor Green $infras = ("sql-data", "nosql-data", "rabbitmq", "keystore-data", "basket-data") -$charts = ("eshop-common", "apigwmm", "apigwms", "apigwwm", "apigwws", "basket-api","catalog-api", "identity-api", "locations-api", "marketing-api", "mobileshoppingagg","ordering-api","ordering-backgroundtasks","ordering-signalrhub", "payment-api", "webmvc", "webshoppingagg", "webspa", "webstatus", "webhooks-api", "webhooks-web") +$charts = ("eshop-common", "basket-api","catalog-api", "identity-api", "locations-api", "marketing-api", "mobileshoppingagg","ordering-api","ordering-backgroundtasks","ordering-signalrhub", "payment-api", "webmvc", "webshoppingagg", "webspa", "webstatus", "webhooks-api", "webhooks-web") +$gateways = ("apigwmm", "apigwms", "apigwwm", "apigwws") if ($deployInfrastructure) { foreach ($infra in $infras) { @@ -83,14 +81,23 @@ else { if ($deployCharts) { foreach ($chart in $charts) { - Write-Host "Installing: $chart" -ForegroundColor Green - if ($useCustomRegistry) { - helm install --set inf.registry.server=$registry --set inf.registry.login=$dockerUser --set inf.registry.pwd=$dockerPassword --set inf.registry.secretName=eshop-docker-scret --values app.yaml --values inf.yaml --values $ingressValuesFile --set app.name=$appName --set inf.k8s.dns=$dns --set "ingress.hosts={$dns}" --set image.tag=$imageTag --set image.pullPolicy=Always --name="$appName-$chart" $chart - } - else { - if ($chart -ne "eshop-common") { # eshop-common is ignored when no secret must be deployed - helm install --values app.yaml --values inf.yaml --values $ingressValuesFile --set app.name=$appName --set inf.k8s.dns=$dns --set "ingress.hosts={$dns}" --set image.tag=$imageTag --set image.pullPolicy=$pullPolicy --name="$appName-$chart" $chart + if ($chartsToDeploy -eq "*" -or $chartsToDeploy.Contains($chart)) { + Write-Host "Installing: $chart" -ForegroundColor Green + if ($useCustomRegistry) { + helm install --set inf.registry.server=$registry --set inf.registry.login=$dockerUser --set inf.registry.pwd=$dockerPassword --set inf.registry.secretName=eshop-docker-scret --values app.yaml --values inf.yaml --values $ingressValuesFile --values $ingressMeshAnnotationsFile --set app.name=$appName --set inf.k8s.dns=$dns --set "ingress.hosts={$dns}" --set image.tag=$imageTag --set image.pullPolicy=$imagePullPolicy --set inf.mesh.enabled=$useMesh --set inf.k8s.local=$useLocalk8s --name="$appName-$chart" $chart } + else { + if ($chart -ne "eshop-common") { # eshop-common is ignored when no secret must be deployed + helm install --values app.yaml --values inf.yaml --values $ingressValuesFile --values $ingressMeshAnnotationsFile --set app.name=$appName --set inf.k8s.dns=$dns --set "ingress.hosts={$dns}" --set image.tag=$imageTag --set image.pullPolicy=$imagePullPolicy --set inf.mesh.enabled=$useMesh --set inf.k8s.local=$useLocalk8s --name="$appName-$chart" $chart + } + } + } + } + + foreach ($chart in $gateways) { + if ($chartsToDeploy -eq "*" -or $chartsToDeploy.Contains($chart)) { + Write-Host "Installing Api Gateway Chart: $chart" -ForegroundColor Green + helm install --values app.yaml --values inf.yaml --values $ingressValuesFile --values $ingressMeshAnnotationsFile --set app.name=$appName --set inf.k8s.dns=$dns --set "ingress.hosts={$dns}" --set image.pullPolicy=$imagePullPolicy --set inf.mesh.enabled=$useMesh --name="$appName-$chart" $chart } } } diff --git a/k8s/helm/identity-api/templates/deployment.yaml b/k8s/helm/identity-api/templates/deployment.yaml index 0a4ee2722..c6ad69067 100644 --- a/k8s/helm/identity-api/templates/deployment.yaml +++ b/k8s/helm/identity-api/templates/deployment.yaml @@ -21,6 +21,10 @@ spec: labels: app: {{ template "identity-api.name" . }} release: {{ .Release.Name }} + {{ if .Values.inf.mesh.enabled -}} + annotations: + linkerd.io/inject: enabled + {{- end }} spec: {{ if .Values.inf.registry -}} imagePullSecrets: diff --git a/k8s/helm/identity-api/templates/ingress-dockerk8s.yaml b/k8s/helm/identity-api/templates/ingress-dockerk8s.yaml new file mode 100644 index 000000000..b6a8980f2 --- /dev/null +++ b/k8s/helm/identity-api/templates/ingress-dockerk8s.yaml @@ -0,0 +1,33 @@ +{{- if .Values.ingress.enabled -}} +{{- if .Values.inf.k8s.local -}} +{{- $ingressPath := include "pathBase" . -}} +{{- $serviceName := .Values.app.svc.identity }} +{{- $name := include "identity-api.fullname" . -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ $name }}-local + labels: + app: {{ template "identity-api.name" . }} + chart: {{ template "identity-api.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +{{- if .Values.inf.mesh.enabled }} +{{- with .Values.ingress.mesh.annotations }} +{{ toYaml . | indent 4 }} +{{- end }} +{{- end }} +spec: + rules: + - http: + paths: + - backend: + serviceName: {{ $serviceName }} + servicePort: http + path: {{ $ingressPath }} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/identity-api/templates/ingress.yaml b/k8s/helm/identity-api/templates/ingress.yaml index 1d2d3d5d5..56ce5d8bf 100644 --- a/k8s/helm/identity-api/templates/ingress.yaml +++ b/k8s/helm/identity-api/templates/ingress.yaml @@ -14,6 +14,11 @@ metadata: annotations: {{ toYaml . | indent 4 }} {{- end }} +{{- if .Values.inf.mesh.enabled }} +{{- with .Values.ingress.mesh.annotations }} +{{ toYaml . | indent 4 }} +{{- end }} +{{- end }} spec: {{- if .Values.ingress.tls }} tls: diff --git a/k8s/helm/inf.yaml b/k8s/helm/inf.yaml index ee4d1fde6..073233ad7 100644 --- a/k8s/helm/inf.yaml +++ b/k8s/helm/inf.yaml @@ -2,6 +2,8 @@ # It is used on all charts, so ** MUST BE INCLUDED ** on every deployment inf: + mesh: + enabled: true sql: # inf.sql defines the sql server databases & logins # host: my-sql-server # Uncomment to specify a custom sql-server to be used. By default "sql-data-" will be used common: @@ -39,6 +41,7 @@ inf: key: "" # App insights to use k8s: # inf.k8s defines Kubernetes cluster global config dns: "" # k8s external DNS. This value or ip value MUST BE PROVIDED + local: false # True when deploying on "local K8s" provided by Docker Desktop. misc: # inf.misc contains miscellaneous configuration related to infrastructure useLoadTest: false # If running under loading test or not useAzureStorage: false # If catalog api uses azure storage or not diff --git a/k8s/helm/ingress_values.yaml b/k8s/helm/ingress_values.yaml index 88540574d..5f4d653c0 100644 --- a/k8s/helm/ingress_values.yaml +++ b/k8s/helm/ingress_values.yaml @@ -1,5 +1,8 @@ +# This file contains common ingress annotations when using AKS with Http Application Routing + ingress: annotations: kubernetes.io/ingress.class: addon-http-application-routing ingress.kubernetes.io/ssl-redirect: "false" nginx.ingress.kubernetes.io/ssl-redirect: "false" + diff --git a/k8s/helm/ingress_values_dockerk8s.yaml b/k8s/helm/ingress_values_dockerk8s.yaml index 75597aac9..f69af8a5b 100644 --- a/k8s/helm/ingress_values_dockerk8s.yaml +++ b/k8s/helm/ingress_values_dockerk8s.yaml @@ -1,3 +1,5 @@ +# This file contains common ingress annotations when using Kubernetes included in Docker Desktop + ingress: annotations: kubernetes.io/ingress.class: "nginx" diff --git a/k8s/helm/ingress_values_linkerd.yaml b/k8s/helm/ingress_values_linkerd.yaml new file mode 100644 index 000000000..f85a3a57f --- /dev/null +++ b/k8s/helm/ingress_values_linkerd.yaml @@ -0,0 +1,16 @@ +# This file contains extra annotations to make Linkerd work with ingress. +# ingress.mesh.annotations are inserted into ingress.annotations of the resource being generated, if mesh is deployed +# +# It is designed to work with NGINX ingress controller or the Http Application Routing +# +# Check https://linkerd.io/2/tasks/using-ingress/ for more info or other ingress controllers +# +# If using your custom file, use -ingressMeshAnnotationsFile parameter in deploy-all.ps1 + +ingress: + mesh: + annotations: + nginx.ingress.kubernetes.io/configuration-snippet: | + proxy_set_header l5d-dst-override $service_name.$namespace.svc.cluster.local:$service_port; + proxy_hide_header l5d-remote-ip; + proxy_hide_header l5d-server-id; \ No newline at end of file diff --git a/k8s/helm/istio/doc.md b/k8s/helm/istio/doc.md index b8c0a0257..5694fe30b 100644 --- a/k8s/helm/istio/doc.md +++ b/k8s/helm/istio/doc.md @@ -173,7 +173,7 @@ The file `inf.yaml` contains the description of the infrastructure used. File is Using Azure storage for catalog (and marketing) photos is not directly supported, but you can accomplish it by editing the file `k8s/helm/catalog-api/templates/configmap.yaml`. Search for lines: ``` -catalog__PicBaseUrl: http://{{ $webshoppingapigw }}/api/v1/c/catalog/items/[0]/pic/ +catalog__PicBaseUrl: http://{{ $webshoppingapigw }}/c/api/v1/catalog/items/[0]/pic/ ``` And replace it for: @@ -185,7 +185,7 @@ catalog__PicBaseUrl: http:/// In the same way, to use Azure storage for the marketing service, have to edit the file `k8s/helm/marketing-api/templates/configmap.yaml` and replacing the line: ``` -marketing__PicBaseUrl: http://{{ $webshoppingapigw }}/api/v1/c/catalog/items/[0]/pic/ +marketing__PicBaseUrl: http://{{ $webshoppingapigw }}/c/api/v1/catalog/items/[0]/pic/ ``` by: diff --git a/k8s/helm/locations-api/templates/deployment.yaml b/k8s/helm/locations-api/templates/deployment.yaml index 9667eb967..9a5bb608c 100644 --- a/k8s/helm/locations-api/templates/deployment.yaml +++ b/k8s/helm/locations-api/templates/deployment.yaml @@ -21,6 +21,10 @@ spec: labels: app: {{ template "locations-api.name" . }} release: {{ .Release.Name }} + {{ if .Values.inf.mesh.enabled -}} + annotations: + linkerd.io/inject: enabled + {{- end }} spec: {{ if .Values.inf.registry -}} imagePullSecrets: diff --git a/k8s/helm/locations-api/templates/ingress.yaml b/k8s/helm/locations-api/templates/ingress.yaml index 8c846944e..5254ba5c0 100644 --- a/k8s/helm/locations-api/templates/ingress.yaml +++ b/k8s/helm/locations-api/templates/ingress.yaml @@ -14,6 +14,11 @@ metadata: annotations: {{ toYaml . | indent 4 }} {{- end }} +{{- if .Values.inf.mesh.enabled }} +{{- with .Values.ingress.mesh.annotations }} +{{ toYaml . | indent 4 }} +{{- end }} +{{- end }} spec: {{- if .Values.ingress.tls }} tls: diff --git a/k8s/helm/marketing-api/templates/configmap.yaml b/k8s/helm/marketing-api/templates/configmap.yaml index 123b21adf..aa68f3003 100644 --- a/k8s/helm/marketing-api/templates/configmap.yaml +++ b/k8s/helm/marketing-api/templates/configmap.yaml @@ -23,4 +23,4 @@ data: marketing__ConnectionString: Server={{ $sqlsrv }};Initial Catalog={{ .Values.inf.sql.marketing.db }};User Id={{ .Values.inf.sql.common.user }};Password={{ .Values.inf.sql.common.pwd }}; marketing__MongoConnectionString: mongodb://{{ $mongo }} marketing__MongoDatabase: {{ .Values.inf.mongo.marketing.database }} - marketing__PicBaseUrl: http://{{ $webshoppingapigw }}/api/v1/c/catalog/items/[0]/pic/ \ No newline at end of file + marketing__PicBaseUrl: http://{{ $webshoppingapigw }}/c/api/v1/catalog/items/[0]/pic/ \ No newline at end of file diff --git a/k8s/helm/marketing-api/templates/deployment.yaml b/k8s/helm/marketing-api/templates/deployment.yaml index c49026c1b..60d4cd1a3 100644 --- a/k8s/helm/marketing-api/templates/deployment.yaml +++ b/k8s/helm/marketing-api/templates/deployment.yaml @@ -21,6 +21,10 @@ spec: labels: app: {{ template "marketing-api.name" . }} release: {{ .Release.Name }} + {{ if .Values.inf.mesh.enabled -}} + annotations: + linkerd.io/inject: enabled + {{- end }} spec: {{ if .Values.inf.registry -}} imagePullSecrets: diff --git a/k8s/helm/marketing-api/templates/ingress.yaml b/k8s/helm/marketing-api/templates/ingress.yaml index 7a5b29b12..94c470f49 100644 --- a/k8s/helm/marketing-api/templates/ingress.yaml +++ b/k8s/helm/marketing-api/templates/ingress.yaml @@ -14,6 +14,11 @@ metadata: annotations: {{ toYaml . | indent 4 }} {{- end }} +{{- if .Values.inf.mesh.enabled }} +{{- with .Values.ingress.mesh.annotations }} +{{ toYaml . | indent 4 }} +{{- end }} +{{- end }} spec: {{- if .Values.ingress.tls }} tls: diff --git a/k8s/helm/mobileshoppingagg/templates/configmap.yaml b/k8s/helm/mobileshoppingagg/templates/configmap.yaml index 6cad653a9..1ca69509f 100644 --- a/k8s/helm/mobileshoppingagg/templates/configmap.yaml +++ b/k8s/helm/mobileshoppingagg/templates/configmap.yaml @@ -24,3 +24,6 @@ data: internalurls__marketing__hc: http://{{ .Values.app.svc.marketing }}/hc internalurls__payment__hc: http://{{ .Values.app.svc.payment }}/hc internalurls__location__hc: http://{{ .Values.app.svc.locations }}/hc + internalurls__grpcBasket: "http://{{ .Values.app.svc.basket }}:{{ .Values.service.grpcPort }}" + internalurls__grpcCatalog: "http://{{ .Values.app.svc.catalog }}:{{ .Values.service.grpcPort }}" + internalurls__grpcOrdering: "http://{{ .Values.app.svc.ordering }}:{{ .Values.service.grpcPort }}" diff --git a/k8s/helm/mobileshoppingagg/templates/deployment.yaml b/k8s/helm/mobileshoppingagg/templates/deployment.yaml index 0f23b3be6..41e1fa75c 100644 --- a/k8s/helm/mobileshoppingagg/templates/deployment.yaml +++ b/k8s/helm/mobileshoppingagg/templates/deployment.yaml @@ -21,6 +21,10 @@ spec: labels: app: {{ template "mobileshoppingagg.name" . }} release: {{ .Release.Name }} + {{ if .Values.inf.mesh.enabled -}} + annotations: + linkerd.io/inject: enabled + {{- end }} spec: {{ if .Values.inf.registry -}} imagePullSecrets: diff --git a/k8s/helm/mobileshoppingagg/templates/ingress.yaml b/k8s/helm/mobileshoppingagg/templates/ingress.yaml index 6c50a574e..c87af986b 100644 --- a/k8s/helm/mobileshoppingagg/templates/ingress.yaml +++ b/k8s/helm/mobileshoppingagg/templates/ingress.yaml @@ -14,6 +14,11 @@ metadata: annotations: {{ toYaml . | indent 4 }} {{- end }} +{{- if .Values.inf.mesh.enabled }} +{{- with .Values.ingress.mesh.annotations }} +{{ toYaml . | indent 4 }} +{{- end }} +{{- end }} spec: {{- if .Values.ingress.tls }} tls: diff --git a/k8s/helm/mobileshoppingagg/values.yaml b/k8s/helm/mobileshoppingagg/values.yaml index fd26c7794..844a59441 100644 --- a/k8s/helm/mobileshoppingagg/values.yaml +++ b/k8s/helm/mobileshoppingagg/values.yaml @@ -10,6 +10,7 @@ image: service: type: ClusterIP port: 80 + grpcPort: 81 ingress: enabled: false @@ -54,6 +55,12 @@ env: key: internalurls__payment__hc - name: LocationUrlHC key: internalurls__location__hc + - name: urls__grpcBasket + key: internalurls__grpcBasket + - name: urls__grpcCatalog + key: internalurls__grpcCatalog + - name: urls__grpcOrdering + key: internalurls__grpcOrdering # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) values: - name: ASPNETCORE_ENVIRONMENT diff --git a/k8s/helm/ordering-api/templates/configmap.yaml b/k8s/helm/ordering-api/templates/configmap.yaml index efc829cda..e64a6c841 100644 --- a/k8s/helm/ordering-api/templates/configmap.yaml +++ b/k8s/helm/ordering-api/templates/configmap.yaml @@ -1,6 +1,5 @@ {{- $name := include "ordering-api.fullname" . -}} {{- $sqlsrv := include "sql-name" . -}} -{{- $identity := include "url-of" (list .Values.app.ingress.entries.identity .) -}} apiVersion: v1 kind: ConfigMap @@ -14,7 +13,7 @@ metadata: data: ordering__ConnectionString: Server={{ $sqlsrv }};Initial Catalog={{ .Values.inf.sql.ordering.db }};User Id={{ .Values.inf.sql.common.user }};Password={{ .Values.inf.sql.common.pwd }}; ordering__EnableLoadTest: "{{ .Values.inf.misc.useLoadTest }}" - urls__IdentityUrl: http://{{ $identity }} + urls__IdentityUrl: http://{{ .Values.app.svc.identity }} all__EventBusConnection: {{ .Values.inf.eventbus.constr }} all__InstrumentationKey: "{{ .Values.inf.appinsights.key }}" all__UseAzureServiceBus: "{{ .Values.inf.eventbus.useAzure }}" \ No newline at end of file diff --git a/k8s/helm/ordering-api/templates/deployment.yaml b/k8s/helm/ordering-api/templates/deployment.yaml index a99ccdc28..327040701 100644 --- a/k8s/helm/ordering-api/templates/deployment.yaml +++ b/k8s/helm/ordering-api/templates/deployment.yaml @@ -21,6 +21,10 @@ spec: labels: app: {{ template "ordering-api.name" . }} release: {{ .Release.Name }} + {{ if .Values.inf.mesh.enabled -}} + annotations: + linkerd.io/inject: enabled + {{- end }} spec: {{ if .Values.inf.registry -}} imagePullSecrets: @@ -75,6 +79,9 @@ spec: - name: http containerPort: 80 protocol: TCP + - name: grpc + containerPort: 81 + protocol: TCP resources: {{ toYaml .Values.resources | indent 12 }} {{- with .Values.nodeSelector }} diff --git a/k8s/helm/ordering-api/templates/service.yaml b/k8s/helm/ordering-api/templates/service.yaml index bedfd6f01..7c2cb0945 100644 --- a/k8s/helm/ordering-api/templates/service.yaml +++ b/k8s/helm/ordering-api/templates/service.yaml @@ -14,6 +14,10 @@ spec: targetPort: http protocol: TCP name: http + - port: {{ .Values.service.grpcPort }} + targetPort: grpc + protocol: TCP + name: grpc selector: app: {{ template "ordering-api.name" . }} release: {{ .Release.Name }} diff --git a/k8s/helm/ordering-api/values.yaml b/k8s/helm/ordering-api/values.yaml index c717d2793..7eff1a48b 100644 --- a/k8s/helm/ordering-api/values.yaml +++ b/k8s/helm/ordering-api/values.yaml @@ -10,6 +10,7 @@ image: service: type: ClusterIP port: 80 + grpcPort: 81 ingress: enabled: false @@ -50,6 +51,10 @@ env: value: Development - name: OrchestratorType value: 'K8S' + - name: PORT + value: "80" + - name: GRPC_PORT + value: "81" probes: liveness: path: /liveness diff --git a/k8s/helm/payment-api/templates/deployment.yaml b/k8s/helm/payment-api/templates/deployment.yaml index 8b01f7394..f83eb37da 100644 --- a/k8s/helm/payment-api/templates/deployment.yaml +++ b/k8s/helm/payment-api/templates/deployment.yaml @@ -21,6 +21,10 @@ spec: labels: app: {{ template "payment-api.name" . }} release: {{ .Release.Name }} + {{ if .Values.inf.mesh.enabled -}} + annotations: + linkerd.io/inject: enabled + {{- end }} spec: {{ if .Values.inf.registry -}} imagePullSecrets: diff --git a/k8s/helm/webhooks-api/templates/deployment.yaml b/k8s/helm/webhooks-api/templates/deployment.yaml index 9eef1d6f1..2ecb885bf 100644 --- a/k8s/helm/webhooks-api/templates/deployment.yaml +++ b/k8s/helm/webhooks-api/templates/deployment.yaml @@ -21,6 +21,10 @@ spec: labels: app: {{ template "webhooks-api.name" . }} release: {{ .Release.Name }} + {{ if .Values.inf.mesh.enabled -}} + annotations: + linkerd.io/inject: enabled + {{- end }} spec: {{ if .Values.inf.registry -}} imagePullSecrets: diff --git a/k8s/helm/webhooks-api/templates/ingress.yaml b/k8s/helm/webhooks-api/templates/ingress.yaml index debf0f84a..1f46b2eb6 100644 --- a/k8s/helm/webhooks-api/templates/ingress.yaml +++ b/k8s/helm/webhooks-api/templates/ingress.yaml @@ -14,6 +14,11 @@ metadata: annotations: {{ toYaml . | indent 4 }} {{- end }} +{{- if .Values.inf.mesh.enabled }} +{{- with .Values.ingress.mesh.annotations }} +{{ toYaml . | indent 4 }} +{{- end }} +{{- end }} spec: {{- if .Values.ingress.tls }} tls: diff --git a/k8s/helm/webhooks-web/templates/deployment.yaml b/k8s/helm/webhooks-web/templates/deployment.yaml index 4c930124a..43d406524 100644 --- a/k8s/helm/webhooks-web/templates/deployment.yaml +++ b/k8s/helm/webhooks-web/templates/deployment.yaml @@ -21,6 +21,10 @@ spec: labels: app: {{ template "webhooks-web.name" . }} release: {{ .Release.Name }} + {{ if .Values.inf.mesh.enabled -}} + annotations: + linkerd.io/inject: enabled + {{- end }} spec: {{ if .Values.inf.registry -}} imagePullSecrets: diff --git a/k8s/helm/webmvc/templates/configmap.yaml b/k8s/helm/webmvc/templates/configmap.yaml index 3e1e10cd1..ac94f5194 100644 --- a/k8s/helm/webmvc/templates/configmap.yaml +++ b/k8s/helm/webmvc/templates/configmap.yaml @@ -3,7 +3,6 @@ {{- $webshoppingapigw := include "url-of" (list .Values.app.ingress.entries.webshoppingapigw .) -}} {{- $mvc := include "url-of" (list .Values.app.ingress.entries.mvc .) -}} - apiVersion: v1 kind: ConfigMap metadata: @@ -20,9 +19,7 @@ data: webmvc__keystore: {{ .Values.inf.redis.keystore.constr }} internalurls__apigwws: http://{{ .Values.app.svc.webshoppingapigw }} internalurls__apigwwm: http://{{ .Values.app.svc.webmarketingapigw }} - internalurls__apigwws__hc: http://{{ .Values.app.svc.webshoppingapigw }}/hc internalurls__identity__hc: http://{{ .Values.app.svc.identity }}/hc - internalurls__apigwwm__hc: http://{{ .Values.app.svc.webmarketingapigw }}/hc urls__apigwws: http://{{ $webshoppingapigw }} urls__mvc: http://{{ $mvc }} urls__IdentityUrl: http://{{ $identity }} diff --git a/k8s/helm/webmvc/templates/deployment.yaml b/k8s/helm/webmvc/templates/deployment.yaml index d972db448..2889dc757 100644 --- a/k8s/helm/webmvc/templates/deployment.yaml +++ b/k8s/helm/webmvc/templates/deployment.yaml @@ -21,6 +21,10 @@ spec: labels: app: {{ template "webmvc.name" . }} release: {{ .Release.Name }} + {{ if .Values.inf.mesh.enabled -}} + annotations: + linkerd.io/inject: enabled + {{- end }} spec: {{ if .Values.inf.registry -}} imagePullSecrets: diff --git a/k8s/helm/webmvc/templates/ingress-dockerk8s.yaml b/k8s/helm/webmvc/templates/ingress-dockerk8s.yaml new file mode 100644 index 000000000..72e043039 --- /dev/null +++ b/k8s/helm/webmvc/templates/ingress-dockerk8s.yaml @@ -0,0 +1,33 @@ +{{- if .Values.ingress.enabled -}} +{{- if .Values.inf.k8s.local -}} +{{- $ingressPath := include "pathBase" . -}} +{{- $serviceName := .Values.app.svc.mvc }} +{{- $name := include "webmvc.fullname" . -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ $name }}-local + labels: + app: {{ template "webmvc.name" . }} + chart: {{ template "webmvc.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +{{- if .Values.inf.mesh.enabled }} +{{- with .Values.ingress.mesh.annotations }} +{{ toYaml . | indent 4 }} +{{- end }} +{{- end }} +spec: + rules: + - http: + paths: + - backend: + serviceName: {{ $serviceName }} + servicePort: http + path: {{ $ingressPath }} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/k8s/helm/webmvc/templates/ingress.yaml b/k8s/helm/webmvc/templates/ingress.yaml index 892fa4273..1195bd4a6 100644 --- a/k8s/helm/webmvc/templates/ingress.yaml +++ b/k8s/helm/webmvc/templates/ingress.yaml @@ -14,6 +14,11 @@ metadata: annotations: {{ toYaml . | indent 4 }} {{- end }} +{{- if .Values.inf.mesh.enabled }} +{{- with .Values.ingress.mesh.annotations }} +{{ toYaml . | indent 4 }} +{{- end }} +{{- end }} spec: {{- if .Values.ingress.tls }} tls: diff --git a/k8s/helm/webmvc/values.yaml b/k8s/helm/webmvc/values.yaml index f4d077fc2..973f187f5 100644 --- a/k8s/helm/webmvc/values.yaml +++ b/k8s/helm/webmvc/values.yaml @@ -46,12 +46,8 @@ env: key: urls__IdentityUrl - name: MarketingUrl key: internalurls__apigwwm - - name: PurchaseUrlHC - key: internalurls__apigwws__hc - name: IdentityUrlHC key: internalurls__identity__hc - - name: MarketingUrlHC - key: internalurls__apigwwm__hc - name: SignalrHubUrl key: urls__apigwws # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) diff --git a/k8s/helm/webshoppingagg/templates/configmap.yaml b/k8s/helm/webshoppingagg/templates/configmap.yaml index efa3c7eaf..d01de8dcd 100644 --- a/k8s/helm/webshoppingagg/templates/configmap.yaml +++ b/k8s/helm/webshoppingagg/templates/configmap.yaml @@ -24,3 +24,6 @@ data: internalurls__marketing__hc: http://{{ .Values.app.svc.marketing }}/hc internalurls__payment__hc: http://{{ .Values.app.svc.payment }}/hc internalurls__location__hc: http://{{ .Values.app.svc.locations }}/hc + internalurls__grpcBasket: "http://{{ .Values.app.svc.basket }}:{{ .Values.service.grpcPort }}" + internalurls__grpcCatalog: "http://{{ .Values.app.svc.catalog }}:{{ .Values.service.grpcPort }}" + internalurls__grpcOrdering: "http://{{ .Values.app.svc.ordering }}:{{ .Values.service.grpcPort }}" diff --git a/k8s/helm/webshoppingagg/templates/deployment.yaml b/k8s/helm/webshoppingagg/templates/deployment.yaml index 8007c74c8..ab5bfc0c9 100644 --- a/k8s/helm/webshoppingagg/templates/deployment.yaml +++ b/k8s/helm/webshoppingagg/templates/deployment.yaml @@ -5,11 +5,10 @@ kind: Deployment metadata: name: {{ template "webshoppingagg.fullname" . }} labels: - ufo: {{ $cfgname}} app: {{ template "webshoppingagg.name" . }} chart: {{ template "webshoppingagg.chart" . }} release: {{ .Release.Name }} - heritage: {{ .Release.Service }} + heritage: {{ .Release.Service }} spec: replicas: {{ .Values.replicaCount }} selector: @@ -21,6 +20,10 @@ spec: labels: app: {{ template "webshoppingagg.name" . }} release: {{ .Release.Name }} + {{ if .Values.inf.mesh.enabled -}} + annotations: + linkerd.io/inject: enabled + {{- end }} spec: {{ if .Values.inf.registry -}} imagePullSecrets: diff --git a/k8s/helm/webshoppingagg/templates/ingress.yaml b/k8s/helm/webshoppingagg/templates/ingress.yaml index 742db4d30..8993b1b09 100644 --- a/k8s/helm/webshoppingagg/templates/ingress.yaml +++ b/k8s/helm/webshoppingagg/templates/ingress.yaml @@ -14,6 +14,11 @@ metadata: annotations: {{ toYaml . | indent 4 }} {{- end }} +{{- if .Values.inf.mesh.enabled }} +{{- with .Values.ingress.mesh.annotations }} +{{ toYaml . | indent 4 }} +{{- end }} +{{- end }} spec: {{- if .Values.ingress.tls }} tls: diff --git a/k8s/helm/webshoppingagg/values.yaml b/k8s/helm/webshoppingagg/values.yaml index f4f2c5fd7..15501c727 100644 --- a/k8s/helm/webshoppingagg/values.yaml +++ b/k8s/helm/webshoppingagg/values.yaml @@ -10,6 +10,7 @@ image: service: type: ClusterIP port: 80 + grpcPort: 81 ingress: enabled: false @@ -54,6 +55,13 @@ env: key: internalurls__payment__hc - name: LocationUrlHC key: internalurls__location__hc + - name: urls__grpcBasket + key: internalurls__grpcBasket + - name: urls__grpcCatalog + key: internalurls__grpcCatalog + - name: urls__grpcOrdering + key: internalurls__grpcOrdering + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) values: - name: ASPNETCORE_ENVIRONMENT diff --git a/k8s/helm/webspa/templates/configmap.yaml b/k8s/helm/webspa/templates/configmap.yaml index ea745436b..d49f8b2d3 100644 --- a/k8s/helm/webspa/templates/configmap.yaml +++ b/k8s/helm/webspa/templates/configmap.yaml @@ -20,9 +20,7 @@ data: all_EnableLoadTest: "{{ .Values.inf.misc.useLoadTest }}" webspa__keystore: {{ .Values.inf.redis.keystore.constr }} internalurls__apigwws: http://{{ .Values.app.svc.webshoppingapigw }} - internalurls__apigwws__hc: http://{{ .Values.app.svc.webshoppingapigw }}/hc internalurls__identity__hc: http://{{ .Values.app.svc.identity }}/hc - internalurls__apigwwm__hc: http://{{ .Values.app.svc.webmarketingapigw }}/hc urls__apigwws: http://{{ $webshoppingapigw }} urls__spa: http://{{ $spa }} urls__IdentityUrl: http://{{ $identity }} diff --git a/k8s/helm/webspa/templates/deployment.yaml b/k8s/helm/webspa/templates/deployment.yaml index 62af2d8b1..20dc696bf 100644 --- a/k8s/helm/webspa/templates/deployment.yaml +++ b/k8s/helm/webspa/templates/deployment.yaml @@ -21,6 +21,10 @@ spec: labels: app: {{ template "webspa.name" . }} release: {{ .Release.Name }} + {{ if .Values.inf.mesh.enabled -}} + annotations: + linkerd.io/inject: enabled + {{- end }} spec: {{ if .Values.inf.registry -}} imagePullSecrets: diff --git a/k8s/helm/webspa/templates/ingress.yaml b/k8s/helm/webspa/templates/ingress.yaml index 85419f8e7..aeb9a4a49 100644 --- a/k8s/helm/webspa/templates/ingress.yaml +++ b/k8s/helm/webspa/templates/ingress.yaml @@ -13,6 +13,11 @@ metadata: annotations: {{ toYaml . | indent 4 }} {{- end }} +{{- if .Values.inf.mesh.enabled }} +{{- with .Values.ingress.mesh.annotations }} +{{ toYaml . | indent 4 }} +{{- end }} +{{- end }} spec: {{- if .Values.ingress.tls }} tls: diff --git a/k8s/helm/webspa/values.yaml b/k8s/helm/webspa/values.yaml index 056b58a0d..e1547ed39 100644 --- a/k8s/helm/webspa/values.yaml +++ b/k8s/helm/webspa/values.yaml @@ -44,12 +44,8 @@ env: key: urls__IdentityUrl - name: MarketingUrl key: urls__apigwwm - - name: PurchaseUrlHC - key: internalurls__apigwws__hc - name: IdentityUrlHC key: internalurls__identity__hc - - name: MarketingUrlHC - key: internalurls__apigwwm__hc - name: SignalrHubUrl key: urls__apigwws # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) diff --git a/k8s/helm/webstatus/templates/configmap.yaml b/k8s/helm/webstatus/templates/configmap.yaml index 4a1b612f2..ae0c0691c 100644 --- a/k8s/helm/webstatus/templates/configmap.yaml +++ b/k8s/helm/webstatus/templates/configmap.yaml @@ -24,13 +24,13 @@ data: name__spa__hc: WebSPA HTTP Check internalurls__spa__hc: http://{{ .Values.app.svc.spa }}/hc name__apigwws__hc: Web Shopping API GW HTTP Check - internalurls__apigwws__hc: http://{{ .Values.app.svc.webshoppingapigw }}/hc + internalurls__apigwws__hc: http://{{ .Values.app.svc.webshoppingapigw }}:8001/ready name__apigwwm__hc: Web Marketing API GW HTTP Check - internalurls__apigwwm__hc: http://{{ .Values.app.svc.webmarketingapigw }}/hc + internalurls__apigwwm__hc: http://{{ .Values.app.svc.webmarketingapigw }}:8001/ready name__apigwms__hc: Mobile Shopping API GW HTTP Check - internalurls__apigwms__hc: http://{{ .Values.app.svc.mobileshoppingapigw }}/hc + internalurls__apigwms__hc: http://{{ .Values.app.svc.mobileshoppingapigw }}:8001/ready name__apigwmm__hc: Mobile Marketing API GW HTTP Check - internalurls__apigwmm__hc: http://{{ .Values.app.svc.mobilemarketingapigw }}/hc + internalurls__apigwmm__hc: http://{{ .Values.app.svc.mobilemarketingapigw }}:8001/ready name__apigwwsagg__hc: Web Shopping Aggregator GW HTTP Check internalurls__apigwwsagg__hc: http://{{ .Values.app.svc.webshoppingagg }}/hc name__apigwmsagg__hc: Mobile Shopping Aggregator HTTP Check diff --git a/k8s/helm/webstatus/templates/deployment.yaml b/k8s/helm/webstatus/templates/deployment.yaml index 6f96f81fb..70b953577 100644 --- a/k8s/helm/webstatus/templates/deployment.yaml +++ b/k8s/helm/webstatus/templates/deployment.yaml @@ -21,6 +21,10 @@ spec: labels: app: {{ template "webstatus.name" . }} release: {{ .Release.Name }} + {{ if .Values.inf.mesh.enabled -}} + annotations: + linkerd.io/inject: enabled + {{- end }} spec: {{ if .Values.inf.registry -}} imagePullSecrets: diff --git a/k8s/helm/webstatus/templates/ingress.yaml b/k8s/helm/webstatus/templates/ingress.yaml index 1ab4e5e22..bad11ae77 100644 --- a/k8s/helm/webstatus/templates/ingress.yaml +++ b/k8s/helm/webstatus/templates/ingress.yaml @@ -14,6 +14,11 @@ metadata: annotations: {{ toYaml . | indent 4 }} {{- end }} +{{- if .Values.inf.mesh.enabled }} +{{- with .Values.ingress.mesh.annotations }} +{{ toYaml . | indent 4 }} +{{- end }} +{{- end }} spec: {{- if .Values.ingress.tls }} tls: diff --git a/k8s/helm/webstatus/values.yaml b/k8s/helm/webstatus/values.yaml index 808fd8ba9..7d23ce227 100644 --- a/k8s/helm/webstatus/values.yaml +++ b/k8s/helm/webstatus/values.yaml @@ -34,74 +34,76 @@ env: configmap: - name: ApplicationInsights__InstrumentationKey key: all__InstrumentationKey - - name: HealthChecksUI__HealthChecks__0__Name + - name: HealthChecks-UI__HealthChecks__0__Name key: name__mvc__hc - - name: HealthChecksUI__HealthChecks__0__Uri + - name: HealthChecks-UI__HealthChecks__0__Uri key: internalurls__mvc__hc - - name: HealthChecksUI__HealthChecks__1__Name + - name: HealthChecks-UI__HealthChecks__1__Name key: name__spa__hc - - name: HealthChecksUI__HealthChecks__1__Uri + - name: HealthChecks-UI__HealthChecks__1__Uri key: internalurls__spa__hc - - name: HealthChecksUI__HealthChecks__2__Name - key: name__apigwws__hc - - name: HealthChecksUI__HealthChecks__2__Uri - key: internalurls__apigwws__hc - - name: HealthChecksUI__HealthChecks__3__Name - key: name__apigwwm__hc - - name: HealthChecksUI__HealthChecks__3__Uri - key: internalurls__apigwwm__hc - - name: HealthChecksUI__HealthChecks__4__Name - key: name__apigwms__hc - - name: HealthChecksUI__HealthChecks__4__Uri - key: internalurls__apigwms__hc - - name: HealthChecksUI__HealthChecks__5__Name - key: name__apigwmm__hc - - name: HealthChecksUI__HealthChecks__5__Uri - key: internalurls__apigwmm__hc - - name: HealthChecksUI__HealthChecks__6__Name + - name: HealthChecks-UI__HealthChecks__2__Name key: name__apigwwsagg__hc - - name: HealthChecksUI__HealthChecks__6__Uri + - name: HealthChecks-UI__HealthChecks__2__Uri key: internalurls__apigwwsagg__hc - - name: HealthChecksUI__HealthChecks__7__Name + - name: HealthChecks-UI__HealthChecks__3__Name key: name__apigwmsagg__hc - - name: HealthChecksUI__HealthChecks__7__Uri + - name: HealthChecks-UI__HealthChecks__3__Uri key: internalurls__apigwmsagg__hc - - name: HealthChecksUI__HealthChecks__8__Name + - name: HealthChecks-UI__HealthChecks__4__Name key: name__ordering__hc - - name: HealthChecksUI__HealthChecks__8__Uri + - name: HealthChecks-UI__HealthChecks__4__Uri key: internalurls__ordering__hc - - name: HealthChecksUI__HealthChecks__9__Name + - name: HealthChecks-UI__HealthChecks__5__Name key: name__orderingbackground__hc - - name: HealthChecksUI__HealthChecks__9__Uri + - name: HealthChecks-UI__HealthChecks__5__Uri key: internalurls__orderingbackground__hc - - name: HealthChecksUI__HealthChecks__10__Name + - name: HealthChecks-UI__HealthChecks__6__Name key: name__signalrhub__hc - - name: HealthChecksUI__HealthChecks__10__Uri + - name: HealthChecks-UI__HealthChecks__6__Uri key: internalurls__signalrhub__hc - - name: HealthChecksUI__HealthChecks__11__Name + - name: HealthChecks-UI__HealthChecks__7__Name key: name__basket__hc - - name: HealthChecksUI__HealthChecks__11__Uri + - name: HealthChecks-UI__HealthChecks__7__Uri key: internalurls__basket__hc - - name: HealthChecksUI__HealthChecks__12__Name + - name: HealthChecks-UI__HealthChecks__8__Name key: name__catalog__hc - - name: HealthChecksUI__HealthChecks__12__Uri + - name: HealthChecks-UI__HealthChecks__8__Uri key: internalurls__catalog__hc - - name: HealthChecksUI__HealthChecks__13__Name + - name: HealthChecks-UI__HealthChecks__9__Name key: name__identity__hc - - name: HealthChecksUI__HealthChecks__13__Uri + - name: HealthChecks-UI__HealthChecks__9__Uri key: internalurls__identity__hc - - name: HealthChecksUI__HealthChecks__14__Name + - name: HealthChecks-UI__HealthChecks__10__Name key: name__marketing__hc - - name: HealthChecksUI__HealthChecks__14__Uri + - name: HealthChecks-UI__HealthChecks__10__Uri key: internalurls__marketing__hc - - name: HealthChecksUI__HealthChecks__15__Name + - name: HealthChecks-UI__HealthChecks__11__Name key: name__locations__hc - - name: HealthChecksUI__HealthChecks__15__Uri + - name: HealthChecks-UI__HealthChecks__11__Uri key: internalurls__locations__hc - - name: HealthChecksUI__HealthChecks__16__Name + - name: HealthChecks-UI__HealthChecks__12__Name key: name__payment__hc - - name: HealthChecksUI__HealthChecks__16__Uri + - name: HealthChecks-UI__HealthChecks__12__Uri key: internalurls__payment__hc + + - name: HealthChecks-UI__HealthChecks__13__Name + key: name__apigwws__hc + - name: HealthChecks-UI__HealthChecks__13__Uri + key: internalurls__apigwws__hc + - name: HealthChecks-UI__HealthChecks__14__Name + key: name__apigwwm__hc + - name: HealthChecks-UI__HealthChecks__14__Uri + key: internalurls__apigwwm__hc + - name: HealthChecks-UI__HealthChecks__15__Name + key: name__apigwms__hc + - name: HealthChecks-UI__HealthChecks__15__Uri + key: internalurls__apigwms__hc + - name: HealthChecks-UI__HealthChecks__16__Name + key: name__apigwmm__hc + - name: HealthChecks-UI__HealthChecks__16__Uri + key: internalurls__apigwmm__hc + # values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value) values: - name: ASPNETCORE_ENVIRONMENT diff --git a/k8s/ingress.yaml b/k8s/ingress.yaml deleted file mode 100644 index b5773bb25..000000000 --- a/k8s/ingress.yaml +++ /dev/null @@ -1,59 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - labels: - app: eshop - component: frontend - name: eshop-ingress - annotations: - ingress.kubernetes.io/ssl-redirect: "false" -spec: - rules: - - http: - paths: - - path: /identity - backend: - serviceName: identity - servicePort: 80 - - path: /webmvc - backend: - serviceName: webmvc - servicePort: 80 - - path: /webstatus - backend: - serviceName: webstatus - servicePort: 80 - - path: /webshoppingapigw - backend: - serviceName: ocelotapigw-ws - servicePort: 80 - - path: /webmarketingapigw - backend: - serviceName: ocelotapigw-wm - servicePort: 80 - - path: /mobilemarketingapigw - backend: - serviceName: ocelotapigw-mm - servicePort: 80 - - path: /mobileshoppingapigw - backend: - serviceName: ocelotapigw-ms - servicePort: 80 - - path: /webshoppingagg - backend: - serviceName: webshoppingagg - servicePort: 80 - - path: /mobileshoppingagg - backend: - serviceName: mobileshoppingagg - servicePort: 80 - - path: /payment-api - backend: - serviceName: payment - servicePort: 80 - - path: / - backend: - serviceName: webspa - servicePort: 80 - - diff --git a/k8s/keystore-data.yaml b/k8s/keystore-data.yaml deleted file mode 100644 index 0e2dfa9b9..000000000 --- a/k8s/keystore-data.yaml +++ /dev/null @@ -1,29 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: keystore-data - name: keystore-data -spec: - ports: - - port: 6379 - selector: - app: eshop - component: keystore-data ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: keystore-data -spec: - template: - metadata: - labels: - app: eshop - component: keystore-data - spec: - containers: - - name: keystore-data - image: redis - diff --git a/k8s/linkerd/basket-api-sp.yaml b/k8s/linkerd/basket-api-sp.yaml new file mode 100644 index 000000000..6b23bdb9f --- /dev/null +++ b/k8s/linkerd/basket-api-sp.yaml @@ -0,0 +1,42 @@ +apiVersion: linkerd.io/v1alpha2 +kind: ServiceProfile +metadata: + creationTimestamp: null + name: basket-api.default.svc.cluster.local + namespace: default +spec: + routes: + - condition: + method: GET + pathRegex: /basket-api/api/v1/basket/[^/]* + name: GET Basket {id} + isRetryable: true + - condition: + method: GET + pathRegex: /hc + name: GET /hc + isRetryable: false + - condition: + method: GET + pathRegex: /liveness + name: GET /liveness + isRetryable: false + - condition: + method: POST + pathRegex: /BasketApi\.Basket/GetBasketById + name: POST /BasketApi.Basket/GetBasketById + isRetryable: true + - condition: + method: POST + pathRegex: /BasketApi\.Basket/UpdateBasket + name: POST /BasketApi.Basket/UpdateBasket + isRetryable: true + - condition: + method: POST + pathRegex: /basket-api/api/v1/basket/checkout + name: POST /v1/basket/checkout + isRetryable: true + retryBudget: + retryRatio: 0.2 + minRetriesPerSecond: 10 + ttl: 10s \ No newline at end of file diff --git a/k8s/linkerd/catalog-api-sp.yaml b/k8s/linkerd/catalog-api-sp.yaml new file mode 100644 index 000000000..6e9afa472 --- /dev/null +++ b/k8s/linkerd/catalog-api-sp.yaml @@ -0,0 +1,47 @@ +apiVersion: linkerd.io/v1alpha2 +kind: ServiceProfile +metadata: + creationTimestamp: null + name: catalog-api.default.svc.cluster.local + namespace: default +spec: + routes: + - condition: + method: GET + pathRegex: /catalog-api/api/v1/catalog/catalogbrands + name: GET /v1/catalog/catalogbrands + isRetryable: true + - condition: + method: GET + pathRegex: /catalog-api/api/v1/catalog/catalogtypes + name: GET /v1/catalog/catalogtypes + isRetryable: true + - condition: + method: GET + pathRegex: /catalog-api/api/v1/catalog/items + name: GET /v1/catalog/items + isRetryable: true + - condition: + method: GET + pathRegex: /api/v1/catalog/items/[^/]*/pic/ + name: GET /v1/catalog/items/{id}/pic/ + isRetryable: false + - condition: + method: GET + pathRegex: /hc + name: GET /hc + isRetryable: false + - condition: + method: GET + pathRegex: /liveness + isRetryable: false + name: GET /liveness + - condition: + method: POST + pathRegex: /CatalogApi\.Catalog/GetItemsByIds + name: POST /CatalogApi.Catalog/GetItemsByIds + isRetryable: true + retryBudget: + retryRatio: 0.2 + minRetriesPerSecond: 10 + ttl: 10s \ No newline at end of file diff --git a/k8s/nosql-data.yaml b/k8s/nosql-data.yaml deleted file mode 100644 index 5dfb67c6e..000000000 --- a/k8s/nosql-data.yaml +++ /dev/null @@ -1,30 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: nosql-data - name: nosql-data -spec: - ports: - - port: 27017 - selector: - app: eshop - component: nosql-data ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: nosql-data -spec: - template: - metadata: - labels: - app: eshop - component: nosql-data - spec: - containers: - - name: nosql-data - image: mongo - ports: - - containerPort: 27017 diff --git a/k8s/ocelot/configuration-mobile-marketing.json b/k8s/ocelot/configuration-mobile-marketing.json deleted file mode 100644 index 666df1633..000000000 --- a/k8s/ocelot/configuration-mobile-marketing.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "ReRoutes": [ - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "marketing", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/m/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "locations", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/l/{everything}", - "UpstreamHttpMethod": [] - } - - ], - "GlobalConfiguration": { - "RequestIdKey": "OcRequestId", - "AdministrationPath": "/administration" - } -} - \ No newline at end of file diff --git a/k8s/ocelot/configuration-mobile-shopping.json b/k8s/ocelot/configuration-mobile-shopping.json deleted file mode 100644 index cf3a48aff..000000000 --- a/k8s/ocelot/configuration-mobile-shopping.json +++ /dev/null @@ -1,142 +0,0 @@ -{ - "ReRoutes": [ - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "catalog", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/c/{everything}", - "UpstreamHttpMethod": [ "GET" ] - }, - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "basket", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/b/{everything}", - "UpstreamHttpMethod": [], - "AuthenticationOptions": { - "AuthenticationProviderKey": "IdentityApiKey", - "AllowedScopes": [] - } - }, - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "ordering", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/o/{everything}", - "UpstreamHttpMethod": [], - "AuthenticationOptions": { - "AuthenticationProviderKey": "IdentityApiKey", - "AllowedScopes": [] - } - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "mobileshoppingagg", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/{everything}", - "UpstreamHttpMethod": [ "POST", "PUT", "GET" ], - "AuthenticationOptions": { - "AuthenticationProviderKey": "IdentityApiKey", - "AllowedScopes": [] - } - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "ordering", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/orders-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "basket", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/basket-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "catalog", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/catalog-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "marketing", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/marketing-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "payment", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/payment-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "locations.api", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/location-api/{everything}", - "UpstreamHttpMethod": [] - } - - ], - "GlobalConfiguration": { - "RequestIdKey": "OcRequestId", - "AdministrationPath": "/administration" - } - } - \ No newline at end of file diff --git a/k8s/ocelot/configuration-web-marketing.json b/k8s/ocelot/configuration-web-marketing.json deleted file mode 100644 index 666df1633..000000000 --- a/k8s/ocelot/configuration-web-marketing.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "ReRoutes": [ - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "marketing", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/m/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "locations", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/l/{everything}", - "UpstreamHttpMethod": [] - } - - ], - "GlobalConfiguration": { - "RequestIdKey": "OcRequestId", - "AdministrationPath": "/administration" - } -} - \ No newline at end of file diff --git a/k8s/ocelot/configuration-web-shopping.json b/k8s/ocelot/configuration-web-shopping.json deleted file mode 100644 index 021056f43..000000000 --- a/k8s/ocelot/configuration-web-shopping.json +++ /dev/null @@ -1,154 +0,0 @@ -{ - "ReRoutes": [ - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "catalog", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/c/{everything}", - "UpstreamHttpMethod": [ "GET" ] - }, - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "basket", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/b/{everything}", - "UpstreamHttpMethod": [], - "AuthenticationOptions": { - "AuthenticationProviderKey": "IdentityApiKey", - "AllowedScopes": [] - } - }, - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "ordering", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/o/{everything}", - "UpstreamHttpMethod": [], - "AuthenticationOptions": { - "AuthenticationProviderKey": "IdentityApiKey", - "AllowedScopes": [] - } - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "webshoppingagg", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/{everything}", - "UpstreamHttpMethod": [ "POST", "PUT", "GET" ], - "AuthenticationOptions": { - "AuthenticationProviderKey": "IdentityApiKey", - "AllowedScopes": [] - } - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "ordering", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/orders-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "ordering-signalrhub", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/hub/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "basket", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/basket-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "catalog", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/catalog-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "marketing", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/marketing-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "payment", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/payment-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "locations.api", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/location-api/{everything}", - "UpstreamHttpMethod": [] - } - - ], - "GlobalConfiguration": { - "RequestIdKey": "OcRequestId", - "AdministrationPath": "/administration" - } - } - \ No newline at end of file diff --git a/k8s/ocelot/deployment.yaml b/k8s/ocelot/deployment.yaml deleted file mode 100644 index 3a114e4ce..000000000 --- a/k8s/ocelot/deployment.yaml +++ /dev/null @@ -1,155 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: apigwmm -spec: - paused: true - template: - metadata: - labels: - app: eshop - component: apigwmm - spec: - containers: - - name: apigwmm - image: eshop/ocelotapigw - imagePullPolicy: Always - env: - - name: PATH_BASE - value: /mobilemarketingapigw - - name: IdentityUrl - valueFrom: - configMapKeyRef: - name: internalurls - key: identity - ports: - - containerPort: 80 - volumeMounts: - - name: config - mountPath: /app/configuration - volumes: - - name: config - configMap: - name: ocelot - items: - - key: mm - path: configuration.json - imagePullSecrets: - - name: registry-key ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: apigwms -spec: - paused: true - template: - metadata: - labels: - app: eshop - component: apigwms - spec: - containers: - - name: apigwms - image: eshop/ocelotapigw - imagePullPolicy: Always - env: - - name: PATH_BASE - value: /mobileshoppingapigw - - name: IdentityUrl - valueFrom: - configMapKeyRef: - name: internalurls - key: identity - ports: - - containerPort: 80 - volumeMounts: - - name: config - mountPath: /app/configuration - volumes: - - name: config - configMap: - name: ocelot - items: - - key: ms - path: configuration.json - imagePullSecrets: - - name: registry-key ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: apigwwm -spec: - paused: true - template: - metadata: - labels: - app: eshop - component: apigwwm - spec: - containers: - - name: apigwwm - image: eshop/ocelotapigw - imagePullPolicy: Always - env: - - name: PATH_BASE - value: /webmarketingapigw - - name: IdentityUrl - valueFrom: - configMapKeyRef: - name: internalurls - key: identity - ports: - - containerPort: 80 - volumeMounts: - - name: config - mountPath: /app/configuration - volumes: - - name: config - configMap: - name: ocelot - items: - - key: wm - path: configuration.json - imagePullSecrets: - - name: registry-key ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: apigwws -spec: - paused: true - template: - metadata: - labels: - app: eshop - component: apigwws - spec: - containers: - - name: apigwws - image: eshop/ocelotapigw - imagePullPolicy: Always - env: - - name: PATH_BASE - value: /webshoppingapigw - - name: IdentityUrl - valueFrom: - configMapKeyRef: - name: internalurls - key: identity - ports: - - containerPort: 80 - volumeMounts: - - name: config - mountPath: /app/configuration - volumes: - - name: config - configMap: - name: ocelot - items: - - key: ws - path: configuration.json - imagePullSecrets: - - name: registry-key \ No newline at end of file diff --git a/k8s/ocelot/service.yaml b/k8s/ocelot/service.yaml deleted file mode 100644 index 858b54b21..000000000 --- a/k8s/ocelot/service.yaml +++ /dev/null @@ -1,55 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: ocelotapigw-mm - name: ocelotapigw-mm -spec: - ports: - - port: 80 - selector: - app: eshop - component: apigwmm ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: ocelotapigw-ms - name: ocelotapigw-ms -spec: - ports: - - port: 80 - selector: - app: eshop - component: apigwms ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: ocelotapigw-wm - name: ocelotapigw-wm -spec: - ports: - - port: 80 - selector: - app: eshop - component: apigwwm ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: ocelotapigw-ws - name: ocelotapigw-ws -spec: - ports: - - port: 80 - selector: - app: eshop - component: apigwws diff --git a/k8s/rabbitmq.yaml b/k8s/rabbitmq.yaml deleted file mode 100644 index d2a7de906..000000000 --- a/k8s/rabbitmq.yaml +++ /dev/null @@ -1,30 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: rabbitmq - name: rabbitmq -spec: - ports: - - port: 5672 - selector: - app: eshop - component: rabbitmq ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: rabbitmq -spec: - template: - metadata: - labels: - app: eshop - component: rabbitmq - spec: - containers: - - name: rabbitmq - image: rabbitmq:3-management - ports: - - containerPort: 5672 diff --git a/k8s/services.yaml b/k8s/services.yaml deleted file mode 100644 index ad537eaf0..000000000 --- a/k8s/services.yaml +++ /dev/null @@ -1,195 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: basket - name: basket -spec: - ports: - - port: 80 - selector: - app: eshop - component: basket ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: catalog - name: catalog -spec: - ports: - - port: 80 - selector: - app: eshop - component: catalog ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: identity - name: identity -spec: - ports: - - port: 80 - selector: - app: eshop - component: identity ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: ordering - name: ordering -spec: - ports: - - port: 80 - selector: - app: eshop - component: ordering ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: ordering-backgroundtasks - name: ordering-background -spec: - ports: - - port: 80 - selector: - app: eshop - component: ordering-backgroundtasks ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: ordering-signalrhub - name: ordering-signalrhub -spec: - ports: - - port: 80 - selector: - app: eshop - component: ordering-signalrhub ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: locations - name: locations -spec: - ports: - - port: 80 - selector: - app: eshop - component: locations ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: payment - name: payment -spec: - ports: - - port: 80 - selector: - app: eshop - component: payment ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: marketing - name: marketing -spec: - ports: - - port: 80 - selector: - app: eshop - component: marketing ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: webshoppingagg - name: webshoppingagg -spec: - ports: - - port: 80 - selector: - app: eshop - component: webshoppingagg ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: mobileshoppingagg - name: mobileshoppingagg -spec: - ports: - - port: 80 - selector: - app: eshop - component: mobileshoppingagg ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: webmvc - name: webmvc -spec: - ports: - - port: 80 - selector: - app: eshop - component: webmvc ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: webstatus - name: webstatus -spec: - ports: - - port: 80 - selector: - app: eshop - component: webstatus ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: webspa - name: webspa -spec: - ports: - - port: 80 - selector: - app: eshop - component: webspa diff --git a/k8s/sql-data.yaml b/k8s/sql-data.yaml deleted file mode 100644 index 245622e83..000000000 --- a/k8s/sql-data.yaml +++ /dev/null @@ -1,35 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: eshop - component: sql-data - name: sql-data -spec: - ports: - - port: 1433 - selector: - app: eshop - component: sql-data ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: sql-data -spec: - template: - metadata: - labels: - app: eshop - component: sql-data - spec: - containers: - - name: sql-data - image: microsoft/mssql-server-linux:2017-latest - env: - - name: ACCEPT_EULA - value: "Y" - - name: MSSQL_PID - value: Developer - - name: MSSQL_SA_PASSWORD - value: Pass@word diff --git a/.dockerignore b/src/.dockerignore similarity index 100% rename from .dockerignore rename to src/.dockerignore diff --git a/.env b/src/.env similarity index 100% rename from .env rename to src/.env diff --git a/src/ApiGateways/ApiGw-Base/Dockerfile b/src/ApiGateways/ApiGw-Base/Dockerfile deleted file mode 100644 index d1b50b231..000000000 --- a/src/ApiGateways/ApiGw-Base/Dockerfile +++ /dev/null @@ -1,59 +0,0 @@ -FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base -WORKDIR /app -EXPOSE 80 - -FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build -WORKDIR /src - -# Keep the project list and command dotnet restore identical in all Dockfiles to maximize image cache utilization -COPY eShopOnContainers-ServicesAndWebApps.sln . -COPY docker-compose.dcproj /src/ -COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/ -COPY src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj src/ApiGateways/Mobile.Bff.Shopping/aggregator/ -COPY src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj src/ApiGateways/Web.Bff.Shopping/aggregator/ -COPY src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj src/BuildingBlocks/Devspaces.Support/ -COPY src/BuildingBlocks/EventBus/EventBus/EventBus.csproj src/BuildingBlocks/EventBus/EventBus/ -COPY src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj src/BuildingBlocks/EventBus/EventBus.Tests/ -COPY src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj src/BuildingBlocks/EventBus/EventBusRabbitMQ/ -COPY src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj src/BuildingBlocks/EventBus/EventBusServiceBus/ -COPY src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj src/BuildingBlocks/EventBus/IntegrationEventLogEF/ -COPY src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj src/BuildingBlocks/WebHostCustomization/WebHost.Customization/ -COPY src/Services/Basket/Basket.API/Basket.API.csproj src/Services/Basket/Basket.API/ -COPY src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj src/Services/Basket/Basket.FunctionalTests/ -COPY src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj src/Services/Basket/Basket.UnitTests/ -COPY src/Services/Catalog/Catalog.API/Catalog.API.csproj src/Services/Catalog/Catalog.API/ -COPY src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj src/Services/Catalog/Catalog.FunctionalTests/ -COPY src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj src/Services/Catalog/Catalog.UnitTests/ -COPY src/Services/Identity/Identity.API/Identity.API.csproj src/Services/Identity/Identity.API/ -COPY src/Services/Location/Locations.API/Locations.API.csproj src/Services/Location/Locations.API/ -COPY src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj src/Services/Location/Locations.FunctionalTests/ -COPY src/Services/Marketing/Marketing.API/Marketing.API.csproj src/Services/Marketing/Marketing.API/ -COPY src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj src/Services/Marketing/Marketing.FunctionalTests/ -COPY src/Services/Ordering/Ordering.API/Ordering.API.csproj src/Services/Ordering/Ordering.API/ -COPY src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj src/Services/Ordering/Ordering.BackgroundTasks/ -COPY src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj src/Services/Ordering/Ordering.Domain/ -COPY src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj src/Services/Ordering/Ordering.FunctionalTests/ -COPY src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj src/Services/Ordering/Ordering.Infrastructure/ -COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/ -COPY src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj src/Services/Ordering/Ordering.UnitTests/ -COPY src/Services/Payment/Payment.API/Payment.API.csproj src/Services/Payment/Payment.API/ -COPY src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj src/Services/Webhooks/Webhooks.API/ -COPY src/Web/WebhookClient/WebhookClient.csproj src/Web/WebhookClient/ -COPY src/Web/WebMVC/WebMVC.csproj src/Web/WebMVC/ -COPY src/Web/WebSPA/WebSPA.csproj src/Web/WebSPA/ -COPY src/Web/WebStatus/WebStatus.csproj src/Web/WebStatus/ -COPY test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj test/ServicesTests/Application.FunctionalTests/ -COPY test/ServicesTests/LoadTest/LoadTest.csproj test/ServicesTests/LoadTest/ - -RUN dotnet restore eShopOnContainers-ServicesAndWebApps.sln - -COPY . . -WORKDIR /src/src/ApiGateways/ApiGw-Base/ -RUN dotnet publish --no-restore -c Release -o /app - -FROM build AS publish - -FROM base AS final -WORKDIR /app -COPY --from=publish /app . -ENTRYPOINT ["dotnet", "OcelotApiGw.dll"] diff --git a/src/ApiGateways/ApiGw-Base/Dockerfile.develop b/src/ApiGateways/ApiGw-Base/Dockerfile.develop deleted file mode 100644 index 4da230d68..000000000 --- a/src/ApiGateways/ApiGw-Base/Dockerfile.develop +++ /dev/null @@ -1,14 +0,0 @@ -FROM microsoft/dotnet:2.2-sdk -ARG BUILD_CONFIGURATION=Debug -ENV ASPNETCORE_ENVIRONMENT=Development -ENV DOTNET_USE_POLLING_FILE_WATCHER=true -EXPOSE 80 - -WORKDIR /src -COPY ["src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj", "src/ApiGateways/ApiGw-Base/"] -RUN dotnet restore "src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj" -COPY . . -WORKDIR "/src/src/ApiGateways/ApiGw-Base" -RUN dotnet build --no-restore "OcelotApiGw.csproj" -c $BUILD_CONFIGURATION - -ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"] \ No newline at end of file diff --git a/src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj b/src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj deleted file mode 100644 index d5622ccc4..000000000 --- a/src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - netcoreapp2.2 - - - - - - - - - - - - - diff --git a/src/ApiGateways/ApiGw-Base/Program.cs b/src/ApiGateways/ApiGw-Base/Program.cs deleted file mode 100644 index bcf1c8d60..000000000 --- a/src/ApiGateways/ApiGw-Base/Program.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.DependencyInjection; -using Serilog; - -namespace OcelotApiGw -{ - public class Program - { - public static void Main(string[] args) - { - BuildWebHost(args).Run(); - } - - public static IWebHost BuildWebHost(string[] args) - { - IWebHostBuilder builder = WebHost.CreateDefaultBuilder(args); - builder.ConfigureServices(s => s.AddSingleton(builder)) - .ConfigureAppConfiguration(ic => ic.AddJsonFile(Path.Combine("configuration", "configuration.json"))) - .UseStartup() - .ConfigureLogging((hostingContext, loggingbuilder) => - { - loggingbuilder.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); - loggingbuilder.AddConsole(); - loggingbuilder.AddDebug(); - }) - .UseSerilog((builderContext, config) => - { - config - .MinimumLevel.Information() - .Enrich.FromLogContext() - .WriteTo.Console(); - }); - IWebHost host = builder.Build(); - return host; - } - } -} diff --git a/src/ApiGateways/ApiGw-Base/Properties/launchSettings.json b/src/ApiGateways/ApiGw-Base/Properties/launchSettings.json deleted file mode 100644 index 2308ca466..000000000 --- a/src/ApiGateways/ApiGw-Base/Properties/launchSettings.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:56755/", - "sslPort": 0 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "OcelotApiGw": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "http://localhost:64021/" - } - } -} \ No newline at end of file diff --git a/src/ApiGateways/ApiGw-Base/Startup.cs b/src/ApiGateways/ApiGw-Base/Startup.cs deleted file mode 100644 index 585c26471..000000000 --- a/src/ApiGateways/ApiGw-Base/Startup.cs +++ /dev/null @@ -1,109 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Diagnostics.HealthChecks; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Ocelot.DependencyInjection; -using Ocelot.Middleware; -using System; -using HealthChecks.UI.Client; -using Microsoft.Extensions.Diagnostics.HealthChecks; - -namespace OcelotApiGw -{ - public class Startup - { - private readonly IConfiguration _cfg; - - public Startup(IConfiguration configuration) - { - _cfg = configuration; - } - - public void ConfigureServices(IServiceCollection services) - { - var identityUrl = _cfg.GetValue("IdentityUrl"); - var authenticationProviderKey = "IdentityApiKey"; - - services.AddHealthChecks() - .AddCheck("self", () => HealthCheckResult.Healthy()) - .AddUrlGroup(new Uri(_cfg["CatalogUrlHC"]), name: "catalogapi-check", tags: new string[] { "catalogapi" }) - .AddUrlGroup(new Uri(_cfg["OrderingUrlHC"]), name: "orderingapi-check", tags: new string[] { "orderingapi" }) - .AddUrlGroup(new Uri(_cfg["BasketUrlHC"]), name: "basketapi-check", tags: new string[] { "basketapi" }) - .AddUrlGroup(new Uri(_cfg["IdentityUrlHC"]), name: "identityapi-check", tags: new string[] { "identityapi" }) - .AddUrlGroup(new Uri(_cfg["MarketingUrlHC"]), name: "marketingapi-check", tags: new string[] { "marketingapi" }) - .AddUrlGroup(new Uri(_cfg["PaymentUrlHC"]), name: "paymentapi-check", tags: new string[] { "paymentapi" }) - .AddUrlGroup(new Uri(_cfg["LocationUrlHC"]), name: "locationapi-check", tags: new string[] { "locationapi" }); - - services.AddCors(options => - { - options.AddPolicy("CorsPolicy", - builder => builder - .AllowAnyMethod() - .AllowAnyHeader() - .SetIsOriginAllowed((host) => true) - .AllowCredentials()); - }); - - services.AddAuthentication() - .AddJwtBearer(authenticationProviderKey, x => - { - x.Authority = identityUrl; - x.RequireHttpsMetadata = false; - x.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters() - { - ValidAudiences = new[] { "orders", "basket", "locations", "marketing", "mobileshoppingagg", "webshoppingagg" } - }; - x.Events = new Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerEvents() - { - OnAuthenticationFailed = async ctx => - { - int i = 0; - }, - OnTokenValidated = async ctx => - { - int i = 0; - }, - - OnMessageReceived = async ctx => - { - int i = 0; - } - }; - }); - - services.AddOcelot(_cfg); - } - - public void Configure(IApplicationBuilder app, IHostingEnvironment env) - { - var pathBase = _cfg["PATH_BASE"]; - - if (!string.IsNullOrEmpty(pathBase)) - { - app.UsePathBase(pathBase); - } - - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - - app.UseHealthChecks("/hc", new HealthCheckOptions() - { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - - app.UseHealthChecks("/liveness", new HealthCheckOptions - { - Predicate = r => r.Name.Contains("self") - }); - - app.UseCors("CorsPolicy"); - - app.UseOcelot().Wait(); - } - } -} diff --git a/src/ApiGateways/ApiGw-Base/appsettings.json b/src/ApiGateways/ApiGw-Base/appsettings.json deleted file mode 100644 index 426750e6a..000000000 --- a/src/ApiGateways/ApiGw-Base/appsettings.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "Logging": { - "IncludeScopes": true, - "LogLevel": { - "Default": "Trace", - "System": "Information", - "Microsoft": "Information" - } - } -} \ No newline at end of file diff --git a/src/ApiGateways/Envoy/config/mobilemarketing/envoy.yaml b/src/ApiGateways/Envoy/config/mobilemarketing/envoy.yaml new file mode 100644 index 000000000..54b1afa06 --- /dev/null +++ b/src/ApiGateways/Envoy/config/mobilemarketing/envoy.yaml @@ -0,0 +1,75 @@ +admin: + access_log_path: "/dev/null" + address: + socket_address: + address: 0.0.0.0 + port_value: 8001 +static_resources: + listeners: + - address: + socket_address: + address: 0.0.0.0 + port_value: 80 + filter_chains: + - filters: + - name: envoy.http_connection_manager + config: + codec_type: auto + stat_prefix: ingress_http + route_config: + name: eshop_backend_route + virtual_hosts: + - name: eshop_backend + domains: + - "*" + routes: + - name: "m-short" + match: + prefix: "/m/" + route: + auto_host_rewrite: true + prefix_rewrite: "/marketing-api/" + cluster: marketing + - name: "m-long" + match: + prefix: "/marketing-api/" + route: + auto_host_rewrite: true + cluster: marketing + http_filters: + - name: envoy.router + access_log: + - name: envoy.file_access_log + filter: + not_health_check_filter: {} + config: + json_format: + time: "%START_TIME%" + protocol: "%PROTOCOL%" + duration: "%DURATION%" + request_method: "%REQ(:METHOD)%" + request_host: "%REQ(HOST)%" + path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%" + response_flags: "%RESPONSE_FLAGS%" + route_name: "%ROUTE_NAME%" + upstream_host: "%UPSTREAM_HOST%" + upstream_cluster: "%UPSTREAM_CLUSTER%" + upstream_local_address: "%UPSTREAM_LOCAL_ADDRESS%" + path: "/tmp/access.log" + clusters: + - name: marketing + connect_timeout: 0.25s + type: logical_dns + lb_policy: round_robin + hosts: + - socket_address: + address: marketing-api + port_value: 80 + - name: locations + connect_timeout: 0.25s + type: logical_dns + lb_policy: round_robin + hosts: + - socket_address: + address: locations-api + port_value: 80 diff --git a/src/ApiGateways/Envoy/config/mobileshopping/envoy.yaml b/src/ApiGateways/Envoy/config/mobileshopping/envoy.yaml new file mode 100644 index 000000000..373806b06 --- /dev/null +++ b/src/ApiGateways/Envoy/config/mobileshopping/envoy.yaml @@ -0,0 +1,124 @@ +admin: + access_log_path: "/dev/null" + address: + socket_address: + address: 0.0.0.0 + port_value: 8001 +static_resources: + listeners: + - address: + socket_address: + address: 0.0.0.0 + port_value: 80 + filter_chains: + - filters: + - name: envoy.http_connection_manager + config: + codec_type: auto + stat_prefix: ingress_http + route_config: + name: eshop_backend_route + virtual_hosts: + - name: eshop_backend + domains: + - "*" + routes: + - name: "c-short" + match: + prefix: "/c/" + route: + auto_host_rewrite: true + prefix_rewrite: "/catalog-api/" + cluster: catalog + - name: "c-long" + match: + prefix: "/catalog-api/" + route: + auto_host_rewrite: true + cluster: catalog + - name: "o-short" + match: + prefix: "/o/" + route: + auto_host_rewrite: true + prefix_rewrite: "/ordering-api/" + cluster: ordering + - name: "o-long" + match: + prefix: "/ordering-api/" + route: + auto_host_rewrite: true + cluster: ordering + - name: "b-short" + match: + prefix: "/b/" + route: + auto_host_rewrite: true + prefix_rewrite: "/basket-api/" + cluster: basket + - name: "b-long" + match: + prefix: "/basket-api/" + route: + auto_host_rewrite: true + cluster: basket + - name: "agg" + match: + prefix: "/" + route: + auto_host_rewrite: true + prefix_rewrite: "/" + cluster: shoppingagg + http_filters: + - name: envoy.router + access_log: + - name: envoy.file_access_log + filter: + not_health_check_filter: {} + config: + json_format: + time: "%START_TIME%" + protocol: "%PROTOCOL%" + duration: "%DURATION%" + request_method: "%REQ(:METHOD)%" + request_host: "%REQ(HOST)%" + path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%" + response_flags: "%RESPONSE_FLAGS%" + route_name: "%ROUTE_NAME%" + upstream_host: "%UPSTREAM_HOST%" + upstream_cluster: "%UPSTREAM_CLUSTER%" + upstream_local_address: "%UPSTREAM_LOCAL_ADDRESS%" + path: "/tmp/access.log" + clusters: + - name: shoppingagg + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + hosts: + - socket_address: + address: webshoppingagg + port_value: 80 + - name: catalog + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + hosts: + - socket_address: + address: catalog-api + port_value: 80 + - name: basket + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + hosts: + - socket_address: + address: basket-api + port_value: 80 + - name: ordering + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + hosts: + - socket_address: + address: ordering-api + port_value: 80 \ No newline at end of file diff --git a/src/ApiGateways/Envoy/config/webmarketing/envoy.yaml b/src/ApiGateways/Envoy/config/webmarketing/envoy.yaml new file mode 100644 index 000000000..c6f3421de --- /dev/null +++ b/src/ApiGateways/Envoy/config/webmarketing/envoy.yaml @@ -0,0 +1,75 @@ +admin: + access_log_path: "/dev/null" + address: + socket_address: + address: 0.0.0.0 + port_value: 8001 +static_resources: + listeners: + - address: + socket_address: + address: 0.0.0.0 + port_value: 80 + filter_chains: + - filters: + - name: envoy.http_connection_manager + config: + codec_type: auto + stat_prefix: ingress_http + route_config: + name: eshop_backend_route + virtual_hosts: + - name: eshop_backend + domains: + - "*" + routes: + - name: "m-short" + match: + prefix: "/m/" + route: + auto_host_rewrite: true + prefix_rewrite: "/marketing-api/" + cluster: marketing + - name: "m-long" + match: + prefix: "/marketing-api/" + route: + auto_host_rewrite: true + cluster: marketing + http_filters: + - name: envoy.router + access_log: + - name: envoy.file_access_log + filter: + not_health_check_filter: {} + config: + json_format: + time: "%START_TIME%" + protocol: "%PROTOCOL%" + duration: "%DURATION%" + request_method: "%REQ(:METHOD)%" + request_host: "%REQ(HOST)%" + path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%" + response_flags: "%RESPONSE_FLAGS%" + route_name: "%ROUTE_NAME%" + upstream_host: "%UPSTREAM_HOST%" + upstream_cluster: "%UPSTREAM_CLUSTER%" + upstream_local_address: "%UPSTREAM_LOCAL_ADDRESS%" + path: "/tmp/access.log" + clusters: + - name: marketing + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + hosts: + - socket_address: + address: marketing-api + port_value: 80 + - name: locations + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + hosts: + - socket_address: + address: locations-api + port_value: 80 diff --git a/src/ApiGateways/Envoy/config/webshopping/envoy.yaml b/src/ApiGateways/Envoy/config/webshopping/envoy.yaml new file mode 100644 index 000000000..1491f37af --- /dev/null +++ b/src/ApiGateways/Envoy/config/webshopping/envoy.yaml @@ -0,0 +1,124 @@ +admin: + access_log_path: "/dev/null" + address: + socket_address: + address: 0.0.0.0 + port_value: 8001 +static_resources: + listeners: + - address: + socket_address: + address: 0.0.0.0 + port_value: 80 + filter_chains: + - filters: + - name: envoy.http_connection_manager + config: + codec_type: auto + stat_prefix: ingress_http + route_config: + name: eshop_backend_route + virtual_hosts: + - name: eshop_backend + domains: + - "*" + routes: + - name: "c-short" + match: + prefix: "/c/" + route: + auto_host_rewrite: true + prefix_rewrite: "/catalog-api/" + cluster: catalog + - name: "c-long" + match: + prefix: "/catalog-api/" + route: + auto_host_rewrite: true + cluster: catalog + - name: "o-short" + match: + prefix: "/o/" + route: + auto_host_rewrite: true + prefix_rewrite: "/ordering-api/" + cluster: ordering + - name: "o-long" + match: + prefix: "/ordering-api/" + route: + auto_host_rewrite: true + cluster: ordering + - name: "b-short" + match: + prefix: "/b/" + route: + auto_host_rewrite: true + prefix_rewrite: "/basket-api/" + cluster: basket + - name: "b-long" + match: + prefix: "/basket-api/" + route: + auto_host_rewrite: true + cluster: basket + - name: "agg" + match: + prefix: "/" + route: + auto_host_rewrite: true + prefix_rewrite: "/" + cluster: shoppingagg + http_filters: + - name: envoy.router + access_log: + - name: envoy.file_access_log + filter: + not_health_check_filter: {} + config: + json_format: + time: "%START_TIME%" + protocol: "%PROTOCOL%" + duration: "%DURATION%" + request_method: "%REQ(:METHOD)%" + request_host: "%REQ(HOST)%" + path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%" + response_flags: "%RESPONSE_FLAGS%" + route_name: "%ROUTE_NAME%" + upstream_host: "%UPSTREAM_HOST%" + upstream_cluster: "%UPSTREAM_CLUSTER%" + upstream_local_address: "%UPSTREAM_LOCAL_ADDRESS%" + path: "/tmp/access.log" + clusters: + - name: shoppingagg + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + hosts: + - socket_address: + address: webshoppingagg + port_value: 80 + - name: catalog + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + hosts: + - socket_address: + address: catalog-api + port_value: 80 + - name: basket + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + hosts: + - socket_address: + address: basket-api + port_value: 80 + - name: ordering + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + hosts: + - socket_address: + address: ordering-api + port_value: 80 \ No newline at end of file diff --git a/src/ApiGateways/Mobile.Bff.Marketing/apigw/azds.yaml b/src/ApiGateways/Mobile.Bff.Marketing/apigw/azds.yaml deleted file mode 100644 index 46375343b..000000000 --- a/src/ApiGateways/Mobile.Bff.Marketing/apigw/azds.yaml +++ /dev/null @@ -1,44 +0,0 @@ -kind: helm-release -apiVersion: 1.1 -build: - context: ..\..\..\..\ - dockerfile: ..\..\..\ApiGateways\ApiGw-Base\Dockerfile -install: - chart: ../../../../k8s/helm/apigwmm - set: - replicaCount: 1 - image: - tag: $(tag) - pullPolicy: Never - ingress: - annotations: - kubernetes.io/ingress.class: traefik-azds - hosts: - # This expands to [space.s.]webmvc...aksapp.io - - $(spacePrefix)eshop$(hostSuffix) - inf: - k8s: - dns: $(spacePrefix)eshop$(hostSuffix) - values: - - values.dev.yaml? - - secrets.dev.yaml? - - inf.yaml - - app.yaml -configurations: - develop: - build: - useGitIgnore: true - dockerfile: ..\..\..\ApiGateways\ApiGw-Base\Dockerfile.develop - args: - BUILD_CONFIGURATION: ${BUILD_CONFIGURATION:-Debug} - container: - sync: - - '**/Pages/**' - - '**/Views/**' - - '**/wwwroot/**' - - '!**/*.{sln,csproj}' - command: [dotnet, run, --no-restore, --no-build, --no-launch-profile, -c, "${BUILD_CONFIGURATION:-Debug}"] - iterate: - processesToKill: [dotnet, vsdbg] - buildCommands: - - [dotnet, build, --no-restore, -c, "${BUILD_CONFIGURATION:-Debug}"] diff --git a/src/ApiGateways/Mobile.Bff.Marketing/apigw/configuration.json b/src/ApiGateways/Mobile.Bff.Marketing/apigw/configuration.json deleted file mode 100644 index 85d6777e6..000000000 --- a/src/ApiGateways/Mobile.Bff.Marketing/apigw/configuration.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "ReRoutes": [ - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "marketing.api", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/m/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "locations.api", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/l/{everything}", - "UpstreamHttpMethod": [] - } - - ], - "GlobalConfiguration": { - "RequestIdKey": "OcRequestId", - "AdministrationPath": "/administration" - } - } - \ No newline at end of file diff --git a/src/ApiGateways/Mobile.Bff.Marketing/apigw/values.dev.yaml b/src/ApiGateways/Mobile.Bff.Marketing/apigw/values.dev.yaml deleted file mode 100644 index fb59d98d5..000000000 --- a/src/ApiGateways/Mobile.Bff.Marketing/apigw/values.dev.yaml +++ /dev/null @@ -1,2 +0,0 @@ -ocelot: - configPath: /src/src/ApiGateways/ApiGw-Base/configuration \ No newline at end of file diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Config/UrlsConfig.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Config/UrlsConfig.cs index e920fbbb2..c0bb9502e 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Config/UrlsConfig.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Config/UrlsConfig.cs @@ -27,5 +27,8 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config public string Basket { get; set; } public string Catalog { get; set; } public string Orders { get; set; } + public string GrpcBasket { get; set; } + public string GrpcCatalog { get; set; } + public string GrpcOrdering { get; set; } } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/BasketController.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/BasketController.cs index a2c0d1fea..64399465a 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/BasketController.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/BasketController.cs @@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services; using System; -using System.Collections.Generic; using System.Linq; using System.Net; using System.Threading.Tasks; @@ -36,11 +35,21 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers } // Retrieve the current basket - var basket = await _basket.GetByIdAsync(data.BuyerId) ?? new BasketData(data.BuyerId); + var basket = await _basket.GetById(data.BuyerId) ?? new BasketData(data.BuyerId); var catalogItems = await _catalog.GetCatalogItemsAsync(data.Items.Select(x => x.ProductId)); - - foreach (var bitem in data.Items) + // group by product id to avoid duplicates + var itemsCalculated = data + .Items + .GroupBy(x => x.ProductId, x => x, (k, i) => new { productId = k, items = i }) + .Select(groupedItem => + { + var item = groupedItem.items.First(); + item.Quantity = groupedItem.items.Sum(i => i.Quantity); + return item; + }); + + foreach (var bitem in itemsCalculated) { var catalogItem = catalogItems.SingleOrDefault(ci => ci.Id == bitem.ProductId); if (catalogItem == null) @@ -48,15 +57,23 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers return BadRequest($"Basket refers to a non-existing catalog item ({bitem.ProductId})"); } - basket.Items.Add(new BasketDataItem() + var itemInBasket = basket.Items.FirstOrDefault(x => x.ProductId == bitem.ProductId); + if (itemInBasket == null) + { + basket.Items.Add(new BasketDataItem() + { + Id = bitem.Id, + ProductId = catalogItem.Id, + ProductName = catalogItem.Name, + PictureUrl = catalogItem.PictureUri, + UnitPrice = catalogItem.Price, + Quantity = bitem.Quantity + }); + } + else { - Id = bitem.Id, - ProductId = catalogItem.Id.ToString(), - ProductName = catalogItem.Name, - PictureUrl = catalogItem.PictureUri, - UnitPrice = catalogItem.Price, - Quantity = bitem.Quantity - }); + itemInBasket.Quantity = bitem.Quantity; + } } await _basket.UpdateAsync(basket); @@ -76,7 +93,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers } // Retrieve the current basket - var currentBasket = await _basket.GetByIdAsync(data.BasketId); + var currentBasket = await _basket.GetById(data.BasketId); if (currentBasket == null) { return BadRequest($"Basket with id {data.BasketId} not found."); @@ -118,13 +135,13 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers //item.PictureUri = // Step 2: Get current basket status - var currentBasket = (await _basket.GetByIdAsync(data.BasketId)) ?? new BasketData(data.BasketId); + var currentBasket = (await _basket.GetById(data.BasketId)) ?? new BasketData(data.BasketId); // Step 3: Merge current status with new product currentBasket.Items.Add(new BasketDataItem() { UnitPrice = item.Price, PictureUrl = item.PictureUri, - ProductId = item.Id.ToString(), + ProductId = item.Id, ProductName = item.Name, Quantity = data.Quantity, Id = Guid.NewGuid().ToString() diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/OrderController.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/OrderController.cs index a4b33c6cb..8bacc80d4 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/OrderController.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/OrderController.cs @@ -13,12 +13,12 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers public class OrderController : ControllerBase { private readonly IBasketService _basketService; - private readonly IOrderApiClient _orderClient; + private readonly IOrderingService _orderingService; - public OrderController(IBasketService basketService, IOrderApiClient orderClient) + public OrderController(IBasketService basketService, IOrderingService orderingService) { _basketService = basketService; - _orderClient = orderClient; + _orderingService = orderingService; } [Route("draft/{basketId}")] @@ -32,14 +32,14 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers return BadRequest("Need a valid basketid"); } // Get the basket data and build a order draft based on it - var basket = await _basketService.GetByIdAsync(basketId); + var basket = await _basketService.GetById(basketId); if (basket == null) { return BadRequest($"No basket found for id {basketId}"); } - return await _orderClient.GetOrderDraftFromBasketAsync(basket); + return await _orderingService.GetOrderDraftAsync(basket); } } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile index 7eb78458e..83a81394c 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile @@ -1,55 +1,20 @@ -FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base +FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base WORKDIR /app EXPOSE 80 -FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build WORKDIR /src -# Keep the project list and command dotnet restore identical in all Dockfiles to maximize image cache utilization -COPY eShopOnContainers-ServicesAndWebApps.sln . -COPY docker-compose.dcproj /src/ -COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/ -COPY src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj src/ApiGateways/Mobile.Bff.Shopping/aggregator/ -COPY src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj src/ApiGateways/Web.Bff.Shopping/aggregator/ -COPY src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj src/BuildingBlocks/Devspaces.Support/ -COPY src/BuildingBlocks/EventBus/EventBus/EventBus.csproj src/BuildingBlocks/EventBus/EventBus/ -COPY src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj src/BuildingBlocks/EventBus/EventBus.Tests/ -COPY src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj src/BuildingBlocks/EventBus/EventBusRabbitMQ/ -COPY src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj src/BuildingBlocks/EventBus/EventBusServiceBus/ -COPY src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj src/BuildingBlocks/EventBus/IntegrationEventLogEF/ -COPY src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj src/BuildingBlocks/WebHostCustomization/WebHost.Customization/ -COPY src/Services/Basket/Basket.API/Basket.API.csproj src/Services/Basket/Basket.API/ -COPY src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj src/Services/Basket/Basket.FunctionalTests/ -COPY src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj src/Services/Basket/Basket.UnitTests/ -COPY src/Services/Catalog/Catalog.API/Catalog.API.csproj src/Services/Catalog/Catalog.API/ -COPY src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj src/Services/Catalog/Catalog.FunctionalTests/ -COPY src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj src/Services/Catalog/Catalog.UnitTests/ -COPY src/Services/Identity/Identity.API/Identity.API.csproj src/Services/Identity/Identity.API/ -COPY src/Services/Location/Locations.API/Locations.API.csproj src/Services/Location/Locations.API/ -COPY src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj src/Services/Location/Locations.FunctionalTests/ -COPY src/Services/Marketing/Marketing.API/Marketing.API.csproj src/Services/Marketing/Marketing.API/ -COPY src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj src/Services/Marketing/Marketing.FunctionalTests/ -COPY src/Services/Ordering/Ordering.API/Ordering.API.csproj src/Services/Ordering/Ordering.API/ -COPY src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj src/Services/Ordering/Ordering.BackgroundTasks/ -COPY src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj src/Services/Ordering/Ordering.Domain/ -COPY src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj src/Services/Ordering/Ordering.FunctionalTests/ -COPY src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj src/Services/Ordering/Ordering.Infrastructure/ -COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/ -COPY src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj src/Services/Ordering/Ordering.UnitTests/ -COPY src/Services/Payment/Payment.API/Payment.API.csproj src/Services/Payment/Payment.API/ -COPY src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj src/Services/Webhooks/Webhooks.API/ -COPY src/Web/WebhookClient/WebhookClient.csproj src/Web/WebhookClient/ -COPY src/Web/WebMVC/WebMVC.csproj src/Web/WebMVC/ -COPY src/Web/WebSPA/WebSPA.csproj src/Web/WebSPA/ -COPY src/Web/WebStatus/WebStatus.csproj src/Web/WebStatus/ -COPY test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj test/ServicesTests/Application.FunctionalTests/ -COPY test/ServicesTests/LoadTest/LoadTest.csproj test/ServicesTests/LoadTest/ +COPY scripts scripts/ -RUN dotnet restore eShopOnContainers-ServicesAndWebApps.sln +COPY ApiGateways/*/*/*.csproj csproj-files/ +COPY BuildingBlocks/*/*/*.csproj csproj-files/ +COPY Services/*/*/*.csproj csproj-files/ +COPY Web/*/*.csproj csproj-files/ COPY . . -WORKDIR /src/src/ApiGateways/Mobile.Bff.Shopping/aggregator -RUN dotnet publish --no-restore -c Release -o /app +WORKDIR /src/ApiGateways/Mobile.Bff.Shopping/aggregator +RUN dotnet publish -c Release -o /app FROM build AS publish diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile.develop b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile.develop index c4330c370..4cfe352f0 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile.develop +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile.develop @@ -1,4 +1,4 @@ -FROM microsoft/dotnet:2.2-sdk +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster ARG BUILD_CONFIGURATION=Debug ENV ASPNETCORE_ENVIRONMENT=Development ENV DOTNET_USE_POLLING_FILE_WATCHER=true diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Filters/AuthorizeCheckOperationFilter.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Filters/AuthorizeCheckOperationFilter.cs index 21997360b..3b8298bfe 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Filters/AuthorizeCheckOperationFilter.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Filters/AuthorizeCheckOperationFilter.cs @@ -1,7 +1,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Filters { using Microsoft.AspNetCore.Authorization; - using Swashbuckle.AspNetCore.Swagger; + using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; using System.Collections.Generic; using System.Linq; @@ -10,7 +10,7 @@ { public class AuthorizeCheckOperationFilter : IOperationFilter { - public void Apply(Operation operation, OperationFilterContext context) + public void Apply(OpenApiOperation operation, OperationFilterContext context) { // Check for authorize attribute var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType().Any() || @@ -18,14 +18,19 @@ if (!hasAuthorize) return; - operation.Responses.TryAdd("401", new Response { Description = "Unauthorized" }); - operation.Responses.TryAdd("403", new Response { Description = "Forbidden" }); + operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" }); + operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" }); - operation.Security = new List>> + var oAuthScheme = new OpenApiSecurityScheme { - new Dictionary> + Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } + }; + + operation.Security = new List + { + new OpenApiSecurityRequirement { - { "oauth2", new [] { "Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator" } } + [ oAuthScheme ] = new [] { "Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator" } } }; } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Infrastructure/HttpClientAuthorizationDelegatingHandler.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Infrastructure/HttpClientAuthorizationDelegatingHandler.cs index 967a8c826..bfc705b5c 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Infrastructure/HttpClientAuthorizationDelegatingHandler.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Infrastructure/HttpClientAuthorizationDelegatingHandler.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; using System.Collections.Generic; using System.Net.Http; using System.Net.Http.Headers; @@ -8,18 +9,22 @@ using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure { - public class HttpClientAuthorizationDelegatingHandler - : DelegatingHandler + public class HttpClientAuthorizationDelegatingHandler : DelegatingHandler { private readonly IHttpContextAccessor _httpContextAccesor; + private readonly ILogger _logger; - public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccesor) + public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccesor, ILogger logger) { _httpContextAccesor = httpContextAccesor; + _logger = logger; } protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { + request.Version = new System.Version(2, 0); + request.Method = HttpMethod.Get; + var authorizationHeader = _httpContextAccesor.HttpContext .Request.Headers["Authorization"]; diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj index d45ab5f26..31d56dda7 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj @@ -1,10 +1,13 @@  - netcoreapp2.2 + $(NetCoreTargetVersion) Mobile.Shopping.HttpAggregator Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator ..\..\..\docker-compose.dcproj + false + true + $(LangVersion) @@ -13,18 +16,29 @@ - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/BasketData.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/BasketData.cs index 1b9348c44..426b8d2b5 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/BasketData.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/BasketData.cs @@ -1,26 +1,28 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Generic; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models { public class BasketData { public string BuyerId { get; set; } - public List Items { get; set; } + + public List Items { get; set; } = new List(); + + public BasketData() + { + + } public BasketData(string buyerId) { BuyerId = buyerId; - Items = new List(); } } public class BasketDataItem { public string Id { get; set; } - public string ProductId { get; set; } + public int ProductId { get; set; } public string ProductName { get; set; } public decimal UnitPrice { get; set; } public decimal OldUnitPrice { get; set; } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/CatalogItem.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/CatalogItem.cs index 25f766719..603c70bd7 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/CatalogItem.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/CatalogItem.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models +namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models { public class CatalogItem { @@ -13,8 +8,6 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models public decimal Price { get; set; } - public string PictureUri { get; set; } - } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/OrderData.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/OrderData.cs index e87cc18f0..e63b453a4 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/OrderData.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/OrderData.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models { @@ -28,6 +26,6 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models public string Buyer { get; set; } - public List OrderItems { get; } = new List(); + public List OrderItems { get; } = new List(); } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/OrderItemData.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/OrderItemData.cs index b0179e470..023cf20e5 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/OrderItemData.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/OrderItemData.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models +namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models { public class OrderItemData { diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/UpdateBasketItemsRequest.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/UpdateBasketItemsRequest.cs index 43cc81b89..35b3e76c0 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/UpdateBasketItemsRequest.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/UpdateBasketItemsRequest.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Generic; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models { diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/UpdateBasketRequest.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/UpdateBasketRequest.cs index cb22bf55f..b377921be 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/UpdateBasketRequest.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/UpdateBasketRequest.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Generic; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models { diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Program.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Program.cs index fc21a70a4..f536ec19a 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Program.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Program.cs @@ -1,20 +1,21 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore; +using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; using Serilog; +using System.IO; +using System.Net; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator { public class Program { + private static IConfiguration _configuration; + public static void Main(string[] args) { + _configuration = GetConfiguration(); + BuildWebHost(args).Run(); } @@ -40,5 +41,17 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator .WriteTo.Console(); }) .Build(); + + private static IConfiguration GetConfiguration() + { + var builder = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) + .AddEnvironmentVariables(); + + var config = builder.Build(); + + return builder.Build(); + } } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/BasketService.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/BasketService.cs index 5186fe361..5c8128be8 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/BasketService.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/BasketService.cs @@ -1,41 +1,108 @@ -using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config; +using Grpc.Net.Client; +using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Newtonsoft.Json; +using System; +using System.Linq; using System.Net.Http; using System.Threading.Tasks; +using GrpcBasket; +using Grpc.Core; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services { public class BasketService : IBasketService { - private readonly HttpClient _httpClient; - private readonly ILogger _logger; private readonly UrlsConfig _urls; + private readonly ILogger _logger; - public BasketService(HttpClient httpClient, ILogger logger, IOptions config) + public BasketService(HttpClient httpClient, IOptions config, ILogger logger) { _httpClient = httpClient; - _logger = logger; _urls = config.Value; + _logger = logger; } - public async Task GetByIdAsync(string id) + public async Task GetById(string id) { - var data = await _httpClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id)); + return await GrpcCallerService.CallService(_urls.GrpcBasket, async channel => + { + + var client = new Basket.BasketClient(channel); + _logger.LogDebug("grpc client created, request = {@id}", id); + var response = await client.GetBasketByIdAsync(new BasketRequest { Id = id }); + _logger.LogDebug("grpc response {@response}", response); - var basket = !string.IsNullOrEmpty(data) ? JsonConvert.DeserializeObject(data) : null; - - return basket; + return MapToBasketData(response); + }); } public async Task UpdateAsync(BasketData currentBasket) { - var basketContent = new StringContent(JsonConvert.SerializeObject(currentBasket), System.Text.Encoding.UTF8, "application/json"); + await GrpcCallerService.CallService(_urls.GrpcBasket, async httpClient => + { + var channel = GrpcChannel.ForAddress(_urls.GrpcBasket); + var client = new Basket.BasketClient(channel); + _logger.LogDebug("Grpc update basket currentBasket {@currentBasket}", currentBasket); + var request = MapToCustomerBasketRequest(currentBasket); + _logger.LogDebug("Grpc update basket request {@request}", request); + + return client.UpdateBasketAsync(request); + }); + } + + private BasketData MapToBasketData(CustomerBasketResponse customerBasketRequest) + { + if (customerBasketRequest == null) + { + return null; + } + + var map = new BasketData + { + BuyerId = customerBasketRequest.Buyerid + }; + + customerBasketRequest.Items.ToList().ForEach(item => map.Items.Add(new BasketDataItem + { + Id = item.Id, + OldUnitPrice = (decimal)item.Oldunitprice, + PictureUrl = item.Pictureurl, + ProductId = item.Productid, + ProductName = item.Productname, + Quantity = item.Quantity, + UnitPrice = (decimal)item.Unitprice + })); + + return map; + } + + private CustomerBasketRequest MapToCustomerBasketRequest(BasketData basketData) + { + if (basketData == null) + { + return null; + } + + var map = new CustomerBasketRequest + { + Buyerid = basketData.BuyerId + }; + + basketData.Items.ToList().ForEach(item => map.Items.Add(new BasketItemResponse + { + Id = item.Id, + Oldunitprice = (double)item.OldUnitPrice, + Pictureurl = item.PictureUrl, + Productid = item.ProductId, + Productname = item.ProductName, + Quantity = item.Quantity, + Unitprice = (double)item.UnitPrice + })); - var data = await _httpClient.PostAsync(_urls.Basket + UrlsConfig.BasketOperations.UpdateBasket(), basketContent); + return map; } } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/CatalogService.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/CatalogService.cs index 69bca2b39..2cf160d80 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/CatalogService.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/CatalogService.cs @@ -1,41 +1,60 @@ -using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config; +using CatalogApi; +using Grpc.Net.Client; +using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Newtonsoft.Json; using System.Collections.Generic; +using System.Linq; using System.Net.Http; using System.Threading.Tasks; +using static CatalogApi.Catalog; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services { public class CatalogService : ICatalogService { private readonly HttpClient _httpClient; - private readonly ILogger _logger; private readonly UrlsConfig _urls; - public CatalogService(HttpClient httpClient, ILogger logger, IOptions config) + public CatalogService(HttpClient httpClient, IOptions config) { _httpClient = httpClient; - _logger = logger; _urls = config.Value; } public async Task GetCatalogItemAsync(int id) { - var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id)); - var catalogItem = JsonConvert.DeserializeObject(stringContent); - return catalogItem; + return await GrpcCallerService.CallService(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id), async channel => + { + var client = new CatalogClient(channel); + var request = new CatalogItemRequest { Id = id }; + var response = await client.GetItemByIdAsync(request); + return MapToCatalogItemResponse(response); + }); } public async Task> GetCatalogItemsAsync(IEnumerable ids) { - var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemsById(ids)); - var catalogItems = JsonConvert.DeserializeObject(stringContent); - return catalogItems; + return await GrpcCallerService.CallService(_urls.GrpcCatalog, async channel=> + { + var client = new CatalogClient(channel); + var request = new CatalogItemsRequest { Ids = string.Join(",", ids), PageIndex = 1, PageSize = 10 }; + var response = await client.GetItemsByIdsAsync(request); + return response.Data.Select(this.MapToCatalogItemResponse); + }); + } + + private CatalogItem MapToCatalogItemResponse(CatalogItemResponse catalogItemResponse) + { + return new CatalogItem + { + Id = catalogItemResponse.Id, + Name = catalogItemResponse.Name, + PictureUri = catalogItemResponse.PictureUri, + Price = (decimal)catalogItemResponse.Price + }; } } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/GrpcCallerService.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/GrpcCallerService.cs new file mode 100644 index 000000000..72ad91daa --- /dev/null +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/GrpcCallerService.cs @@ -0,0 +1,77 @@ +using System.Net.Http; +using System.Threading.Tasks; +using System; +using Grpc.Core; +using Serilog; +using Grpc.Net.Client; + +namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services +{ + public static class GrpcCallerService + { + public static async Task CallService(string urlGrpc, Func> func) + { + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", true); + + var channel = GrpcChannel.ForAddress(urlGrpc); + + /* + using var httpClientHandler = new HttpClientHandler + { + ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; } + }; + + */ + + + Log.Information("Creating grpc client base address urlGrpc ={@urlGrpc}, BaseAddress={@BaseAddress} ", urlGrpc, channel.Target); + + try + { + return await func(channel); + } + catch (RpcException e) + { + Log.Error($"Error calling via grpc: {e.Status} - {e.Message}"); + return default; + } + finally + { + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", false); + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", false); + } + } + + public static async Task CallService(string urlGrpc, Func func) + { + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", true); + + /* + using var httpClientHandler = new HttpClientHandler + { + ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; } + }; + */ + + var channel = GrpcChannel.ForAddress(urlGrpc); + + Log.Debug("Creating grpc client base address {@httpClient.BaseAddress} ", channel.Target); + + try + { + await func(channel); + } + catch (RpcException e) + { + Log.Error($"Error calling via grpc: {e.Status} - {e.Message}"); + } + finally + { + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", false); + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", false); + } + } + } +} diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IBasketService.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IBasketService.cs index ad49e1adb..d7a390c75 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IBasketService.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IBasketService.cs @@ -5,7 +5,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services { public interface IBasketService { - Task GetByIdAsync(string id); + Task GetById(string id); Task UpdateAsync(BasketData currentBasket); diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IOrderingService.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IOrderingService.cs new file mode 100644 index 000000000..5518a4bbf --- /dev/null +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IOrderingService.cs @@ -0,0 +1,10 @@ +using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; +using System.Threading.Tasks; + +namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services +{ + public interface IOrderingService + { + Task GetOrderDraftAsync(BasketData basketData); + } +} \ No newline at end of file diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/OrderingService.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/OrderingService.cs new file mode 100644 index 000000000..a48c942de --- /dev/null +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/OrderingService.cs @@ -0,0 +1,90 @@ +using Grpc.Net.Client; +using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config; +using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using GrpcOrdering; + +namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services +{ + public class OrderingService : IOrderingService + { + private readonly HttpClient _httpClient; + private readonly UrlsConfig _urls; + private readonly ILogger _logger; + + public OrderingService(HttpClient httpClient, IOptions config, ILogger logger) + { + _httpClient = httpClient; + _urls = config.Value; + _logger = logger; + } + + public async Task GetOrderDraftAsync(BasketData basketData) + { + + return await GrpcCallerService.CallService(_urls.GrpcOrdering, async channel => + { + var client = new OrderingGrpc.OrderingGrpcClient(channel); + _logger.LogDebug(" grpc client created, basketData={@basketData}", basketData); + + var command = MapToOrderDraftCommand(basketData); + var response = await client.CreateOrderDraftFromBasketDataAsync(command); + _logger.LogDebug(" grpc response: {@response}", response); + + return MapToResponse(response, basketData); + }); + } + + private OrderData MapToResponse(GrpcOrdering.OrderDraftDTO orderDraft, BasketData basketData) + { + if (orderDraft == null) + { + return null; + } + + var data = new OrderData + { + Buyer = basketData.BuyerId, + Total = (decimal)orderDraft.Total, + }; + + orderDraft.OrderItems.ToList().ForEach(o => data.OrderItems.Add(new OrderItemData + { + Discount = (decimal)o.Discount, + PictureUrl = o.PictureUrl, + ProductId = o.ProductId, + ProductName = o.ProductName, + UnitPrice = (decimal)o.UnitPrice, + Units = o.Units, + })); + + return data; + } + + private CreateOrderDraftCommand MapToOrderDraftCommand(BasketData basketData) + { + var command = new CreateOrderDraftCommand + { + BuyerId = basketData.BuyerId, + }; + + basketData.Items.ForEach(i => command.Items.Add(new BasketItem + { + Id = i.Id, + OldUnitPrice = (double)i.OldUnitPrice, + PictureUrl = i.PictureUrl, + ProductId = i.ProductId, + ProductName = i.ProductName, + Quantity = i.Quantity, + UnitPrice = (double)i.UnitPrice, + })); + + return command; + } + + } +} diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs index eee0d9c6e..fb438221e 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs @@ -1,26 +1,22 @@ -using System; -using System.Collections.Generic; -using System.IdentityModel.Tokens.Jwt; -using System.Net.Http; +using Devspaces.Support; +using HealthChecks.UI.Client; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Polly; -using Polly.Extensions.Http; -using Swashbuckle.AspNetCore.Swagger; -using HealthChecks.UI.Client; -using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.Extensions.Diagnostics.HealthChecks; -using Devspaces.Support; +using Microsoft.Extensions.Logging; +using Microsoft.OpenApi.Models; +using System; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator { @@ -63,42 +59,41 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator app.UsePathBase(pathBase); } - app.UseHealthChecks("/hc", new HealthCheckOptions() - { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - - app.UseHealthChecks("/liveness", new HealthCheckOptions - { - Predicate = r => r.Name.Contains("self") - }); - - app.UseCors("CorsPolicy"); - if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } - else - { - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); - } + - app.UseAuthentication(); - app.UseHttpsRedirection(); - app.UseMvc(); + app.UseCors("CorsPolicy"); app.UseSwagger().UseSwaggerUI(c => - { - c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1"); - - c.OAuthClientId("Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregatorwaggerui"); - c.OAuthClientSecret(string.Empty); - c.OAuthRealm(string.Empty); - c.OAuthAppName("Purchase BFF Swagger UI"); - }); + { + c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1"); + + c.OAuthClientId("mobileshoppingaggswaggerui"); + c.OAuthClientSecret(string.Empty); + c.OAuthRealm(string.Empty); + c.OAuthAppName("Purchase BFF Swagger UI"); + }); + + app.UseRouting(); + app.UseAuthentication(); + app.UseAuthorization(); + app.UseEndpoints(endpoints => + { + endpoints.MapDefaultControllerRoute(); + endpoints.MapControllers(); + endpoints.MapHealthChecks("/hc", new HealthCheckOptions() + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + endpoints.MapHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = r => r.Name.Contains("self") + }); + }); } } @@ -109,29 +104,33 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator services.AddOptions(); services.Configure(configuration.GetSection("urls")); - services.AddMvc() - .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); + services.AddControllers() + .AddNewtonsoftJson(); services.AddSwaggerGen(options => { options.DescribeAllEnumsAsStrings(); - options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info + options.SwaggerDoc("v1", new OpenApiInfo { Title = "Shopping Aggregator for Mobile Clients", Version = "v1", - Description = "Shopping Aggregator for Mobile Clients", - TermsOfService = "Terms Of Service" + Description = "Shopping Aggregator for Mobile Clients" }); - - options.AddSecurityDefinition("oauth2", new OAuth2Scheme + options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme { - Type = "oauth2", - Flow = "implicit", - AuthorizationUrl = $"{configuration.GetValue("IdentityUrlExternal")}/connect/authorize", - TokenUrl = $"{configuration.GetValue("IdentityUrlExternal")}/connect/token", - Scopes = new Dictionary() + Type = SecuritySchemeType.OAuth2, + Flows = new OpenApiOAuthFlows() { - { "mobileshoppingagg", "Shopping Aggregator for Mobile Clients" } + Implicit = new OpenApiOAuthFlow() + { + AuthorizationUrl = new Uri($"{configuration.GetValue("IdentityUrlExternal")}/connect/authorize"), + TokenUrl = new Uri($"{configuration.GetValue("IdentityUrlExternal")}/connect/token"), + + Scopes = new Dictionary() + { + { "mobileshoppingagg", "Shopping Aggregator for Mobile Clients" } + } + } } }); @@ -152,7 +151,8 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator } public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) { - JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub"); + var identityUrl = configuration.GetValue("urls:identity"); services.AddAuthentication(options => @@ -166,15 +166,6 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator options.Authority = identityUrl; options.RequireHttpsMetadata = false; options.Audience = "mobileshoppingagg"; - options.Events = new JwtBearerEvents() - { - OnAuthenticationFailed = async ctx => - { - }, - OnTokenValidated = async ctx => - { - } - }; }); return services; @@ -187,38 +178,22 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator services.AddSingleton(); //register http services - services.AddHttpClient() + services + .AddHttpClient() .AddHttpMessageHandler() - .AddPolicyHandler(GetRetryPolicy()) - .AddPolicyHandler(GetCircuitBreakerPolicy()) .AddDevspacesSupport(); services.AddHttpClient() - .AddPolicyHandler(GetRetryPolicy()) - .AddPolicyHandler(GetCircuitBreakerPolicy()) .AddDevspacesSupport(); services.AddHttpClient() - .AddPolicyHandler(GetRetryPolicy()) - .AddPolicyHandler(GetCircuitBreakerPolicy()) .AddDevspacesSupport(); - return services; - } + services.AddHttpClient() + .AddDevspacesSupport(); - private static IAsyncPolicy GetRetryPolicy() - { - return HttpPolicyExtensions - .HandleTransientHttpError() - .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound) - .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); + return services; } - private static IAsyncPolicy GetCircuitBreakerPolicy() - { - return HttpPolicyExtensions - .HandleTransientHttpError() - .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)); - } } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/appsettings.localhost.json b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/appsettings.localhost.json index 57b5e894d..86fd1541d 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/appsettings.localhost.json +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/appsettings.localhost.json @@ -3,6 +3,24 @@ "basket": "http://localhost:55105", "catalog": "http://localhost:55101", "orders": "http://localhost:55102", - "identity": "http://localhost:55105" + "identity": "http://localhost:55105", + "grpcBasket": "http://localhost:5580", + "grpcCatalog": "http://localhost:81", + "grpcOrdering": "http://localhost:5581" + }, + "IdentityUrlExternal": "http://localhost:5105", + "IdentityUrl": "http://localhost:5105", + "Logging": { + "IncludeScopes": false, + "Debug": { + "LogLevel": { + "Default": "Debug" + } + }, + "Console": { + "LogLevel": { + "Default": "Debug" + } + } } } diff --git a/src/ApiGateways/Web.Bff.Marketing/apigw/azds.yaml b/src/ApiGateways/Web.Bff.Marketing/apigw/azds.yaml deleted file mode 100644 index 8f60cbcc7..000000000 --- a/src/ApiGateways/Web.Bff.Marketing/apigw/azds.yaml +++ /dev/null @@ -1,44 +0,0 @@ -kind: helm-release -apiVersion: 1.1 -build: - context: ..\..\..\..\ - dockerfile: ..\..\..\ApiGateways\ApiGw-Base\Dockerfile -install: - chart: ../../../../k8s/helm/apigwwm - set: - replicaCount: 1 - image: - tag: $(tag) - pullPolicy: Never - ingress: - annotations: - kubernetes.io/ingress.class: traefik-azds - hosts: - # This expands to [space.s.]webmvc...aksapp.io - - $(spacePrefix)eshop$(hostSuffix) - inf: - k8s: - dns: $(spacePrefix)eshop$(hostSuffix) - values: - - values.dev.yaml? - - secrets.dev.yaml? - - inf.yaml - - app.yaml -configurations: - develop: - build: - useGitIgnore: true - dockerfile: ..\..\..\ApiGateways\ApiGw-Base\Dockerfile.develop - args: - BUILD_CONFIGURATION: ${BUILD_CONFIGURATION:-Debug} - container: - sync: - - '**/Pages/**' - - '**/Views/**' - - '**/wwwroot/**' - - '!**/*.{sln,csproj}' - command: [dotnet, run, --no-restore, --no-build, --no-launch-profile, -c, "${BUILD_CONFIGURATION:-Debug}"] - iterate: - processesToKill: [dotnet, vsdbg] - buildCommands: - - [dotnet, build, --no-restore, -c, "${BUILD_CONFIGURATION:-Debug}"] diff --git a/src/ApiGateways/Web.Bff.Marketing/apigw/configuration.json b/src/ApiGateways/Web.Bff.Marketing/apigw/configuration.json deleted file mode 100644 index 8afe4a4d6..000000000 --- a/src/ApiGateways/Web.Bff.Marketing/apigw/configuration.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "ReRoutes": [ - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "marketing.api", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/m/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "locations.api", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/l/{everything}", - "UpstreamHttpMethod": [] - } - - ], - "GlobalConfiguration": { - "RequestIdKey": "OcRequestId", - "AdministrationPath": "/administration" - } -} - \ No newline at end of file diff --git a/src/ApiGateways/Web.Bff.Marketing/apigw/values.dev.yaml b/src/ApiGateways/Web.Bff.Marketing/apigw/values.dev.yaml deleted file mode 100644 index fb59d98d5..000000000 --- a/src/ApiGateways/Web.Bff.Marketing/apigw/values.dev.yaml +++ /dev/null @@ -1,2 +0,0 @@ -ocelot: - configPath: /src/src/ApiGateways/ApiGw-Base/configuration \ No newline at end of file diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Config/UrlsConfig.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Config/UrlsConfig.cs index 19be27dce..dccccab35 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Config/UrlsConfig.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Config/UrlsConfig.cs @@ -9,8 +9,11 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config { public class CatalogOperations { + // grpc call under REST must go trough port 80 public static string GetItemById(int id) => $"/api/v1/catalog/items/{id}"; - public static string GetItemsById(IEnumerable ids) => $"/api/v1/catalog/items?ids={string.Join(',', ids)}"; + public static string GetItemById(string ids) => $"/api/v1/catalog/items/ids/{string.Join(',', ids)}"; + // REST call standard must go through port 5000 + public static string GetItemsById(IEnumerable ids) => $":5000/api/v1/catalog/items?ids={string.Join(',', ids)}"; } public class BasketOperations @@ -27,5 +30,8 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config public string Basket { get; set; } public string Catalog { get; set; } public string Orders { get; set; } + public string GrpcBasket { get; set; } + public string GrpcCatalog { get; set; } + public string GrpcOrdering { get; set; } } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/BasketController.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/BasketController.cs index 00cf506a4..dd5d4e85c 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/BasketController.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/BasketController.cs @@ -7,6 +7,8 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Threading.Tasks; +using Serilog; +using Newtonsoft.Json; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers { @@ -36,11 +38,21 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers } // Retrieve the current basket - var basket = await _basket.GetByIdAsync(data.BuyerId) ?? new BasketData(data.BuyerId); - + var basket = await _basket.GetById(data.BuyerId) ?? new BasketData(data.BuyerId); var catalogItems = await _catalog.GetCatalogItemsAsync(data.Items.Select(x => x.ProductId)); - foreach (var bitem in data.Items) + // group by product id to avoid duplicates + var itemsCalculated = data + .Items + .GroupBy(x => x.ProductId, x => x, (k, i) => new { productId = k, items = i }) + .Select(groupedItem => + { + var item = groupedItem.items.First(); + item.Quantity = groupedItem.items.Sum(i => i.Quantity); + return item; + }); + + foreach (var bitem in itemsCalculated) { var catalogItem = catalogItems.SingleOrDefault(ci => ci.Id == bitem.ProductId); if (catalogItem == null) @@ -48,15 +60,23 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers return BadRequest($"Basket refers to a non-existing catalog item ({bitem.ProductId})"); } - basket.Items.Add(new BasketDataItem() + var itemInBasket = basket.Items.FirstOrDefault(x => x.ProductId == bitem.ProductId); + if (itemInBasket == null) { - Id = bitem.Id, - ProductId = catalogItem.Id.ToString(), - ProductName = catalogItem.Name, - PictureUrl = catalogItem.PictureUri, - UnitPrice = catalogItem.Price, - Quantity = bitem.Quantity - }); + basket.Items.Add(new BasketDataItem() + { + Id = bitem.Id, + ProductId = catalogItem.Id, + ProductName = catalogItem.Name, + PictureUrl = catalogItem.PictureUri, + UnitPrice = catalogItem.Price, + Quantity = bitem.Quantity + }); + } + else + { + itemInBasket.Quantity = bitem.Quantity; + } } await _basket.UpdateAsync(basket); @@ -76,7 +96,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers } // Retrieve the current basket - var currentBasket = await _basket.GetByIdAsync(data.BasketId); + var currentBasket = await _basket.GetById(data.BasketId); if (currentBasket == null) { return BadRequest($"Basket with id {data.BasketId} not found."); @@ -116,19 +136,29 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers //item.PictureUri = // Step 2: Get current basket status - var currentBasket = (await _basket.GetByIdAsync(data.BasketId)) ?? new BasketData(data.BasketId); - // Step 3: Merge current status with new product - currentBasket.Items.Add(new BasketDataItem() + var currentBasket = (await _basket.GetById(data.BasketId)) ?? new BasketData(data.BasketId); + // Step 3: Search if exist product into basket + var product = currentBasket.Items.SingleOrDefault(i => i.ProductId == item.Id); + if (product != null) { - UnitPrice = item.Price, - PictureUrl = item.PictureUri, - ProductId = item.Id.ToString(), - ProductName = item.Name, - Quantity = data.Quantity, - Id = Guid.NewGuid().ToString() - }); - - // Step 4: Update basket + // Step 4: Update quantity for product + product.Quantity += data.Quantity; + } + else + { + // Step 4: Merge current status with new product + currentBasket.Items.Add(new BasketDataItem() + { + UnitPrice = item.Price, + PictureUrl = item.PictureUri, + ProductId = item.Id, + ProductName = item.Name, + Quantity = data.Quantity, + Id = Guid.NewGuid().ToString() + }); + } + + // Step 5: Update basket await _basket.UpdateAsync(currentBasket); return Ok(); diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/OrderController.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/OrderController.cs index de3e4cc55..4b88c45b6 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/OrderController.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/OrderController.cs @@ -16,11 +16,11 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers public class OrderController : ControllerBase { private readonly IBasketService _basketService; - private readonly IOrderApiClient _orderClient; - public OrderController(IBasketService basketService, IOrderApiClient orderClient) + private readonly IOrderingService _orderingService; + public OrderController(IBasketService basketService, IOrderingService orderingService) { _basketService = basketService; - _orderClient = orderClient; + _orderingService = orderingService; } [Route("draft/{basketId}")] @@ -34,14 +34,14 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers return BadRequest("Need a valid basketid"); } // Get the basket data and build a order draft based on it - var basket = await _basketService.GetByIdAsync(basketId); + var basket = await _basketService.GetById(basketId); if (basket == null) { return BadRequest($"No basket found for id {basketId}"); } - return await _orderClient.GetOrderDraftFromBasketAsync(basket); + return await _orderingService.GetOrderDraftAsync(basket); } } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile b/src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile index e97db900b..19bdb9b84 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile @@ -1,55 +1,20 @@ -FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base +FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base WORKDIR /app EXPOSE 80 -FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build WORKDIR /src -# Keep the project list and command dotnet restore identical in all Dockfiles to maximize image cache utilization -COPY eShopOnContainers-ServicesAndWebApps.sln . -COPY docker-compose.dcproj /src/ -COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/ -COPY src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj src/ApiGateways/Mobile.Bff.Shopping/aggregator/ -COPY src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj src/ApiGateways/Web.Bff.Shopping/aggregator/ -COPY src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj src/BuildingBlocks/Devspaces.Support/ -COPY src/BuildingBlocks/EventBus/EventBus/EventBus.csproj src/BuildingBlocks/EventBus/EventBus/ -COPY src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj src/BuildingBlocks/EventBus/EventBus.Tests/ -COPY src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj src/BuildingBlocks/EventBus/EventBusRabbitMQ/ -COPY src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj src/BuildingBlocks/EventBus/EventBusServiceBus/ -COPY src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj src/BuildingBlocks/EventBus/IntegrationEventLogEF/ -COPY src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj src/BuildingBlocks/WebHostCustomization/WebHost.Customization/ -COPY src/Services/Basket/Basket.API/Basket.API.csproj src/Services/Basket/Basket.API/ -COPY src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj src/Services/Basket/Basket.FunctionalTests/ -COPY src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj src/Services/Basket/Basket.UnitTests/ -COPY src/Services/Catalog/Catalog.API/Catalog.API.csproj src/Services/Catalog/Catalog.API/ -COPY src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj src/Services/Catalog/Catalog.FunctionalTests/ -COPY src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj src/Services/Catalog/Catalog.UnitTests/ -COPY src/Services/Identity/Identity.API/Identity.API.csproj src/Services/Identity/Identity.API/ -COPY src/Services/Location/Locations.API/Locations.API.csproj src/Services/Location/Locations.API/ -COPY src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj src/Services/Location/Locations.FunctionalTests/ -COPY src/Services/Marketing/Marketing.API/Marketing.API.csproj src/Services/Marketing/Marketing.API/ -COPY src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj src/Services/Marketing/Marketing.FunctionalTests/ -COPY src/Services/Ordering/Ordering.API/Ordering.API.csproj src/Services/Ordering/Ordering.API/ -COPY src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj src/Services/Ordering/Ordering.BackgroundTasks/ -COPY src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj src/Services/Ordering/Ordering.Domain/ -COPY src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj src/Services/Ordering/Ordering.FunctionalTests/ -COPY src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj src/Services/Ordering/Ordering.Infrastructure/ -COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/ -COPY src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj src/Services/Ordering/Ordering.UnitTests/ -COPY src/Services/Payment/Payment.API/Payment.API.csproj src/Services/Payment/Payment.API/ -COPY src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj src/Services/Webhooks/Webhooks.API/ -COPY src/Web/WebhookClient/WebhookClient.csproj src/Web/WebhookClient/ -COPY src/Web/WebMVC/WebMVC.csproj src/Web/WebMVC/ -COPY src/Web/WebSPA/WebSPA.csproj src/Web/WebSPA/ -COPY src/Web/WebStatus/WebStatus.csproj src/Web/WebStatus/ -COPY test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj test/ServicesTests/Application.FunctionalTests/ -COPY test/ServicesTests/LoadTest/LoadTest.csproj test/ServicesTests/LoadTest/ +COPY scripts scripts/ -RUN dotnet restore eShopOnContainers-ServicesAndWebApps.sln +COPY ApiGateways/*/*/*.csproj csproj-files/ +COPY BuildingBlocks/*/*/*.csproj csproj-files/ +COPY Services/*/*/*.csproj csproj-files/ +COPY Web/*/*.csproj csproj-files/ COPY . . -WORKDIR /src/src/ApiGateways/Web.Bff.Shopping/aggregator -RUN dotnet publish --no-restore -c Release -o /app +WORKDIR /src/ApiGateways/Web.Bff.Shopping/aggregator +RUN dotnet publish -c Release -o /app FROM build AS publish diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile.develop b/src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile.develop index 3d0d16dd3..79f531777 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile.develop +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile.develop @@ -1,4 +1,4 @@ -FROM microsoft/dotnet:2.2-sdk +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster ARG BUILD_CONFIGURATION=Debug ENV ASPNETCORE_ENVIRONMENT=Development ENV DOTNET_USE_POLLING_FILE_WATCHER=true diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Filters/AuthorizeCheckOperationFilter.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Filters/AuthorizeCheckOperationFilter.cs index e93ec157c..45c191104 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Filters/AuthorizeCheckOperationFilter.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Filters/AuthorizeCheckOperationFilter.cs @@ -1,7 +1,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters { using Microsoft.AspNetCore.Authorization; - using Swashbuckle.AspNetCore.Swagger; + using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; using System.Collections.Generic; using System.Linq; @@ -10,7 +10,7 @@ { public class AuthorizeCheckOperationFilter : IOperationFilter { - public void Apply(Operation operation, OperationFilterContext context) + public void Apply(OpenApiOperation operation, OperationFilterContext context) { // Check for authorize attribute var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType().Any() || @@ -18,14 +18,19 @@ if (!hasAuthorize) return; - operation.Responses.TryAdd("401", new Response { Description = "Unauthorized" }); - operation.Responses.TryAdd("403", new Response { Description = "Forbidden" }); + operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" }); + operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" }); - operation.Security = new List>> + var oAuthScheme = new OpenApiSecurityScheme { - new Dictionary> + Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } + }; + + operation.Security = new List + { + new OpenApiSecurityRequirement { - { "oauth2", new [] { "Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator" } } + [ oAuthScheme ] = new [] { "Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator" } } }; } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Models/BasketData.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Models/BasketData.cs index 01831a5c9..507c7cdb7 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Models/BasketData.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Models/BasketData.cs @@ -1,26 +1,28 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Generic; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models { public class BasketData { public string BuyerId { get; set; } - public List Items { get; set; } + + public List Items { get; set; } = new List(); + + public BasketData() + { + + } public BasketData(string buyerId) { BuyerId = buyerId; - Items = new List(); } } public class BasketDataItem { public string Id { get; set; } - public string ProductId { get; set; } + public int ProductId { get; set; } public string ProductName { get; set; } public decimal UnitPrice { get; set; } public decimal OldUnitPrice { get; set; } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Models/CatalogItem.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Models/CatalogItem.cs index c6085f934..43e8e1cd1 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Models/CatalogItem.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Models/CatalogItem.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models +namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models { public class CatalogItem { @@ -13,8 +8,6 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models public decimal Price { get; set; } - public string PictureUri { get; set; } - } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Program.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Program.cs index 4bbac21e6..b601d67f2 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Program.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Program.cs @@ -1,12 +1,5 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore; +using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; using Serilog; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator @@ -40,5 +33,6 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator .WriteTo.Console(); }) .Build(); + } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/BasketService.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/BasketService.cs index d0fb5c008..b289e98d6 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/BasketService.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/BasketService.cs @@ -2,38 +2,116 @@ using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Newtonsoft.Json; -using System.Net.Http; using System.Threading.Tasks; +using Grpc.Net.Client; +using System.Linq; +using GrpcBasket; +using System.Net.Http; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services { public class BasketService : IBasketService { - private readonly HttpClient _apiClient; - private readonly ILogger _logger; private readonly UrlsConfig _urls; + public readonly HttpClient _httpClient; + private readonly ILogger _logger; - public BasketService(HttpClient httpClient,ILogger logger, IOptions config) + public BasketService(HttpClient httpClient, IOptions config, ILogger logger) { - _apiClient = httpClient; - _logger = logger; _urls = config.Value; + _httpClient = httpClient; + _logger = logger; } - public async Task GetByIdAsync(string id) + + public async Task GetById(string id) { - var data = await _apiClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id)); - var basket = !string.IsNullOrEmpty(data) ? JsonConvert.DeserializeObject(data) : null; + return await GrpcCallerService.CallService(_urls.GrpcBasket, async channel => + { + var client = new Basket.BasketClient(channel); + _logger.LogDebug("grpc client created, request = {@id}", id); + var response = await client.GetBasketByIdAsync(new BasketRequest { Id = id }); + _logger.LogDebug("grpc response {@response}", response); - return basket; + return MapToBasketData(response); + }); } public async Task UpdateAsync(BasketData currentBasket) { - var basketContent = new StringContent(JsonConvert.SerializeObject(currentBasket), System.Text.Encoding.UTF8, "application/json"); + await GrpcCallerService.CallService(_urls.GrpcBasket, async channel => + { + var client = new Basket.BasketClient(channel); + _logger.LogDebug("Grpc update basket currentBasket {@currentBasket}", currentBasket); + var request = MapToCustomerBasketRequest(currentBasket); + _logger.LogDebug("Grpc update basket request {@request}", request); + + return await client.UpdateBasketAsync(request); + }); + } + + private BasketData MapToBasketData(CustomerBasketResponse customerBasketRequest) + { + if (customerBasketRequest == null) + { + return null; + } + + var map = new BasketData + { + BuyerId = customerBasketRequest.Buyerid + }; + + customerBasketRequest.Items.ToList().ForEach(item => + { + if (item.Id != null) + { + map.Items.Add(new BasketDataItem + { + Id = item.Id, + OldUnitPrice = (decimal)item.Oldunitprice, + PictureUrl = item.Pictureurl, + ProductId = item.Productid, + ProductName = item.Productname, + Quantity = item.Quantity, + UnitPrice = (decimal)item.Unitprice + }); + } + }); + + return map; + } + + private CustomerBasketRequest MapToCustomerBasketRequest(BasketData basketData) + { + if (basketData == null) + { + return null; + } + + var map = new CustomerBasketRequest + { + Buyerid = basketData.BuyerId + }; + + basketData.Items.ToList().ForEach(item => + { + if (item.Id != null) + { + map.Items.Add(new BasketItemResponse + { + Id = item.Id, + Oldunitprice = (double)item.OldUnitPrice, + Pictureurl = item.PictureUrl, + Productid = item.ProductId, + Productname = item.ProductName, + Quantity = item.Quantity, + Unitprice = (double)item.UnitPrice + }); + } + }); - await _apiClient.PostAsync(_urls.Basket + UrlsConfig.BasketOperations.UpdateBasket(), basketContent); + return map; } } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/CatalogService.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/CatalogService.cs index 159e56d85..c10094928 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/CatalogService.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/CatalogService.cs @@ -2,10 +2,14 @@ using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Newtonsoft.Json; using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; +using CatalogApi; +using Grpc.Net.Client; +using System; +using static CatalogApi.Catalog; +using System.Linq; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services { @@ -24,16 +28,39 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services public async Task GetCatalogItemAsync(int id) { - var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id)); - - return JsonConvert.DeserializeObject(stringContent); + return await GrpcCallerService.CallService(_urls.GrpcCatalog, async channel => + { + var client = new CatalogClient(channel); + var request = new CatalogItemRequest { Id = id }; + _logger.LogInformation("grpc client created, request = {@request}", request); + var response = await client.GetItemByIdAsync(request); + _logger.LogInformation("grpc response {@response}", response); + return MapToCatalogItemResponse(response); + }); } public async Task> GetCatalogItemsAsync(IEnumerable ids) { - var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemsById(ids)); + return await GrpcCallerService.CallService(_urls.GrpcCatalog, async channel => + { + var client = new CatalogClient(channel); + var request = new CatalogItemsRequest { Ids = string.Join(",", ids), PageIndex = 1, PageSize = 10 }; + _logger.LogInformation("grpc client created, request = {@request}", request); + var response = await client.GetItemsByIdsAsync(request); + _logger.LogInformation("grpc response {@response}", response); + return response.Data.Select(this.MapToCatalogItemResponse); + }); + } - return JsonConvert.DeserializeObject(stringContent); + private CatalogItem MapToCatalogItemResponse(CatalogItemResponse catalogItemResponse) + { + return new CatalogItem + { + Id = catalogItemResponse.Id, + Name = catalogItemResponse.Name, + PictureUri = catalogItemResponse.PictureUri, + Price = (decimal)catalogItemResponse.Price + }; } } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/GrpcCallerService.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/GrpcCallerService.cs new file mode 100644 index 000000000..68d096ce5 --- /dev/null +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/GrpcCallerService.cs @@ -0,0 +1,78 @@ +using System.Threading.Tasks; +using System; +using Grpc.Core; +using Serilog; +using Grpc.Net.Client; + +namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services +{ + public static class GrpcCallerService + { + public static async Task CallService(string urlGrpc, Func> func) + { + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", true); + + var channel = GrpcChannel.ForAddress(urlGrpc); + + /* + using var httpClientHandler = new HttpClientHandler + { + ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; } + }; + + */ + + + Log.Information("Creating grpc client base address urlGrpc ={@urlGrpc}, BaseAddress={@BaseAddress} ", urlGrpc, channel.Target); + + try + { + return await func(channel); + } + catch (RpcException e) + { + Log.Error($"Error calling via grpc: {e.Status} - {e.Message}"); + return default; + } + finally + { + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", false); + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", false); + } + + + } + + public static async Task CallService(string urlGrpc, Func func) + { + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", true); + + /* + using var httpClientHandler = new HttpClientHandler + { + ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; } + }; + */ + + var channel = GrpcChannel.ForAddress(urlGrpc); + + Log.Debug("Creating grpc client base address {@httpClient.BaseAddress} ", channel.Target); + + try + { + await func(channel); + } + catch (RpcException e) + { + Log.Error($"Error calling via grpc: {e.Status} - {e.Message}"); + } + finally + { + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", false); + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", false); + } + } + } +} diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IBasketService.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IBasketService.cs index 046ef753d..fba539b7a 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IBasketService.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IBasketService.cs @@ -5,7 +5,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services { public interface IBasketService { - Task GetByIdAsync(string id); + Task GetById(string id); Task UpdateAsync(BasketData currentBasket); } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IOrderingService.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IOrderingService.cs new file mode 100644 index 000000000..a20520747 --- /dev/null +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IOrderingService.cs @@ -0,0 +1,10 @@ +using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; +using System.Threading.Tasks; + +namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services +{ + public interface IOrderingService + { + Task GetOrderDraftAsync(BasketData basketData); + } +} \ No newline at end of file diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/OrderingService.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/OrderingService.cs new file mode 100644 index 000000000..8075a507c --- /dev/null +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/OrderingService.cs @@ -0,0 +1,91 @@ +using Grpc.Net.Client; +using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config; +using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using GrpcOrdering; +using Grpc.Core; + +namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services +{ + public class OrderingService : IOrderingService + { + private readonly UrlsConfig _urls; + private readonly ILogger _logger; + public readonly HttpClient _httpClient; + + public OrderingService(HttpClient httpClient, IOptions config, ILogger logger) + { + _urls = config.Value; + _httpClient = httpClient; + _logger = logger; + } + + public async Task GetOrderDraftAsync(BasketData basketData) + { + return await GrpcCallerService.CallService(_urls.GrpcOrdering, async channel => + { + var client = new OrderingGrpc.OrderingGrpcClient(channel); + _logger.LogDebug(" grpc client created, basketData={@basketData}", basketData); + + var command = MapToOrderDraftCommand(basketData); + var response = await client.CreateOrderDraftFromBasketDataAsync(command); + _logger.LogDebug(" grpc response: {@response}", response); + + return MapToResponse(response, basketData); + }); + } + + private OrderData MapToResponse(GrpcOrdering.OrderDraftDTO orderDraft, BasketData basketData) + { + if (orderDraft == null) + { + return null; + } + + var data = new OrderData + { + Buyer = basketData.BuyerId, + Total = (decimal)orderDraft.Total, + }; + + orderDraft.OrderItems.ToList().ForEach(o => data.OrderItems.Add(new OrderItemData + { + Discount = (decimal)o.Discount, + PictureUrl = o.PictureUrl, + ProductId = o.ProductId, + ProductName = o.ProductName, + UnitPrice = (decimal)o.UnitPrice, + Units = o.Units, + })); + + return data; + } + + private CreateOrderDraftCommand MapToOrderDraftCommand(BasketData basketData) + { + var command = new CreateOrderDraftCommand + { + BuyerId = basketData.BuyerId, + }; + + basketData.Items.ForEach(i => command.Items.Add(new BasketItem + { + Id = i.Id, + OldUnitPrice = (double)i.OldUnitPrice, + PictureUrl = i.PictureUrl, + ProductId = i.ProductId, + ProductName = i.ProductName, + Quantity = i.Quantity, + UnitPrice = (double)i.UnitPrice, + })); + + return command; + } + + } +} diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs index dd5e1cc8c..f99a7a5aa 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs @@ -1,5 +1,8 @@ -using Microsoft.AspNetCore.Authentication.JwtBearer; +using Devspaces.Support; +using HealthChecks.UI.Client; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -9,19 +12,12 @@ using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure; using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; -using Polly; -using Polly.Extensions.Http; -using Polly.Timeout; -using Swashbuckle.AspNetCore.Swagger; +using Microsoft.OpenApi.Models; using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; -using System.Net.Http; -using HealthChecks.UI.Client; -using Microsoft.AspNetCore.Diagnostics.HealthChecks; -using Microsoft.Extensions.Diagnostics.HealthChecks; -using Devspaces.Support; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator { @@ -63,39 +59,43 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator app.UsePathBase(pathBase); } - app.UseHealthChecks("/hc", new HealthCheckOptions() - { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - - app.UseHealthChecks("/liveness", new HealthCheckOptions - { - Predicate = r => r.Name.Contains("self") - }); - - app.UseCors("CorsPolicy"); - if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } - else + + + app.UseCors("CorsPolicy"); + app.UseHttpsRedirection(); + + app.UseSwagger().UseSwaggerUI(c => { - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); - } + c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1"); + + c.OAuthClientId("webshoppingaggswaggerui"); + c.OAuthClientSecret(string.Empty); + c.OAuthRealm(string.Empty); + c.OAuthAppName("web shopping bff Swagger UI"); + }); + app.UseRouting(); app.UseAuthentication(); - app.UseHttpsRedirection(); - app.UseMvc(); + app.UseAuthorization(); - app.UseSwagger() - .UseSwaggerUI(c => + app.UseEndpoints(endpoints => + { + endpoints.MapDefaultControllerRoute(); + endpoints.MapControllers(); + endpoints.MapHealthChecks("/hc", new HealthCheckOptions() + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + endpoints.MapHealthChecks("/liveness", new HealthCheckOptions { - c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1"); - //c.ConfigureOAuth2("Microsoft.eShopOnContainers.Web.Shopping.HttpAggregatorwaggerui", "", "", "Purchase BFF Swagger UI"); + Predicate = r => r.Name.Contains("self") }); + }); } } @@ -103,29 +103,20 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator { public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) { - JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub"); + var identityUrl = configuration.GetValue("urls:identity"); services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - }).AddJwtBearer(options => + }) + .AddJwtBearer(options => { options.Authority = identityUrl; options.RequireHttpsMetadata = false; options.Audience = "webshoppingagg"; - options.Events = new JwtBearerEvents() - { - OnAuthenticationFailed = async ctx => - { - int i = 0; - }, - OnTokenValidated = async ctx => - { - int i = 0; - } - }; }); return services; @@ -136,29 +127,35 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator services.AddOptions(); services.Configure(configuration.GetSection("urls")); - services.AddMvc() - .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); + services.AddControllers() + .AddNewtonsoftJson(); services.AddSwaggerGen(options => { options.DescribeAllEnumsAsStrings(); - options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info + + options.SwaggerDoc("v1", new OpenApiInfo { Title = "Shopping Aggregator for Web Clients", Version = "v1", - Description = "Shopping Aggregator for Web Clients", - TermsOfService = "Terms Of Service" + Description = "Shopping Aggregator for Web Clients" }); - options.AddSecurityDefinition("oauth2", new OAuth2Scheme + options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme { - Type = "oauth2", - Flow = "implicit", - AuthorizationUrl = $"{configuration.GetValue("IdentityUrlExternal")}/connect/authorize", - TokenUrl = $"{configuration.GetValue("IdentityUrlExternal")}/connect/token", - Scopes = new Dictionary() + Type = SecuritySchemeType.OAuth2, + Flows = new OpenApiOAuthFlows() { - { "webshoppingagg", "Shopping Aggregator for Web Clients" } + Implicit = new OpenApiOAuthFlow() + { + AuthorizationUrl = new Uri($"{configuration.GetValue("IdentityUrlExternal")}/connect/authorize"), + TokenUrl = new Uri($"{configuration.GetValue("IdentityUrlExternal")}/connect/token"), + + Scopes = new Dictionary() + { + { "webshoppingagg", "Shopping Aggregator for Web Clients" } + } + } } }); @@ -187,38 +184,22 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator services.AddHttpClient() .AddHttpMessageHandler() - .AddPolicyHandler(GetRetryPolicy()) - .AddPolicyHandler(GetCircuitBreakerPolicy()) .AddDevspacesSupport(); services.AddHttpClient() - .AddPolicyHandler(GetRetryPolicy()) - .AddPolicyHandler(GetCircuitBreakerPolicy()) .AddDevspacesSupport(); services.AddHttpClient() .AddHttpMessageHandler() - .AddPolicyHandler(GetRetryPolicy()) - .AddPolicyHandler(GetCircuitBreakerPolicy()) + .AddDevspacesSupport(); + + services.AddHttpClient() + .AddHttpMessageHandler() .AddDevspacesSupport(); return services; } - static IAsyncPolicy GetRetryPolicy() - { - return HttpPolicyExtensions - .HandleTransientHttpError() - .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound) - .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); - - } - static IAsyncPolicy GetCircuitBreakerPolicy() - { - return HttpPolicyExtensions - .HandleTransientHttpError() - .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)); - } } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj b/src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj index 8b74eacef..0f8ae5efe 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj @@ -1,10 +1,13 @@  - netcoreapp2.2 + $(NetCoreTargetVersion) Web.Shopping.HttpAggregator Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator ..\..\..\docker-compose.dcproj + false + true + $(LangVersion) @@ -13,17 +16,30 @@ - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/appsettings.Development.json b/src/ApiGateways/Web.Bff.Shopping/aggregator/appsettings.Development.json new file mode 100644 index 000000000..19b8c1529 --- /dev/null +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/appsettings.Development.json @@ -0,0 +1,15 @@ +{ + "Logging": { + "IncludeScopes": false, + "Debug": { + "LogLevel": { + "Default": "Debug" + } + }, + "Console": { + "LogLevel": { + "Default": "Debug" + } + } + } +} diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/appsettings.localhost.json b/src/ApiGateways/Web.Bff.Shopping/aggregator/appsettings.localhost.json index 57b5e894d..57c5afc34 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/appsettings.localhost.json +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/appsettings.localhost.json @@ -3,6 +3,9 @@ "basket": "http://localhost:55105", "catalog": "http://localhost:55101", "orders": "http://localhost:55102", - "identity": "http://localhost:55105" + "identity": "http://localhost:55105", + "grpcBasket": "http://localhost:5580", + "grpcCatalog": "http://localhost:81", + "grpcOrdering": "http://localhost:5581" } } diff --git a/src/ApiGateways/Web.Bff.Shopping/apigw/azds.yaml b/src/ApiGateways/Web.Bff.Shopping/apigw/azds.yaml deleted file mode 100644 index 69f26cdca..000000000 --- a/src/ApiGateways/Web.Bff.Shopping/apigw/azds.yaml +++ /dev/null @@ -1,43 +0,0 @@ -kind: helm-release -apiVersion: 1.1 -build: - context: ..\..\..\..\ - dockerfile: ..\..\..\..\ApiGateways\ApiGw-Base\Dockerfile -install: - chart: ../../../../k8s/helm/apigwws - set: - replicaCount: 1 - image: - tag: $(tag) - pullPolicy: Never - ingress: - annotations: - kubernetes.io/ingress.class: traefik-azds - hosts: - - $(spacePrefix)eshop$(hostSuffix) - inf: - k8s: - dns: $(spacePrefix)eshop$(hostSuffix) - values: - - values.dev.yaml? - - secrets.dev.yaml? - - inf.yaml - - app.yaml -configurations: - develop: - build: - useGitIgnore: true - dockerfile: ..\..\..\ApiGateways\ApiGw-Base\Dockerfile.develop - args: - BUILD_CONFIGURATION: ${BUILD_CONFIGURATION:-Debug} - container: - sync: - - '**/Pages/**' - - '**/Views/**' - - '**/wwwroot/**' - - '!**/*.{sln,csproj}' - command: [dotnet, run, --no-restore, --no-build, --no-launch-profile, -c, "${BUILD_CONFIGURATION:-Debug}"] - iterate: - processesToKill: [dotnet, vsdbg] - buildCommands: - - [dotnet, build, --no-restore, -c, "${BUILD_CONFIGURATION:-Debug}"] diff --git a/src/ApiGateways/Web.Bff.Shopping/apigw/configuration.json b/src/ApiGateways/Web.Bff.Shopping/apigw/configuration.json deleted file mode 100644 index b3e01d773..000000000 --- a/src/ApiGateways/Web.Bff.Shopping/apigw/configuration.json +++ /dev/null @@ -1,130 +0,0 @@ -{ - "ReRoutes": [ - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "catalog.api", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/c/{everything}", - "UpstreamHttpMethod": [ "GET" ] - }, - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "basket.api", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/b/{everything}", - "UpstreamHttpMethod": [], - "AuthenticationOptions": { - "AuthenticationProviderKey": "IdentityApiKey", - "AllowedScopes": [] - } - }, - { - "DownstreamPathTemplate": "/api/{version}/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "ordering.api", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/api/{version}/o/{everything}", - "UpstreamHttpMethod": [], - "AuthenticationOptions": { - "AuthenticationProviderKey": "IdentityApiKey", - "AllowedScopes": [] - } - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "webshoppingagg", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/{everything}", - "UpstreamHttpMethod": [ "POST", "PUT", "GET" ], - "AuthenticationOptions": { - "AuthenticationProviderKey": "IdentityApiKey", - "AllowedScopes": [] - } - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "ordering.api", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/orders-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "ordering.signalrhub", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/hub/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "basket.api", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/basket-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "catalog.api", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/catalog-api/{everything}", - "UpstreamHttpMethod": [] - }, - { - "DownstreamPathTemplate": "/{everything}", - "DownstreamScheme": "http", - "DownstreamHostAndPorts": [ - { - "Host": "payment.api", - "Port": 80 - } - ], - "UpstreamPathTemplate": "/payment-api/{everything}", - "UpstreamHttpMethod": [] - } - - ], - "GlobalConfiguration": { - "RequestIdKey": "OcRequestId", - "AdministrationPath": "/administration" - } - } - \ No newline at end of file diff --git a/src/ApiGateways/Web.Bff.Shopping/apigw/values.dev.yaml b/src/ApiGateways/Web.Bff.Shopping/apigw/values.dev.yaml deleted file mode 100644 index fb59d98d5..000000000 --- a/src/ApiGateways/Web.Bff.Shopping/apigw/values.dev.yaml +++ /dev/null @@ -1,2 +0,0 @@ -ocelot: - configPath: /src/src/ApiGateways/ApiGw-Base/configuration \ No newline at end of file diff --git a/src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj b/src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj index 81a897bad..0679c99a6 100644 --- a/src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj +++ b/src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj @@ -4,8 +4,8 @@ netstandard2.0 - - - + + + diff --git a/src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj b/src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj index 3f73ec223..1d3f2bc0f 100644 --- a/src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj +++ b/src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj @@ -1,13 +1,13 @@  - netstandard2.0 + $(NetStandardTargetVersion) - - - + + + diff --git a/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj b/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj index 9704f6ff5..53d0a36a2 100644 --- a/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj +++ b/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj @@ -1,12 +1,12 @@  - netstandard2.0 + $(NetStandardTargetVersion) Microsoft.eShopOnContainers.BuildingBlocks.EventBus - + \ No newline at end of file diff --git a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj index 62373d1b3..a6116abec 100644 --- a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj +++ b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj @@ -1,18 +1,18 @@  - netstandard2.0 + $(NetStandardTargetVersion) Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ - - - - - - - + + + + + + + diff --git a/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj b/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj index 3de07e329..362bccf6c 100644 --- a/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj +++ b/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj @@ -1,15 +1,15 @@  - netstandard2.0 + $(NetStandardTargetVersion) Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus - - - - + + + + diff --git a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj index 4059d7f41..14b867059 100644 --- a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj +++ b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj @@ -1,17 +1,20 @@  - netstandard2.0 + $(NetStandardTargetVersion) Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF - - - - - - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + diff --git a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEntry.cs b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEntry.cs index dc65fa525..f9cf4a2c1 100644 --- a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEntry.cs +++ b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEntry.cs @@ -6,6 +6,8 @@ using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; using System.Linq; using System.ComponentModel.DataAnnotations.Schema; using System.Reflection; +using Microsoft.Extensions.Logging; +using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services; namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF { @@ -22,7 +24,6 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF TimesSent = 0; TransactionId = transactionId.ToString(); } - public Guid EventId { get; private set; } public string EventTypeName { get; private set; } [NotMapped] diff --git a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Services/IntegrationEventLogService.cs b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Services/IntegrationEventLogService.cs index 758055e69..04fa84618 100644 --- a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Services/IntegrationEventLogService.cs +++ b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Services/IntegrationEventLogService.cs @@ -3,6 +3,7 @@ using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using System; using System.Collections; @@ -39,11 +40,15 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Servi { var tid = transactionId.ToString(); - return await _integrationEventLogContext.IntegrationEventLogs - .Where(e => e.TransactionId == tid && e.State == EventStateEnum.NotPublished) - .OrderBy(o => o.CreationTime) - .Select(e => e.DeserializeJsonContent(_eventTypes.Find(t=> t.Name == e.EventTypeShortName))) - .ToListAsync(); + var result = await _integrationEventLogContext.IntegrationEventLogs + .Where(e => e.TransactionId == tid && e.State == EventStateEnum.NotPublished).ToListAsync(); + + if(result != null && result.Any()){ + return result.OrderBy(o => o.CreationTime) + .Select(e => e.DeserializeJsonContent(_eventTypes.Find(t=> t.Name == e.EventTypeShortName))); + } + + return new List(); } public Task SaveEventAsync(IntegrationEvent @event, IDbContextTransaction transaction) diff --git a/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj b/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj index 87709e6fe..38ab6b285 100644 --- a/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj +++ b/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj @@ -1,12 +1,22 @@  - netcoreapp2.2 + $(NetCoreTargetVersion) + false - - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + diff --git a/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHostExtensions.cs b/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHostExtensions.cs index fa06e0a0b..6316ae59d 100644 --- a/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHostExtensions.cs +++ b/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHostExtensions.cs @@ -3,7 +3,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Polly; -using Polly.Retry; using System; using System.Data.SqlClient; @@ -18,16 +17,14 @@ namespace Microsoft.AspNetCore.Hosting return orchestratorType?.ToUpper() == "K8S"; } - public static IWebHost MigrateDbContext(this IWebHost webHost, Action seeder) where TContext : DbContext + public static IWebHost MigrateDbContext(this IWebHost webHost, Action seeder) where TContext : DbContext { var underK8s = webHost.IsInKubernetes(); using (var scope = webHost.Services.CreateScope()) { var services = scope.ServiceProvider; - var logger = services.GetRequiredService>(); - var context = services.GetService(); try @@ -40,13 +37,15 @@ namespace Microsoft.AspNetCore.Hosting } else { + var retries = 10; var retry = Policy.Handle() - .WaitAndRetry(new TimeSpan[] - { - TimeSpan.FromSeconds(3), - TimeSpan.FromSeconds(5), - TimeSpan.FromSeconds(8), - }); + .WaitAndRetry( + retryCount: retries, + sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), + onRetry: (exception, timeSpan, retry, ctx) => + { + logger.LogWarning(exception, "[{prefix}] Exception {ExceptionType} with message {Message} detected on attempt {retry} of {retries}", nameof(TContext), exception.GetType().Name, exception.Message, retry, retries); + }); //if the sql server container is not created on run docker compose this //migration can't fail for network related exception. The retry options for DbContext only @@ -71,7 +70,7 @@ namespace Microsoft.AspNetCore.Hosting } private static void InvokeSeeder(Action seeder, TContext context, IServiceProvider services) - where TContext : DbContext + where TContext : DbContext { context.Database.Migrate(); seeder(context, services); diff --git a/src/Clients/Clients.Grpc.Caller/Clients.Grpc.Caller.csproj b/src/Clients/Clients.Grpc.Caller/Clients.Grpc.Caller.csproj new file mode 100644 index 000000000..7cf903982 --- /dev/null +++ b/src/Clients/Clients.Grpc.Caller/Clients.Grpc.Caller.csproj @@ -0,0 +1,17 @@ + + + + Exe + netcoreapp3.0 + + + + + + + + + + + + diff --git a/src/Clients/Clients.Grpc.Caller/Program.cs b/src/Clients/Clients.Grpc.Caller/Program.cs new file mode 100644 index 000000000..5a671ac6e --- /dev/null +++ b/src/Clients/Clients.Grpc.Caller/Program.cs @@ -0,0 +1,50 @@ +using System; +using System.Net.Http; +using System.Threading.Tasks; +using Grpc.Core; +using Grpc.Net.Client; +using GrpcBasket; +namespace Clients.Grpc.Caller +{ + class Program + { + static async Task Main(string[] args) + { + Console.WriteLine("Starting..."); + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", true); + + using (var httpClientHandler = new HttpClientHandler()) + { + httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; }; + using (var httpClient = new HttpClient(httpClientHandler)) + { + // Make your request... + // var httpClient = new HttpClient(); + // The port number(5001) must match the port of the gRPC server. + //httpClient.BaseAddress = new Uri("http://localhost:5103"); + httpClient.BaseAddress = new Uri("http://localhost:5580"); + //httpClient.DefaultRequestVersion = Version.Parse("2.0"); + var client = GrpcClient.Create(httpClient); + + try + { + var reply = await client.GetBasketByIdAsync( + new BasketRequest { Id = "4f71a02f-4738-43a9-8c81-7652877e7102" }); + Console.WriteLine("Greeting: " + reply.Buyerid); + Console.WriteLine("Greeting: " + reply.Items); + + } + //catch(Grpc) + catch (RpcException e) + { + Console.WriteLine($"Error calling via grpc: {e.Status} - {e.Message}"); + } + + Console.WriteLine("Press any key to exit..."); + Console.ReadKey(); + } + } + } + } +} diff --git a/src/Clients/Clients.Grpc.Caller/Protos/basket.proto b/src/Clients/Clients.Grpc.Caller/Protos/basket.proto new file mode 100644 index 000000000..f23c2f38e --- /dev/null +++ b/src/Clients/Clients.Grpc.Caller/Protos/basket.proto @@ -0,0 +1,34 @@ +syntax = "proto3"; + +option csharp_namespace = "GrpcBasket"; + +package BasketApi; + +service Basket { + rpc GetBasketById(BasketRequest) returns (CustomerBasketResponse); + rpc UpdateBasket(CustomerBasketRequest) returns (CustomerBasketResponse); +} + +message BasketRequest { + string id = 1; +} + +message CustomerBasketRequest { + string buyerid = 1; + repeated BasketItemResponse items = 2; +} + +message CustomerBasketResponse { + string buyerid = 1; + repeated BasketItemResponse items = 2; +} + +message BasketItemResponse { + string id = 1; + int32 productid = 2; + string productname = 3; + double unitprice = 4; + double oldunitprice = 5; + int32 quantity = 6; + string pictureurl = 7; +} \ No newline at end of file diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 000000000..b137daefc --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/NuGet.config b/src/NuGet.config similarity index 63% rename from NuGet.config rename to src/NuGet.config index 0a3819dd2..b9234a5b7 100644 --- a/NuGet.config +++ b/src/NuGet.config @@ -4,10 +4,9 @@ - - - - + + + \ No newline at end of file diff --git a/src/Services/Basket/Basket.API/Auth/Server/AuthorizationHeaderParameterOperationFilter.cs b/src/Services/Basket/Basket.API/Auth/Server/AuthorizationHeaderParameterOperationFilter.cs index 90aa89322..7fe19bae3 100644 --- a/src/Services/Basket/Basket.API/Auth/Server/AuthorizationHeaderParameterOperationFilter.cs +++ b/src/Services/Basket/Basket.API/Auth/Server/AuthorizationHeaderParameterOperationFilter.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc.Authorization; +using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.Swagger; using Swashbuckle.AspNetCore.SwaggerGen; using System.Collections.Generic; @@ -8,7 +9,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Auth.Server { public class AuthorizationHeaderParameterOperationFilter : IOperationFilter { - public void Apply(Operation operation, OperationFilterContext context) + public void Apply(OpenApiOperation operation, OperationFilterContext context) { var filterPipeline = context.ApiDescription.ActionDescriptor.FilterDescriptors; var isAuthorized = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is AuthorizeFilter); @@ -17,15 +18,15 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Auth.Server if (isAuthorized && !allowAnonymous) { if (operation.Parameters == null) - operation.Parameters = new List(); + operation.Parameters = new List(); - operation.Parameters.Add(new NonBodyParameter + + operation.Parameters.Add(new OpenApiParameter { Name = "Authorization", - In = "header", + In = ParameterLocation.Header, Description = "access token", - Required = true, - Type = "string" + Required = true }); } } diff --git a/src/Services/Basket/Basket.API/Auth/Server/IdentitySecurityScheme.cs b/src/Services/Basket/Basket.API/Auth/Server/IdentitySecurityScheme.cs deleted file mode 100644 index 397f66db4..000000000 --- a/src/Services/Basket/Basket.API/Auth/Server/IdentitySecurityScheme.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Swashbuckle.AspNetCore.Swagger; -using System.Collections.Generic; - -namespace Microsoft.eShopOnContainers.Services.Basket.API.Auth.Server -{ - public class IdentitySecurityScheme:SecurityScheme - { - public IdentitySecurityScheme() - { - Type = "IdentitySecurityScheme"; - Description = "Security definition that provides to the user of Swagger a mechanism to obtain a token from the identity service that secures the api"; - Extensions.Add("authorizationUrl", "http://localhost:5103/Auth/Client/popup.html"); - Extensions.Add("flow", "implicit"); - Extensions.Add("scopes", new List - { - "basket" - }); - } - } -} diff --git a/src/Services/Basket/Basket.API/Basket.API.csproj b/src/Services/Basket/Basket.API/Basket.API.csproj index 5b5ed12a2..df260ed7e 100644 --- a/src/Services/Basket/Basket.API/Basket.API.csproj +++ b/src/Services/Basket/Basket.API/Basket.API.csproj @@ -1,9 +1,12 @@  - netcoreapp2.2 + $(NetCoreTargetVersion) $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; ..\..\..\..\docker-compose.dcproj + false + true + $(LangVersion) @@ -13,28 +16,35 @@ - - - + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Services/Basket/Basket.API/Controllers/BasketController.cs b/src/Services/Basket/Basket.API/Controllers/BasketController.cs index 0bf15fc42..9864e21e8 100644 --- a/src/Services/Basket/Basket.API/Controllers/BasketController.cs +++ b/src/Services/Basket/Basket.API/Controllers/BasketController.cs @@ -7,7 +7,9 @@ using Microsoft.eShopOnContainers.Services.Basket.API.Model; using Microsoft.eShopOnContainers.Services.Basket.API.Services; using Microsoft.Extensions.Logging; using System; +using System.Linq; using System.Net; +using System.Security.Claims; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers @@ -68,7 +70,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers return BadRequest(); } - var userName = User.FindFirst(x => x.Type == "unique_name").Value; + var userName = this.HttpContext.User.FindFirst(x => x.Type == ClaimTypes.Name).Value; var eventMessage = new UserCheckoutAcceptedIntegrationEvent(userId, userName, basketCheckout.City, basketCheckout.Street, basketCheckout.State, basketCheckout.Country, basketCheckout.ZipCode, basketCheckout.CardNumber, basketCheckout.CardHolderName, @@ -79,8 +81,6 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers // order creation process try { - _logger.LogInformation("----- Publishing integration event: {IntegrationEventId} from {AppName} - ({@IntegrationEvent})", eventMessage.Id, Program.AppName, eventMessage); - _eventBus.Publish(eventMessage); } catch (Exception ex) diff --git a/src/Services/Basket/Basket.API/Dockerfile b/src/Services/Basket/Basket.API/Dockerfile index 6fb28f69a..793b010ab 100644 --- a/src/Services/Basket/Basket.API/Dockerfile +++ b/src/Services/Basket/Basket.API/Dockerfile @@ -1,61 +1,26 @@ -FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base +FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base WORKDIR /app EXPOSE 80 -FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build WORKDIR /src -# Keep the project list and command dotnet restore identical in all Dockfiles to maximize image cache utilization -COPY eShopOnContainers-ServicesAndWebApps.sln . -COPY docker-compose.dcproj /src/ -COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/ -COPY src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj src/ApiGateways/Mobile.Bff.Shopping/aggregator/ -COPY src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj src/ApiGateways/Web.Bff.Shopping/aggregator/ -COPY src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj src/BuildingBlocks/Devspaces.Support/ -COPY src/BuildingBlocks/EventBus/EventBus/EventBus.csproj src/BuildingBlocks/EventBus/EventBus/ -COPY src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj src/BuildingBlocks/EventBus/EventBus.Tests/ -COPY src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj src/BuildingBlocks/EventBus/EventBusRabbitMQ/ -COPY src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj src/BuildingBlocks/EventBus/EventBusServiceBus/ -COPY src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj src/BuildingBlocks/EventBus/IntegrationEventLogEF/ -COPY src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj src/BuildingBlocks/WebHostCustomization/WebHost.Customization/ -COPY src/Services/Basket/Basket.API/Basket.API.csproj src/Services/Basket/Basket.API/ -COPY src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj src/Services/Basket/Basket.FunctionalTests/ -COPY src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj src/Services/Basket/Basket.UnitTests/ -COPY src/Services/Catalog/Catalog.API/Catalog.API.csproj src/Services/Catalog/Catalog.API/ -COPY src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj src/Services/Catalog/Catalog.FunctionalTests/ -COPY src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj src/Services/Catalog/Catalog.UnitTests/ -COPY src/Services/Identity/Identity.API/Identity.API.csproj src/Services/Identity/Identity.API/ -COPY src/Services/Location/Locations.API/Locations.API.csproj src/Services/Location/Locations.API/ -COPY src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj src/Services/Location/Locations.FunctionalTests/ -COPY src/Services/Marketing/Marketing.API/Marketing.API.csproj src/Services/Marketing/Marketing.API/ -COPY src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj src/Services/Marketing/Marketing.FunctionalTests/ -COPY src/Services/Ordering/Ordering.API/Ordering.API.csproj src/Services/Ordering/Ordering.API/ -COPY src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj src/Services/Ordering/Ordering.BackgroundTasks/ -COPY src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj src/Services/Ordering/Ordering.Domain/ -COPY src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj src/Services/Ordering/Ordering.FunctionalTests/ -COPY src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj src/Services/Ordering/Ordering.Infrastructure/ -COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/ -COPY src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj src/Services/Ordering/Ordering.UnitTests/ -COPY src/Services/Payment/Payment.API/Payment.API.csproj src/Services/Payment/Payment.API/ -COPY src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj src/Services/Webhooks/Webhooks.API/ -COPY src/Web/WebhookClient/WebhookClient.csproj src/Web/WebhookClient/ -COPY src/Web/WebMVC/WebMVC.csproj src/Web/WebMVC/ -COPY src/Web/WebSPA/WebSPA.csproj src/Web/WebSPA/ -COPY src/Web/WebStatus/WebStatus.csproj src/Web/WebStatus/ -COPY test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj test/ServicesTests/Application.FunctionalTests/ -COPY test/ServicesTests/LoadTest/LoadTest.csproj test/ServicesTests/LoadTest/ +COPY scripts scripts/ -RUN dotnet restore eShopOnContainers-ServicesAndWebApps.sln +COPY ApiGateways/*/*/*.csproj csproj-files/ +COPY BuildingBlocks/*/*/*.csproj csproj-files/ +COPY Services/*/*/*.csproj csproj-files/ +COPY Web/*/*.csproj csproj-files/ COPY . . -WORKDIR /src/src/Services/Basket/Basket.API -RUN dotnet publish --no-restore -c Release -o /app +WORKDIR /src/Services/Basket/Basket.API +RUN dotnet publish -c Release -o /app FROM build as unittest -WORKDIR /src/src/Services/Basket/Basket.UnitTests +WORKDIR /src/Services/Basket/Basket.UnitTests FROM build as functionaltest -WORKDIR /src/src/Services/Basket/Basket.FunctionalTests +WORKDIR /src/Services/Basket/Basket.FunctionalTests FROM build AS publish diff --git a/src/Services/Basket/Basket.API/Dockerfile.develop b/src/Services/Basket/Basket.API/Dockerfile.develop index 5ae5cc235..66ea6a07d 100644 --- a/src/Services/Basket/Basket.API/Dockerfile.develop +++ b/src/Services/Basket/Basket.API/Dockerfile.develop @@ -1,4 +1,4 @@ -FROM microsoft/dotnet:2.2-sdk +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster ARG BUILD_CONFIGURATION=Debug ENV ASPNETCORE_ENVIRONMENT=Development ENV DOTNET_USE_POLLING_FILE_WATCHER=true @@ -6,14 +6,14 @@ EXPOSE 80 WORKDIR /src -COPY ["src/BuildingBlocks/EventBus/EventBus/EventBus.csproj", "src/BuildingBlocks/EventBus/EventBus/"] -COPY ["src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "src/BuildingBlocks/EventBus/EventBusRabbitMQ/"] -COPY ["src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "src/BuildingBlocks/EventBus/EventBusServiceBus/"] -COPY ["src/Services/Basket/Basket.API/Basket.API.csproj", "src/Services/Basket/Basket.API/"] +COPY ["BuildingBlocks/EventBus/EventBus/EventBus.csproj", "BuildingBlocks/EventBus/EventBus/"] +COPY ["BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "BuildingBlocks/EventBus/EventBusRabbitMQ/"] +COPY ["BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "BuildingBlocks/EventBus/EventBusServiceBus/"] +COPY ["Services/Basket/Basket.API/Basket.API.csproj", "Services/Basket/Basket.API/"] -RUN dotnet restore src/Services/Basket/Basket.API/Basket.API.csproj -nowarn:msb3202,nu1503 +RUN dotnet restore Services/Basket/Basket.API/Basket.API.csproj -nowarn:msb3202,nu1503 COPY . . -WORKDIR /src/src/Services/Basket/Basket.API +WORKDIR /src/Services/Basket/Basket.API RUN dotnet build --no-restore -c $BUILD_CONFIGURATION ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"] \ No newline at end of file diff --git a/src/Services/Basket/Basket.API/Grpc/BasketService.cs b/src/Services/Basket/Basket.API/Grpc/BasketService.cs new file mode 100644 index 000000000..e92190c73 --- /dev/null +++ b/src/Services/Basket/Basket.API/Grpc/BasketService.cs @@ -0,0 +1,103 @@ +using Grpc.Core; +using Microsoft.AspNetCore.Authorization; +using Microsoft.eShopOnContainers.Services.Basket.API.Model; +using Microsoft.Extensions.Logging; +using System.Linq; +using System.Threading.Tasks; +using GrpcBasket; + +namespace GrpcBasket +{ + public class BasketService : Basket.BasketBase + { + private readonly IBasketRepository _repository; + private readonly ILogger _logger; + + public BasketService(IBasketRepository repository, ILogger logger) + { + _repository = repository; + _logger = logger; + } + + [AllowAnonymous] + public override async Task GetBasketById(BasketRequest request, ServerCallContext context) + { + _logger.LogInformation($"Begin grpc call from method {context.Method} for basket id {request.Id}"); + + var data = await _repository.GetBasketAsync(request.Id); + + if (data != null) + { + context.Status = new Status(StatusCode.OK, $"Basket with id {request.Id} do exist"); + + return MapToCustomerBasketResponse(data); + } + else + { + context.Status = new Status(StatusCode.NotFound, $"Basket with id {request.Id} do not exist"); + } + + return new CustomerBasketResponse(); + } + + public override async Task UpdateBasket(CustomerBasketRequest request, ServerCallContext context) + { + _logger.LogInformation($"Begin grpc call BasketService.UpdateBasketAsync for buyer id {request.Buyerid}"); + + var customerBasket = MapToCustomerBasket(request); + + var response = await _repository.UpdateBasketAsync(customerBasket); + + if (response != null) + { + return MapToCustomerBasketResponse(response); + } + + context.Status = new Status(StatusCode.NotFound, $"Basket with buyer id {request.Buyerid} do not exist"); + + return null; + } + + private CustomerBasketResponse MapToCustomerBasketResponse(CustomerBasket customerBasket) + { + var response = new CustomerBasketResponse + { + Buyerid = customerBasket.BuyerId + }; + + customerBasket.Items.ForEach(item => response.Items.Add(new BasketItemResponse + { + Id = item.Id, + Oldunitprice = (double)item.OldUnitPrice, + Pictureurl = item.PictureUrl, + Productid = item.ProductId, + Productname = item.ProductName, + Quantity = item.Quantity, + Unitprice = (double)item.UnitPrice + })); + + return response; + } + + private CustomerBasket MapToCustomerBasket(CustomerBasketRequest customerBasketRequest) + { + var response = new CustomerBasket + { + BuyerId = customerBasketRequest.Buyerid + }; + + customerBasketRequest.Items.ToList().ForEach(item => response.Items.Add(new BasketItem + { + Id = item.Id, + OldUnitPrice = (decimal)item.Oldunitprice, + PictureUrl = item.Pictureurl, + ProductId = item.Productid, + ProductName = item.Productname, + Quantity = item.Quantity, + UnitPrice = (decimal)item.Unitprice + })); + + return response; + } + } +} diff --git a/src/Services/Basket/Basket.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs b/src/Services/Basket/Basket.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs deleted file mode 100644 index 1ae38c8b0..000000000 --- a/src/Services/Basket/Basket.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Swashbuckle.AspNetCore.Swagger; -using Swashbuckle.AspNetCore.SwaggerGen; -using System.Collections.Generic; -using System.Linq; - -namespace Basket.API.Infrastructure.Filters -{ - public class AuthorizeCheckOperationFilter : IOperationFilter - { - public void Apply(Operation operation, OperationFilterContext context) - { - // Check for authorize attribute - var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType().Any() || - context.MethodInfo.GetCustomAttributes(true).OfType().Any(); - - if (!hasAuthorize) return; - - operation.Responses.TryAdd("401", new Response { Description = "Unauthorized" }); - operation.Responses.TryAdd("403", new Response { Description = "Forbidden" }); - - operation.Security = new List>> - { - new Dictionary> - { - { "oauth2", new [] { "basketapi" } } - } - }; - } - } -} \ No newline at end of file diff --git a/src/Services/Basket/Basket.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs b/src/Services/Basket/Basket.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs index dab725915..0fd08a0a9 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs @@ -3,17 +3,19 @@ using Basket.API.Infrastructure.Exceptions; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using System.Net; + namespace Basket.API.Infrastructure.Filters { public partial class HttpGlobalExceptionFilter : IExceptionFilter { - private readonly IHostingEnvironment env; + private readonly IWebHostEnvironment env; private readonly ILogger logger; - public HttpGlobalExceptionFilter(IHostingEnvironment env, ILogger logger) + public HttpGlobalExceptionFilter(IWebHostEnvironment env, ILogger logger) { this.env = env; this.logger = logger; diff --git a/src/Services/Basket/Basket.API/Infrastructure/Middlewares/AuthorizeCheckOperationFilter.cs b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/AuthorizeCheckOperationFilter.cs new file mode 100644 index 000000000..4a1c24aa6 --- /dev/null +++ b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/AuthorizeCheckOperationFilter.cs @@ -0,0 +1,36 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; +using System.Collections.Generic; +using System.Linq; + +namespace Basket.API.Infrastructure.Filters +{ + public class AuthorizeCheckOperationFilter : IOperationFilter + { + public void Apply(OpenApiOperation operation, OperationFilterContext context) + { + // Check for authorize attribute + var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType().Any() || + context.MethodInfo.GetCustomAttributes(true).OfType().Any(); + + if (!hasAuthorize) return; + + operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" }); + operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" }); + + var oAuthScheme = new OpenApiSecurityScheme + { + Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } + }; + + operation.Security = new List + { + new OpenApiSecurityRequirement + { + [ oAuthScheme ] = new [] { "basketapi" } + } + }; + } + } +} \ No newline at end of file diff --git a/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingMiddleware.cs b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingMiddleware.cs index 875749b5f..852c61d1f 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingMiddleware.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingMiddleware.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; using System; using System.Linq; using System.Threading.Tasks; @@ -10,11 +11,13 @@ namespace Basket.API.Infrastructure.Middlewares private readonly RequestDelegate _next; private bool _mustFail; private readonly FailingOptions _options; - public FailingMiddleware(RequestDelegate next, FailingOptions options) + private readonly ILogger _logger; + public FailingMiddleware(RequestDelegate next, ILogger logger, FailingOptions options) { _next = next; _options = options; _mustFail = false; + _logger = logger; } public async Task Invoke(HttpContext context) { @@ -27,6 +30,7 @@ namespace Basket.API.Infrastructure.Middlewares if (MustFail(context)) { + _logger.LogInformation($"Response for path {path} will fail."); context.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError; context.Response.ContentType = "text/plain"; await context.Response.WriteAsync("Failed due to FailingMiddleware enabled."); @@ -74,8 +78,15 @@ namespace Basket.API.Infrastructure.Middlewares private bool MustFail(HttpContext context) { + var rpath = context.Request.Path.Value; + + if (_options.NotFilteredPaths.Any(p => p.Equals(rpath, StringComparison.InvariantCultureIgnoreCase))) + { + return false; + } + return _mustFail && - (_options.EndpointPaths.Any(x => x == context.Request.Path.Value) + (_options.EndpointPaths.Any(x => x == rpath) || _options.EndpointPaths.Count == 0); } } diff --git a/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingOptions.cs b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingOptions.cs index 45989832c..63e1e5525 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingOptions.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingOptions.cs @@ -6,5 +6,7 @@ namespace Basket.API.Infrastructure.Middlewares { public string ConfigPath = "/Failing"; public List EndpointPaths { get; set; } = new List(); + + public List NotFilteredPaths {get; set;} = new List(); } } diff --git a/src/Services/Basket/Basket.API/Infrastructure/Repositories/RedisBasketRepository.cs b/src/Services/Basket/Basket.API/Infrastructure/Repositories/RedisBasketRepository.cs index 6653f5ed1..93adcc023 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Repositories/RedisBasketRepository.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Repositories/RedisBasketRepository.cs @@ -28,7 +28,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Infrastructure.Reposit public IEnumerable GetUsers() { - var server = GetServer(); + var server = GetServer(); var data = server.Keys(); return data?.Select(k => k.ToString()); diff --git a/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/OrderStartedIntegrationEventHandler.cs b/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/OrderStartedIntegrationEventHandler.cs index cb7b6a2d6..4fc2e2ec0 100644 --- a/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/OrderStartedIntegrationEventHandler.cs +++ b/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/OrderStartedIntegrationEventHandler.cs @@ -26,8 +26,6 @@ namespace Basket.API.IntegrationEvents.EventHandling { using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) { - _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); - await _repository.DeleteBasketAsync(@event.UserId.ToString()); } } diff --git a/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/ProductPriceChangedIntegrationEventHandler.cs b/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/ProductPriceChangedIntegrationEventHandler.cs index c27200e6f..0e2d1b7a0 100644 --- a/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/ProductPriceChangedIntegrationEventHandler.cs +++ b/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/ProductPriceChangedIntegrationEventHandler.cs @@ -26,8 +26,6 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Even { using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) { - _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); - var userIds = _repository.GetUsers(); foreach (var id in userIds) @@ -41,13 +39,10 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Even private async Task UpdatePriceInBasketItems(int productId, decimal newPrice, decimal oldPrice, CustomerBasket basket) { - string match = productId.ToString(); - var itemsToUpdate = basket?.Items?.Where(x => x.ProductId == match).ToList(); + var itemsToUpdate = basket?.Items?.Where(x => x.ProductId == productId).ToList(); if (itemsToUpdate != null) { - _logger.LogInformation("----- ProductPriceChangedIntegrationEventHandler - Updating items in basket for user: {BuyerId} ({@Items})", basket.BuyerId, itemsToUpdate); - foreach (var item in itemsToUpdate) { if (item.UnitPrice == oldPrice) diff --git a/src/Services/Basket/Basket.API/Model/BasketItem.cs b/src/Services/Basket/Basket.API/Model/BasketItem.cs index a41945145..4d2e4f331 100644 --- a/src/Services/Basket/Basket.API/Model/BasketItem.cs +++ b/src/Services/Basket/Basket.API/Model/BasketItem.cs @@ -6,7 +6,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model public class BasketItem : IValidatableObject { public string Id { get; set; } - public string ProductId { get; set; } + public int ProductId { get; set; } public string ProductName { get; set; } public decimal UnitPrice { get; set; } public decimal OldUnitPrice { get; set; } diff --git a/src/Services/Basket/Basket.API/Model/CustomerBasket.cs b/src/Services/Basket/Basket.API/Model/CustomerBasket.cs index 3dd034f6c..9ae495d4f 100644 --- a/src/Services/Basket/Basket.API/Model/CustomerBasket.cs +++ b/src/Services/Basket/Basket.API/Model/CustomerBasket.cs @@ -4,13 +4,18 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model { public class CustomerBasket { - public string BuyerId { get; set; } - public List Items { get; set; } + public string BuyerId { get; set; } + + public List Items { get; set; } = new List(); + + public CustomerBasket() + { + + } public CustomerBasket(string customerId) { BuyerId = customerId; - Items = new List(); } } } diff --git a/src/Services/Basket/Basket.API/Program.cs b/src/Services/Basket/Basket.API/Program.cs index 40cc0eebc..ac7294c15 100644 --- a/src/Services/Basket/Basket.API/Program.cs +++ b/src/Services/Basket/Basket.API/Program.cs @@ -2,11 +2,12 @@ using Microsoft.AspNetCore; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; using Serilog; using System; using System.IO; +using System.Net; namespace Microsoft.eShopOnContainers.Services.Basket.API { @@ -45,8 +46,24 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) => WebHost.CreateDefaultBuilder(args) .CaptureStartupErrors(false) - .UseFailing(options => - options.ConfigPath = "/Failing") + .ConfigureKestrel(options => + { + var ports = GetDefinedPorts(configuration); + options.Listen(IPAddress.Any, ports.httpPort, listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http1AndHttp2; + }); + + options.Listen(IPAddress.Any, ports.grpcPort, listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http2; + }); + + }) + .UseFailing(options => { + options.ConfigPath = "/Failing"; + options.NotFilteredPaths.AddRange(new[] {"/hc","/liveness"}); + }) .UseStartup() .UseApplicationInsights() .UseContentRoot(Directory.GetCurrentDirectory()) @@ -88,5 +105,12 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API return builder.Build(); } + + private static (int httpPort, int grpcPort) GetDefinedPorts(IConfiguration config) + { + var grpcPort = config.GetValue("GRPC_PORT", 5001); + var port = config.GetValue("PORT", 80); + return (port, grpcPort); + } } } diff --git a/src/Services/Basket/Basket.API/Proto/basket.proto b/src/Services/Basket/Basket.API/Proto/basket.proto new file mode 100644 index 000000000..76ad33912 --- /dev/null +++ b/src/Services/Basket/Basket.API/Proto/basket.proto @@ -0,0 +1,34 @@ +syntax = "proto3"; + +option csharp_namespace = "GrpcBasket"; + +package BasketApi; + +service Basket { + rpc GetBasketById(BasketRequest) returns (CustomerBasketResponse) {} + rpc UpdateBasket(CustomerBasketRequest) returns (CustomerBasketResponse) {} +} + +message BasketRequest { + string id = 1; +} + +message CustomerBasketRequest { + string buyerid = 1; + repeated BasketItemResponse items = 2; +} + +message CustomerBasketResponse { + string buyerid = 1; + repeated BasketItemResponse items = 2; +} + +message BasketItemResponse { + string id = 1; + int32 productid = 2; + string productname = 3; + double unitprice = 4; + double oldunitprice = 5; + int32 quantity = 6; + string pictureurl = 7; +} diff --git a/src/Services/Basket/Basket.API/Startup.cs b/src/Services/Basket/Basket.API/Startup.cs index 9cfabf20a..d9554bcb8 100644 --- a/src/Services/Basket/Basket.API/Startup.cs +++ b/src/Services/Basket/Basket.API/Startup.cs @@ -5,20 +5,17 @@ using Basket.API.Infrastructure.Middlewares; using Basket.API.IntegrationEvents.EventHandling; using Basket.API.IntegrationEvents.Events; using HealthChecks.UI.Client; - -using Microsoft.ApplicationInsights.Extensibility; -using Microsoft.ApplicationInsights.ServiceFabric; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.ServiceBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus; +using Microsoft.eShopOnContainers.Services.Basket.API.Controllers; using Microsoft.eShopOnContainers.Services.Basket.API.Infrastructure.Repositories; using Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.EventHandling; using Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Events; @@ -29,12 +26,16 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Microsoft.OpenApi.Models; using RabbitMQ.Client; using StackExchange.Redis; -using Swashbuckle.AspNetCore.Swagger; using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; +using System.IO; +using GrpcBasket; +using Microsoft.AspNetCore.Http.Features; +using Serilog; namespace Microsoft.eShopOnContainers.Services.Basket.API { @@ -47,21 +48,54 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API public IConfiguration Configuration { get; } - // This method gets called by the runtime. Use this method to add services to the container. - public IServiceProvider ConfigureServices(IServiceCollection services) + public virtual IServiceProvider ConfigureServices(IServiceCollection services) { + services.AddGrpc(options => + { + options.EnableDetailedErrors = true; + }); + RegisterAppInsights(services); - // Add framework services. - services.AddMvc(options => + services.AddControllers(options => { options.Filters.Add(typeof(HttpGlobalExceptionFilter)); options.Filters.Add(typeof(ValidateModelStateFilter)); - }) - .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) - .AddControllersAsServices(); + }) // Added for functional tests + .AddApplicationPart(typeof(BasketController).Assembly) + .AddNewtonsoftJson(); + + services.AddSwaggerGen(options => + { + options.DescribeAllEnumsAsStrings(); + options.SwaggerDoc("v1", new OpenApiInfo + { + Title = "eShopOnContainers - Basket HTTP API", + Version = "v1", + Description = "The Basket Service HTTP API" + }); + + options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme + { + Type = SecuritySchemeType.OAuth2, + Flows = new OpenApiOAuthFlows() + { + Implicit = new OpenApiOAuthFlow() + { + AuthorizationUrl = new Uri($"{Configuration.GetValue("IdentityUrlExternal")}/connect/authorize"), + TokenUrl = new Uri($"{Configuration.GetValue("IdentityUrlExternal")}/connect/token"), + Scopes = new Dictionary() + { + { "basket", "Basket API" } + } + } + } + }); + + options.OperationFilter(); + }); ConfigureAuthService(services); @@ -132,31 +166,6 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API RegisterEventBus(services); - services.AddSwaggerGen(options => - { - options.DescribeAllEnumsAsStrings(); - options.SwaggerDoc("v1", new Info - { - Title = "Basket HTTP API", - Version = "v1", - Description = "The Basket Service HTTP API", - TermsOfService = "Terms Of Service" - }); - - options.AddSecurityDefinition("oauth2", new OAuth2Scheme - { - Type = "oauth2", - Flow = "implicit", - AuthorizationUrl = $"{Configuration.GetValue("IdentityUrlExternal")}/connect/authorize", - TokenUrl = $"{Configuration.GetValue("IdentityUrlExternal")}/connect/token", - Scopes = new Dictionary() - { - { "basket", "Basket API" } - } - }); - - options.OperationFilter(); - }); services.AddCors(options => { @@ -178,10 +187,9 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API return new AutofacServiceProvider(container.Build()); } - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) { //loggerFactory.AddAzureWebAppDiagnostics(); //loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace); @@ -192,72 +200,77 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API app.UsePathBase(pathBase); } - app.UseHealthChecks("/hc", new HealthCheckOptions() - { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - - app.UseHealthChecks("/liveness", new HealthCheckOptions - { - Predicate = r => r.Name.Contains("self") - }); - - app.UseStaticFiles(); - app.UseCors("CorsPolicy"); + app.UseSwagger() + .UseSwaggerUI(setup => + { + setup.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Basket.API V1"); + setup.OAuthClientId("basketswaggerui"); + setup.OAuthAppName("Basket Swagger UI"); + }); + app.UseRouting(); ConfigureAuth(app); - app.UseMvcWithDefaultRoute(); + app.UseStaticFiles(); - app.UseSwagger() - .UseSwaggerUI(c => - { - c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Basket.API V1"); - c.OAuthClientId ("basketswaggerui"); - c.OAuthAppName("Basket Swagger UI"); - }); + app.UseCors("CorsPolicy"); + app.UseEndpoints(endpoints => + { + endpoints.MapGrpcService(); + endpoints.MapDefaultControllerRoute(); + endpoints.MapControllers(); + endpoints.MapGet("/_proto/", async ctx => + { + ctx.Response.ContentType = "text/plain"; + using var fs = new FileStream(Path.Combine(env.ContentRootPath, "Proto", "basket.proto"), FileMode.Open, FileAccess.Read); + using var sr = new StreamReader(fs); + while (!sr.EndOfStream) + { + var line = await sr.ReadLineAsync(); + if (line != "/* >>" || line != "<< */") + { + await ctx.Response.WriteAsync(line); + } + } + }); + endpoints.MapHealthChecks("/hc", new HealthCheckOptions() + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + endpoints.MapHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = r => r.Name.Contains("self") + }); + }); ConfigureEventBus(app); - } private void RegisterAppInsights(IServiceCollection services) { services.AddApplicationInsightsTelemetry(Configuration); - var orchestratorType = Configuration.GetValue("OrchestratorType"); - - if (orchestratorType?.ToUpper() == "K8S") - { - // Enable K8s telemetry initializer - services.AddApplicationInsightsKubernetesEnricher(); - } - if (orchestratorType?.ToUpper() == "SF") - { - // Enable SF telemetry initializer - services.AddSingleton((serviceProvider) => - new FabricTelemetryInitializer()); - } + services.AddApplicationInsightsKubernetesEnricher(); } private void ConfigureAuthService(IServiceCollection services) { - // prevent from mapping "sub" claim to nameidentifier. - JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); - - var identityUrl = Configuration.GetValue("IdentityUrl"); - - services.AddAuthentication(options => - { - options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - - }).AddJwtBearer(options => - { - options.Authority = identityUrl; - options.RequireHttpsMetadata = false; - options.Audience = "basket"; - }); + // prevent from mapping "sub" claim to nameidentifier. + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub"); + + var identityUrl = Configuration.GetValue("IdentityUrl"); + + services.AddAuthentication(options => + { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + + }).AddJwtBearer(options => + { + options.Authority = identityUrl; + options.RequireHttpsMetadata = false; + options.Audience = "basket"; + }); } protected virtual void ConfigureAuth(IApplicationBuilder app) @@ -268,6 +281,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API } app.UseAuthentication(); + app.UseAuthorization(); } private void RegisterEventBus(IServiceCollection services) @@ -281,7 +295,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API var serviceBusPersisterConnection = sp.GetRequiredService(); var iLifetimeScope = sp.GetRequiredService(); var logger = sp.GetRequiredService>(); - var eventBusSubcriptionsManager = sp.GetRequiredService(); + var eventBusSubcriptionsManager = sp.GetRequiredService(); return new EventBusServiceBus(serviceBusPersisterConnection, logger, eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); @@ -318,7 +332,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API eventBus.Subscribe(); eventBus.Subscribe(); - } + } } public static class CustomExtensionMethods @@ -329,7 +343,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API hcBuilder.AddCheck("self", () => HealthCheckResult.Healthy()); - hcBuilder + hcBuilder .AddRedis( configuration["ConnectionString"], name: "redis-check", diff --git a/src/Services/Basket/Basket.API/TestHttpResponseTrailersFeature.cs b/src/Services/Basket/Basket.API/TestHttpResponseTrailersFeature.cs new file mode 100644 index 000000000..7cab5a07b --- /dev/null +++ b/src/Services/Basket/Basket.API/TestHttpResponseTrailersFeature.cs @@ -0,0 +1,10 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; + +namespace Microsoft.eShopOnContainers.Services.Basket.API +{ + internal class TestHttpResponseTrailersFeature : IHttpResponseTrailersFeature + { + public IHeaderDictionary Trailers { get; set; } + } +} \ No newline at end of file diff --git a/src/Services/Basket/Basket.API/appsettings.Development.json b/src/Services/Basket/Basket.API/appsettings.Development.json new file mode 100644 index 000000000..f4a3b9407 --- /dev/null +++ b/src/Services/Basket/Basket.API/appsettings.Development.json @@ -0,0 +1,17 @@ +{ + "Serilog": { + "MinimumLevel": { + "Default": "Debug", + "Override": { + "Microsoft": "Warning", + "Microsoft.eShopOnContainers": "Debug", + "System": "Warning" + } + } + }, + "IdentityUrlExternal": "http://localhost:5105", + "IdentityUrl": "http://localhost:5105", + "ConnectionString": "127.0.0.1", + "AzureServiceBusEnabled": false, + "EventBusConnection": "localhost" +} \ No newline at end of file diff --git a/src/Services/Basket/Basket.API/appsettings.json b/src/Services/Basket/Basket.API/appsettings.json index fc8fc544a..a5b723116 100644 --- a/src/Services/Basket/Basket.API/appsettings.json +++ b/src/Services/Basket/Basket.API/appsettings.json @@ -11,9 +11,11 @@ } } }, - "IdentityUrl": "http://localhost:5105", - "ConnectionString": "127.0.0.1", - "AzureServiceBusEnabled": false, + "Kestrel": { + "EndpointDefaults": { + "Protocols": "Http2" + } + }, "SubscriptionClientName": "Basket", "ApplicationInsights": { "InstrumentationKey": "" diff --git a/src/Services/Basket/Basket.API/web.config b/src/Services/Basket/Basket.API/web.config index dc0514fca..a2cf1fe26 100644 --- a/src/Services/Basket/Basket.API/web.config +++ b/src/Services/Basket/Basket.API/web.config @@ -1,14 +1,17 @@  - - - + - + + + + + + - + \ No newline at end of file diff --git a/src/Services/Basket/Basket.FunctionalTests/Base/AutoAuthorizeMiddleware.cs b/src/Services/Basket/Basket.FunctionalTests/Base/AutoAuthorizeMiddleware.cs index 6b6677595..d83f81996 100644 --- a/src/Services/Basket/Basket.FunctionalTests/Base/AutoAuthorizeMiddleware.cs +++ b/src/Services/Basket/Basket.FunctionalTests/Base/AutoAuthorizeMiddleware.cs @@ -21,6 +21,7 @@ namespace Basket.FunctionalTests.Base identity.AddClaim(new Claim("sub", IDENTITY_ID)); identity.AddClaim(new Claim("unique_name", IDENTITY_ID)); + identity.AddClaim(new Claim(ClaimTypes.Name, IDENTITY_ID)); httpContext.User.AddIdentity(identity); diff --git a/src/Services/Basket/Basket.FunctionalTests/Base/BasketTestStartup.cs b/src/Services/Basket/Basket.FunctionalTests/Base/BasketTestStartup.cs index 4d77f6dc5..cb8ec8641 100644 --- a/src/Services/Basket/Basket.FunctionalTests/Base/BasketTestStartup.cs +++ b/src/Services/Basket/Basket.FunctionalTests/Base/BasketTestStartup.cs @@ -1,6 +1,9 @@ -using Microsoft.AspNetCore.Builder; +using System; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Routing; using Microsoft.eShopOnContainers.Services.Basket.API; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; namespace Basket.FunctionalTests.Base { @@ -10,6 +13,14 @@ namespace Basket.FunctionalTests.Base { } + public override IServiceProvider ConfigureServices(IServiceCollection services) + { + // Added to avoid the Authorize data annotation in test environment. + // Property "SuppressCheckForUnhandledSecurityMetadata" in appsettings.json + services.Configure(Configuration); + return base.ConfigureServices(services); + } + protected override void ConfigureAuth(IApplicationBuilder app) { if (Configuration["isTest"] == bool.TrueString.ToLowerInvariant()) diff --git a/src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj b/src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj index 866744b04..5e9e5c036 100644 --- a/src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj +++ b/src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj @@ -1,8 +1,7 @@  - netcoreapp2.2 - + $(NetCoreTargetVersion) false @@ -17,12 +16,10 @@ - - - - - - + + + + all runtime; build; native; contentfiles; analyzers @@ -31,8 +28,6 @@ - - diff --git a/src/Services/Basket/Basket.FunctionalTests/BasketScenarios.cs b/src/Services/Basket/Basket.FunctionalTests/BasketScenarios.cs index 83d507ade..c5eacfa4e 100644 --- a/src/Services/Basket/Basket.FunctionalTests/BasketScenarios.cs +++ b/src/Services/Basket/Basket.FunctionalTests/BasketScenarios.cs @@ -5,7 +5,6 @@ using System; using System.Net.Http; using System.Text; using System.Threading.Tasks; -using WebMVC.Services.ModelDTOs; using Xunit; namespace Basket.FunctionalTests @@ -63,7 +62,7 @@ namespace Basket.FunctionalTests order.Items.Add(new BasketItem { - ProductId = "1", + ProductId = 1, ProductName = ".NET Bot Black Hoodie", UnitPrice = 10, Quantity = 1 @@ -74,7 +73,7 @@ namespace Basket.FunctionalTests string BuildCheckout() { - var checkoutBasket = new BasketDTO() + var checkoutBasket = new { City = "city", Street = "street", diff --git a/src/Services/Basket/Basket.FunctionalTests/RedisBasketRepositoryTests.cs b/src/Services/Basket/Basket.FunctionalTests/RedisBasketRepositoryTests.cs index f3f6d196d..67931c443 100644 --- a/src/Services/Basket/Basket.FunctionalTests/RedisBasketRepositoryTests.cs +++ b/src/Services/Basket/Basket.FunctionalTests/RedisBasketRepositoryTests.cs @@ -75,7 +75,7 @@ namespace Basket.FunctionalTests { Id = "basketId", PictureUrl = "pictureurl", - ProductId = "productId", + ProductId = 1, ProductName = "productName", Quantity = 1, UnitPrice = 1 diff --git a/src/Services/Basket/Basket.FunctionalTests/appsettings.json b/src/Services/Basket/Basket.FunctionalTests/appsettings.json index 5e8dbc02e..3f882d1bc 100644 --- a/src/Services/Basket/Basket.FunctionalTests/appsettings.json +++ b/src/Services/Basket/Basket.FunctionalTests/appsettings.json @@ -11,5 +11,6 @@ "ConnectionString": "127.0.0.1", "isTest": "true", "EventBusConnection": "localhost", - "SubscriptionClientName": "Basket" + "SubscriptionClientName": "Basket", + "SuppressCheckForUnhandledSecurityMetadata":true } diff --git a/src/Services/Basket/Basket.UnitTests/Application/BasketWebApiTest.cs b/src/Services/Basket/Basket.UnitTests/Application/BasketWebApiTest.cs index 2864b8b9f..000183dec 100644 --- a/src/Services/Basket/Basket.UnitTests/Application/BasketWebApiTest.cs +++ b/src/Services/Basket/Basket.UnitTests/Application/BasketWebApiTest.cs @@ -125,7 +125,11 @@ namespace UnitTest.Basket.Application HttpContext = new DefaultHttpContext() { User = new ClaimsPrincipal( - new ClaimsIdentity(new Claim[] { new Claim("unique_name", "testuser") })) + new ClaimsIdentity(new Claim[] { + new Claim("sub", "testuser"), + new Claim("unique_name", "testuser"), + new Claim(ClaimTypes.Name, "testuser") + })) } }; diff --git a/src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj b/src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj index 6c529c737..92731fb9c 100644 --- a/src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj +++ b/src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj @@ -1,18 +1,20 @@  - netcoreapp2.2 - + $(NetCoreTargetVersion) + false false - - - - - - + + + + + + + + all runtime; build; native; contentfiles; analyzers diff --git a/src/Services/Catalog/Catalog.API/Catalog.API.csproj b/src/Services/Catalog/Catalog.API/Catalog.API.csproj index 8f14ee0a3..662c55c08 100644 --- a/src/Services/Catalog/Catalog.API/Catalog.API.csproj +++ b/src/Services/Catalog/Catalog.API/Catalog.API.csproj @@ -1,13 +1,16 @@  - netcoreapp2.2 + $(NetCoreTargetVersion) portable true Catalog.API Catalog.API aspnet-Catalog.API-20161122013618 ..\..\..\..\docker-compose.dcproj + false + true + $(LangVersion) @@ -32,30 +35,36 @@ + + + + + - - - - + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + @@ -63,7 +72,6 @@ - diff --git a/src/Services/Catalog/Catalog.API/Controllers/PicController.cs b/src/Services/Catalog/Catalog.API/Controllers/PicController.cs index 7d798597e..0aa376832 100644 --- a/src/Services/Catalog/Catalog.API/Controllers/PicController.cs +++ b/src/Services/Catalog/Catalog.API/Controllers/PicController.cs @@ -13,10 +13,10 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers [ApiController] public class PicController : ControllerBase { - private readonly IHostingEnvironment _env; + private readonly IWebHostEnvironment _env; private readonly CatalogContext _catalogContext; - public PicController(IHostingEnvironment env, + public PicController(IWebHostEnvironment env, CatalogContext catalogContext) { _env = env; diff --git a/src/Services/Catalog/Catalog.API/Dockerfile b/src/Services/Catalog/Catalog.API/Dockerfile index 13559672b..57d30ef1b 100644 --- a/src/Services/Catalog/Catalog.API/Dockerfile +++ b/src/Services/Catalog/Catalog.API/Dockerfile @@ -1,65 +1,33 @@ -FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base +FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base WORKDIR /app EXPOSE 80 +EXPOSE 443 -FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build WORKDIR /src -# Keep the project list and command dotnet restore identical in all Dockfiles to maximize image cache utilization -COPY eShopOnContainers-ServicesAndWebApps.sln . -COPY docker-compose.dcproj /src/ -COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/ -COPY src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj src/ApiGateways/Mobile.Bff.Shopping/aggregator/ -COPY src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj src/ApiGateways/Web.Bff.Shopping/aggregator/ -COPY src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj src/BuildingBlocks/Devspaces.Support/ -COPY src/BuildingBlocks/EventBus/EventBus/EventBus.csproj src/BuildingBlocks/EventBus/EventBus/ -COPY src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj src/BuildingBlocks/EventBus/EventBus.Tests/ -COPY src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj src/BuildingBlocks/EventBus/EventBusRabbitMQ/ -COPY src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj src/BuildingBlocks/EventBus/EventBusServiceBus/ -COPY src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj src/BuildingBlocks/EventBus/IntegrationEventLogEF/ -COPY src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj src/BuildingBlocks/WebHostCustomization/WebHost.Customization/ -COPY src/Services/Basket/Basket.API/Basket.API.csproj src/Services/Basket/Basket.API/ -COPY src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj src/Services/Basket/Basket.FunctionalTests/ -COPY src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj src/Services/Basket/Basket.UnitTests/ -COPY src/Services/Catalog/Catalog.API/Catalog.API.csproj src/Services/Catalog/Catalog.API/ -COPY src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj src/Services/Catalog/Catalog.FunctionalTests/ -COPY src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj src/Services/Catalog/Catalog.UnitTests/ -COPY src/Services/Identity/Identity.API/Identity.API.csproj src/Services/Identity/Identity.API/ -COPY src/Services/Location/Locations.API/Locations.API.csproj src/Services/Location/Locations.API/ -COPY src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj src/Services/Location/Locations.FunctionalTests/ -COPY src/Services/Marketing/Marketing.API/Marketing.API.csproj src/Services/Marketing/Marketing.API/ -COPY src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj src/Services/Marketing/Marketing.FunctionalTests/ -COPY src/Services/Ordering/Ordering.API/Ordering.API.csproj src/Services/Ordering/Ordering.API/ -COPY src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj src/Services/Ordering/Ordering.BackgroundTasks/ -COPY src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj src/Services/Ordering/Ordering.Domain/ -COPY src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj src/Services/Ordering/Ordering.FunctionalTests/ -COPY src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj src/Services/Ordering/Ordering.Infrastructure/ -COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/ -COPY src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj src/Services/Ordering/Ordering.UnitTests/ -COPY src/Services/Payment/Payment.API/Payment.API.csproj src/Services/Payment/Payment.API/ -COPY src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj src/Services/Webhooks/Webhooks.API/ -COPY src/Web/WebhookClient/WebhookClient.csproj src/Web/WebhookClient/ -COPY src/Web/WebMVC/WebMVC.csproj src/Web/WebMVC/ -COPY src/Web/WebSPA/WebSPA.csproj src/Web/WebSPA/ -COPY src/Web/WebStatus/WebStatus.csproj src/Web/WebStatus/ -COPY test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj test/ServicesTests/Application.FunctionalTests/ -COPY test/ServicesTests/LoadTest/LoadTest.csproj test/ServicesTests/LoadTest/ +COPY scripts scripts/ -RUN dotnet restore eShopOnContainers-ServicesAndWebApps.sln +COPY ApiGateways/*/*/*.csproj csproj-files/ +COPY BuildingBlocks/*/*/*.csproj csproj-files/ +COPY Services/*/*/*.csproj csproj-files/ +COPY Web/*/*.csproj csproj-files/ COPY . . -WORKDIR /src/src/Services/Catalog/Catalog.API -RUN dotnet publish --no-restore -c Release -o /app +WORKDIR /src/Services/Catalog/Catalog.API +RUN dotnet publish -c Release -o /app FROM build as unittest -WORKDIR /src/src/Services/Catalog/Catalog.UnitTests +WORKDIR /src/Services/Catalog/Catalog.UnitTests FROM build as functionaltest -WORKDIR /src/src/Services/Catalog/Catalog.FunctionalTests +WORKDIR /src/Services/Catalog/Catalog.FunctionalTests FROM build AS publish FROM base AS final WORKDIR /app COPY --from=publish /app . +COPY --from=build /src/Services/Catalog/Catalog.API/Proto /app/Proto +COPY --from=build /src/Services/Catalog/Catalog.API/eshop.pfx . ENTRYPOINT ["dotnet", "Catalog.API.dll"] diff --git a/src/Services/Catalog/Catalog.API/Dockerfile.develop b/src/Services/Catalog/Catalog.API/Dockerfile.develop index 11034a2bc..bb79af28d 100644 --- a/src/Services/Catalog/Catalog.API/Dockerfile.develop +++ b/src/Services/Catalog/Catalog.API/Dockerfile.develop @@ -1,4 +1,4 @@ -FROM microsoft/dotnet:2.2-sdk +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster ARG BUILD_CONFIGURATION=Debug ENV ASPNETCORE_ENVIRONMENT=Development ENV DOTNET_USE_POLLING_FILE_WATCHER=true @@ -6,16 +6,16 @@ EXPOSE 80 WORKDIR /src -COPY ["src/BuildingBlocks/EventBus/EventBus/EventBus.csproj", "src/BuildingBlocks/EventBus/EventBus/"] -COPY ["src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "src/BuildingBlocks/EventBus/EventBusRabbitMQ/"] -COPY ["src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "src/BuildingBlocks/EventBus/EventBusServiceBus/"] -COPY ["src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj", "src/BuildingBlocks/EventBus/IntegrationEventLogEF/"] -COPY ["src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj", "src/BuildingBlocks/WebHostCustomization/WebHost.Customization/"] -COPY ["src/Services/Catalog/Catalog.API/Catalog.API.csproj", "src/Services/Catalog/Catalog.API/"] +COPY ["BuildingBlocks/EventBus/EventBus/EventBus.csproj", "BuildingBlocks/EventBus/EventBus/"] +COPY ["BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "BuildingBlocks/EventBus/EventBusRabbitMQ/"] +COPY ["BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "BuildingBlocks/EventBus/EventBusServiceBus/"] +COPY ["BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj", "BuildingBlocks/EventBus/IntegrationEventLogEF/"] +COPY ["BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj", "BuildingBlocks/WebHostCustomization/WebHost.Customization/"] +COPY ["Services/Catalog/Catalog.API/Catalog.API.csproj", "Services/Catalog/Catalog.API/"] -RUN dotnet restore src/Services/Catalog/Catalog.API/Catalog.API.csproj -nowarn:msb3202,nu1503 +RUN dotnet restore Services/Catalog/Catalog.API/Catalog.API.csproj -nowarn:msb3202,nu1503 COPY . . -WORKDIR "/src/src/Services/Catalog/Catalog.API" +WORKDIR "/src/Services/Catalog/Catalog.API" RUN dotnet build --no-restore -c $BUILD_CONFIGURATION ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"] \ No newline at end of file diff --git a/src/Services/Catalog/Catalog.API/Extensions/HostExtensions.cs b/src/Services/Catalog/Catalog.API/Extensions/HostExtensions.cs new file mode 100644 index 000000000..cfa7e9d2f --- /dev/null +++ b/src/Services/Catalog/Catalog.API/Extensions/HostExtensions.cs @@ -0,0 +1,83 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using System; +using Microsoft.Extensions.DependencyInjection; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Polly; +using System.Data.SqlClient; + +namespace Catalog.API.Extensions +{ + public static class HostExtensions + { + public static bool IsInKubernetes(this IHost host) + { + var cfg = host.Services.GetService(); + var orchestratorType = cfg.GetValue("OrchestratorType"); + return orchestratorType?.ToUpper() == "K8S"; + } + + public static IHost MigrateDbContext(this IHost host, Action seeder) where TContext : DbContext + { + var underK8s = host.IsInKubernetes(); + + using (var scope = host.Services.CreateScope()) + { + var services = scope.ServiceProvider; + + var logger = services.GetRequiredService>(); + + var context = services.GetService(); + + try + { + logger.LogInformation("Migrating database associated with context {DbContextName}", typeof(TContext).Name); + + if (underK8s) + { + InvokeSeeder(seeder, context, services); + } + else + { + var retry = Policy.Handle() + .WaitAndRetry(new TimeSpan[] + { + TimeSpan.FromSeconds(3), + TimeSpan.FromSeconds(5), + TimeSpan.FromSeconds(8), + }); + + //if the sql server container is not created on run docker compose this + //migration can't fail for network related exception. The retry options for DbContext only + //apply to transient exceptions + // Note that this is NOT applied when running some orchestrators (let the orchestrator to recreate the failing service) + retry.Execute(() => InvokeSeeder(seeder, context, services)); + } + + logger.LogInformation("Migrated database associated with context {DbContextName}", typeof(TContext).Name); + } + catch (Exception ex) + { + logger.LogError(ex, "An error occurred while migrating the database used on context {DbContextName}", typeof(TContext).Name); + if (underK8s) + { + throw; // Rethrow under k8s because we rely on k8s to re-run the pod + } + } + } + + return host; + } + + private static void InvokeSeeder(Action seeder, TContext context, IServiceProvider services) + where TContext : DbContext + { + context.Database.Migrate(); + seeder(context, services); + } + } +} diff --git a/src/Services/Catalog/Catalog.API/Extensions/WebHostExtensions.cs b/src/Services/Catalog/Catalog.API/Extensions/WebHostExtensions.cs new file mode 100644 index 000000000..b7a982b2e --- /dev/null +++ b/src/Services/Catalog/Catalog.API/Extensions/WebHostExtensions.cs @@ -0,0 +1,80 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using System; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Polly; +using System.Data.SqlClient; +using Microsoft.AspNetCore.Hosting; + +namespace Catalog.API.Extensions +{ + public static class WebHostExtensions + { + public static bool IsInKubernetes(this IWebHost host) + { + var cfg = host.Services.GetService(); + var orchestratorType = cfg.GetValue("OrchestratorType"); + return orchestratorType?.ToUpper() == "K8S"; + } + + public static IWebHost MigrateDbContext(this IWebHost host, Action seeder) where TContext : DbContext + { + var underK8s = host.IsInKubernetes(); + + using (var scope = host.Services.CreateScope()) + { + var services = scope.ServiceProvider; + + var logger = services.GetRequiredService>(); + + var context = services.GetService(); + + try + { + logger.LogInformation("Migrating database associated with context {DbContextName}", typeof(TContext).Name); + + if (underK8s) + { + InvokeSeeder(seeder, context, services); + } + else + { + var retry = Policy.Handle() + .WaitAndRetry(new TimeSpan[] + { + TimeSpan.FromSeconds(3), + TimeSpan.FromSeconds(5), + TimeSpan.FromSeconds(8), + }); + + //if the sql server container is not created on run docker compose this + //migration can't fail for network related exception. The retry options for DbContext only + //apply to transient exceptions + // Note that this is NOT applied when running some orchestrators (let the orchestrator to recreate the failing service) + retry.Execute(() => InvokeSeeder(seeder, context, services)); + } + + logger.LogInformation("Migrated database associated with context {DbContextName}", typeof(TContext).Name); + } + catch (Exception ex) + { + logger.LogError(ex, "An error occurred while migrating the database used on context {DbContextName}", typeof(TContext).Name); + if (underK8s) + { + throw; // Rethrow under k8s because we rely on k8s to re-run the pod + } + } + } + + return host; + } + + private static void InvokeSeeder(Action seeder, TContext context, IServiceProvider services) + where TContext : DbContext + { + context.Database.Migrate(); + seeder(context, services); + } + } +} diff --git a/src/Services/Catalog/Catalog.API/Grpc/CatalogService.cs b/src/Services/Catalog/Catalog.API/Grpc/CatalogService.cs new file mode 100644 index 000000000..39d7828c2 --- /dev/null +++ b/src/Services/Catalog/Catalog.API/Grpc/CatalogService.cs @@ -0,0 +1,189 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using CatalogApi; +using Grpc.Core; +using Microsoft.EntityFrameworkCore; +using Microsoft.eShopOnContainers.Services.Catalog.API; +using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; +using Microsoft.eShopOnContainers.Services.Catalog.API.Model; +using Microsoft.eShopOnContainers.Services.Catalog.API.ViewModel; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using static CatalogApi.Catalog; + +namespace Catalog.API.Grpc +{ + public class CatalogService : CatalogBase + { + private readonly CatalogContext _catalogContext; + private readonly CatalogSettings _settings; + private readonly ILogger _logger; + public CatalogService(CatalogContext dbContext, IOptions settings, ILogger logger) + { + _settings = settings.Value; + _catalogContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); + _logger = logger; + } + + public override async Task GetItemById(CatalogItemRequest request, ServerCallContext context) + { + _logger.LogInformation($"Begin grpc call CatalogService.GetItemById for product id {request.Id}"); + if (request.Id <= 0) + { + context.Status = new Status(StatusCode.FailedPrecondition, $"Id must be > 0 (received {request.Id})"); + return null; + } + + var item = await _catalogContext.CatalogItems.SingleOrDefaultAsync(ci => ci.Id == request.Id); + var baseUri = _settings.PicBaseUrl; + var azureStorageEnabled = _settings.AzureStorageEnabled; + item.FillProductUrl(baseUri, azureStorageEnabled: azureStorageEnabled); + + if (item != null) + { + return new CatalogItemResponse() + { + AvailableStock = item.AvailableStock, + Description = item.Description, + Id = item.Id, + MaxStockThreshold = item.MaxStockThreshold, + Name = item.Name, + OnReorder = item.OnReorder, + PictureFileName = item.PictureFileName, + PictureUri = item.PictureUri, + Price = (double)item.Price, + RestockThreshold = item.RestockThreshold + }; + } + + context.Status = new Status(StatusCode.NotFound, $"Product with id {request.Id} do not exist"); + return null; + } + + public override async Task GetItemsByIds(CatalogItemsRequest request, ServerCallContext context) + { + if (!string.IsNullOrEmpty(request.Ids)) + { + var items = await GetItemsByIdsAsync(request.Ids); + + if (!items.Any()) + { + context.Status = new Status(StatusCode.NotFound, $"ids value invalid. Must be comma-separated list of numbers"); + } + context.Status = new Status(StatusCode.OK, string.Empty); + return this.MapToResponse(items); + } + + var totalItems = await _catalogContext.CatalogItems + .LongCountAsync(); + + var itemsOnPage = await _catalogContext.CatalogItems + .OrderBy(c => c.Name) + .Skip(request.PageSize * request.PageIndex) + .Take(request.PageSize) + .ToListAsync(); + + /* The "awesome" fix for testing Devspaces */ + + /* + foreach (var pr in itemsOnPage) { + pr.Name = "Awesome " + pr.Name; + } + + */ + + itemsOnPage = ChangeUriPlaceholder(itemsOnPage); + + var model = this.MapToResponse(itemsOnPage, totalItems, request.PageIndex, request.PageSize); + context.Status = new Status(StatusCode.OK, string.Empty); + + return model; + } + + private PaginatedItemsResponse MapToResponse(List items) + { + return this.MapToResponse(items, items.Count(), 1, items.Count()); + } + + private PaginatedItemsResponse MapToResponse(List items, long count, int pageIndex, int pageSize) + { + var result = new PaginatedItemsResponse() + { + Count = count, + PageIndex = pageIndex, + PageSize = pageSize, + }; + + items.ForEach(i => + { + var brand = i.CatalogBrand == null + ? null + : new CatalogApi.CatalogBrand() + { + Id = i.CatalogBrand.Id, + Name = i.CatalogBrand.Brand, + }; + var catalogType = i.CatalogType == null + ? null + : new CatalogApi.CatalogType() + { + Id = i.CatalogType.Id, + Type = i.CatalogType.Type, + }; + + result.Data.Add(new CatalogItemResponse() + { + AvailableStock = i.AvailableStock, + Description = i.Description, + Id = i.Id, + MaxStockThreshold = i.MaxStockThreshold, + Name = i.Name, + OnReorder = i.OnReorder, + PictureFileName = i.PictureFileName, + PictureUri = i.PictureUri, + RestockThreshold = i.RestockThreshold, + CatalogBrand = brand, + CatalogType = catalogType, + Price = (double)i.Price, + }); + }); + + return result; + } + + + private async Task> GetItemsByIdsAsync(string ids) + { + var numIds = ids.Split(',').Select(id => (Ok: int.TryParse(id, out int x), Value: x)); + + if (!numIds.All(nid => nid.Ok)) + { + return new List(); + } + + var idsToSelect = numIds + .Select(id => id.Value); + + var items = await _catalogContext.CatalogItems.Where(ci => idsToSelect.Contains(ci.Id)).ToListAsync(); + + items = ChangeUriPlaceholder(items); + + return items; + } + + private List ChangeUriPlaceholder(List items) + { + var baseUri = _settings.PicBaseUrl; + var azureStorageEnabled = _settings.AzureStorageEnabled; + + foreach (var item in items) + { + item.FillProductUrl(baseUri, azureStorageEnabled: azureStorageEnabled); + } + + return items; + } + } +} diff --git a/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs index 8bdd2a401..cd1ea4ab1 100644 --- a/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs +++ b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Options; using Model; using Polly; + using Polly.Retry; using System; using System.Collections.Generic; using System.Data.SqlClient; @@ -18,7 +19,7 @@ public class CatalogContextSeed { - public async Task SeedAsync(CatalogContext context,IHostingEnvironment env,IOptions settings,ILogger logger) + public async Task SeedAsync(CatalogContext context,IWebHostEnvironment env,IOptions settings,ILogger logger) { var policy = CreatePolicy(logger, nameof(CatalogContextSeed)); @@ -369,7 +370,7 @@ } } - private Policy CreatePolicy( ILogger logger, string prefix,int retries = 3) + private AsyncRetryPolicy CreatePolicy( ILogger logger, string prefix,int retries = 3) { return Policy.Handle(). WaitAndRetryAsync( diff --git a/src/Services/Catalog/Catalog.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs b/src/Services/Catalog/Catalog.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs index 1c1dfd45f..5ddb81d63 100644 --- a/src/Services/Catalog/Catalog.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs +++ b/src/Services/Catalog/Catalog.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using System.Net; @@ -11,10 +12,10 @@ namespace Catalog.API.Infrastructure.Filters { public class HttpGlobalExceptionFilter : IExceptionFilter { - private readonly IHostingEnvironment env; + private readonly IWebHostEnvironment env; private readonly ILogger logger; - public HttpGlobalExceptionFilter(IHostingEnvironment env, ILogger logger) + public HttpGlobalExceptionFilter(IWebHostEnvironment env, ILogger logger) { this.env = env; this.logger = logger; diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/CatalogIntegrationEventService.cs b/src/Services/Catalog/Catalog.API/IntegrationEvents/CatalogIntegrationEventService.cs index bb3a23d40..e84de7e9e 100644 --- a/src/Services/Catalog/Catalog.API/IntegrationEvents/CatalogIntegrationEventService.cs +++ b/src/Services/Catalog/Catalog.API/IntegrationEvents/CatalogIntegrationEventService.cs @@ -39,8 +39,6 @@ namespace Catalog.API.IntegrationEvents { try { - _logger.LogInformation("----- Publishing integration event: {IntegrationEventId_published} from {AppName} - ({@IntegrationEvent})", evt.Id, Program.AppName, evt); - await _eventLogService.MarkEventAsInProgressAsync(evt.Id); _eventBus.Publish(evt); await _eventLogService.MarkEventAsPublishedAsync(evt.Id); @@ -54,8 +52,6 @@ namespace Catalog.API.IntegrationEvents public async Task SaveEventAndCatalogContextChangesAsync(IntegrationEvent evt) { - _logger.LogInformation("----- CatalogIntegrationEventService - Saving changes and integrationEvent: {IntegrationEventId}", evt.Id); - //Use of an EF Core resiliency strategy when using multiple DbContexts within an explicit BeginTransaction(): //See: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency await ResilientTransaction.New(_catalogContext).ExecuteAsync(async () => diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/OrderStatusChangedToAwaitingValidationIntegrationEventHandler.cs b/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/OrderStatusChangedToAwaitingValidationIntegrationEventHandler.cs index 493a271cc..2c9fd337c 100644 --- a/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/OrderStatusChangedToAwaitingValidationIntegrationEventHandler.cs +++ b/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/OrderStatusChangedToAwaitingValidationIntegrationEventHandler.cs @@ -32,8 +32,6 @@ { using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) { - _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); - var confirmedOrderStockItems = new List(); foreach (var orderStockItem in @event.OrderStockItems) diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs b/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs index 7d383254f..e7520a651 100644 --- a/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs +++ b/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs @@ -25,8 +25,6 @@ { using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) { - _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); - //we're not blocking stock/inventory foreach (var orderStockItem in @event.OrderStockItems) { diff --git a/src/Services/Catalog/Catalog.API/Program.cs b/src/Services/Catalog/Catalog.API/Program.cs index 39b071c46..f3198e7bd 100644 --- a/src/Services/Catalog/Catalog.API/Program.cs +++ b/src/Services/Catalog/Catalog.API/Program.cs @@ -1,14 +1,21 @@ -using Microsoft.AspNetCore; +using Autofac.Extensions.DependencyInjection; +using Catalog.API.Extensions; +using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF; using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Serilog; using System; +using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Net; namespace Microsoft.eShopOnContainers.Services.Catalog.API { @@ -26,12 +33,12 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API try { Log.Information("Configuring web host ({ApplicationContext})...", AppName); - var host = BuildWebHost(configuration, args); + var host = CreateHostBuilder(configuration, args); Log.Information("Applying migrations ({ApplicationContext})...", AppName); host.MigrateDbContext((context, services) => { - var env = services.GetService(); + var env = services.GetService(); var settings = services.GetService>(); var logger = services.GetService>(); @@ -57,14 +64,27 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API } } - private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) => + private static IWebHost CreateHostBuilder(IConfiguration configuration, string[] args) => WebHost.CreateDefaultBuilder(args) + .UseConfiguration(configuration) .CaptureStartupErrors(false) + .ConfigureKestrel(options => + { + var ports = GetDefinedPorts(configuration); + options.Listen(IPAddress.Any, ports.httpPort, listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http1AndHttp2; + }); + options.Listen(IPAddress.Any, ports.grpcPort, listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http2; + }); + + }) .UseStartup() .UseApplicationInsights() .UseContentRoot(Directory.GetCurrentDirectory()) .UseWebRoot("Pics") - .UseConfiguration(configuration) .UseSerilog() .Build(); @@ -83,6 +103,13 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API .CreateLogger(); } + private static (int httpPort, int grpcPort) GetDefinedPorts(IConfiguration config) + { + var grpcPort = config.GetValue("GRPC_PORT", 81); + var port = config.GetValue("PORT", 80); + return (port, grpcPort); + } + private static IConfiguration GetConfiguration() { var builder = new ConfigurationBuilder() @@ -103,4 +130,4 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API return builder.Build(); } } -} \ No newline at end of file +} diff --git a/src/Services/Catalog/Catalog.API/Properties/launchSettings.json b/src/Services/Catalog/Catalog.API/Properties/launchSettings.json index f842f80d0..a29630269 100644 --- a/src/Services/Catalog/Catalog.API/Properties/launchSettings.json +++ b/src/Services/Catalog/Catalog.API/Properties/launchSettings.json @@ -14,10 +14,10 @@ "launchUrl": "/swagger", "environmentVariables": { "ConnectionString": "server=localhost,5433;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word", + "Serilog:LogstashgUrl": "http://locahost:8080", "ASPNETCORE_ENVIRONMENT": "Development", "EventBusConnection": "localhost", - "Serilog:SeqServerUrl": "http://locahost:5340", - "Serilog:LogstashgUrl":"http://locahost:8080", + "Serilog:SeqServerUrl": "http://locahost:5340" } }, "Microsoft.eShopOnContainers.Services.Catalog.API": { diff --git a/src/Services/Catalog/Catalog.API/Proto/catalog.proto b/src/Services/Catalog/Catalog.API/Proto/catalog.proto new file mode 100644 index 000000000..fa83d45c4 --- /dev/null +++ b/src/Services/Catalog/Catalog.API/Proto/catalog.proto @@ -0,0 +1,60 @@ +syntax = "proto3"; + +/* >> +import "google/api/annotations.proto"; +<< */ + + +package CatalogApi; + +message CatalogItemRequest { + int32 id = 1; +} +message CatalogItemsRequest { + string ids = 1; + int32 pageSize = 2; + int32 pageIndex = 3; +} + +message CatalogItemResponse { + int32 id = 1; + string name = 2; + string description=3; + double price=4; + string picture_file_name=5; + string picture_uri=6; + CatalogType catalog_type=8; + CatalogBrand catalog_brand=10; + int32 available_stock=11; + int32 restock_threshold=12; + int32 max_stock_threshold=13; + bool on_reorder=14; +} + +message CatalogBrand { + int32 id = 1; + string name = 2; +} + +message CatalogType { + int32 id = 1; + string type = 2; +} + +message PaginatedItemsResponse { + int32 pageIndex = 1; + int32 pageSize = 2; + int64 count = 3; + repeated CatalogItemResponse data = 4; +} + +service Catalog { + rpc GetItemById (CatalogItemRequest) returns (CatalogItemResponse) { + /* >> + option (google.api.http) = { + get: "/api/v1/catalog/items/{id}" + }; + << */ + } + rpc GetItemsByIds (CatalogItemsRequest) returns (PaginatedItemsResponse) {} +} \ No newline at end of file diff --git a/src/Services/Catalog/Catalog.API/Startup.cs b/src/Services/Catalog/Catalog.API/Startup.cs index 1a51a86fb..64441f9ea 100644 --- a/src/Services/Catalog/Catalog.API/Startup.cs +++ b/src/Services/Catalog/Catalog.API/Startup.cs @@ -1,10 +1,11 @@ using Autofac; using Autofac.Extensions.DependencyInjection; +using Catalog.API.Grpc; using global::Catalog.API.Infrastructure.Filters; using global::Catalog.API.IntegrationEvents; -using Microsoft.ApplicationInsights.Extensibility; -using Microsoft.ApplicationInsights.ServiceFabric; +using HealthChecks.UI.Client; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -22,15 +23,15 @@ using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.EventHa using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Microsoft.OpenApi.Models; using RabbitMQ.Client; using System; using System.Data.Common; +using System.IO; using System.Reflection; -using HealthChecks.UI.Client; -using Microsoft.AspNetCore.Diagnostics.HealthChecks; -using Microsoft.Extensions.Diagnostics.HealthChecks; namespace Microsoft.eShopOnContainers.Services.Catalog.API { @@ -46,21 +47,22 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddAppInsight(Configuration) + .AddGrpc().Services .AddCustomMVC(Configuration) .AddCustomDbContext(Configuration) .AddCustomOptions(Configuration) .AddIntegrationServices(Configuration) .AddEventBus(Configuration) - .AddSwagger() + .AddSwagger(Configuration) .AddCustomHealthCheck(Configuration); var container = new ContainerBuilder(); container.Populate(services); - return new AutofacServiceProvider(container.Build()); + return new AutofacServiceProvider(container.Build()); } - public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) { //Configure logs @@ -75,27 +77,44 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API app.UsePathBase(pathBase); } - app.UseHealthChecks("/hc", new HealthCheckOptions() - { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); + app.UseSwagger() + .UseSwaggerUI(c => + { + c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Catalog.API V1"); + }); - app.UseHealthChecks("/liveness", new HealthCheckOptions + app.UseCors("CorsPolicy"); + app.UseRouting(); + app.UseEndpoints(endpoints => { - Predicate = r => r.Name.Contains("self") + endpoints.MapDefaultControllerRoute(); + endpoints.MapControllers(); + endpoints.MapGet("/_proto/", async ctx => + { + ctx.Response.ContentType = "text/plain"; + using var fs = new FileStream(Path.Combine(env.ContentRootPath, "Proto", "catalog.proto"), FileMode.Open, FileAccess.Read); + using var sr = new StreamReader(fs); + while (!sr.EndOfStream) + { + var line = await sr.ReadLineAsync(); + if (line != "/* >>" || line != "<< */") + { + await ctx.Response.WriteAsync(line); + } + } + }); + endpoints.MapGrpcService(); + endpoints.MapHealthChecks("/hc", new HealthCheckOptions() + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + endpoints.MapHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = r => r.Name.Contains("self") + }); }); - app.UseCors("CorsPolicy"); - - app.UseMvcWithDefaultRoute(); - - app.UseSwagger() - .UseSwaggerUI(c => - { - c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Catalog.API V1"); - }); - ConfigureEventBus(app); } @@ -112,31 +131,17 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API public static IServiceCollection AddAppInsight(this IServiceCollection services, IConfiguration configuration) { services.AddApplicationInsightsTelemetry(configuration); - var orchestratorType = configuration.GetValue("OrchestratorType"); - - if (orchestratorType?.ToUpper() == "K8S") - { - // Enable K8s telemetry initializer - services.AddApplicationInsightsKubernetesEnricher(); - } - if (orchestratorType?.ToUpper() == "SF") - { - // Enable SF telemetry initializer - services.AddSingleton((serviceProvider) => - new FabricTelemetryInitializer()); - } + services.AddApplicationInsightsKubernetesEnricher(); return services; } public static IServiceCollection AddCustomMVC(this IServiceCollection services, IConfiguration configuration) - { - services.AddMvc(options => - { - options.Filters.Add(typeof(HttpGlobalExceptionFilter)); - }) - .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) - .AddControllersAsServices(); + { + services.AddControllers(options => + { + options.Filters.Add(typeof(HttpGlobalExceptionFilter)); + }).AddNewtonsoftJson(); services.AddCors(options => { @@ -166,7 +171,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API tags: new string[] { "catalogdb" }); if (!string.IsNullOrEmpty(accountName) && !string.IsNullOrEmpty(accountKey)) - { + { hcBuilder .AddAzureBlobStorage( $"DefaultEndpointsProtocol=https;AccountName={accountName};AccountKey={accountKey};EndpointSuffix=core.windows.net", @@ -197,14 +202,15 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API public static IServiceCollection AddCustomDbContext(this IServiceCollection services, IConfiguration configuration) { - services.AddDbContext(options => + services.AddEntityFrameworkSqlServer() + .AddDbContext(options => { options.UseSqlServer(configuration["ConnectionString"], sqlServerOptionsAction: sqlOptions => { sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); //Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency - sqlOptions.EnableRetryOnFailure(maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); + sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); }); // Changing default behavior when client evaluation occurs to throw. @@ -220,7 +226,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API { sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); //Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency - sqlOptions.EnableRetryOnFailure(maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); + sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); }); }); @@ -251,17 +257,16 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API return services; } - public static IServiceCollection AddSwagger(this IServiceCollection services) + public static IServiceCollection AddSwagger(this IServiceCollection services, IConfiguration configuration) { services.AddSwaggerGen(options => { options.DescribeAllEnumsAsStrings(); - options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info + options.SwaggerDoc("v1", new OpenApiInfo { Title = "eShopOnContainers - Catalog HTTP API", Version = "v1", - Description = "The Catalog Microservice HTTP API. This is a Data-Driven/CRUD microservice sample", - TermsOfService = "Terms Of Service" + Description = "The Catalog Microservice HTTP API. This is a Data-Driven/CRUD microservice sample" }); }); diff --git a/src/Services/Catalog/Catalog.API/appsettings.Development.json b/src/Services/Catalog/Catalog.API/appsettings.Development.json new file mode 100644 index 000000000..1d5574f63 --- /dev/null +++ b/src/Services/Catalog/Catalog.API/appsettings.Development.json @@ -0,0 +1,15 @@ +{ + "ConnectionString": "Server=tcp:127.0.0.1,5433;Initial Catalog=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word", + "PicBaseUrl": "http://localhost:5101/api/v1/catalog/items/[0]/pic/", + "Serilog": { + "MinimumLevel": { + "Default": "Debug", + "Override": { + "Microsoft": "Warning", + "Microsoft.eShopOnContainers": "Debug", + "System": "Warning" + } + } + }, + "EventBusConnection": "localhost" +} \ No newline at end of file diff --git a/src/Services/Catalog/Catalog.API/appsettings.json b/src/Services/Catalog/Catalog.API/appsettings.json index cc7b1b1fb..e9103c7a6 100644 --- a/src/Services/Catalog/Catalog.API/appsettings.json +++ b/src/Services/Catalog/Catalog.API/appsettings.json @@ -1,6 +1,4 @@ { - "ConnectionString": "Server=tcp:127.0.0.1,5433;Initial Catalog=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word", - "PicBaseUrl": "http://localhost:5101/api/v1/catalog/items/[0]/pic/", "UseCustomizationData": false, "Serilog": { "SeqServerUrl": null, @@ -27,4 +25,6 @@ "ClientId": "your-clien-id", "ClientSecret": "your-client-secret" } + } + \ No newline at end of file diff --git a/src/Services/Catalog/Catalog.API/eshop.pfx b/src/Services/Catalog/Catalog.API/eshop.pfx new file mode 100644 index 000000000..8af82972f Binary files /dev/null and b/src/Services/Catalog/Catalog.API/eshop.pfx differ diff --git a/src/Services/Catalog/Catalog.API/web.config b/src/Services/Catalog/Catalog.API/web.config index 2157aef31..6da4550d8 100644 --- a/src/Services/Catalog/Catalog.API/web.config +++ b/src/Services/Catalog/Catalog.API/web.config @@ -4,8 +4,15 @@ - - + + + + + + + + + \ No newline at end of file diff --git a/src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj b/src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj index 16e5aec67..5e7fcefbe 100644 --- a/src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj +++ b/src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj @@ -1,7 +1,7 @@  - netcoreapp2.2 + $(NetCoreTargetVersion) false @@ -33,11 +33,9 @@ - - - - - + + + all runtime; build; native; contentfiles; analyzers diff --git a/src/Services/Catalog/Catalog.FunctionalTests/CatalogScenarioBase.cs b/src/Services/Catalog/Catalog.FunctionalTests/CatalogScenarioBase.cs index 46bdb07d1..6a8cbd72f 100644 --- a/src/Services/Catalog/Catalog.FunctionalTests/CatalogScenarioBase.cs +++ b/src/Services/Catalog/Catalog.FunctionalTests/CatalogScenarioBase.cs @@ -1,3 +1,5 @@ +using Autofac.Extensions.DependencyInjection; +using Catalog.API.Extensions; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF; @@ -5,6 +7,7 @@ using Microsoft.eShopOnContainers.Services.Catalog.API; using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System.IO; @@ -25,14 +28,16 @@ namespace Catalog.FunctionalTests { cb.AddJsonFile("appsettings.json", optional: false) .AddEnvironmentVariables(); - }).UseStartup(); + }) + .UseStartup(); + var testServer = new TestServer(hostBuilder); testServer.Host .MigrateDbContext((context, services) => { - var env = services.GetService(); + var env = services.GetService(); var settings = services.GetService>(); var logger = services.GetService>(); diff --git a/src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj b/src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj index 762361d65..44b5660c1 100644 --- a/src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj +++ b/src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj @@ -1,17 +1,17 @@  - netcoreapp2.2 - + $(NetCoreTargetVersion) + false false - - - - - + + + + + all runtime; build; native; contentfiles; analyzers diff --git a/src/Services/Identity/Identity.API/Configuration/Config.cs b/src/Services/Identity/Identity.API/Configuration/Config.cs index dcb3a8c7a..04a9aa043 100644 --- a/src/Services/Identity/Identity.API/Configuration/Config.cs +++ b/src/Services/Identity/Identity.API/Configuration/Config.cs @@ -284,7 +284,8 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration AllowedScopes = { - "webshoppingagg" + "webshoppingagg", + "basket" } }, new Client diff --git a/src/Services/Identity/Identity.API/Dockerfile b/src/Services/Identity/Identity.API/Dockerfile index bb7fed9ec..9bc9ede38 100644 --- a/src/Services/Identity/Identity.API/Dockerfile +++ b/src/Services/Identity/Identity.API/Dockerfile @@ -1,55 +1,20 @@ -FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base +FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base WORKDIR /app EXPOSE 80 -FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build WORKDIR /src -# Keep the project list and command dotnet restore identical in all Dockfiles to maximize image cache utilization -COPY eShopOnContainers-ServicesAndWebApps.sln . -COPY docker-compose.dcproj /src/ -COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/ -COPY src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj src/ApiGateways/Mobile.Bff.Shopping/aggregator/ -COPY src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj src/ApiGateways/Web.Bff.Shopping/aggregator/ -COPY src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj src/BuildingBlocks/Devspaces.Support/ -COPY src/BuildingBlocks/EventBus/EventBus/EventBus.csproj src/BuildingBlocks/EventBus/EventBus/ -COPY src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj src/BuildingBlocks/EventBus/EventBus.Tests/ -COPY src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj src/BuildingBlocks/EventBus/EventBusRabbitMQ/ -COPY src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj src/BuildingBlocks/EventBus/EventBusServiceBus/ -COPY src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj src/BuildingBlocks/EventBus/IntegrationEventLogEF/ -COPY src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj src/BuildingBlocks/WebHostCustomization/WebHost.Customization/ -COPY src/Services/Basket/Basket.API/Basket.API.csproj src/Services/Basket/Basket.API/ -COPY src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj src/Services/Basket/Basket.FunctionalTests/ -COPY src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj src/Services/Basket/Basket.UnitTests/ -COPY src/Services/Catalog/Catalog.API/Catalog.API.csproj src/Services/Catalog/Catalog.API/ -COPY src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj src/Services/Catalog/Catalog.FunctionalTests/ -COPY src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj src/Services/Catalog/Catalog.UnitTests/ -COPY src/Services/Identity/Identity.API/Identity.API.csproj src/Services/Identity/Identity.API/ -COPY src/Services/Location/Locations.API/Locations.API.csproj src/Services/Location/Locations.API/ -COPY src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj src/Services/Location/Locations.FunctionalTests/ -COPY src/Services/Marketing/Marketing.API/Marketing.API.csproj src/Services/Marketing/Marketing.API/ -COPY src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj src/Services/Marketing/Marketing.FunctionalTests/ -COPY src/Services/Ordering/Ordering.API/Ordering.API.csproj src/Services/Ordering/Ordering.API/ -COPY src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj src/Services/Ordering/Ordering.BackgroundTasks/ -COPY src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj src/Services/Ordering/Ordering.Domain/ -COPY src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj src/Services/Ordering/Ordering.FunctionalTests/ -COPY src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj src/Services/Ordering/Ordering.Infrastructure/ -COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/ -COPY src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj src/Services/Ordering/Ordering.UnitTests/ -COPY src/Services/Payment/Payment.API/Payment.API.csproj src/Services/Payment/Payment.API/ -COPY src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj src/Services/Webhooks/Webhooks.API/ -COPY src/Web/WebhookClient/WebhookClient.csproj src/Web/WebhookClient/ -COPY src/Web/WebMVC/WebMVC.csproj src/Web/WebMVC/ -COPY src/Web/WebSPA/WebSPA.csproj src/Web/WebSPA/ -COPY src/Web/WebStatus/WebStatus.csproj src/Web/WebStatus/ -COPY test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj test/ServicesTests/Application.FunctionalTests/ -COPY test/ServicesTests/LoadTest/LoadTest.csproj test/ServicesTests/LoadTest/ +COPY scripts scripts/ -RUN dotnet restore eShopOnContainers-ServicesAndWebApps.sln +COPY ApiGateways/*/*/*.csproj csproj-files/ +COPY BuildingBlocks/*/*/*.csproj csproj-files/ +COPY Services/*/*/*.csproj csproj-files/ +COPY Web/*/*.csproj csproj-files/ COPY . . -WORKDIR /src/src/Services/Identity/Identity.API -RUN dotnet publish --no-restore -c Release -o /app +WORKDIR /src/Services/Identity/Identity.API +RUN dotnet publish -c Release -o /app FROM build AS publish diff --git a/src/Services/Identity/Identity.API/Dockerfile.develop b/src/Services/Identity/Identity.API/Dockerfile.develop index 3ab1fbe7c..746354008 100644 --- a/src/Services/Identity/Identity.API/Dockerfile.develop +++ b/src/Services/Identity/Identity.API/Dockerfile.develop @@ -1,15 +1,15 @@ -FROM microsoft/dotnet:2.2-sdk +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster ARG BUILD_CONFIGURATION=Debug ENV ASPNETCORE_ENVIRONMENT=Development ENV DOTNET_USE_POLLING_FILE_WATCHER=true EXPOSE 80 WORKDIR /src -COPY ["src/Services/Identity/Identity.API/Identity.API.csproj", "src/Services/Identity/Identity.API/"] -COPY ["src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj", "src/BuildingBlocks/WebHostCustomization/WebHost.Customization/"] -RUN dotnet restore src/Services/Identity/Identity.API/Identity.API.csproj -nowarn:msb3202,nu1503 +COPY ["Services/Identity/Identity.API/Identity.API.csproj", "Services/Identity/Identity.API/"] +COPY ["BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj", "BuildingBlocks/WebHostCustomization/WebHost.Customization/"] +RUN dotnet restore Services/Identity/Identity.API/Identity.API.csproj -nowarn:msb3202,nu1503 COPY . . -WORKDIR "/src/src/Services/Identity/Identity.API" +WORKDIR "/src/Services/Identity/Identity.API" RUN dotnet build --no-restore -c $BUILD_CONFIGURATION ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"] diff --git a/src/Services/Identity/Identity.API/Factories/ApplicationDbContextFactory.cs b/src/Services/Identity/Identity.API/Factories/ApplicationDbContextFactory.cs new file mode 100644 index 000000000..bb3f7bfe2 --- /dev/null +++ b/src/Services/Identity/Identity.API/Factories/ApplicationDbContextFactory.cs @@ -0,0 +1,26 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Design; +using Microsoft.eShopOnContainers.Services.Identity.API.Data; +using Microsoft.Extensions.Configuration; +using System.IO; + +namespace Identity.API.Factories +{ + public class ApplicationDbContextFactory : IDesignTimeDbContextFactory + { + public ApplicationDbContext CreateDbContext(string[] args) + { + var config = new ConfigurationBuilder() + .SetBasePath(Path.Combine(Directory.GetCurrentDirectory())) + .AddJsonFile("appsettings.json") + .AddEnvironmentVariables() + .Build(); + + var optionsBuilder = new DbContextOptionsBuilder(); + + optionsBuilder.UseSqlServer(config["ConnectionString"], sqlServerOptionsAction: o => o.MigrationsAssembly("Identity.API")); + + return new ApplicationDbContext(optionsBuilder.Options); + } + } +} \ No newline at end of file diff --git a/src/Services/Identity/Identity.API/Factories/ConfigurationDbContextFactory.cs b/src/Services/Identity/Identity.API/Factories/ConfigurationDbContextFactory.cs new file mode 100644 index 000000000..e304f50a8 --- /dev/null +++ b/src/Services/Identity/Identity.API/Factories/ConfigurationDbContextFactory.cs @@ -0,0 +1,28 @@ +using IdentityServer4.EntityFramework.DbContexts; +using IdentityServer4.EntityFramework.Options; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Design; +using Microsoft.Extensions.Configuration; +using System.IO; + +namespace Identity.API.Factories +{ + public class ConfigurationDbContextFactory : IDesignTimeDbContextFactory + { + public ConfigurationDbContext CreateDbContext(string[] args) + { + var config = new ConfigurationBuilder() + .SetBasePath(Path.Combine(Directory.GetCurrentDirectory())) + .AddJsonFile("appsettings.json") + .AddEnvironmentVariables() + .Build(); + + var optionsBuilder = new DbContextOptionsBuilder(); + var storeOptions = new ConfigurationStoreOptions(); + + optionsBuilder.UseSqlServer(config["ConnectionString"], sqlServerOptionsAction: o => o.MigrationsAssembly("Identity.API")); + + return new ConfigurationDbContext(optionsBuilder.Options, storeOptions); + } + } +} \ No newline at end of file diff --git a/src/Services/Identity/Identity.API/Factories/PersistedGrantDbContextFactory.cs b/src/Services/Identity/Identity.API/Factories/PersistedGrantDbContextFactory.cs new file mode 100644 index 000000000..b3dff8d9a --- /dev/null +++ b/src/Services/Identity/Identity.API/Factories/PersistedGrantDbContextFactory.cs @@ -0,0 +1,28 @@ +using IdentityServer4.EntityFramework.DbContexts; +using IdentityServer4.EntityFramework.Options; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Design; +using Microsoft.Extensions.Configuration; +using System.IO; + +namespace Identity.API.Factories +{ + public class PersistedGrantDbContextFactory : IDesignTimeDbContextFactory + { + public PersistedGrantDbContext CreateDbContext(string[] args) + { + var config = new ConfigurationBuilder() + .SetBasePath(Path.Combine(Directory.GetCurrentDirectory())) + .AddJsonFile("appsettings.json") + .AddEnvironmentVariables() + .Build(); + + var optionsBuilder = new DbContextOptionsBuilder(); + var operationOptions = new OperationalStoreOptions(); + + optionsBuilder.UseSqlServer(config["ConnectionString"], sqlServerOptionsAction: o => o.MigrationsAssembly("Identity.API")); + + return new PersistedGrantDbContext(optionsBuilder.Options, operationOptions); + } + } +} \ No newline at end of file diff --git a/src/Services/Identity/Identity.API/IWebHostExtensions.cs b/src/Services/Identity/Identity.API/IWebHostExtensions.cs new file mode 100644 index 000000000..aff262b73 --- /dev/null +++ b/src/Services/Identity/Identity.API/IWebHostExtensions.cs @@ -0,0 +1,79 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Polly; +using System; +using System.Data.SqlClient; + +namespace Microsoft.AspNetCore.Hosting +{ + public static class IWebHostExtensions + { + public static bool IsInKubernetes(this IWebHost webHost) + { + var cfg = webHost.Services.GetService(); + var orchestratorType = cfg.GetValue("OrchestratorType"); + return orchestratorType?.ToUpper() == "K8S"; + } + + public static IWebHost MigrateDbContext(this IWebHost webHost, Action seeder) where TContext : DbContext + { + var underK8s = webHost.IsInKubernetes(); + + using (var scope = webHost.Services.CreateScope()) + { + var services = scope.ServiceProvider; + var logger = services.GetRequiredService>(); + var context = services.GetService(); + + try + { + logger.LogInformation("Migrating database associated with context {DbContextName}", typeof(TContext).Name); + + if (underK8s) + { + InvokeSeeder(seeder, context, services); + } + else + { + var retries = 10; + var retry = Policy.Handle() + .WaitAndRetry( + retryCount: retries, + sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), + onRetry: (exception, timeSpan, retry, ctx) => + { + logger.LogWarning(exception, "[{prefix}] Exception {ExceptionType} with message {Message} detected on attempt {retry} of {retries}", nameof(TContext), exception.GetType().Name, exception.Message, retry, retries); + }); + + //if the sql server container is not created on run docker compose this + //migration can't fail for network related exception. The retry options for DbContext only + //apply to transient exceptions + // Note that this is NOT applied when running some orchestrators (let the orchestrator to recreate the failing service) + retry.Execute(() => InvokeSeeder(seeder, context, services)); + } + + logger.LogInformation("Migrated database associated with context {DbContextName}", typeof(TContext).Name); + } + catch (Exception ex) + { + logger.LogError(ex, "An error occurred while migrating the database used on context {DbContextName}", typeof(TContext).Name); + if (underK8s) + { + throw; // Rethrow under k8s because we rely on k8s to re-run the pod + } + } + } + + return webHost; + } + + private static void InvokeSeeder(Action seeder, TContext context, IServiceProvider services) + where TContext : DbContext + { + context.Database.Migrate(); + seeder(context, services); + } + } +} diff --git a/src/Services/Identity/Identity.API/Identity.API.csproj b/src/Services/Identity/Identity.API/Identity.API.csproj index 020802bf4..f2e7bec58 100644 --- a/src/Services/Identity/Identity.API/Identity.API.csproj +++ b/src/Services/Identity/Identity.API/Identity.API.csproj @@ -1,9 +1,12 @@  - netcoreapp2.2 + $(NetCoreTargetVersion) aspnet-eShopOnContainers.Identity-90487118-103c-4ff0-b9da-e5e26f7ab0c5 ..\..\..\..\docker-compose.dcproj + false + true + $(LangVersion) @@ -13,47 +16,45 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + - - - - PreserveNewest diff --git a/src/Services/Identity/Identity.API/Migrations/20170912114036_Initial.Designer.cs b/src/Services/Identity/Identity.API/Migrations/20190729091724_InitialMigration.Designer.cs similarity index 80% rename from src/Services/Identity/Identity.API/Migrations/20170912114036_Initial.Designer.cs rename to src/Services/Identity/Identity.API/Migrations/20190729091724_InitialMigration.Designer.cs index 0850b37b9..5ad802992 100644 --- a/src/Services/Identity/Identity.API/Migrations/20170912114036_Initial.Designer.cs +++ b/src/Services/Identity/Identity.API/Migrations/20190729091724_InitialMigration.Designer.cs @@ -1,114 +1,29 @@ // +using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.eShopOnContainers.Services.Identity.API.Data; -using System; namespace Identity.API.Migrations { [DbContext(typeof(ApplicationDbContext))] - [Migration("20170912114036_Initial")] - partial class Initial + [Migration("20190729091724_InitialMigration")] + partial class InitialMigration { protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "2.0.0-rtm-26452") + .HasAnnotation("ProductVersion", "3.0.0-preview7.19362.6") + .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - modelBuilder.Entity("Identity.API.Models.ApplicationUser", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("AccessFailedCount"); - - b.Property("CardHolderName") - .IsRequired(); - - b.Property("CardNumber") - .IsRequired(); - - b.Property("CardType"); - - b.Property("City") - .IsRequired(); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken(); - - b.Property("Country") - .IsRequired(); - - b.Property("Email") - .HasMaxLength(256); - - b.Property("EmailConfirmed"); - - b.Property("Expiration") - .IsRequired(); - - b.Property("LastName") - .IsRequired(); - - b.Property("LockoutEnabled"); - - b.Property("LockoutEnd"); - - b.Property("Name") - .IsRequired(); - - b.Property("NormalizedEmail") - .HasMaxLength(256); - - b.Property("NormalizedUserName") - .HasMaxLength(256); - - b.Property("PasswordHash"); - - b.Property("PhoneNumber"); - - b.Property("PhoneNumberConfirmed"); - - b.Property("SecurityNumber") - .IsRequired(); - - b.Property("SecurityStamp"); - - b.Property("State") - .IsRequired(); - - b.Property("Street") - .IsRequired(); - - b.Property("TwoFactorEnabled"); - - b.Property("UserName") - .HasMaxLength(256); - - b.Property("ZipCode") - .IsRequired(); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasName("UserNameIndex") - .HasFilter("[NormalizedUserName] IS NOT NULL"); - - b.ToTable("AspNetUsers"); - }); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => { - b.Property("Id") - .ValueGeneratedOnAdd(); + b.Property("Id"); b.Property("ConcurrencyStamp") .IsConcurrencyToken(); @@ -132,7 +47,8 @@ namespace Identity.API.Migrations modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); b.Property("ClaimType"); @@ -151,7 +67,8 @@ namespace Identity.API.Migrations modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); b.Property("ClaimType"); @@ -213,49 +130,140 @@ namespace Identity.API.Migrations b.ToTable("AspNetUserTokens"); }); + modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Identity.API.Models.ApplicationUser", b => + { + b.Property("Id"); + + b.Property("AccessFailedCount"); + + b.Property("CardHolderName") + .IsRequired(); + + b.Property("CardNumber") + .IsRequired(); + + b.Property("CardType"); + + b.Property("City") + .IsRequired(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Country") + .IsRequired(); + + b.Property("Email") + .HasMaxLength(256); + + b.Property("EmailConfirmed"); + + b.Property("Expiration") + .IsRequired(); + + b.Property("LastName") + .IsRequired(); + + b.Property("LockoutEnabled"); + + b.Property("LockoutEnd"); + + b.Property("Name") + .IsRequired(); + + b.Property("NormalizedEmail") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .HasMaxLength(256); + + b.Property("PasswordHash"); + + b.Property("PhoneNumber"); + + b.Property("PhoneNumberConfirmed"); + + b.Property("SecurityNumber") + .IsRequired(); + + b.Property("SecurityStamp"); + + b.Property("State") + .IsRequired(); + + b.Property("Street") + .IsRequired(); + + b.Property("TwoFactorEnabled"); + + b.Property("UserName") + .HasMaxLength(256); + + b.Property("ZipCode") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers"); + }); + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) .WithMany() .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("Identity.API.Models.ApplicationUser") + b.HasOne("Microsoft.eShopOnContainers.Services.Identity.API.Models.ApplicationUser", null) .WithMany() .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("Identity.API.Models.ApplicationUser") + b.HasOne("Microsoft.eShopOnContainers.Services.Identity.API.Models.ApplicationUser", null) .WithMany() .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) .WithMany() .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); - b.HasOne("Identity.API.Models.ApplicationUser") + b.HasOne("Microsoft.eShopOnContainers.Services.Identity.API.Models.ApplicationUser", null) .WithMany() .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("Identity.API.Models.ApplicationUser") + b.HasOne("Microsoft.eShopOnContainers.Services.Identity.API.Models.ApplicationUser", null) .WithMany() .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); #pragma warning restore 612, 618 } diff --git a/src/Services/Identity/Identity.API/Migrations/20170912114036_Initial.cs b/src/Services/Identity/Identity.API/Migrations/20190729091724_InitialMigration.cs similarity index 58% rename from src/Services/Identity/Identity.API/Migrations/20170912114036_Initial.cs rename to src/Services/Identity/Identity.API/Migrations/20190729091724_InitialMigration.cs index cf771dac8..447369dd0 100644 --- a/src/Services/Identity/Identity.API/Migrations/20170912114036_Initial.cs +++ b/src/Services/Identity/Identity.API/Migrations/20190729091724_InitialMigration.cs @@ -1,11 +1,10 @@ -using Microsoft.EntityFrameworkCore.Metadata; +using System; +using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -using System; -using System.Collections.Generic; namespace Identity.API.Migrations { - public partial class Initial : Migration + public partial class InitialMigration : Migration { protected override void Up(MigrationBuilder migrationBuilder) { @@ -13,10 +12,10 @@ namespace Identity.API.Migrations name: "AspNetRoles", columns: table => new { - Id = table.Column(type: "nvarchar(450)", nullable: false), - ConcurrencyStamp = table.Column(type: "nvarchar(max)", nullable: true), - Name = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - NormalizedName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true) + Id = table.Column(nullable: false), + Name = table.Column(maxLength: 256, nullable: true), + NormalizedName = table.Column(maxLength: 256, nullable: true), + ConcurrencyStamp = table.Column(nullable: true) }, constraints: table => { @@ -27,33 +26,33 @@ namespace Identity.API.Migrations name: "AspNetUsers", columns: table => new { - Id = table.Column(type: "nvarchar(450)", nullable: false), - AccessFailedCount = table.Column(type: "int", nullable: false), - CardHolderName = table.Column(type: "nvarchar(max)", nullable: false), - CardNumber = table.Column(type: "nvarchar(max)", nullable: false), - CardType = table.Column(type: "int", nullable: false), - City = table.Column(type: "nvarchar(max)", nullable: false), - ConcurrencyStamp = table.Column(type: "nvarchar(max)", nullable: true), - Country = table.Column(type: "nvarchar(max)", nullable: false), - Email = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - EmailConfirmed = table.Column(type: "bit", nullable: false), - Expiration = table.Column(type: "nvarchar(max)", nullable: false), - LastName = table.Column(type: "nvarchar(max)", nullable: false), - LockoutEnabled = table.Column(type: "bit", nullable: false), - LockoutEnd = table.Column(type: "datetimeoffset", nullable: true), - Name = table.Column(type: "nvarchar(max)", nullable: false), - NormalizedEmail = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - NormalizedUserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - PasswordHash = table.Column(type: "nvarchar(max)", nullable: true), - PhoneNumber = table.Column(type: "nvarchar(max)", nullable: true), - PhoneNumberConfirmed = table.Column(type: "bit", nullable: false), - SecurityNumber = table.Column(type: "nvarchar(max)", nullable: false), - SecurityStamp = table.Column(type: "nvarchar(max)", nullable: true), - State = table.Column(type: "nvarchar(max)", nullable: false), - Street = table.Column(type: "nvarchar(max)", nullable: false), - TwoFactorEnabled = table.Column(type: "bit", nullable: false), - UserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - ZipCode = table.Column(type: "nvarchar(max)", nullable: false) + Id = table.Column(nullable: false), + UserName = table.Column(maxLength: 256, nullable: true), + NormalizedUserName = table.Column(maxLength: 256, nullable: true), + Email = table.Column(maxLength: 256, nullable: true), + NormalizedEmail = table.Column(maxLength: 256, nullable: true), + EmailConfirmed = table.Column(nullable: false), + PasswordHash = table.Column(nullable: true), + SecurityStamp = table.Column(nullable: true), + ConcurrencyStamp = table.Column(nullable: true), + PhoneNumber = table.Column(nullable: true), + PhoneNumberConfirmed = table.Column(nullable: false), + TwoFactorEnabled = table.Column(nullable: false), + LockoutEnd = table.Column(nullable: true), + LockoutEnabled = table.Column(nullable: false), + AccessFailedCount = table.Column(nullable: false), + CardNumber = table.Column(nullable: false), + SecurityNumber = table.Column(nullable: false), + Expiration = table.Column(nullable: false), + CardHolderName = table.Column(nullable: false), + CardType = table.Column(nullable: false), + Street = table.Column(nullable: false), + City = table.Column(nullable: false), + State = table.Column(nullable: false), + Country = table.Column(nullable: false), + ZipCode = table.Column(nullable: false), + Name = table.Column(nullable: false), + LastName = table.Column(nullable: false) }, constraints: table => { @@ -64,11 +63,11 @@ namespace Identity.API.Migrations name: "AspNetRoleClaims", columns: table => new { - Id = table.Column(type: "int", nullable: false) + Id = table.Column(nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClaimType = table.Column(type: "nvarchar(max)", nullable: true), - ClaimValue = table.Column(type: "nvarchar(max)", nullable: true), - RoleId = table.Column(type: "nvarchar(450)", nullable: false) + RoleId = table.Column(nullable: false), + ClaimType = table.Column(nullable: true), + ClaimValue = table.Column(nullable: true) }, constraints: table => { @@ -85,11 +84,11 @@ namespace Identity.API.Migrations name: "AspNetUserClaims", columns: table => new { - Id = table.Column(type: "int", nullable: false) + Id = table.Column(nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClaimType = table.Column(type: "nvarchar(max)", nullable: true), - ClaimValue = table.Column(type: "nvarchar(max)", nullable: true), - UserId = table.Column(type: "nvarchar(450)", nullable: false) + UserId = table.Column(nullable: false), + ClaimType = table.Column(nullable: true), + ClaimValue = table.Column(nullable: true) }, constraints: table => { @@ -106,10 +105,10 @@ namespace Identity.API.Migrations name: "AspNetUserLogins", columns: table => new { - LoginProvider = table.Column(type: "nvarchar(450)", nullable: false), - ProviderKey = table.Column(type: "nvarchar(450)", nullable: false), - ProviderDisplayName = table.Column(type: "nvarchar(max)", nullable: true), - UserId = table.Column(type: "nvarchar(450)", nullable: false) + LoginProvider = table.Column(nullable: false), + ProviderKey = table.Column(nullable: false), + ProviderDisplayName = table.Column(nullable: true), + UserId = table.Column(nullable: false) }, constraints: table => { @@ -126,8 +125,8 @@ namespace Identity.API.Migrations name: "AspNetUserRoles", columns: table => new { - UserId = table.Column(type: "nvarchar(450)", nullable: false), - RoleId = table.Column(type: "nvarchar(450)", nullable: false) + UserId = table.Column(nullable: false), + RoleId = table.Column(nullable: false) }, constraints: table => { @@ -150,10 +149,10 @@ namespace Identity.API.Migrations name: "AspNetUserTokens", columns: table => new { - UserId = table.Column(type: "nvarchar(450)", nullable: false), - LoginProvider = table.Column(type: "nvarchar(450)", nullable: false), - Name = table.Column(type: "nvarchar(450)", nullable: false), - Value = table.Column(type: "nvarchar(max)", nullable: true) + UserId = table.Column(nullable: false), + LoginProvider = table.Column(nullable: false), + Name = table.Column(nullable: false), + Value = table.Column(nullable: true) }, constraints: table => { diff --git a/src/Services/Identity/Identity.API/Migrations/ApplicationDbContextModelSnapshot.cs b/src/Services/Identity/Identity.API/Migrations/ApplicationDbContextModelSnapshot.cs index dcc87bc73..2819cd6eb 100644 --- a/src/Services/Identity/Identity.API/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/src/Services/Identity/Identity.API/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1,9 +1,10 @@ // +using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.eShopOnContainers.Services.Identity.API.Data; -using System; namespace Identity.API.Migrations { @@ -14,99 +15,13 @@ namespace Identity.API.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "2.0.0-rtm-26452") + .HasAnnotation("ProductVersion", "3.0.0-preview7.19362.6") + .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - modelBuilder.Entity("Identity.API.Models.ApplicationUser", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("AccessFailedCount"); - - b.Property("CardHolderName") - .IsRequired(); - - b.Property("CardNumber") - .IsRequired(); - - b.Property("CardType"); - - b.Property("City") - .IsRequired(); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken(); - - b.Property("Country") - .IsRequired(); - - b.Property("Email") - .HasMaxLength(256); - - b.Property("EmailConfirmed"); - - b.Property("Expiration") - .IsRequired(); - - b.Property("LastName") - .IsRequired(); - - b.Property("LockoutEnabled"); - - b.Property("LockoutEnd"); - - b.Property("Name") - .IsRequired(); - - b.Property("NormalizedEmail") - .HasMaxLength(256); - - b.Property("NormalizedUserName") - .HasMaxLength(256); - - b.Property("PasswordHash"); - - b.Property("PhoneNumber"); - - b.Property("PhoneNumberConfirmed"); - - b.Property("SecurityNumber") - .IsRequired(); - - b.Property("SecurityStamp"); - - b.Property("State") - .IsRequired(); - - b.Property("Street") - .IsRequired(); - - b.Property("TwoFactorEnabled"); - - b.Property("UserName") - .HasMaxLength(256); - - b.Property("ZipCode") - .IsRequired(); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasName("UserNameIndex") - .HasFilter("[NormalizedUserName] IS NOT NULL"); - - b.ToTable("AspNetUsers"); - }); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => { - b.Property("Id") - .ValueGeneratedOnAdd(); + b.Property("Id"); b.Property("ConcurrencyStamp") .IsConcurrencyToken(); @@ -130,7 +45,8 @@ namespace Identity.API.Migrations modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); b.Property("ClaimType"); @@ -149,7 +65,8 @@ namespace Identity.API.Migrations modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); b.Property("ClaimType"); @@ -211,49 +128,140 @@ namespace Identity.API.Migrations b.ToTable("AspNetUserTokens"); }); + modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Identity.API.Models.ApplicationUser", b => + { + b.Property("Id"); + + b.Property("AccessFailedCount"); + + b.Property("CardHolderName") + .IsRequired(); + + b.Property("CardNumber") + .IsRequired(); + + b.Property("CardType"); + + b.Property("City") + .IsRequired(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Country") + .IsRequired(); + + b.Property("Email") + .HasMaxLength(256); + + b.Property("EmailConfirmed"); + + b.Property("Expiration") + .IsRequired(); + + b.Property("LastName") + .IsRequired(); + + b.Property("LockoutEnabled"); + + b.Property("LockoutEnd"); + + b.Property("Name") + .IsRequired(); + + b.Property("NormalizedEmail") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .HasMaxLength(256); + + b.Property("PasswordHash"); + + b.Property("PhoneNumber"); + + b.Property("PhoneNumberConfirmed"); + + b.Property("SecurityNumber") + .IsRequired(); + + b.Property("SecurityStamp"); + + b.Property("State") + .IsRequired(); + + b.Property("Street") + .IsRequired(); + + b.Property("TwoFactorEnabled"); + + b.Property("UserName") + .HasMaxLength(256); + + b.Property("ZipCode") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers"); + }); + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) .WithMany() .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("Identity.API.Models.ApplicationUser") + b.HasOne("Microsoft.eShopOnContainers.Services.Identity.API.Models.ApplicationUser", null) .WithMany() .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("Identity.API.Models.ApplicationUser") + b.HasOne("Microsoft.eShopOnContainers.Services.Identity.API.Models.ApplicationUser", null) .WithMany() .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) .WithMany() .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); - b.HasOne("Identity.API.Models.ApplicationUser") + b.HasOne("Microsoft.eShopOnContainers.Services.Identity.API.Models.ApplicationUser", null) .WithMany() .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("Identity.API.Models.ApplicationUser") + b.HasOne("Microsoft.eShopOnContainers.Services.Identity.API.Models.ApplicationUser", null) .WithMany() .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); #pragma warning restore 612, 618 } diff --git a/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20170927170433_Config.Designer.cs b/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20190729092011_InitialConfigurationMigration.Designer.cs similarity index 68% rename from src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20170927170433_Config.Designer.cs rename to src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20190729092011_InitialConfigurationMigration.Designer.cs index 327d2fee0..5e801b306 100644 --- a/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20170927170433_Config.Designer.cs +++ b/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20190729092011_InitialConfigurationMigration.Designer.cs @@ -1,30 +1,33 @@ // +using System; using IdentityServer4.EntityFramework.DbContexts; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.EntityFrameworkCore.Storage.Internal; -using System; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace Identity.API.Migrations.ConfigurationDb { [DbContext(typeof(ConfigurationDbContext))] - [Migration("20170927170433_Config")] - partial class Config + [Migration("20190729092011_InitialConfigurationMigration")] + partial class InitialConfigurationMigration { protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "2.0.0-rtm-26452") + .HasAnnotation("ProductVersion", "3.0.0-preview7.19362.6") + .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResource", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Created"); b.Property("Description") .HasMaxLength(1000); @@ -34,10 +37,16 @@ namespace Identity.API.Migrations.ConfigurationDb b.Property("Enabled"); + b.Property("LastAccessed"); + b.Property("Name") .IsRequired() .HasMaxLength(200); + b.Property("NonEditable"); + + b.Property("Updated"); + b.HasKey("Id"); b.HasIndex("Name") @@ -49,10 +58,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ApiResourceId") - .IsRequired(); + b.Property("ApiResourceId"); b.Property("Type") .IsRequired() @@ -65,13 +74,36 @@ namespace Identity.API.Migrations.ConfigurationDb b.ToTable("ApiClaims"); }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ApiResourceId"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiProperties"); + }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ApiResourceId") - .IsRequired(); + b.Property("ApiResourceId"); b.Property("Description") .HasMaxLength(1000); @@ -102,10 +134,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ApiScopeId") - .IsRequired(); + b.Property("ApiScopeId"); b.Property("Type") .IsRequired() @@ -121,10 +153,12 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiSecret", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ApiResourceId") - .IsRequired(); + b.Property("ApiResourceId"); + + b.Property("Created"); b.Property("Description") .HasMaxLength(1000); @@ -132,10 +166,12 @@ namespace Identity.API.Migrations.ConfigurationDb b.Property("Expiration"); b.Property("Type") + .IsRequired() .HasMaxLength(250); b.Property("Value") - .HasMaxLength(2000); + .IsRequired() + .HasMaxLength(4000); b.HasKey("Id"); @@ -147,7 +183,8 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.Client", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); b.Property("AbsoluteRefreshTokenLifetime"); @@ -189,9 +226,13 @@ namespace Identity.API.Migrations.ConfigurationDb b.Property("ConsentLifetime"); + b.Property("Created"); + b.Property("Description") .HasMaxLength(1000); + b.Property("DeviceCodeLifetime"); + b.Property("EnableLocalLogin"); b.Property("Enabled"); @@ -205,9 +246,13 @@ namespace Identity.API.Migrations.ConfigurationDb b.Property("IncludeJwtId"); + b.Property("LastAccessed"); + b.Property("LogoUri") .HasMaxLength(2000); + b.Property("NonEditable"); + b.Property("PairWiseSubjectSalt") .HasMaxLength(200); @@ -229,6 +274,13 @@ namespace Identity.API.Migrations.ConfigurationDb b.Property("UpdateAccessTokenClaimsOnRefresh"); + b.Property("Updated"); + + b.Property("UserCodeType") + .HasMaxLength(100); + + b.Property("UserSsoLifetime"); + b.HasKey("Id"); b.HasIndex("ClientId") @@ -240,10 +292,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ClientId") - .IsRequired(); + b.Property("ClientId"); b.Property("Type") .IsRequired() @@ -263,10 +315,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ClientId") - .IsRequired(); + b.Property("ClientId"); b.Property("Origin") .IsRequired() @@ -282,10 +334,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ClientId") - .IsRequired(); + b.Property("ClientId"); b.Property("GrantType") .IsRequired() @@ -301,10 +353,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ClientId") - .IsRequired(); + b.Property("ClientId"); b.Property("Provider") .IsRequired() @@ -320,10 +372,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ClientId") - .IsRequired(); + b.Property("ClientId"); b.Property("PostLogoutRedirectUri") .IsRequired() @@ -339,10 +391,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ClientId") - .IsRequired(); + b.Property("ClientId"); b.Property("Key") .IsRequired() @@ -362,10 +414,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ClientId") - .IsRequired(); + b.Property("ClientId"); b.Property("RedirectUri") .IsRequired() @@ -381,10 +433,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ClientId") - .IsRequired(); + b.Property("ClientId"); b.Property("Scope") .IsRequired() @@ -400,10 +452,12 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ClientId") - .IsRequired(); + b.Property("ClientId"); + + b.Property("Created"); b.Property("Description") .HasMaxLength(2000); @@ -411,11 +465,12 @@ namespace Identity.API.Migrations.ConfigurationDb b.Property("Expiration"); b.Property("Type") + .IsRequired() .HasMaxLength(250); b.Property("Value") .IsRequired() - .HasMaxLength(2000); + .HasMaxLength(4000); b.HasKey("Id"); @@ -427,10 +482,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityClaim", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("IdentityResourceId") - .IsRequired(); + b.Property("IdentityResourceId"); b.Property("Type") .IsRequired() @@ -446,7 +501,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResource", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Created"); b.Property("Description") .HasMaxLength(1000); @@ -462,10 +520,14 @@ namespace Identity.API.Migrations.ConfigurationDb .IsRequired() .HasMaxLength(200); + b.Property("NonEditable"); + b.Property("Required"); b.Property("ShowInDiscoveryDocument"); + b.Property("Updated"); + b.HasKey("Id"); b.HasIndex("Name") @@ -474,12 +536,45 @@ namespace Identity.API.Migrations.ConfigurationDb b.ToTable("IdentityResources"); }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("IdentityResourceId"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("IdentityResourceId"); + + b.ToTable("IdentityProperties"); + }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b => { b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") .WithMany("UserClaims") .HasForeignKey("ApiResourceId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") + .WithMany("Properties") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b => @@ -487,7 +582,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") .WithMany("Scopes") .HasForeignKey("ApiResourceId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b => @@ -495,7 +591,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "ApiScope") .WithMany("UserClaims") .HasForeignKey("ApiScopeId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiSecret", b => @@ -503,7 +600,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") .WithMany("Secrets") .HasForeignKey("ApiResourceId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b => @@ -511,7 +609,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") .WithMany("Claims") .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b => @@ -519,7 +618,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") .WithMany("AllowedCorsOrigins") .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b => @@ -527,7 +627,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") .WithMany("AllowedGrantTypes") .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b => @@ -535,7 +636,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") .WithMany("IdentityProviderRestrictions") .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b => @@ -543,7 +645,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") .WithMany("PostLogoutRedirectUris") .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b => @@ -551,7 +654,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") .WithMany("Properties") .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b => @@ -559,7 +663,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") .WithMany("RedirectUris") .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b => @@ -567,7 +672,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") .WithMany("AllowedScopes") .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b => @@ -575,7 +681,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") .WithMany("ClientSecrets") .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityClaim", b => @@ -583,7 +690,17 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource") .WithMany("UserClaims") .HasForeignKey("IdentityResourceId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource") + .WithMany("Properties") + .HasForeignKey("IdentityResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); #pragma warning restore 612, 618 } diff --git a/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20170927170433_Config.cs b/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20190729092011_InitialConfigurationMigration.cs similarity index 62% rename from src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20170927170433_Config.cs rename to src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20190729092011_InitialConfigurationMigration.cs index 754c75486..05155a83c 100644 --- a/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20170927170433_Config.cs +++ b/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20190729092011_InitialConfigurationMigration.cs @@ -1,10 +1,10 @@ -using Microsoft.EntityFrameworkCore.Metadata; +using System; +using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -using System; namespace Identity.API.Migrations.ConfigurationDb { - public partial class Config : Migration + public partial class InitialConfigurationMigration : Migration { protected override void Up(MigrationBuilder migrationBuilder) { @@ -12,12 +12,16 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ApiResources", columns: table => new { - Id = table.Column(type: "int", nullable: false) + Id = table.Column(nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), - DisplayName = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: true), - Enabled = table.Column(type: "bit", nullable: false), - Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false) + Enabled = table.Column(nullable: false), + Name = table.Column(maxLength: 200, nullable: false), + DisplayName = table.Column(maxLength: 200, nullable: true), + Description = table.Column(maxLength: 1000, nullable: true), + Created = table.Column(nullable: false), + Updated = table.Column(nullable: true), + LastAccessed = table.Column(nullable: true), + NonEditable = table.Column(nullable: false) }, constraints: table => { @@ -28,42 +32,49 @@ namespace Identity.API.Migrations.ConfigurationDb name: "Clients", columns: table => new { - Id = table.Column(type: "int", nullable: false) + Id = table.Column(nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - AbsoluteRefreshTokenLifetime = table.Column(type: "int", nullable: false), - AccessTokenLifetime = table.Column(type: "int", nullable: false), - AccessTokenType = table.Column(type: "int", nullable: false), - AllowAccessTokensViaBrowser = table.Column(type: "bit", nullable: false), - AllowOfflineAccess = table.Column(type: "bit", nullable: false), - AllowPlainTextPkce = table.Column(type: "bit", nullable: false), - AllowRememberConsent = table.Column(type: "bit", nullable: false), - AlwaysIncludeUserClaimsInIdToken = table.Column(type: "bit", nullable: false), - AlwaysSendClientClaims = table.Column(type: "bit", nullable: false), - AuthorizationCodeLifetime = table.Column(type: "int", nullable: false), - BackChannelLogoutSessionRequired = table.Column(type: "bit", nullable: false), - BackChannelLogoutUri = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true), - ClientClaimsPrefix = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: true), - ClientId = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), - ClientName = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: true), - ClientUri = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true), - ConsentLifetime = table.Column(type: "int", nullable: true), - Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), - EnableLocalLogin = table.Column(type: "bit", nullable: false), - Enabled = table.Column(type: "bit", nullable: false), - FrontChannelLogoutSessionRequired = table.Column(type: "bit", nullable: false), - FrontChannelLogoutUri = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true), - IdentityTokenLifetime = table.Column(type: "int", nullable: false), - IncludeJwtId = table.Column(type: "bit", nullable: false), - LogoUri = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true), - PairWiseSubjectSalt = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: true), - ProtocolType = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), - RefreshTokenExpiration = table.Column(type: "int", nullable: false), - RefreshTokenUsage = table.Column(type: "int", nullable: false), - RequireClientSecret = table.Column(type: "bit", nullable: false), - RequireConsent = table.Column(type: "bit", nullable: false), - RequirePkce = table.Column(type: "bit", nullable: false), - SlidingRefreshTokenLifetime = table.Column(type: "int", nullable: false), - UpdateAccessTokenClaimsOnRefresh = table.Column(type: "bit", nullable: false) + Enabled = table.Column(nullable: false), + ClientId = table.Column(maxLength: 200, nullable: false), + ProtocolType = table.Column(maxLength: 200, nullable: false), + RequireClientSecret = table.Column(nullable: false), + ClientName = table.Column(maxLength: 200, nullable: true), + Description = table.Column(maxLength: 1000, nullable: true), + ClientUri = table.Column(maxLength: 2000, nullable: true), + LogoUri = table.Column(maxLength: 2000, nullable: true), + RequireConsent = table.Column(nullable: false), + AllowRememberConsent = table.Column(nullable: false), + AlwaysIncludeUserClaimsInIdToken = table.Column(nullable: false), + RequirePkce = table.Column(nullable: false), + AllowPlainTextPkce = table.Column(nullable: false), + AllowAccessTokensViaBrowser = table.Column(nullable: false), + FrontChannelLogoutUri = table.Column(maxLength: 2000, nullable: true), + FrontChannelLogoutSessionRequired = table.Column(nullable: false), + BackChannelLogoutUri = table.Column(maxLength: 2000, nullable: true), + BackChannelLogoutSessionRequired = table.Column(nullable: false), + AllowOfflineAccess = table.Column(nullable: false), + IdentityTokenLifetime = table.Column(nullable: false), + AccessTokenLifetime = table.Column(nullable: false), + AuthorizationCodeLifetime = table.Column(nullable: false), + ConsentLifetime = table.Column(nullable: true), + AbsoluteRefreshTokenLifetime = table.Column(nullable: false), + SlidingRefreshTokenLifetime = table.Column(nullable: false), + RefreshTokenUsage = table.Column(nullable: false), + UpdateAccessTokenClaimsOnRefresh = table.Column(nullable: false), + RefreshTokenExpiration = table.Column(nullable: false), + AccessTokenType = table.Column(nullable: false), + EnableLocalLogin = table.Column(nullable: false), + IncludeJwtId = table.Column(nullable: false), + AlwaysSendClientClaims = table.Column(nullable: false), + ClientClaimsPrefix = table.Column(maxLength: 200, nullable: true), + PairWiseSubjectSalt = table.Column(maxLength: 200, nullable: true), + Created = table.Column(nullable: false), + Updated = table.Column(nullable: true), + LastAccessed = table.Column(nullable: true), + UserSsoLifetime = table.Column(nullable: true), + UserCodeType = table.Column(maxLength: 100, nullable: true), + DeviceCodeLifetime = table.Column(nullable: false), + NonEditable = table.Column(nullable: false) }, constraints: table => { @@ -74,15 +85,18 @@ namespace Identity.API.Migrations.ConfigurationDb name: "IdentityResources", columns: table => new { - Id = table.Column(type: "int", nullable: false) + Id = table.Column(nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), - DisplayName = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: true), - Emphasize = table.Column(type: "bit", nullable: false), - Enabled = table.Column(type: "bit", nullable: false), - Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), - Required = table.Column(type: "bit", nullable: false), - ShowInDiscoveryDocument = table.Column(type: "bit", nullable: false) + Enabled = table.Column(nullable: false), + Name = table.Column(maxLength: 200, nullable: false), + DisplayName = table.Column(maxLength: 200, nullable: true), + Description = table.Column(maxLength: 1000, nullable: true), + Required = table.Column(nullable: false), + Emphasize = table.Column(nullable: false), + ShowInDiscoveryDocument = table.Column(nullable: false), + Created = table.Column(nullable: false), + Updated = table.Column(nullable: true), + NonEditable = table.Column(nullable: false) }, constraints: table => { @@ -93,10 +107,10 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ApiClaims", columns: table => new { - Id = table.Column(type: "int", nullable: false) + Id = table.Column(nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ApiResourceId = table.Column(type: "int", nullable: false), - Type = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false) + Type = table.Column(maxLength: 200, nullable: false), + ApiResourceId = table.Column(nullable: false) }, constraints: table => { @@ -109,19 +123,40 @@ namespace Identity.API.Migrations.ConfigurationDb onDelete: ReferentialAction.Cascade); }); + migrationBuilder.CreateTable( + name: "ApiProperties", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), + Key = table.Column(maxLength: 250, nullable: false), + Value = table.Column(maxLength: 2000, nullable: false), + ApiResourceId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ApiProperties", x => x.Id); + table.ForeignKey( + name: "FK_ApiProperties_ApiResources_ApiResourceId", + column: x => x.ApiResourceId, + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + migrationBuilder.CreateTable( name: "ApiScopes", columns: table => new { - Id = table.Column(type: "int", nullable: false) + Id = table.Column(nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ApiResourceId = table.Column(type: "int", nullable: false), - Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), - DisplayName = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: true), - Emphasize = table.Column(type: "bit", nullable: false), - Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), - Required = table.Column(type: "bit", nullable: false), - ShowInDiscoveryDocument = table.Column(type: "bit", nullable: false) + Name = table.Column(maxLength: 200, nullable: false), + DisplayName = table.Column(maxLength: 200, nullable: true), + Description = table.Column(maxLength: 1000, nullable: true), + Required = table.Column(nullable: false), + Emphasize = table.Column(nullable: false), + ShowInDiscoveryDocument = table.Column(nullable: false), + ApiResourceId = table.Column(nullable: false) }, constraints: table => { @@ -138,13 +173,14 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ApiSecrets", columns: table => new { - Id = table.Column(type: "int", nullable: false) + Id = table.Column(nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ApiResourceId = table.Column(type: "int", nullable: false), - Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), - Expiration = table.Column(type: "datetime2", nullable: true), - Type = table.Column(type: "nvarchar(250)", maxLength: 250, nullable: true), - Value = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true) + Description = table.Column(maxLength: 1000, nullable: true), + Value = table.Column(maxLength: 4000, nullable: false), + Expiration = table.Column(nullable: true), + Type = table.Column(maxLength: 250, nullable: false), + Created = table.Column(nullable: false), + ApiResourceId = table.Column(nullable: false) }, constraints: table => { @@ -161,11 +197,11 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ClientClaims", columns: table => new { - Id = table.Column(type: "int", nullable: false) + Id = table.Column(nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClientId = table.Column(type: "int", nullable: false), - Type = table.Column(type: "nvarchar(250)", maxLength: 250, nullable: false), - Value = table.Column(type: "nvarchar(250)", maxLength: 250, nullable: false) + Type = table.Column(maxLength: 250, nullable: false), + Value = table.Column(maxLength: 250, nullable: false), + ClientId = table.Column(nullable: false) }, constraints: table => { @@ -182,10 +218,10 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ClientCorsOrigins", columns: table => new { - Id = table.Column(type: "int", nullable: false) + Id = table.Column(nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClientId = table.Column(type: "int", nullable: false), - Origin = table.Column(type: "nvarchar(150)", maxLength: 150, nullable: false) + Origin = table.Column(maxLength: 150, nullable: false), + ClientId = table.Column(nullable: false) }, constraints: table => { @@ -202,10 +238,10 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ClientGrantTypes", columns: table => new { - Id = table.Column(type: "int", nullable: false) + Id = table.Column(nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClientId = table.Column(type: "int", nullable: false), - GrantType = table.Column(type: "nvarchar(250)", maxLength: 250, nullable: false) + GrantType = table.Column(maxLength: 250, nullable: false), + ClientId = table.Column(nullable: false) }, constraints: table => { @@ -222,10 +258,10 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ClientIdPRestrictions", columns: table => new { - Id = table.Column(type: "int", nullable: false) + Id = table.Column(nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClientId = table.Column(type: "int", nullable: false), - Provider = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false) + Provider = table.Column(maxLength: 200, nullable: false), + ClientId = table.Column(nullable: false) }, constraints: table => { @@ -242,10 +278,10 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ClientPostLogoutRedirectUris", columns: table => new { - Id = table.Column(type: "int", nullable: false) + Id = table.Column(nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClientId = table.Column(type: "int", nullable: false), - PostLogoutRedirectUri = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: false) + PostLogoutRedirectUri = table.Column(maxLength: 2000, nullable: false), + ClientId = table.Column(nullable: false) }, constraints: table => { @@ -262,11 +298,11 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ClientProperties", columns: table => new { - Id = table.Column(type: "int", nullable: false) + Id = table.Column(nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClientId = table.Column(type: "int", nullable: false), - Key = table.Column(type: "nvarchar(250)", maxLength: 250, nullable: false), - Value = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: false) + Key = table.Column(maxLength: 250, nullable: false), + Value = table.Column(maxLength: 2000, nullable: false), + ClientId = table.Column(nullable: false) }, constraints: table => { @@ -283,10 +319,10 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ClientRedirectUris", columns: table => new { - Id = table.Column(type: "int", nullable: false) + Id = table.Column(nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClientId = table.Column(type: "int", nullable: false), - RedirectUri = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: false) + RedirectUri = table.Column(maxLength: 2000, nullable: false), + ClientId = table.Column(nullable: false) }, constraints: table => { @@ -303,10 +339,10 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ClientScopes", columns: table => new { - Id = table.Column(type: "int", nullable: false) + Id = table.Column(nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClientId = table.Column(type: "int", nullable: false), - Scope = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false) + Scope = table.Column(maxLength: 200, nullable: false), + ClientId = table.Column(nullable: false) }, constraints: table => { @@ -323,13 +359,14 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ClientSecrets", columns: table => new { - Id = table.Column(type: "int", nullable: false) + Id = table.Column(nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClientId = table.Column(type: "int", nullable: false), - Description = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true), - Expiration = table.Column(type: "datetime2", nullable: true), - Type = table.Column(type: "nvarchar(250)", maxLength: 250, nullable: true), - Value = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: false) + Description = table.Column(maxLength: 2000, nullable: true), + Value = table.Column(maxLength: 4000, nullable: false), + Expiration = table.Column(nullable: true), + Type = table.Column(maxLength: 250, nullable: false), + Created = table.Column(nullable: false), + ClientId = table.Column(nullable: false) }, constraints: table => { @@ -346,10 +383,10 @@ namespace Identity.API.Migrations.ConfigurationDb name: "IdentityClaims", columns: table => new { - Id = table.Column(type: "int", nullable: false) + Id = table.Column(nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - IdentityResourceId = table.Column(type: "int", nullable: false), - Type = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false) + Type = table.Column(maxLength: 200, nullable: false), + IdentityResourceId = table.Column(nullable: false) }, constraints: table => { @@ -362,14 +399,35 @@ namespace Identity.API.Migrations.ConfigurationDb onDelete: ReferentialAction.Cascade); }); + migrationBuilder.CreateTable( + name: "IdentityProperties", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), + Key = table.Column(maxLength: 250, nullable: false), + Value = table.Column(maxLength: 2000, nullable: false), + IdentityResourceId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityProperties", x => x.Id); + table.ForeignKey( + name: "FK_IdentityProperties_IdentityResources_IdentityResourceId", + column: x => x.IdentityResourceId, + principalTable: "IdentityResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + migrationBuilder.CreateTable( name: "ApiScopeClaims", columns: table => new { - Id = table.Column(type: "int", nullable: false) + Id = table.Column(nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ApiScopeId = table.Column(type: "int", nullable: false), - Type = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false) + Type = table.Column(maxLength: 200, nullable: false), + ApiScopeId = table.Column(nullable: false) }, constraints: table => { @@ -387,6 +445,11 @@ namespace Identity.API.Migrations.ConfigurationDb table: "ApiClaims", column: "ApiResourceId"); + migrationBuilder.CreateIndex( + name: "IX_ApiProperties_ApiResourceId", + table: "ApiProperties", + column: "ApiResourceId"); + migrationBuilder.CreateIndex( name: "IX_ApiResources_Name", table: "ApiResources", @@ -470,6 +533,11 @@ namespace Identity.API.Migrations.ConfigurationDb table: "IdentityClaims", column: "IdentityResourceId"); + migrationBuilder.CreateIndex( + name: "IX_IdentityProperties_IdentityResourceId", + table: "IdentityProperties", + column: "IdentityResourceId"); + migrationBuilder.CreateIndex( name: "IX_IdentityResources_Name", table: "IdentityResources", @@ -482,6 +550,9 @@ namespace Identity.API.Migrations.ConfigurationDb migrationBuilder.DropTable( name: "ApiClaims"); + migrationBuilder.DropTable( + name: "ApiProperties"); + migrationBuilder.DropTable( name: "ApiScopeClaims"); @@ -518,6 +589,9 @@ namespace Identity.API.Migrations.ConfigurationDb migrationBuilder.DropTable( name: "IdentityClaims"); + migrationBuilder.DropTable( + name: "IdentityProperties"); + migrationBuilder.DropTable( name: "ApiScopes"); diff --git a/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/ConfigurationDbContextModelSnapshot.cs b/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/ConfigurationDbContextModelSnapshot.cs index 88d9baba3..ec91a8841 100644 --- a/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/ConfigurationDbContextModelSnapshot.cs +++ b/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/ConfigurationDbContextModelSnapshot.cs @@ -1,12 +1,10 @@ // +using System; using IdentityServer4.EntityFramework.DbContexts; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.EntityFrameworkCore.Storage.Internal; -using System; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace Identity.API.Migrations.ConfigurationDb { @@ -17,13 +15,17 @@ namespace Identity.API.Migrations.ConfigurationDb { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "2.0.0-rtm-26452") + .HasAnnotation("ProductVersion", "3.0.0-preview7.19362.6") + .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResource", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Created"); b.Property("Description") .HasMaxLength(1000); @@ -33,10 +35,16 @@ namespace Identity.API.Migrations.ConfigurationDb b.Property("Enabled"); + b.Property("LastAccessed"); + b.Property("Name") .IsRequired() .HasMaxLength(200); + b.Property("NonEditable"); + + b.Property("Updated"); + b.HasKey("Id"); b.HasIndex("Name") @@ -48,10 +56,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ApiResourceId") - .IsRequired(); + b.Property("ApiResourceId"); b.Property("Type") .IsRequired() @@ -64,13 +72,36 @@ namespace Identity.API.Migrations.ConfigurationDb b.ToTable("ApiClaims"); }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ApiResourceId"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiProperties"); + }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ApiResourceId") - .IsRequired(); + b.Property("ApiResourceId"); b.Property("Description") .HasMaxLength(1000); @@ -101,10 +132,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ApiScopeId") - .IsRequired(); + b.Property("ApiScopeId"); b.Property("Type") .IsRequired() @@ -120,10 +151,12 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiSecret", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ApiResourceId") - .IsRequired(); + b.Property("ApiResourceId"); + + b.Property("Created"); b.Property("Description") .HasMaxLength(1000); @@ -131,10 +164,12 @@ namespace Identity.API.Migrations.ConfigurationDb b.Property("Expiration"); b.Property("Type") + .IsRequired() .HasMaxLength(250); b.Property("Value") - .HasMaxLength(2000); + .IsRequired() + .HasMaxLength(4000); b.HasKey("Id"); @@ -146,7 +181,8 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.Client", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); b.Property("AbsoluteRefreshTokenLifetime"); @@ -188,9 +224,13 @@ namespace Identity.API.Migrations.ConfigurationDb b.Property("ConsentLifetime"); + b.Property("Created"); + b.Property("Description") .HasMaxLength(1000); + b.Property("DeviceCodeLifetime"); + b.Property("EnableLocalLogin"); b.Property("Enabled"); @@ -204,9 +244,13 @@ namespace Identity.API.Migrations.ConfigurationDb b.Property("IncludeJwtId"); + b.Property("LastAccessed"); + b.Property("LogoUri") .HasMaxLength(2000); + b.Property("NonEditable"); + b.Property("PairWiseSubjectSalt") .HasMaxLength(200); @@ -228,6 +272,13 @@ namespace Identity.API.Migrations.ConfigurationDb b.Property("UpdateAccessTokenClaimsOnRefresh"); + b.Property("Updated"); + + b.Property("UserCodeType") + .HasMaxLength(100); + + b.Property("UserSsoLifetime"); + b.HasKey("Id"); b.HasIndex("ClientId") @@ -239,10 +290,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ClientId") - .IsRequired(); + b.Property("ClientId"); b.Property("Type") .IsRequired() @@ -262,10 +313,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ClientId") - .IsRequired(); + b.Property("ClientId"); b.Property("Origin") .IsRequired() @@ -281,10 +332,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ClientId") - .IsRequired(); + b.Property("ClientId"); b.Property("GrantType") .IsRequired() @@ -300,10 +351,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ClientId") - .IsRequired(); + b.Property("ClientId"); b.Property("Provider") .IsRequired() @@ -319,10 +370,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ClientId") - .IsRequired(); + b.Property("ClientId"); b.Property("PostLogoutRedirectUri") .IsRequired() @@ -338,10 +389,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ClientId") - .IsRequired(); + b.Property("ClientId"); b.Property("Key") .IsRequired() @@ -361,10 +412,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ClientId") - .IsRequired(); + b.Property("ClientId"); b.Property("RedirectUri") .IsRequired() @@ -380,10 +431,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ClientId") - .IsRequired(); + b.Property("ClientId"); b.Property("Scope") .IsRequired() @@ -399,10 +450,12 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ClientId") - .IsRequired(); + b.Property("ClientId"); + + b.Property("Created"); b.Property("Description") .HasMaxLength(2000); @@ -410,11 +463,12 @@ namespace Identity.API.Migrations.ConfigurationDb b.Property("Expiration"); b.Property("Type") + .IsRequired() .HasMaxLength(250); b.Property("Value") .IsRequired() - .HasMaxLength(2000); + .HasMaxLength(4000); b.HasKey("Id"); @@ -426,10 +480,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityClaim", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("IdentityResourceId") - .IsRequired(); + b.Property("IdentityResourceId"); b.Property("Type") .IsRequired() @@ -445,7 +499,10 @@ namespace Identity.API.Migrations.ConfigurationDb modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResource", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Created"); b.Property("Description") .HasMaxLength(1000); @@ -461,10 +518,14 @@ namespace Identity.API.Migrations.ConfigurationDb .IsRequired() .HasMaxLength(200); + b.Property("NonEditable"); + b.Property("Required"); b.Property("ShowInDiscoveryDocument"); + b.Property("Updated"); + b.HasKey("Id"); b.HasIndex("Name") @@ -473,12 +534,45 @@ namespace Identity.API.Migrations.ConfigurationDb b.ToTable("IdentityResources"); }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("IdentityResourceId"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("IdentityResourceId"); + + b.ToTable("IdentityProperties"); + }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b => { b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") .WithMany("UserClaims") .HasForeignKey("ApiResourceId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") + .WithMany("Properties") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b => @@ -486,7 +580,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") .WithMany("Scopes") .HasForeignKey("ApiResourceId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b => @@ -494,7 +589,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "ApiScope") .WithMany("UserClaims") .HasForeignKey("ApiScopeId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiSecret", b => @@ -502,7 +598,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") .WithMany("Secrets") .HasForeignKey("ApiResourceId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b => @@ -510,7 +607,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") .WithMany("Claims") .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b => @@ -518,7 +616,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") .WithMany("AllowedCorsOrigins") .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b => @@ -526,7 +625,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") .WithMany("AllowedGrantTypes") .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b => @@ -534,7 +634,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") .WithMany("IdentityProviderRestrictions") .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b => @@ -542,7 +643,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") .WithMany("PostLogoutRedirectUris") .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b => @@ -550,7 +652,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") .WithMany("Properties") .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b => @@ -558,7 +661,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") .WithMany("RedirectUris") .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b => @@ -566,7 +670,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") .WithMany("AllowedScopes") .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b => @@ -574,7 +679,8 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") .WithMany("ClientSecrets") .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityClaim", b => @@ -582,7 +688,17 @@ namespace Identity.API.Migrations.ConfigurationDb b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource") .WithMany("UserClaims") .HasForeignKey("IdentityResourceId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource") + .WithMany("Properties") + .HasForeignKey("IdentityResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); #pragma warning restore 612, 618 } diff --git a/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20170927170423_Grants.cs b/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20170927170423_Grants.cs deleted file mode 100644 index 4017f8bf0..000000000 --- a/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20170927170423_Grants.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; -using System; - -namespace Identity.API.Migrations.PersistedGrantDb -{ - public partial class Grants : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "PersistedGrants", - columns: table => new - { - Key = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), - ClientId = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), - CreationTime = table.Column(type: "datetime2", nullable: false), - Data = table.Column(type: "nvarchar(max)", maxLength: 50000, nullable: false), - Expiration = table.Column(type: "datetime2", nullable: true), - SubjectId = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: true), - Type = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_PersistedGrants", x => x.Key); - }); - - migrationBuilder.CreateIndex( - name: "IX_PersistedGrants_SubjectId_ClientId_Type", - table: "PersistedGrants", - columns: new[] { "SubjectId", "ClientId", "Type" }); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "PersistedGrants"); - } - } -} diff --git a/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20170927170423_Grants.Designer.cs b/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20190729092100_InitialPersistedGrantMigration.Designer.cs similarity index 54% rename from src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20170927170423_Grants.Designer.cs rename to src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20190729092100_InitialPersistedGrantMigration.Designer.cs index aaf24d10c..0518894dc 100644 --- a/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20170927170423_Grants.Designer.cs +++ b/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20190729092100_InitialPersistedGrantMigration.Designer.cs @@ -1,25 +1,59 @@ // +using System; using IdentityServer4.EntityFramework.DbContexts; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.Internal; -using System; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace Identity.API.Migrations.PersistedGrantDb { [DbContext(typeof(PersistedGrantDbContext))] - [Migration("20170927170423_Grants")] - partial class Grants + [Migration("20190729092100_InitialPersistedGrantMigration")] + partial class InitialPersistedGrantMigration { protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "2.0.0-rtm-26452") + .HasAnnotation("ProductVersion", "3.0.0-preview7.19362.6") + .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b => + { + b.Property("UserCode") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200); + + b.Property("CreationTime"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(50000); + + b.Property("DeviceCode") + .IsRequired() + .HasMaxLength(200); + + b.Property("Expiration") + .IsRequired(); + + b.Property("SubjectId") + .HasMaxLength(200); + + b.HasKey("UserCode"); + + b.HasIndex("DeviceCode") + .IsUnique(); + + b.ToTable("DeviceCodes"); + }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => { b.Property("Key") diff --git a/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20190729092100_InitialPersistedGrantMigration.cs b/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20190729092100_InitialPersistedGrantMigration.cs new file mode 100644 index 000000000..076f12323 --- /dev/null +++ b/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20190729092100_InitialPersistedGrantMigration.cs @@ -0,0 +1,65 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Identity.API.Migrations.PersistedGrantDb +{ + public partial class InitialPersistedGrantMigration : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "DeviceCodes", + columns: table => new + { + UserCode = table.Column(maxLength: 200, nullable: false), + DeviceCode = table.Column(maxLength: 200, nullable: false), + SubjectId = table.Column(maxLength: 200, nullable: true), + ClientId = table.Column(maxLength: 200, nullable: false), + CreationTime = table.Column(nullable: false), + Expiration = table.Column(nullable: false), + Data = table.Column(maxLength: 50000, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_DeviceCodes", x => x.UserCode); + }); + + migrationBuilder.CreateTable( + name: "PersistedGrants", + columns: table => new + { + Key = table.Column(maxLength: 200, nullable: false), + Type = table.Column(maxLength: 50, nullable: false), + SubjectId = table.Column(maxLength: 200, nullable: true), + ClientId = table.Column(maxLength: 200, nullable: false), + CreationTime = table.Column(nullable: false), + Expiration = table.Column(nullable: true), + Data = table.Column(maxLength: 50000, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_PersistedGrants", x => x.Key); + }); + + migrationBuilder.CreateIndex( + name: "IX_DeviceCodes_DeviceCode", + table: "DeviceCodes", + column: "DeviceCode", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_PersistedGrants_SubjectId_ClientId_Type", + table: "PersistedGrants", + columns: new[] { "SubjectId", "ClientId", "Type" }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "DeviceCodes"); + + migrationBuilder.DropTable( + name: "PersistedGrants"); + } + } +} diff --git a/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/PersistedGrantDbContextModelSnapshot.cs b/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/PersistedGrantDbContextModelSnapshot.cs index 7989f0586..3188904ef 100644 --- a/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/PersistedGrantDbContextModelSnapshot.cs +++ b/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/PersistedGrantDbContextModelSnapshot.cs @@ -1,11 +1,10 @@ // +using System; using IdentityServer4.EntityFramework.DbContexts; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.Internal; -using System; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace Identity.API.Migrations.PersistedGrantDb { @@ -16,9 +15,43 @@ namespace Identity.API.Migrations.PersistedGrantDb { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "2.0.0-rtm-26452") + .HasAnnotation("ProductVersion", "3.0.0-preview7.19362.6") + .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b => + { + b.Property("UserCode") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200); + + b.Property("CreationTime"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(50000); + + b.Property("DeviceCode") + .IsRequired() + .HasMaxLength(200); + + b.Property("Expiration") + .IsRequired(); + + b.Property("SubjectId") + .HasMaxLength(200); + + b.HasKey("UserCode"); + + b.HasIndex("DeviceCode") + .IsUnique(); + + b.ToTable("DeviceCodes"); + }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => { b.Property("Key") diff --git a/src/Services/Identity/Identity.API/Startup.cs b/src/Services/Identity/Identity.API/Startup.cs index 6ea7e3888..feefbcee3 100644 --- a/src/Services/Identity/Identity.API/Startup.cs +++ b/src/Services/Identity/Identity.API/Startup.cs @@ -1,28 +1,25 @@ using Autofac; using Autofac.Extensions.DependencyInjection; +using HealthChecks.UI.Client; using IdentityServer4.Services; -using Microsoft.ApplicationInsights.Extensibility; -using Microsoft.ApplicationInsights.ServiceFabric; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.eShopOnContainers.Services.Identity.API.Certificates; using Microsoft.eShopOnContainers.Services.Identity.API.Data; +using Microsoft.eShopOnContainers.Services.Identity.API.Devspaces; using Microsoft.eShopOnContainers.Services.Identity.API.Models; using Microsoft.eShopOnContainers.Services.Identity.API.Services; -using Microsoft.eShopOnContainers.Services.Identity.API.Devspaces; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; using StackExchange.Redis; using System; using System.Reflection; -using HealthChecks.UI.Client; -using Microsoft.AspNetCore.Diagnostics.HealthChecks; -using Microsoft.Extensions.Diagnostics.HealthChecks; namespace Microsoft.eShopOnContainers.Services.Identity.API { @@ -42,13 +39,13 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API // Add framework services. services.AddDbContext(options => - options.UseSqlServer(Configuration["ConnectionString"], - sqlServerOptionsAction: sqlOptions => - { - sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); - //Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency - sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); - })); + options.UseSqlServer(Configuration["ConnectionString"], + sqlServerOptionsAction: sqlOptions => + { + sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); + //Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency + sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); + })); services.AddIdentity() .AddEntityFrameworkStores() @@ -56,9 +53,6 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API services.Configure(Configuration); - services.AddMvc() - .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); - if (Configuration.GetValue("IsClusterEnv") == bool.TrueString) { services.AddDataProtection(opts => @@ -73,7 +67,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API .AddSqlServer(Configuration["ConnectionString"], name: "IdentityDB-check", tags: new string[] { "IdentityDB" }); - + services.AddTransient, EFLoginService>(); services.AddTransient(); @@ -100,17 +94,22 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API }); }) .AddOperationalStore(options => - { - options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString, - sqlServerOptionsAction: sqlOptions => - { - sqlOptions.MigrationsAssembly(migrationsAssembly); - //Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency - sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); - }); - }) + { + options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString, + sqlServerOptionsAction: sqlOptions => + { + sqlOptions.MigrationsAssembly(migrationsAssembly); + //Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency + sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); + }); + }) .Services.AddTransient(); + //services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0); + services.AddControllers(); + services.AddControllersWithViews(); + services.AddRazorPages(); + var container = new ContainerBuilder(); container.Populate(services); @@ -142,20 +141,8 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API app.UsePathBase(pathBase); } - app.UseHealthChecks("/hc", new HealthCheckOptions() - { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - - app.UseHealthChecks("/liveness", new HealthCheckOptions - { - Predicate = r => r.Name.Contains("self") - }); - app.UseStaticFiles(); - // Make work identity server redirections in Edge and lastest versions of browers. WARN: Not valid in a production environment. app.Use(async (context, next) => { @@ -166,32 +153,27 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API app.UseForwardedHeaders(); // Adds IdentityServer app.UseIdentityServer(); - - app.UseHttpsRedirection(); - app.UseMvc(routes => + app.UseRouting(); + app.UseEndpoints(endpoints => { - routes.MapRoute( - name: "default", - template: "{controller=Home}/{action=Index}/{id?}"); + endpoints.MapDefaultControllerRoute(); + endpoints.MapControllers(); + endpoints.MapHealthChecks("/hc", new HealthCheckOptions() + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + endpoints.MapHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = r => r.Name.Contains("self") + }); }); } private void RegisterAppInsights(IServiceCollection services) { services.AddApplicationInsightsTelemetry(Configuration); - var orchestratorType = Configuration.GetValue("OrchestratorType"); - - if (orchestratorType?.ToUpper() == "K8S") - { - // Enable K8s telemetry initializer - services.AddApplicationInsightsKubernetesEnricher(); - } - if (orchestratorType?.ToUpper() == "SF") - { - // Enable SF telemetry initializer - services.AddSingleton((serviceProvider) => - new FabricTelemetryInitializer()); - } + services.AddApplicationInsightsKubernetesEnricher(); } } } diff --git a/src/Services/Identity/Identity.API/Views/Account/Login.cshtml b/src/Services/Identity/Identity.API/Views/Account/Login.cshtml index 315810419..b74d7d8b9 100644 --- a/src/Services/Identity/Identity.API/Views/Account/Login.cshtml +++ b/src/Services/Identity/Identity.API/Views/Account/Login.cshtml @@ -1,7 +1,4 @@ -@using System.Collections.Generic -@using Microsoft.AspNetCore.Http -@using Microsoft.AspNetCore.Http.Authentication -@model Microsoft.eShopOnContainers.Services.Identity.API.Models.AccountViewModels.LoginViewModel +@model Microsoft.eShopOnContainers.Services.Identity.API.Models.AccountViewModels.LoginViewModel @{ diff --git a/src/Services/Location/Locations.API/Dockerfile b/src/Services/Location/Locations.API/Dockerfile index 3a3e54261..5ffacb4d6 100644 --- a/src/Services/Location/Locations.API/Dockerfile +++ b/src/Services/Location/Locations.API/Dockerfile @@ -1,58 +1,23 @@ -FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base +FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base WORKDIR /app EXPOSE 80 -FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build WORKDIR /src -# Keep the project list and command dotnet restore identical in all Dockfiles to maximize image cache utilization -COPY eShopOnContainers-ServicesAndWebApps.sln . -COPY docker-compose.dcproj /src/ -COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/ -COPY src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj src/ApiGateways/Mobile.Bff.Shopping/aggregator/ -COPY src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj src/ApiGateways/Web.Bff.Shopping/aggregator/ -COPY src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj src/BuildingBlocks/Devspaces.Support/ -COPY src/BuildingBlocks/EventBus/EventBus/EventBus.csproj src/BuildingBlocks/EventBus/EventBus/ -COPY src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj src/BuildingBlocks/EventBus/EventBus.Tests/ -COPY src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj src/BuildingBlocks/EventBus/EventBusRabbitMQ/ -COPY src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj src/BuildingBlocks/EventBus/EventBusServiceBus/ -COPY src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj src/BuildingBlocks/EventBus/IntegrationEventLogEF/ -COPY src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj src/BuildingBlocks/WebHostCustomization/WebHost.Customization/ -COPY src/Services/Basket/Basket.API/Basket.API.csproj src/Services/Basket/Basket.API/ -COPY src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj src/Services/Basket/Basket.FunctionalTests/ -COPY src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj src/Services/Basket/Basket.UnitTests/ -COPY src/Services/Catalog/Catalog.API/Catalog.API.csproj src/Services/Catalog/Catalog.API/ -COPY src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj src/Services/Catalog/Catalog.FunctionalTests/ -COPY src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj src/Services/Catalog/Catalog.UnitTests/ -COPY src/Services/Identity/Identity.API/Identity.API.csproj src/Services/Identity/Identity.API/ -COPY src/Services/Location/Locations.API/Locations.API.csproj src/Services/Location/Locations.API/ -COPY src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj src/Services/Location/Locations.FunctionalTests/ -COPY src/Services/Marketing/Marketing.API/Marketing.API.csproj src/Services/Marketing/Marketing.API/ -COPY src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj src/Services/Marketing/Marketing.FunctionalTests/ -COPY src/Services/Ordering/Ordering.API/Ordering.API.csproj src/Services/Ordering/Ordering.API/ -COPY src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj src/Services/Ordering/Ordering.BackgroundTasks/ -COPY src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj src/Services/Ordering/Ordering.Domain/ -COPY src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj src/Services/Ordering/Ordering.FunctionalTests/ -COPY src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj src/Services/Ordering/Ordering.Infrastructure/ -COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/ -COPY src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj src/Services/Ordering/Ordering.UnitTests/ -COPY src/Services/Payment/Payment.API/Payment.API.csproj src/Services/Payment/Payment.API/ -COPY src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj src/Services/Webhooks/Webhooks.API/ -COPY src/Web/WebhookClient/WebhookClient.csproj src/Web/WebhookClient/ -COPY src/Web/WebMVC/WebMVC.csproj src/Web/WebMVC/ -COPY src/Web/WebSPA/WebSPA.csproj src/Web/WebSPA/ -COPY src/Web/WebStatus/WebStatus.csproj src/Web/WebStatus/ -COPY test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj test/ServicesTests/Application.FunctionalTests/ -COPY test/ServicesTests/LoadTest/LoadTest.csproj test/ServicesTests/LoadTest/ +COPY scripts scripts/ -RUN dotnet restore eShopOnContainers-ServicesAndWebApps.sln +COPY ApiGateways/*/*/*.csproj csproj-files/ +COPY BuildingBlocks/*/*/*.csproj csproj-files/ +COPY Services/*/*/*.csproj csproj-files/ +COPY Web/*/*.csproj csproj-files/ COPY . . -WORKDIR /src/src/Services/Location/Locations.API -RUN dotnet publish --no-restore -c Release -o /app +WORKDIR /src/Services/Location/Locations.API +RUN dotnet publish -c Release -o /app FROM build as functionaltest -WORKDIR /src/src/Services/Location/Locations.FunctionalTests +WORKDIR /src/Services/Location/Locations.FunctionalTests FROM build AS publish diff --git a/src/Services/Location/Locations.API/Dockerfile.develop b/src/Services/Location/Locations.API/Dockerfile.develop index a847b6c30..ab1f7bfb8 100644 --- a/src/Services/Location/Locations.API/Dockerfile.develop +++ b/src/Services/Location/Locations.API/Dockerfile.develop @@ -1,17 +1,17 @@ -FROM microsoft/dotnet:2.2-sdk +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster ARG BUILD_CONFIGURATION=Debug ENV ASPNETCORE_ENVIRONMENT=Development ENV DOTNET_USE_POLLING_FILE_WATCHER=true EXPOSE 80 WORKDIR /src -COPY ["src/Services/Location/Locations.API/Locations.API.csproj", "src/Services/Location/Locations.API/"] -COPY ["src/BuildingBlocks/EventBus/EventBus/EventBus.csproj", "src/BuildingBlocks/EventBus/EventBus/"] -COPY ["src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "src/BuildingBlocks/EventBus/EventBusRabbitMQ/"] -COPY ["src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "src/BuildingBlocks/EventBus/EventBusServiceBus/"] -RUN dotnet restore src/Services/Location/Locations.API/Locations.API.csproj -nowarn:msb3202,nu1503 +COPY ["Services/Location/Locations.API/Locations.API.csproj", "Services/Location/Locations.API/"] +COPY ["BuildingBlocks/EventBus/EventBus/EventBus.csproj", "BuildingBlocks/EventBus/EventBus/"] +COPY ["BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "BuildingBlocks/EventBus/EventBusRabbitMQ/"] +COPY ["BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "BuildingBlocks/EventBus/EventBusServiceBus/"] +RUN dotnet restore Services/Location/Locations.API/Locations.API.csproj -nowarn:msb3202,nu1503 COPY . . -WORKDIR "/src/src/Services/Location/Locations.API" +WORKDIR "/src/Services/Location/Locations.API" RUN dotnet build --no-restore -c $BUILD_CONFIGURATION ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"] diff --git a/src/Services/Location/Locations.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs b/src/Services/Location/Locations.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs index e4194daeb..e2d4c9aed 100644 --- a/src/Services/Location/Locations.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs +++ b/src/Services/Location/Locations.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs @@ -1,6 +1,6 @@  using Microsoft.AspNetCore.Authorization; -using Swashbuckle.AspNetCore.Swagger; +using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; using System.Collections.Generic; using System.Linq; @@ -9,7 +9,7 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Filt { internal class AuthorizeCheckOperationFilter : IOperationFilter { - public void Apply(Operation operation, OperationFilterContext context) + public void Apply(OpenApiOperation operation, OperationFilterContext context) { // Check for authorize attribute var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType().Any() || @@ -17,16 +17,21 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Filt if (!hasAuthorize) return; - operation.Responses.TryAdd("401", new Response { Description = "Unauthorized" }); - operation.Responses.TryAdd("403", new Response { Description = "Forbidden" }); + operation.Responses.TryAdd("401", new OpenApiResponse() { Description = "Unauthorized" }); + operation.Responses.TryAdd("403", new OpenApiResponse() { Description = "Forbidden" }); - operation.Security = new List>> + var oAuthScheme = new OpenApiSecurityScheme { - new Dictionary> - { - { "oauth2", new [] { "locationsapi" } } - } + Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } }; + + operation.Security = new List + { + new OpenApiSecurityRequirement + { + [ oAuthScheme ] = new [] { "locationsapi" } + } + }; } } } diff --git a/src/Services/Location/Locations.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs b/src/Services/Location/Locations.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs index 30b9df1fa..12cffe878 100644 --- a/src/Services/Location/Locations.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs +++ b/src/Services/Location/Locations.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs @@ -5,15 +5,16 @@ using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.ActionResults; using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Exceptions; + using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using System.Net; public class HttpGlobalExceptionFilter : IExceptionFilter { - private readonly IHostingEnvironment env; + private readonly IHostEnvironment env; private readonly ILogger logger; - public HttpGlobalExceptionFilter(IHostingEnvironment env, ILogger logger) + public HttpGlobalExceptionFilter(IHostEnvironment env, ILogger logger) { this.env = env; this.logger = logger; diff --git a/src/Services/Location/Locations.API/Infrastructure/Services/LocationsService.cs b/src/Services/Location/Locations.API/Infrastructure/Services/LocationsService.cs index f6b9ed708..dc91d0d50 100644 --- a/src/Services/Location/Locations.API/Infrastructure/Services/LocationsService.cs +++ b/src/Services/Location/Locations.API/Infrastructure/Services/LocationsService.cs @@ -72,9 +72,6 @@ { var newUserLocations = MapUserLocationDetails(newLocations); var @event = new UserLocationUpdatedIntegrationEvent(userId, newUserLocations); - - _logger.LogInformation("----- Publishing integration event: {IntegrationEventId} from {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); - _eventBus.Publish(@event); } diff --git a/src/Services/Location/Locations.API/Locations.API.csproj b/src/Services/Location/Locations.API/Locations.API.csproj index 58c8f98dc..4cbab433a 100644 --- a/src/Services/Location/Locations.API/Locations.API.csproj +++ b/src/Services/Location/Locations.API/Locations.API.csproj @@ -1,35 +1,38 @@  - netcoreapp2.2 + $(NetCoreTargetVersion) ..\..\..\..\docker-compose.dcproj aspnet-Locations.API-20161122013619 + false + true + $(LangVersion) + - - - + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/src/Services/Location/Locations.API/Model/Core/LocationPoint.cs b/src/Services/Location/Locations.API/Model/Core/LocationPoint.cs new file mode 100644 index 000000000..48b6e32a7 --- /dev/null +++ b/src/Services/Location/Locations.API/Model/Core/LocationPoint.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Locations.API.Model.Core +{ + public class LocationPoint + { + public LocationPoint() + { + } + + public LocationPoint(double longitude, double latitude) + { + this.coordinates.Add(longitude); + this.coordinates.Add(latitude); + } + + public string type { get; private set; } = "Point"; + + public List coordinates { get; private set; } = new List(); + } +} diff --git a/src/Services/Location/Locations.API/Model/Core/LocationPolygon.cs b/src/Services/Location/Locations.API/Model/Core/LocationPolygon.cs new file mode 100644 index 000000000..18380cc79 --- /dev/null +++ b/src/Services/Location/Locations.API/Model/Core/LocationPolygon.cs @@ -0,0 +1,25 @@ +using MongoDB.Driver.GeoJsonObjectModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Locations.API.Model.Core +{ + public class LocationPolygon + { + public LocationPolygon() + { + } + + public LocationPolygon(List coordinatesList) + { + var coordinatesMapped = coordinatesList.Select(x => new List() { x.Longitude, x.Latitude }).ToList(); + this.coordinates.Add(coordinatesMapped); + } + + public string type { get; private set; } = "Polygon"; + + public List>> coordinates { get; private set; } = new List>>(); + } +} diff --git a/src/Services/Location/Locations.API/Model/Locations.cs b/src/Services/Location/Locations.API/Model/Locations.cs index 7c0580fc6..ba3dbe62c 100644 --- a/src/Services/Location/Locations.API/Model/Locations.cs +++ b/src/Services/Location/Locations.API/Model/Locations.cs @@ -1,5 +1,6 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API.Model { + using global::Locations.API.Model.Core; using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; using MongoDB.Driver.GeoJsonObjectModel; @@ -17,8 +18,12 @@ public string Description { get; set; } public double Latitude { get; set; } public double Longitude { get; set; } - public GeoJsonPoint Location { get; private set; } - public GeoJsonPolygon Polygon { get; private set; } + public LocationPoint Location { get; private set; } + public LocationPolygon Polygon { get; private set; } + + // Temporal commented in previewVersion7 of netcore and 2.9.0-beta2 of Mongo packages, review in next versions + // public GeoJsonPoint Location { get; private set; } + // public GeoJsonPolygon Polygon { get; private set; } public void SetLocation(double lon, double lat) => SetPosition(lon, lat); public void SetArea(List coordinatesList) => SetPolygon(coordinatesList); @@ -26,14 +31,12 @@ { Latitude = lat; Longitude = lon; - Location = new GeoJsonPoint( - new GeoJson2DGeographicCoordinates(lon, lat)); + Location = new LocationPoint(lon, lat); } private void SetPolygon(List coordinatesList) { - Polygon = new GeoJsonPolygon(new GeoJsonPolygonCoordinates( - new GeoJsonLinearRingCoordinates(coordinatesList))); + Polygon = new LocationPolygon(coordinatesList); } } } diff --git a/src/Services/Location/Locations.API/Startup.cs b/src/Services/Location/Locations.API/Startup.cs index 4664381d0..4f79b8977 100644 --- a/src/Services/Location/Locations.API/Startup.cs +++ b/src/Services/Location/Locations.API/Startup.cs @@ -1,14 +1,12 @@ using Autofac; using Autofac.Extensions.DependencyInjection; using HealthChecks.UI.Client; -using Microsoft.ApplicationInsights.Extensibility; -using Microsoft.ApplicationInsights.ServiceFabric; +using Locations.API.Controllers; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.ServiceBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; @@ -23,8 +21,8 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; +using Microsoft.OpenApi.Models; using RabbitMQ.Client; -using Swashbuckle.AspNetCore.Swagger; using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; @@ -40,18 +38,19 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API public IConfiguration Configuration { get; } - public IServiceProvider ConfigureServices(IServiceCollection services) + public virtual IServiceProvider ConfigureServices(IServiceCollection services) { RegisterAppInsights(services); - services - .AddCustomHealthCheck(Configuration) - .AddMvc(options => + services.AddCustomHealthCheck(Configuration); + + services.AddControllers(options => { options.Filters.Add(typeof(HttpGlobalExceptionFilter)); }) - .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) - .AddControllersAsServices(); + // Added for functional tests + .AddApplicationPart(typeof(LocationsController).Assembly) + .AddNewtonsoftJson(); ConfigureAuthService(services); @@ -99,7 +98,7 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount); }); - } + } RegisterEventBus(services); @@ -107,23 +106,27 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API services.AddSwaggerGen(options => { options.DescribeAllEnumsAsStrings(); - options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info + options.SwaggerDoc("v1", new OpenApiInfo { Title = "eShopOnContainers - Location HTTP API", Version = "v1", Description = "The Location Microservice HTTP API. This is a Data-Driven/CRUD microservice sample", - TermsOfService = "Terms Of Service" }); - options.AddSecurityDefinition("oauth2", new OAuth2Scheme + options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme { - Type = "oauth2", - Flow = "implicit", - AuthorizationUrl = $"{Configuration.GetValue("IdentityUrlExternal")}/connect/authorize", - TokenUrl = $"{Configuration.GetValue("IdentityUrlExternal")}/connect/token", - Scopes = new Dictionary() + Type = SecuritySchemeType.OAuth2, + Flows = new OpenApiOAuthFlows() { - { "locations", "Locations API" } + Implicit = new OpenApiOAuthFlow() + { + AuthorizationUrl = new Uri($"{Configuration.GetValue("IdentityUrlExternal")}/connect/authorize"), + TokenUrl = new Uri($"{Configuration.GetValue("IdentityUrlExternal")}/connect/token"), + Scopes = new Dictionary() + { + { "locations", "Locations API" } + } + } } }); @@ -154,7 +157,7 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) { //loggerFactory.AddAzureWebAppDiagnostics(); //loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace); @@ -165,22 +168,25 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API app.UsePathBase(pathBase); } - app.UseHealthChecks("/liveness", new HealthCheckOptions - { - Predicate = r => r.Name.Contains("self") - }); - - app.UseHealthChecks("/hc", new HealthCheckOptions() - { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - app.UseCors("CorsPolicy"); + app.UseRouting(); ConfigureAuth(app); - app.UseMvcWithDefaultRoute(); + app.UseEndpoints(endpoints => + { + endpoints.MapDefaultControllerRoute(); + endpoints.MapControllers(); + endpoints.MapHealthChecks("/hc", new HealthCheckOptions() + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + endpoints.MapHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = r => r.Name.Contains("self") + }); + }); app.UseSwagger() .UseSwaggerUI(c => @@ -197,19 +203,7 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API private void RegisterAppInsights(IServiceCollection services) { services.AddApplicationInsightsTelemetry(Configuration); - var orchestratorType = Configuration.GetValue("OrchestratorType"); - - if (orchestratorType?.ToUpper() == "K8S") - { - // Enable K8s telemetry initializer - services.AddApplicationInsightsKubernetesEnricher(); - } - if (orchestratorType?.ToUpper() == "SF") - { - // Enable SF telemetry initializer - services.AddSingleton((serviceProvider) => - new FabricTelemetryInitializer()); - } + services.AddApplicationInsightsKubernetesEnricher(); } private void ConfigureAuthService(IServiceCollection services) @@ -238,6 +232,7 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API } app.UseAuthentication(); + app.UseAuthorization(); } private void RegisterEventBus(IServiceCollection services) diff --git a/src/Services/Location/Locations.FunctionalTests/LocationTestsStartup.cs b/src/Services/Location/Locations.FunctionalTests/LocationTestsStartup.cs index 21d0814a0..08bf2ffa5 100644 --- a/src/Services/Location/Locations.FunctionalTests/LocationTestsStartup.cs +++ b/src/Services/Location/Locations.FunctionalTests/LocationTestsStartup.cs @@ -1,7 +1,11 @@ -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; using Microsoft.eShopOnContainers.Services.Locations.API; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System; using System.Security.Claims; using System.Threading.Tasks; @@ -13,6 +17,13 @@ namespace Locations.FunctionalTests { } + public override IServiceProvider ConfigureServices(IServiceCollection services) + { + // Added to avoid the Authorize data annotation in test environment. + // Property "SuppressCheckForUnhandledSecurityMetadata" in appsettings.json + services.Configure(Configuration); + return base.ConfigureServices(services); + } protected override void ConfigureAuth(IApplicationBuilder app) { if (Configuration["isTest"] == bool.TrueString.ToLowerInvariant()) diff --git a/src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj b/src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj index b1b807730..1e3e15e8a 100644 --- a/src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj +++ b/src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj @@ -1,8 +1,8 @@  - netcoreapp2.2 - + $(NetCoreTargetVersion) + false false @@ -17,11 +17,9 @@ - - - - - + + + all runtime; build; native; contentfiles; analyzers diff --git a/src/Services/Location/Locations.FunctionalTests/LocationsScenarios.cs b/src/Services/Location/Locations.FunctionalTests/LocationsScenarios.cs index d08f777fd..5f8c90dfd 100644 --- a/src/Services/Location/Locations.FunctionalTests/LocationsScenarios.cs +++ b/src/Services/Location/Locations.FunctionalTests/LocationsScenarios.cs @@ -52,21 +52,24 @@ namespace Locations.FunctionalTests var userId = "4611ce3f-380d-4db5-8d76-87a8689058ed"; var content = new StringContent(BuildLocationsRequest(-122.119998, 47.690876), UTF8Encoding.UTF8, "application/json"); + var client = server.CreateClient(); + // Expected result var expectedLocation = "REDM"; // Act - var response = await server.CreateClient() - .PostAsync(Post.AddNewLocation, content); - var userLocationResponse = await server.CreateClient() - .GetAsync(Get.UserLocationBy(userId)); + var response = await client.PostAsync(Post.AddNewLocation, content); + + var userLocationResponse = await client.GetAsync(Get.UserLocationBy(userId)); + userLocationResponse.EnsureSuccessStatusCode(); var responseBody = await userLocationResponse.Content.ReadAsStringAsync(); var userLocation = JsonConvert.DeserializeObject(responseBody); - var locationResponse = await server.CreateClient() - .GetAsync(Get.LocationBy(userLocation.LocationId)); + Assert.NotNull(userLocation); + + var locationResponse = await client.GetAsync(Get.LocationBy(userLocation.LocationId)); responseBody = await locationResponse.Content.ReadAsStringAsync(); var location = JsonConvert.DeserializeObject(responseBody); diff --git a/src/Services/Location/Locations.FunctionalTests/appsettings.json b/src/Services/Location/Locations.FunctionalTests/appsettings.json index 398cd54c0..6880b2ee1 100644 --- a/src/Services/Location/Locations.FunctionalTests/appsettings.json +++ b/src/Services/Location/Locations.FunctionalTests/appsettings.json @@ -5,5 +5,6 @@ "IdentityUrl": "http://localhost:5105", "isTest": "true", "EventBusConnection": "localhost", - "SubscriptionClientName": "Locations" + "SubscriptionClientName": "Locations", + "SuppressCheckForUnhandledSecurityMetadata":true } diff --git a/src/Services/Marketing/Infrastructure/AzureFunctions/marketing-functions.csproj b/src/Services/Marketing/Infrastructure/AzureFunctions/marketing-functions.csproj index 7f54ce86b..33e93b625 100644 --- a/src/Services/Marketing/Infrastructure/AzureFunctions/marketing-functions.csproj +++ b/src/Services/Marketing/Infrastructure/AzureFunctions/marketing-functions.csproj @@ -2,12 +2,13 @@ net461 + - + diff --git a/src/Services/Marketing/Marketing.API/Dockerfile b/src/Services/Marketing/Marketing.API/Dockerfile index 34724a5f8..b254761b4 100644 --- a/src/Services/Marketing/Marketing.API/Dockerfile +++ b/src/Services/Marketing/Marketing.API/Dockerfile @@ -1,58 +1,23 @@ -FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base +FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base WORKDIR /app EXPOSE 80 -FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build WORKDIR /src -# Keep the project list and command dotnet restore identical in all Dockfiles to maximize image cache utilization -COPY eShopOnContainers-ServicesAndWebApps.sln . -COPY docker-compose.dcproj /src/ -COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/ -COPY src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj src/ApiGateways/Mobile.Bff.Shopping/aggregator/ -COPY src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj src/ApiGateways/Web.Bff.Shopping/aggregator/ -COPY src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj src/BuildingBlocks/Devspaces.Support/ -COPY src/BuildingBlocks/EventBus/EventBus/EventBus.csproj src/BuildingBlocks/EventBus/EventBus/ -COPY src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj src/BuildingBlocks/EventBus/EventBus.Tests/ -COPY src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj src/BuildingBlocks/EventBus/EventBusRabbitMQ/ -COPY src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj src/BuildingBlocks/EventBus/EventBusServiceBus/ -COPY src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj src/BuildingBlocks/EventBus/IntegrationEventLogEF/ -COPY src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj src/BuildingBlocks/WebHostCustomization/WebHost.Customization/ -COPY src/Services/Basket/Basket.API/Basket.API.csproj src/Services/Basket/Basket.API/ -COPY src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj src/Services/Basket/Basket.FunctionalTests/ -COPY src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj src/Services/Basket/Basket.UnitTests/ -COPY src/Services/Catalog/Catalog.API/Catalog.API.csproj src/Services/Catalog/Catalog.API/ -COPY src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj src/Services/Catalog/Catalog.FunctionalTests/ -COPY src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj src/Services/Catalog/Catalog.UnitTests/ -COPY src/Services/Identity/Identity.API/Identity.API.csproj src/Services/Identity/Identity.API/ -COPY src/Services/Location/Locations.API/Locations.API.csproj src/Services/Location/Locations.API/ -COPY src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj src/Services/Location/Locations.FunctionalTests/ -COPY src/Services/Marketing/Marketing.API/Marketing.API.csproj src/Services/Marketing/Marketing.API/ -COPY src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj src/Services/Marketing/Marketing.FunctionalTests/ -COPY src/Services/Ordering/Ordering.API/Ordering.API.csproj src/Services/Ordering/Ordering.API/ -COPY src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj src/Services/Ordering/Ordering.BackgroundTasks/ -COPY src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj src/Services/Ordering/Ordering.Domain/ -COPY src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj src/Services/Ordering/Ordering.FunctionalTests/ -COPY src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj src/Services/Ordering/Ordering.Infrastructure/ -COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/ -COPY src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj src/Services/Ordering/Ordering.UnitTests/ -COPY src/Services/Payment/Payment.API/Payment.API.csproj src/Services/Payment/Payment.API/ -COPY src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj src/Services/Webhooks/Webhooks.API/ -COPY src/Web/WebhookClient/WebhookClient.csproj src/Web/WebhookClient/ -COPY src/Web/WebMVC/WebMVC.csproj src/Web/WebMVC/ -COPY src/Web/WebSPA/WebSPA.csproj src/Web/WebSPA/ -COPY src/Web/WebStatus/WebStatus.csproj src/Web/WebStatus/ -COPY test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj test/ServicesTests/Application.FunctionalTests/ -COPY test/ServicesTests/LoadTest/LoadTest.csproj test/ServicesTests/LoadTest/ +COPY scripts scripts/ -RUN dotnet restore eShopOnContainers-ServicesAndWebApps.sln +COPY ApiGateways/*/*/*.csproj csproj-files/ +COPY BuildingBlocks/*/*/*.csproj csproj-files/ +COPY Services/*/*/*.csproj csproj-files/ +COPY Web/*/*.csproj csproj-files/ COPY . . -WORKDIR /src/src/Services/Marketing/Marketing.API -RUN dotnet publish --no-restore -c Release -o /app +WORKDIR /src/Services/Marketing/Marketing.API +RUN dotnet publish -c Release -o /app FROM build as functionaltest -WORKDIR /src/src/Services/Marketing/Marketing.FunctionalTests +WORKDIR /src/Services/Marketing/Marketing.FunctionalTests FROM build AS publish diff --git a/src/Services/Marketing/Marketing.API/Dockerfile.develop b/src/Services/Marketing/Marketing.API/Dockerfile.develop index 60fc6dd7c..8425f47c1 100644 --- a/src/Services/Marketing/Marketing.API/Dockerfile.develop +++ b/src/Services/Marketing/Marketing.API/Dockerfile.develop @@ -1,18 +1,18 @@ -FROM microsoft/dotnet:2.2-sdk +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster ARG BUILD_CONFIGURATION=Debug ENV ASPNETCORE_ENVIRONMENT=Development ENV DOTNET_USE_POLLING_FILE_WATCHER=true EXPOSE 80 WORKDIR /src -COPY ["src/Services/Marketing/Marketing.API/Marketing.API.csproj", "src/Services/Marketing/Marketing.API/"] -COPY ["src/BuildingBlocks/EventBus/EventBus/EventBus.csproj", "src/BuildingBlocks/EventBus/EventBus/"] -COPY ["src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "src/BuildingBlocks/EventBus/EventBusRabbitMQ/"] -COPY ["src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "src/BuildingBlocks/EventBus/EventBusServiceBus/"] -COPY ["src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj", "src/BuildingBlocks/WebHostCustomization/WebHost.Customization/"] -RUN dotnet restore src/Services/Marketing/Marketing.API/Marketing.API.csproj -nowarn:msb3202,nu1503 +COPY [Services/Marketing/Marketing.API/Marketing.API.csproj", "Services/Marketing/Marketing.API/"] +COPY [BuildingBlocks/EventBus/EventBus/EventBus.csproj", "BuildingBlocks/EventBus/EventBus/"] +COPY [BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "BuildingBlocks/EventBus/EventBusRabbitMQ/"] +COPY [BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "BuildingBlocks/EventBus/EventBusServiceBus/"] +COPY [BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj", "BuildingBlocks/WebHostCustomization/WebHost.Customization/"] +RUN dotnet restore Services/Marketing/Marketing.API/Marketing.API.csproj -nowarn:msb3202,nu1503 COPY . . -WORKDIR "/src/src/Services/Marketing/Marketing.API" +WORKDIR "/src/Services/Marketing/Marketing.API" RUN dotnet build --no-restore -c $BUILD_CONFIGURATION ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"] diff --git a/src/Services/Marketing/Marketing.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs b/src/Services/Marketing/Marketing.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs index 3f19140bf..d013597d9 100644 --- a/src/Services/Marketing/Marketing.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs +++ b/src/Services/Marketing/Marketing.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs @@ -1,5 +1,5 @@ using Microsoft.AspNetCore.Authorization; -using Swashbuckle.AspNetCore.Swagger; +using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; using System.Collections.Generic; using System.Linq; @@ -8,7 +8,7 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.Filt { public class AuthorizeCheckOperationFilter : IOperationFilter { - public void Apply(Operation operation, OperationFilterContext context) + public void Apply(OpenApiOperation operation, OperationFilterContext context) { // Check for authorize attribute var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType().Any() || @@ -16,16 +16,21 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.Filt if (!hasAuthorize) return; - operation.Responses.TryAdd("401", new Response { Description = "Unauthorized" }); - operation.Responses.TryAdd("403", new Response { Description = "Forbidden" }); + operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" }); + operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" }); - operation.Security = new List>> + var oAuthScheme = new OpenApiSecurityScheme { - new Dictionary> - { - { "oauth2", new [] { "marketingapi" } } - } + Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } }; + + operation.Security = new List + { + new OpenApiSecurityRequirement + { + [ oAuthScheme ] = new [] { "marketingapi" } + } + }; } } } \ No newline at end of file diff --git a/src/Services/Marketing/Marketing.API/Infrastructure/MarketingContext.cs b/src/Services/Marketing/Marketing.API/Infrastructure/MarketingContext.cs index dae9b5bb4..e06106b5e 100644 --- a/src/Services/Marketing/Marketing.API/Infrastructure/MarketingContext.cs +++ b/src/Services/Marketing/Marketing.API/Infrastructure/MarketingContext.cs @@ -1,9 +1,12 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure { + using System; + using System.IO; using EntityConfigurations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using Microsoft.eShopOnContainers.Services.Marketing.API.Model; + using Microsoft.Extensions.Configuration; public class MarketingContext : DbContext { @@ -27,9 +30,15 @@ { public MarketingContext CreateDbContext(string[] args) { - var optionsBuilder = new DbContextOptionsBuilder() - .UseSqlServer("Server=.;Initial Catalog=Microsoft.eShopOnContainers.Services.MarketingDb;Integrated Security=true"); + IConfigurationRoot configuration = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) + .AddEnvironmentVariables() + .Build(); + var connectionString = configuration["ConnectionString"]; + var optionsBuilder = new DbContextOptionsBuilder() + .UseSqlServer(connectionString); return new MarketingContext(optionsBuilder.Options); } } diff --git a/src/Services/Marketing/Marketing.API/Infrastructure/MarketingContextSeed.cs b/src/Services/Marketing/Marketing.API/Infrastructure/MarketingContextSeed.cs index af1786940..ac800909e 100644 --- a/src/Services/Marketing/Marketing.API/Infrastructure/MarketingContextSeed.cs +++ b/src/Services/Marketing/Marketing.API/Infrastructure/MarketingContextSeed.cs @@ -3,6 +3,7 @@ using Microsoft.eShopOnContainers.Services.Marketing.API.Model; using Microsoft.Extensions.Logging; using Polly; + using Polly.Retry; using System; using System.Collections.Generic; using System.Data.SqlClient; @@ -68,7 +69,7 @@ }; } - private Policy CreatePolicy(int retries, ILogger logger, string prefix) + private AsyncRetryPolicy CreatePolicy(int retries, ILogger logger, string prefix) { return Policy.Handle(). WaitAndRetryAsync( diff --git a/src/Services/Marketing/Marketing.API/IntegrationEvents/Handlers/UserLocationUpdatedIntegrationEventHandler.cs b/src/Services/Marketing/Marketing.API/IntegrationEvents/Handlers/UserLocationUpdatedIntegrationEventHandler.cs index 3d5e62e45..5b93a17d0 100644 --- a/src/Services/Marketing/Marketing.API/IntegrationEvents/Handlers/UserLocationUpdatedIntegrationEventHandler.cs +++ b/src/Services/Marketing/Marketing.API/IntegrationEvents/Handlers/UserLocationUpdatedIntegrationEventHandler.cs @@ -28,8 +28,6 @@ { using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) { - _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); - var userMarketingData = await _marketingDataRepository.GetAsync(@event.UserId); userMarketingData = userMarketingData ?? new MarketingData() { UserId = @event.UserId }; diff --git a/src/Services/Marketing/Marketing.API/Marketing.API.csproj b/src/Services/Marketing/Marketing.API/Marketing.API.csproj index 1681cc87a..497cefa4a 100644 --- a/src/Services/Marketing/Marketing.API/Marketing.API.csproj +++ b/src/Services/Marketing/Marketing.API/Marketing.API.csproj @@ -1,14 +1,17 @@  - netcoreapp2.2 + $(NetCoreTargetVersion) ..\..\..\..\docker-compose.dcproj Microsoft.eShopOnContainers.Services.Marketing.API $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + true aspnet-Marketing.API-20161122013619 /subscriptions/6c22bb55-0221-4ce4-9bf1-3c4a10a7294c/resourcegroups/eshop-log/providers/microsoft.insights/components/eshopappinsights /subscriptions/6c22bb55-0221-4ce4-9bf1-3c4a10a7294c/resourcegroups/eshop-log/providers/microsoft.insights/components/eshopappinsights + $(LangVersion) @@ -21,33 +24,31 @@ - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/src/Services/Marketing/Marketing.API/Startup.cs b/src/Services/Marketing/Marketing.API/Startup.cs index 7f990e3ad..ff6fdd43a 100644 --- a/src/Services/Marketing/Marketing.API/Startup.cs +++ b/src/Services/Marketing/Marketing.API/Startup.cs @@ -21,16 +21,15 @@ using Infrastructure.Services; using IntegrationEvents.Events; using Marketing.API.IntegrationEvents.Handlers; - using Microsoft.ApplicationInsights.Extensibility; - using Microsoft.ApplicationInsights.ServiceFabric; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore.Diagnostics; + using Microsoft.eShopOnContainers.Services.Marketing.API.Controllers; using Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.Middlewares; using Microsoft.Extensions.Diagnostics.HealthChecks; + using Microsoft.OpenApi.Models; using RabbitMQ.Client; - using Swashbuckle.AspNetCore.Swagger; using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; @@ -47,32 +46,31 @@ // This method gets called by the runtime. Use this method to add services to the container. - public IServiceProvider ConfigureServices(IServiceCollection services) + public virtual IServiceProvider ConfigureServices(IServiceCollection services) { RegisterAppInsights(services); // Add framework services. + services.AddCustomHealthCheck(Configuration); services - .AddCustomHealthCheck(Configuration) - .AddMvc(options => - { - options.Filters.Add(typeof(HttpGlobalExceptionFilter)); - }) - .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) - .AddControllersAsServices(); //Injecting Controllers themselves thru DIFor further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services - + .AddControllers() + // Added for functional tests + .AddApplicationPart(typeof(LocationsController).Assembly) + .AddNewtonsoftJson() + .SetCompatibilityVersion(CompatibilityVersion.Version_3_0); services.Configure(Configuration); - ConfigureAuthService(services); + ConfigureAuthService(services); - services.AddDbContext(options => + services.AddEntityFrameworkSqlServer() + .AddDbContext(options => { options.UseSqlServer(Configuration["ConnectionString"], sqlServerOptionsAction: sqlOptions => { sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); //Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency - sqlOptions.EnableRetryOnFailure(maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); + sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); }); // Changing default behavior when client evaluation occurs to throw. @@ -123,35 +121,11 @@ return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount); }); - } + } // Add framework services. - services.AddSwaggerGen(options => - { - options.DescribeAllEnumsAsStrings(); - options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info - { - Title = "Marketing HTTP API", - Version = "v1", - Description = "The Marketing Service HTTP API", - TermsOfService = "Terms Of Service" - }); - - options.AddSecurityDefinition("oauth2", new OAuth2Scheme - { - Type = "oauth2", - Flow = "implicit", - AuthorizationUrl = $"{Configuration.GetValue("IdentityUrlExternal")}/connect/authorize", - TokenUrl = $"{Configuration.GetValue("IdentityUrlExternal")}/connect/token", - Scopes = new Dictionary() - { - { "marketing", "Marketing API" } - } - }); - - options.OperationFilter(); - }); + AddCustomSwagger(services); services.AddCors(options => { options.AddPolicy("CorsPolicy", @@ -178,7 +152,7 @@ } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env,ILoggerFactory loggerFactory) + public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { //loggerFactory.AddAzureWebAppDiagnostics(); //loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace); @@ -190,68 +164,92 @@ app.UsePathBase(pathBase); } - app.UseHealthChecks("/hc", new HealthCheckOptions() - { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - - app.UseHealthChecks("/liveness", new HealthCheckOptions - { - Predicate = r => r.Name.Contains("self") - }); - app.UseCors("CorsPolicy"); + app.UseRouting(); ConfigureAuth(app); - app.UseMvcWithDefaultRoute(); + app.UseEndpoints(endpoints => + { + endpoints.MapDefaultControllerRoute(); + endpoints.MapControllers(); + endpoints.MapHealthChecks("/hc", new HealthCheckOptions() + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + endpoints.MapHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = r => r.Name.Contains("self") + }); + }); app.UseSwagger() - .UseSwaggerUI(c => + .UseSwaggerUI(setup => { - c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Marketing.API V1"); - c.OAuthClientId("marketingswaggerui"); - c.OAuthAppName("Marketing Swagger UI"); - }); + setup.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Marketing.API V1"); + setup.OAuthClientId("marketingswaggerui"); + setup.OAuthAppName("Marketing Swagger UI"); + }); ConfigureEventBus(app); } + private void AddCustomSwagger(IServiceCollection services) + { + services.AddSwaggerGen(options => + { + options.DescribeAllEnumsAsStrings(); + options.SwaggerDoc("v1", new OpenApiInfo + { + Title = "eShopOnContainers - Marketing HTTP API", + Version = "v1", + Description = "The Marketing Service HTTP API" + }); + + options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme + { + Type = SecuritySchemeType.OAuth2, + Flows = new OpenApiOAuthFlows() + { + Implicit = new OpenApiOAuthFlow() + { + AuthorizationUrl = new Uri($"{Configuration.GetValue("IdentityUrlExternal")}/connect/authorize"), + TokenUrl = new Uri($"{Configuration.GetValue("IdentityUrlExternal")}/connect/token"), + Scopes = new Dictionary() + { + { "marketing", "Marketing API" } + } + } + } + }); + + options.OperationFilter(); + }); + } + private void RegisterAppInsights(IServiceCollection services) { services.AddApplicationInsightsTelemetry(Configuration); - var orchestratorType = Configuration.GetValue("OrchestratorType"); - - if (orchestratorType?.ToUpper() == "K8S") - { - // Enable K8s telemetry initializer - services.AddApplicationInsightsKubernetesEnricher(); - } - if (orchestratorType?.ToUpper() == "SF") - { - // Enable SF telemetry initializer - services.AddSingleton((serviceProvider) => - new FabricTelemetryInitializer()); - } + services.AddApplicationInsightsKubernetesEnricher(); } private void ConfigureAuthService(IServiceCollection services) { // prevent from mapping "sub" claim to nameidentifier. - JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub"); - services.AddAuthentication(options=> + services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(options => - { - options.Authority = Configuration.GetValue("IdentityUrl"); - options.Audience = "marketing"; - options.RequireHttpsMetadata = false; - }); + { + options.Authority = Configuration.GetValue("IdentityUrl"); + options.Audience = "marketing"; + options.RequireHttpsMetadata = false; + }); } private void RegisterEventBus(IServiceCollection services) @@ -265,7 +263,7 @@ var serviceBusPersisterConnection = sp.GetRequiredService(); var iLifetimeScope = sp.GetRequiredService(); var logger = sp.GetRequiredService>(); - var eventBusSubcriptionsManager = sp.GetRequiredService(); + var eventBusSubcriptionsManager = sp.GetRequiredService(); return new EventBusServiceBus(serviceBusPersisterConnection, logger, eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); @@ -308,6 +306,7 @@ } app.UseAuthentication(); + app.UseAuthorization(); } } diff --git a/src/Services/Marketing/Marketing.FunctionalTests/CampaignScenarios.cs b/src/Services/Marketing/Marketing.FunctionalTests/CampaignScenarios.cs index abeb4a504..3742b80c6 100644 --- a/src/Services/Marketing/Marketing.FunctionalTests/CampaignScenarios.cs +++ b/src/Services/Marketing/Marketing.FunctionalTests/CampaignScenarios.cs @@ -9,6 +9,7 @@ using Xunit; namespace Marketing.FunctionalTests { + [Collection("Sequential")] public class CampaignScenarios : CampaignScenarioBase { @@ -75,7 +76,7 @@ namespace Marketing.FunctionalTests var campaignResponse = await server.CreateClient() .PostAsync(Post.AddNewCampaign, content); - if (int.TryParse(campaignResponse.Headers.Location.Segments[4], out int id)) + if (int.TryParse(campaignResponse.Headers.Location.Segments[3], out int id)) { var response = await server.CreateClient() .DeleteAsync(Delete.CampaignBy(id)); @@ -99,7 +100,7 @@ namespace Marketing.FunctionalTests var campaignResponse = await server.CreateClient() .PostAsync(Post.AddNewCampaign, content); - if (int.TryParse(campaignResponse.Headers.Location.Segments[4], out int id)) + if (int.TryParse(campaignResponse.Headers.Location.Segments[3], out int id)) { fakeCampaignDto.Description = "FakeCampaignUpdatedDescription"; content = new StringContent(JsonConvert.SerializeObject(fakeCampaignDto), Encoding.UTF8, "application/json"); diff --git a/src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj b/src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj index db409dbd6..9f51dfbbc 100644 --- a/src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj +++ b/src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj @@ -1,7 +1,7 @@  - netcoreapp2.2 + $(NetCoreTargetVersion) false @@ -17,11 +17,9 @@ - - - - - + + + all runtime; build; native; contentfiles; analyzers diff --git a/src/Services/Marketing/Marketing.FunctionalTests/MarketingScenarioBase.cs b/src/Services/Marketing/Marketing.FunctionalTests/MarketingScenarioBase.cs index 274db5f69..025934220 100644 --- a/src/Services/Marketing/Marketing.FunctionalTests/MarketingScenarioBase.cs +++ b/src/Services/Marketing/Marketing.FunctionalTests/MarketingScenarioBase.cs @@ -1,11 +1,16 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; +using Microsoft.eShopOnContainers.Services.Marketing.API; using Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System; using System.IO; using System.Reflection; +using System.Threading; +using System.Threading.Tasks; namespace Marketing.FunctionalTests { @@ -23,8 +28,10 @@ namespace Marketing.FunctionalTests .ConfigureAppConfiguration(cb => { cb.AddJsonFile("appsettings.json", optional: false) - .AddEnvironmentVariables(); - }).UseStartup(); + .AddEnvironmentVariables(); + }) + .CaptureStartupErrors(true) + .UseStartup(); var testServer = new TestServer(hostBuilder); @@ -36,7 +43,6 @@ namespace Marketing.FunctionalTests new MarketingContextSeed() .SeedAsync(context, logger) .Wait(); - }); return testServer; diff --git a/src/Services/Marketing/Marketing.FunctionalTests/MarketingTestStartup.cs b/src/Services/Marketing/Marketing.FunctionalTests/MarketingTestStartup.cs index e227deff6..87d0fb991 100644 --- a/src/Services/Marketing/Marketing.FunctionalTests/MarketingTestStartup.cs +++ b/src/Services/Marketing/Marketing.FunctionalTests/MarketingTestStartup.cs @@ -1,6 +1,9 @@ -using Microsoft.AspNetCore.Builder; +using System; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Routing; using Microsoft.eShopOnContainers.Services.Marketing.API; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; namespace Marketing.FunctionalTests { @@ -10,6 +13,14 @@ namespace Marketing.FunctionalTests { } + public override IServiceProvider ConfigureServices(IServiceCollection services) + { + // Added to avoid the Authorize data annotation in test environment. + // Property "SuppressCheckForUnhandledSecurityMetadata" in appsettings.json + services.Configure(Configuration); + return base.ConfigureServices(services); + } + protected override void ConfigureAuth(IApplicationBuilder app) { if (Configuration["isTest"] == bool.TrueString.ToLowerInvariant()) diff --git a/src/Services/Marketing/Marketing.FunctionalTests/UserLocationRoleScenarios.cs b/src/Services/Marketing/Marketing.FunctionalTests/UserLocationRoleScenarios.cs index b8ee38e17..fe76923e0 100644 --- a/src/Services/Marketing/Marketing.FunctionalTests/UserLocationRoleScenarios.cs +++ b/src/Services/Marketing/Marketing.FunctionalTests/UserLocationRoleScenarios.cs @@ -8,6 +8,7 @@ using Xunit; namespace Marketing.FunctionalTests { + [Collection("Sequential")] public class UserLocationRoleScenarios : UserLocationRoleScenariosBase { diff --git a/src/Services/Marketing/Marketing.FunctionalTests/appsettings.json b/src/Services/Marketing/Marketing.FunctionalTests/appsettings.json index 4a57bb0f5..11a1e090d 100644 --- a/src/Services/Marketing/Marketing.FunctionalTests/appsettings.json +++ b/src/Services/Marketing/Marketing.FunctionalTests/appsettings.json @@ -6,5 +6,6 @@ "isTest": "true", "EventBusConnection": "localhost", "PicBaseUrl": "http://localhost:5110/api/v1/campaigns/[0]/pic/", - "SubscriptionClientName": "Marketing" + "SubscriptionClientName": "Marketing", + "SuppressCheckForUnhandledSecurityMetadata":true } diff --git a/src/Services/Ordering/Ordering.API/Application/Behaviors/ValidatorBehavior.cs b/src/Services/Ordering/Ordering.API/Application/Behaviors/ValidatorBehavior.cs index 6fc12258b..9be24e20f 100644 --- a/src/Services/Ordering/Ordering.API/Application/Behaviors/ValidatorBehavior.cs +++ b/src/Services/Ordering/Ordering.API/Application/Behaviors/ValidatorBehavior.cs @@ -24,8 +24,6 @@ namespace Ordering.API.Application.Behaviors { var typeName = request.GetGenericTypeName(); - _logger.LogInformation("----- Validating command {CommandType}", typeName); - var failures = _validators .Select(v => v.Validate(request)) .SelectMany(result => result.Errors) diff --git a/src/Services/Ordering/Ordering.API/Application/Commands/CancelOrderCommand.cs b/src/Services/Ordering/Ordering.API/Application/Commands/CancelOrderCommand.cs index 0672807f3..c2a1c2be5 100644 --- a/src/Services/Ordering/Ordering.API/Application/Commands/CancelOrderCommand.cs +++ b/src/Services/Ordering/Ordering.API/Application/Commands/CancelOrderCommand.cs @@ -12,7 +12,10 @@ namespace Ordering.API.Application.Commands [DataMember] public int OrderNumber { get; private set; } + public CancelOrderCommand() + { + } public CancelOrderCommand(int orderNumber) { OrderNumber = orderNumber; diff --git a/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs b/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs index b2fff253d..1cbd21536 100644 --- a/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs @@ -53,8 +53,6 @@ order.AddOrderItem(item.ProductId, item.ProductName, item.UnitPrice, item.Discount, item.PictureUrl, item.Units); } - _logger.LogInformation("----- Creating Order - Order: {@Order}", order); - _orderRepository.Add(order); return await _orderRepository.UnitOfWork diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/BuyerAndPaymentMethodVerified/UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/BuyerAndPaymentMethodVerified/UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler.cs index bea8eaac5..4d3a3280c 100644 --- a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/BuyerAndPaymentMethodVerified/UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/BuyerAndPaymentMethodVerified/UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler.cs @@ -26,12 +26,12 @@ namespace Ordering.API.Application.DomainEventHandlers.BuyerAndPaymentMethodVeri // then we can update the original Order with the BuyerId and PaymentId (foreign keys) public async Task Handle(BuyerAndPaymentMethodVerifiedDomainEvent buyerPaymentMethodVerifiedEvent, CancellationToken cancellationToken) { + var log = _logger.CreateLogger(); var orderToUpdate = await _orderRepository.GetAsync(buyerPaymentMethodVerifiedEvent.OrderId); orderToUpdate.SetBuyerId(buyerPaymentMethodVerifiedEvent.Buyer.Id); orderToUpdate.SetPaymentId(buyerPaymentMethodVerifiedEvent.Payment.Id); - _logger.CreateLogger() - .LogTrace("Order with Id: {OrderId} has been successfully updated with a payment method {PaymentMethod} ({Id})", + log.LogTrace("Order with Id: {OrderId} has been successfully updated with a payment method {PaymentMethod} ({Id})", buyerPaymentMethodVerifiedEvent.OrderId, nameof(buyerPaymentMethodVerifiedEvent.Payment), buyerPaymentMethodVerifiedEvent.Payment.Id); } } diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStartedEvent/ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStartedEvent/ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler.cs index 054c20de5..5b8f19b00 100644 --- a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStartedEvent/ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStartedEvent/ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler.cs @@ -12,7 +12,7 @@ using System.Threading.Tasks; namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent { - public class ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler + public class ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler : INotificationHandler { private readonly ILoggerFactory _logger; @@ -21,8 +21,8 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; public ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler( - ILoggerFactory logger, - IBuyerRepository buyerRepository, + ILoggerFactory logger, + IBuyerRepository buyerRepository, IIdentityService identityService, IOrderingIntegrationEventService orderingIntegrationEventService) { @@ -33,13 +33,13 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent } public async Task Handle(OrderStartedDomainEvent orderStartedEvent, CancellationToken cancellationToken) - { + { var cardTypeId = (orderStartedEvent.CardTypeId != 0) ? orderStartedEvent.CardTypeId : 1; var buyer = await _buyerRepository.FindAsync(orderStartedEvent.UserId); bool buyerOriginallyExisted = (buyer == null) ? false : true; if (!buyerOriginallyExisted) - { + { buyer = new Buyer(orderStartedEvent.UserId, orderStartedEvent.UserName); } @@ -51,8 +51,8 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent orderStartedEvent.CardExpiration, orderStartedEvent.Order.Id); - var buyerUpdated = buyerOriginallyExisted ? - _buyerRepository.Update(buyer) : + var buyerUpdated = buyerOriginallyExisted ? + _buyerRepository.Update(buyer) : _buyerRepository.Add(buyer); await _buyerRepository.UnitOfWork @@ -60,7 +60,6 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent var orderStatusChangedTosubmittedIntegrationEvent = new OrderStatusChangedToSubmittedIntegrationEvent(orderStartedEvent.Order.Id, orderStartedEvent.Order.OrderStatus.Name, buyer.Name); await _orderingIntegrationEventService.AddAndSaveEventAsync(orderStatusChangedTosubmittedIntegrationEvent); - _logger.CreateLogger() .LogTrace("Buyer {BuyerId} and related payment method were validated or updated for orderId: {OrderId}.", buyerUpdated.Id, orderStartedEvent.Order.Id); diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/GracePeriodConfirmedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/GracePeriodConfirmedIntegrationEventHandler.cs index 2e003b322..e3df4d11d 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/GracePeriodConfirmedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/GracePeriodConfirmedIntegrationEventHandler.cs @@ -37,8 +37,6 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling { using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) { - _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); - var command = new SetAwaitingValidationOrderStatusCommand(@event.OrderId); _logger.LogInformation( diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentFailedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentFailedIntegrationEventHandler.cs index a123dd891..e54a14fb0 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentFailedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentFailedIntegrationEventHandler.cs @@ -31,8 +31,6 @@ { using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) { - _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); - var command = new CancelOrderCommand(@event.OrderId); _logger.LogInformation( diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSucceededIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSucceededIntegrationEventHandler.cs index fdb6c2c0b..57a9829a2 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSucceededIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSucceededIntegrationEventHandler.cs @@ -31,8 +31,6 @@ { using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) { - _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); - var command = new SetPaidOrderStatusCommand(@event.OrderId); _logger.LogInformation( diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs index 6438b01d0..8572a09dd 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs @@ -31,8 +31,6 @@ { using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) { - _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); - var command = new SetStockConfirmedOrderStatusCommand(@event.OrderId); _logger.LogInformation( diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockRejectedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockRejectedIntegrationEventHandler.cs index b457211ed..1c6a3edd6 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockRejectedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockRejectedIntegrationEventHandler.cs @@ -30,8 +30,6 @@ { using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) { - _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); - var orderStockRejectedItems = @event.OrderStockItems .FindAll(c => !c.HasStock) .Select(c => c.ProductId) diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs index a1452b23c..f55542b34 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs @@ -35,11 +35,9 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling /// /// public async Task Handle(UserCheckoutAcceptedIntegrationEvent @event) - { + { using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) { - _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); - var result = false; if (@event.RequestId != Guid.Empty) @@ -62,11 +60,7 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling result = await _mediator.Send(requestCreateOrder); - if (result) - { - _logger.LogInformation("----- CreateOrderCommand suceeded - RequestId: {RequestId}", @event.RequestId); - } - else + if (!result) { _logger.LogWarning("CreateOrderCommand failed - RequestId: {RequestId}", @event.RequestId); } diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/OrderingIntegrationEventService.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/OrderingIntegrationEventService.cs index cb7ce5513..776b90927 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/OrderingIntegrationEventService.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/OrderingIntegrationEventService.cs @@ -45,8 +45,6 @@ namespace Ordering.API.Application.IntegrationEvents foreach (var logEvt in pendingLogEvents) { - _logger.LogInformation("----- Publishing integration event: {IntegrationEventId} from {AppName} - ({@IntegrationEvent})", logEvt.EventId, Program.AppName, logEvt.IntegrationEvent); - try { await _eventLogService.MarkEventAsInProgressAsync(logEvt.EventId); @@ -64,8 +62,6 @@ namespace Ordering.API.Application.IntegrationEvents public async Task AddAndSaveEventAsync(IntegrationEvent evt) { - _logger.LogInformation("----- Enqueuing integration event {IntegrationEventId} to repository ({@IntegrationEvent})", evt.Id, evt); - await _eventLogService.SaveEventAsync(evt, _orderingContext.GetCurrentTransaction()); } } diff --git a/src/Services/Ordering/Ordering.API/Application/Models/BasketItem.cs b/src/Services/Ordering/Ordering.API/Application/Models/BasketItem.cs index 698bdea3e..271524c69 100644 --- a/src/Services/Ordering/Ordering.API/Application/Models/BasketItem.cs +++ b/src/Services/Ordering/Ordering.API/Application/Models/BasketItem.cs @@ -8,7 +8,7 @@ namespace Ordering.API.Application.Models public class BasketItem { public string Id { get; set; } - public string ProductId { get; set; } + public int ProductId { get; set; } public string ProductName { get; set; } public decimal UnitPrice { get; set; } public decimal OldUnitPrice { get; set; } diff --git a/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs b/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs index 7a592bfb8..58640412b 100644 --- a/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs +++ b/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs @@ -49,7 +49,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers { var requestCancelOrder = new IdentifiedCommand(command, guid); - _logger.LogInformation( + _logger.LogTrace( "----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})", requestCancelOrder.GetGenericTypeName(), nameof(requestCancelOrder.Command.OrderNumber), @@ -79,7 +79,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers { var requestShipOrder = new IdentifiedCommand(command, guid); - _logger.LogInformation( + _logger.LogTrace( "----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})", requestShipOrder.GetGenericTypeName(), nameof(requestShipOrder.Command.OrderNumber), @@ -141,7 +141,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers [HttpPost] public async Task> CreateOrderDraftFromBasketDataAsync([FromBody] CreateOrderDraftCommand createOrderDraftCommand) { - _logger.LogInformation( + _logger.LogTrace( "----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})", createOrderDraftCommand.GetGenericTypeName(), nameof(createOrderDraftCommand.BuyerId), diff --git a/src/Services/Ordering/Ordering.API/Dockerfile b/src/Services/Ordering/Ordering.API/Dockerfile index cec7cde61..a4fba1949 100644 --- a/src/Services/Ordering/Ordering.API/Dockerfile +++ b/src/Services/Ordering/Ordering.API/Dockerfile @@ -1,61 +1,26 @@ -FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base +FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base WORKDIR /app EXPOSE 80 -FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build WORKDIR /src -# Keep the project list and command dotnet restore identical in all Dockfiles to maximize image cache utilization -COPY eShopOnContainers-ServicesAndWebApps.sln . -COPY docker-compose.dcproj /src/ -COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/ -COPY src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj src/ApiGateways/Mobile.Bff.Shopping/aggregator/ -COPY src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj src/ApiGateways/Web.Bff.Shopping/aggregator/ -COPY src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj src/BuildingBlocks/Devspaces.Support/ -COPY src/BuildingBlocks/EventBus/EventBus/EventBus.csproj src/BuildingBlocks/EventBus/EventBus/ -COPY src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj src/BuildingBlocks/EventBus/EventBus.Tests/ -COPY src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj src/BuildingBlocks/EventBus/EventBusRabbitMQ/ -COPY src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj src/BuildingBlocks/EventBus/EventBusServiceBus/ -COPY src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj src/BuildingBlocks/EventBus/IntegrationEventLogEF/ -COPY src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj src/BuildingBlocks/WebHostCustomization/WebHost.Customization/ -COPY src/Services/Basket/Basket.API/Basket.API.csproj src/Services/Basket/Basket.API/ -COPY src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj src/Services/Basket/Basket.FunctionalTests/ -COPY src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj src/Services/Basket/Basket.UnitTests/ -COPY src/Services/Catalog/Catalog.API/Catalog.API.csproj src/Services/Catalog/Catalog.API/ -COPY src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj src/Services/Catalog/Catalog.FunctionalTests/ -COPY src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj src/Services/Catalog/Catalog.UnitTests/ -COPY src/Services/Identity/Identity.API/Identity.API.csproj src/Services/Identity/Identity.API/ -COPY src/Services/Location/Locations.API/Locations.API.csproj src/Services/Location/Locations.API/ -COPY src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj src/Services/Location/Locations.FunctionalTests/ -COPY src/Services/Marketing/Marketing.API/Marketing.API.csproj src/Services/Marketing/Marketing.API/ -COPY src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj src/Services/Marketing/Marketing.FunctionalTests/ -COPY src/Services/Ordering/Ordering.API/Ordering.API.csproj src/Services/Ordering/Ordering.API/ -COPY src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj src/Services/Ordering/Ordering.BackgroundTasks/ -COPY src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj src/Services/Ordering/Ordering.Domain/ -COPY src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj src/Services/Ordering/Ordering.FunctionalTests/ -COPY src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj src/Services/Ordering/Ordering.Infrastructure/ -COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/ -COPY src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj src/Services/Ordering/Ordering.UnitTests/ -COPY src/Services/Payment/Payment.API/Payment.API.csproj src/Services/Payment/Payment.API/ -COPY src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj src/Services/Webhooks/Webhooks.API/ -COPY src/Web/WebhookClient/WebhookClient.csproj src/Web/WebhookClient/ -COPY src/Web/WebMVC/WebMVC.csproj src/Web/WebMVC/ -COPY src/Web/WebSPA/WebSPA.csproj src/Web/WebSPA/ -COPY src/Web/WebStatus/WebStatus.csproj src/Web/WebStatus/ -COPY test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj test/ServicesTests/Application.FunctionalTests/ -COPY test/ServicesTests/LoadTest/LoadTest.csproj test/ServicesTests/LoadTest/ +COPY scripts scripts/ -RUN dotnet restore eShopOnContainers-ServicesAndWebApps.sln +COPY ApiGateways/*/*/*.csproj csproj-files/ +COPY BuildingBlocks/*/*/*.csproj csproj-files/ +COPY Services/*/*/*.csproj csproj-files/ +COPY Web/*/*.csproj csproj-files/ COPY . . -WORKDIR /src/src/Services/Ordering/Ordering.API -RUN dotnet publish --no-restore -c Release -o /app +WORKDIR /src/Services/Ordering/Ordering.API +RUN dotnet publish -c Release -o /app FROM build as unittest -WORKDIR /src/src/Services/Ordering/Ordering.UnitTests +WORKDIR /src/Services/Ordering/Ordering.UnitTests FROM build as functionaltest -WORKDIR /src/src/Services/Ordering/Ordering.FunctionalTests +WORKDIR /src/Services/Ordering/Ordering.FunctionalTests FROM build AS publish diff --git a/src/Services/Ordering/Ordering.API/Dockerfile.develop b/src/Services/Ordering/Ordering.API/Dockerfile.develop index f91a71bd8..70fbab4bf 100644 --- a/src/Services/Ordering/Ordering.API/Dockerfile.develop +++ b/src/Services/Ordering/Ordering.API/Dockerfile.develop @@ -1,22 +1,22 @@ -FROM microsoft/dotnet:2.2-sdk +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster ARG BUILD_CONFIGURATION=Debug ENV ASPNETCORE_ENVIRONMENT=Development ENV DOTNET_USE_POLLING_FILE_WATCHER=true EXPOSE 80 WORKDIR /src -COPY ["src/BuildingBlocks/EventBus/EventBus/EventBus.csproj", "src/BuildingBlocks/EventBus/EventBus/"] -COPY ["src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "src/BuildingBlocks/EventBus/EventBusRabbitMQ/"] -COPY ["src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "src/BuildingBlocks/EventBus/EventBusServiceBus/"] -COPY ["src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj", "src/BuildingBlocks/EventBus/IntegrationEventLogEF/"] -COPY ["src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj", "src/BuildingBlocks/WebHostCustomization/WebHost.Customization/"] -COPY ["src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj", "src/Services/Ordering/Ordering.Domain/"] -COPY ["src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj", "src/Services/Ordering/Ordering.Infrastructure/"] -COPY ["src/Services/Ordering/Ordering.API/Ordering.API.csproj", "src/Services/Ordering/Ordering.API/"] +COPY ["BuildingBlocks/EventBus/EventBus/EventBus.csproj", "BuildingBlocks/EventBus/EventBus/"] +COPY ["BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "BuildingBlocks/EventBus/EventBusRabbitMQ/"] +COPY ["BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "BuildingBlocks/EventBus/EventBusServiceBus/"] +COPY ["BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj", "BuildingBlocks/EventBus/IntegrationEventLogEF/"] +COPY ["BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj", "BuildingBlocks/WebHostCustomization/WebHost.Customization/"] +COPY ["Services/Ordering/Ordering.Domain/Ordering.Domain.csproj", "Services/Ordering/Ordering.Domain/"] +COPY ["Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj", "Services/Ordering/Ordering.Infrastructure/"] +COPY ["Services/Ordering/Ordering.API/Ordering.API.csproj", "Services/Ordering/Ordering.API/"] -RUN dotnet restore src/Services/Ordering/Ordering.API/Ordering.API.csproj +RUN dotnet restore Services/Ordering/Ordering.API/Ordering.API.csproj COPY . . -WORKDIR /src/src/Services/Ordering/Ordering.API +WORKDIR /src/Services/Ordering/Ordering.API RUN dotnet build --no-restore -c $BUILD_CONFIGURATION ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"] \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Extensions/BasketItemExtensions.cs b/src/Services/Ordering/Ordering.API/Extensions/BasketItemExtensions.cs index 56f280978..ba2b7e01f 100644 --- a/src/Services/Ordering/Ordering.API/Extensions/BasketItemExtensions.cs +++ b/src/Services/Ordering/Ordering.API/Extensions/BasketItemExtensions.cs @@ -21,7 +21,7 @@ namespace Ordering.API.Application.Models { return new OrderItemDTO() { - ProductId = int.TryParse(item.ProductId, out int id) ? id : -1, + ProductId = item.ProductId, ProductName = item.ProductName, PictureUrl = item.PictureUrl, UnitPrice = item.UnitPrice, diff --git a/src/Services/Ordering/Ordering.API/Grpc/OrderingService.cs b/src/Services/Ordering/Ordering.API/Grpc/OrderingService.cs new file mode 100644 index 000000000..adc210a1a --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Grpc/OrderingService.cs @@ -0,0 +1,92 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Logging; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions; +using MediatR; +using Grpc.Core; +using AppCommand = Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; +using ApiModels = Ordering.API.Application.Models; +using Google.Protobuf.Collections; +using System.Collections.Generic; + +namespace GrpcOrdering +{ + public class OrderingService : OrderingGrpc.OrderingGrpcBase + { + private readonly IMediator _mediator; + private readonly ILogger _logger; + + public OrderingService(IMediator mediator, ILogger logger) + { + _mediator = mediator; + _logger = logger; + } + + public override async Task CreateOrderDraftFromBasketData(CreateOrderDraftCommand createOrderDraftCommand, ServerCallContext context) + { + _logger.LogInformation($"Begin grpc call from method {context.Method} for ordering get order draft {createOrderDraftCommand}"); + _logger.LogTrace( + "----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})", + createOrderDraftCommand.GetGenericTypeName(), + nameof(createOrderDraftCommand.BuyerId), + createOrderDraftCommand.BuyerId, + createOrderDraftCommand); + + var command = new AppCommand.CreateOrderDraftCommand( + createOrderDraftCommand.BuyerId, + this.MapBasketItems(createOrderDraftCommand.Items)); + + + var data = await _mediator.Send(command); + + if (data != null) + { + context.Status = new Status(StatusCode.OK, $" ordering get order draft {createOrderDraftCommand} do exist"); + + return this.MapResponse(data); + } + else + { + context.Status = new Status(StatusCode.NotFound, $" ordering get order draft {createOrderDraftCommand} do not exist"); + } + + return new OrderDraftDTO(); + } + + public OrderDraftDTO MapResponse(AppCommand.OrderDraftDTO order) + { + var result = new OrderDraftDTO() + { + Total = (double)order.Total, + }; + + order.OrderItems.ToList().ForEach(i => result.OrderItems.Add(new OrderItemDTO() + { + Discount = (double)i.Discount, + PictureUrl = i.PictureUrl, + ProductId = i.ProductId, + ProductName = i.ProductName, + UnitPrice = (double)i.UnitPrice, + Units = i.Units, + })); + + return result; + } + + public IEnumerable MapBasketItems(RepeatedField items) + { + return items.Select(x => new ApiModels.BasketItem() + { + Id = x.Id, + ProductId = x.ProductId, + ProductName = x.ProductName, + UnitPrice = (decimal)x.UnitPrice, + OldUnitPrice = (decimal)x.OldUnitPrice, + Quantity = x.Quantity, + PictureUrl = x.PictureUrl, + }); + } + } +} diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/Auth/AuthorizationHeaderParameterOperationFilter.cs b/src/Services/Ordering/Ordering.API/Infrastructure/Auth/AuthorizationHeaderParameterOperationFilter.cs index f780ff4a5..7e30a69fc 100644 --- a/src/Services/Ordering/Ordering.API/Infrastructure/Auth/AuthorizationHeaderParameterOperationFilter.cs +++ b/src/Services/Ordering/Ordering.API/Infrastructure/Auth/AuthorizationHeaderParameterOperationFilter.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc.Authorization; +using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.Swagger; using Swashbuckle.AspNetCore.SwaggerGen; using System.Collections.Generic; @@ -8,7 +9,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Auth { public class AuthorizationHeaderParameterOperationFilter : IOperationFilter { - public void Apply(Operation operation, OperationFilterContext context) + public void Apply(OpenApiOperation operation, OperationFilterContext context) { var filterPipeline = context.ApiDescription.ActionDescriptor.FilterDescriptors; var isAuthorized = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is AuthorizeFilter); @@ -17,17 +18,18 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Auth if (isAuthorized && !allowAnonymous) { if (operation.Parameters == null) - operation.Parameters = new List(); + operation.Parameters = new List(); - operation.Parameters.Add(new NonBodyParameter + + operation.Parameters.Add(new OpenApiParameter { Name = "Authorization", - In = "header", + In = ParameterLocation.Header, Description = "access token", - Required = true, - Type = "string" + Required = true }); } } + } } diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/Factories/OrderingDbContextFactory.cs b/src/Services/Ordering/Ordering.API/Infrastructure/Factories/OrderingDbContextFactory.cs new file mode 100644 index 000000000..a3079b32f --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Infrastructure/Factories/OrderingDbContextFactory.cs @@ -0,0 +1,36 @@ +using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Design; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; + +namespace Ordering.API.Infrastructure.Factories +{ + public class OrderingDbContextFactory : IDesignTimeDbContextFactory + { + public OrderingContext CreateDbContext(string[] args) + { + var config = new ConfigurationBuilder() + .SetBasePath(Path.Combine(Directory.GetCurrentDirectory())) + .AddJsonFile("appsettings.json") + .AddEnvironmentVariables() + .Build(); + + var optionsBuilder = new DbContextOptionsBuilder(); + + optionsBuilder.UseSqlServer(config["ConnectionString"], sqlServerOptionsAction: o => o.MigrationsAssembly("Ordering.API")); + + return new OrderingContext(optionsBuilder.Options); + } + } +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs b/src/Services/Ordering/Ordering.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs index ee0301cc5..34b897a40 100644 --- a/src/Services/Ordering/Ordering.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs +++ b/src/Services/Ordering/Ordering.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs @@ -1,16 +1,14 @@ using Microsoft.AspNetCore.Authorization; -using Swashbuckle.AspNetCore.Swagger; +using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; -using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; namespace Ordering.API.Infrastructure.Filters { public class AuthorizeCheckOperationFilter : IOperationFilter { - public void Apply(Operation operation, OperationFilterContext context) + public void Apply(OpenApiOperation operation, OperationFilterContext context) { // Check for authorize attribute var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType().Any() || @@ -18,16 +16,21 @@ namespace Ordering.API.Infrastructure.Filters if (!hasAuthorize) return; - operation.Responses.TryAdd("401", new Response { Description = "Unauthorized" }); - operation.Responses.TryAdd("403", new Response { Description = "Forbidden" }); + operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" }); + operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" }); - operation.Security = new List>> + var oAuthScheme = new OpenApiSecurityScheme { - new Dictionary> - { - { "oauth2", new [] { "orderingapi" } } - } + Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } }; + + operation.Security = new List + { + new OpenApiSecurityRequirement + { + [ oAuthScheme ] = new [] { "orderingapi" } + } + }; } } } \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20190808132242_Change_Relation_Of_Orders.Designer.cs b/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20190808132242_Change_Relation_Of_Orders.Designer.cs new file mode 100644 index 000000000..c9d553287 --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20190808132242_Change_Relation_Of_Orders.Designer.cs @@ -0,0 +1,252 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; + +namespace Ordering.API.Infrastructure.Migrations +{ + [DbContext(typeof(OrderingContext))] + [Migration("20190808132242_Change_Relation_Of_Orders")] + partial class Change_Relation_Of_Orders + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.0.0-preview7.19362.6") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("Relational:Sequence:.orderitemseq", "'orderitemseq', '', '1', '10', '', '', 'Int64', 'False'") + .HasAnnotation("Relational:Sequence:ordering.buyerseq", "'buyerseq', 'ordering', '1', '10', '', '', 'Int64', 'False'") + .HasAnnotation("Relational:Sequence:ordering.orderseq", "'orderseq', 'ordering', '1', '10', '', '', 'Int64', 'False'") + .HasAnnotation("Relational:Sequence:ordering.paymentseq", "'paymentseq', 'ordering', '1', '10', '', '', 'Int64', 'False'") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:HiLoSequenceName", "buyerseq") + .HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo); + + b.Property("IdentityGuid") + .IsRequired() + .HasMaxLength(200); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("IdentityGuid") + .IsUnique(); + + b.ToTable("buyers","ordering"); + }); + + modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.CardType", b => + { + b.Property("Id") + .HasDefaultValue(1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200); + + b.HasKey("Id"); + + b.ToTable("cardtypes","ordering"); + }); + + modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:HiLoSequenceName", "paymentseq") + .HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo); + + b.Property("Alias") + .IsRequired() + .HasMaxLength(200); + + b.Property("BuyerId"); + + b.Property("CardHolderName") + .IsRequired() + .HasMaxLength(200); + + b.Property("CardNumber") + .IsRequired() + .HasMaxLength(25); + + b.Property("CardTypeId"); + + b.Property("Expiration"); + + b.HasKey("Id"); + + b.HasIndex("BuyerId"); + + b.HasIndex("CardTypeId"); + + b.ToTable("paymentmethods","ordering"); + }); + + modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:HiLoSequenceName", "orderseq") + .HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo); + + b.Property("BuyerId"); + + b.Property("Description"); + + b.Property("OrderDate"); + + b.Property("OrderStatusId"); + + b.Property("PaymentMethodId"); + + b.HasKey("Id"); + + b.HasIndex("BuyerId"); + + b.HasIndex("OrderStatusId"); + + b.HasIndex("PaymentMethodId"); + + b.ToTable("orders","ordering"); + }); + + modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:HiLoSequenceName", "orderitemseq") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo); + + b.Property("Discount"); + + b.Property("OrderId"); + + b.Property("PictureUrl"); + + b.Property("ProductId"); + + b.Property("ProductName") + .IsRequired(); + + b.Property("UnitPrice"); + + b.Property("Units"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.ToTable("orderItems","ordering"); + }); + + modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderStatus", b => + { + b.Property("Id") + .HasDefaultValue(1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200); + + b.HasKey("Id"); + + b.ToTable("orderstatus","ordering"); + }); + + modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency.ClientRequest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Name") + .IsRequired(); + + b.Property("Time"); + + b.HasKey("Id"); + + b.ToTable("requests","ordering"); + }); + + modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", b => + { + b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer", null) + .WithMany("PaymentMethods") + .HasForeignKey("BuyerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.CardType", "CardType") + .WithMany() + .HasForeignKey("CardTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order", b => + { + b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer", null) + .WithMany() + .HasForeignKey("BuyerId"); + + b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderStatus", "OrderStatus") + .WithMany() + .HasForeignKey("OrderStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", null) + .WithMany() + .HasForeignKey("PaymentMethodId") + .OnDelete(DeleteBehavior.Restrict); + + b.OwnsOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", "Address", b1 => + { + b1.Property("OrderId"); + + b1.Property("City"); + + b1.Property("Country"); + + b1.Property("State"); + + b1.Property("Street"); + + b1.Property("ZipCode"); + + b1.HasKey("OrderId"); + + b1.ToTable("orders"); + + b1.WithOwner() + .HasForeignKey("OrderId"); + }); + }); + + modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderItem", b => + { + b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order", null) + .WithMany("OrderItems") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20190808132242_Change_Relation_Of_Orders.cs b/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20190808132242_Change_Relation_Of_Orders.cs new file mode 100644 index 000000000..ba01fdcec --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20190808132242_Change_Relation_Of_Orders.cs @@ -0,0 +1,16 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Ordering.API.Infrastructure.Migrations +{ + public partial class Change_Relation_Of_Orders : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/OrderingContextModelSnapshot.cs b/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/OrderingContextModelSnapshot.cs index fc5e0d1da..ab7951bc7 100644 --- a/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/OrderingContextModelSnapshot.cs +++ b/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/OrderingContextModelSnapshot.cs @@ -1,12 +1,10 @@ // +using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.EntityFrameworkCore.Storage.Internal; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; -using System; namespace Ordering.API.Migrations { @@ -17,7 +15,8 @@ namespace Ordering.API.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "2.0.1-rtm-125") + .HasAnnotation("ProductVersion", "3.0.0-preview7.19362.6") + .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("Relational:Sequence:.orderitemseq", "'orderitemseq', '', '1', '10', '', '', 'Int64', 'False'") .HasAnnotation("Relational:Sequence:ordering.buyerseq", "'buyerseq', 'ordering', '1', '10', '', '', 'Int64', 'False'") .HasAnnotation("Relational:Sequence:ordering.orderseq", "'orderseq', 'ordering', '1', '10', '', '', 'Int64', 'False'") @@ -184,29 +183,32 @@ namespace Ordering.API.Migrations modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", b => { - b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer") + b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer", null) .WithMany("PaymentMethods") .HasForeignKey("BuyerId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.CardType", "CardType") .WithMany() .HasForeignKey("CardTypeId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order", b => { - b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer") + b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer", null) .WithMany() .HasForeignKey("BuyerId"); b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderStatus", "OrderStatus") .WithMany() .HasForeignKey("OrderStatusId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); - b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod") + b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", null) .WithMany() .HasForeignKey("PaymentMethodId") .OnDelete(DeleteBehavior.Restrict); @@ -215,21 +217,32 @@ namespace Ordering.API.Migrations { b1.Property("OrderId"); - b1.ToTable("orders","ordering"); + b1.Property("City"); + + b1.Property("Country"); - b1.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order") - .WithOne("Address") - .HasForeignKey("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", "OrderId") - .OnDelete(DeleteBehavior.Cascade); + b1.Property("State"); + + b1.Property("Street"); + + b1.Property("ZipCode"); + + b1.HasKey("OrderId"); + + b1.ToTable("orders"); + + b1.WithOwner() + .HasForeignKey("OrderId"); }); }); modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderItem", b => { - b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order") + b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order", null) .WithMany("OrderItems") .HasForeignKey("OrderId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); #pragma warning restore 612, 618 } diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/OrderingContextSeed.cs b/src/Services/Ordering/Ordering.API/Infrastructure/OrderingContextSeed.cs index 1e95df7dc..7dcbe194e 100644 --- a/src/Services/Ordering/Ordering.API/Infrastructure/OrderingContextSeed.cs +++ b/src/Services/Ordering/Ordering.API/Infrastructure/OrderingContextSeed.cs @@ -10,6 +10,7 @@ using Microsoft.Extensions.Options; using Ordering.Infrastructure; using Polly; + using Polly.Retry; using System; using System.Collections.Generic; using System.Data.SqlClient; @@ -174,7 +175,7 @@ } - private Policy CreatePolicy( ILogger logger, string prefix, int retries =3) + private AsyncRetryPolicy CreatePolicy( ILogger logger, string prefix, int retries =3) { return Policy.Handle(). WaitAndRetryAsync( diff --git a/src/Services/Ordering/Ordering.API/Ordering.API.csproj b/src/Services/Ordering/Ordering.API/Ordering.API.csproj index ae3c8cad7..e3e5c8767 100644 --- a/src/Services/Ordering/Ordering.API/Ordering.API.csproj +++ b/src/Services/Ordering/Ordering.API/Ordering.API.csproj @@ -1,11 +1,13 @@  - netcoreapp2.2 + $(NetCoreTargetVersion) aspnet-Ordering.API-20161122013547 $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; ..\..\..\..\docker-compose.dcproj - latest + false + true + $(LangVersion) @@ -17,6 +19,13 @@ + + + + + + + @@ -28,36 +37,40 @@ - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + PreserveNewest diff --git a/src/Services/Ordering/Ordering.API/OrderingSettings.cs b/src/Services/Ordering/Ordering.API/OrderingSettings.cs index af38823ae..7459bfd1c 100644 --- a/src/Services/Ordering/Ordering.API/OrderingSettings.cs +++ b/src/Services/Ordering/Ordering.API/OrderingSettings.cs @@ -3,10 +3,13 @@ public class OrderingSettings { public bool UseCustomizationData { get; set; } + public string ConnectionString { get; set; } public string EventBusConnection { get; set; } + public int GracePeriodTime { get; set; } + public int CheckUpdateTime { get; set; } } } diff --git a/src/Services/Ordering/Ordering.API/Program.cs b/src/Services/Ordering/Ordering.API/Program.cs index a0b7dc40e..899871b3d 100644 --- a/src/Services/Ordering/Ordering.API/Program.cs +++ b/src/Services/Ordering/Ordering.API/Program.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF; using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure; using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; @@ -10,6 +11,7 @@ using Microsoft.Extensions.Options; using Serilog; using System; using System.IO; +using System.Net; namespace Microsoft.eShopOnContainers.Services.Ordering.API { @@ -61,6 +63,20 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) => WebHost.CreateDefaultBuilder(args) .CaptureStartupErrors(false) + .ConfigureKestrel(options => + { + var ports = GetDefinedPorts(configuration); + options.Listen(IPAddress.Any, ports.httpPort, listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http1AndHttp2; + }); + + options.Listen(IPAddress.Any, ports.grpcPort, listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http2; + }); + + }) .UseStartup() .UseApplicationInsights() .UseContentRoot(Directory.GetCurrentDirectory()) @@ -68,7 +84,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API .UseSerilog() .Build(); - private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration) + private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration) { var seqServerUrl = configuration["Serilog:SeqServerUrl"]; var logstashUrl = configuration["Serilog:LogstashgUrl"]; @@ -102,5 +118,11 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API return builder.Build(); } + private static (int httpPort, int grpcPort) GetDefinedPorts(IConfiguration config) + { + var grpcPort = config.GetValue("GRPC_PORT", 5001); + var port = config.GetValue("PORT", 80); + return (port, grpcPort); + } } } \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Proto/ordering.proto b/src/Services/Ordering/Ordering.API/Proto/ordering.proto new file mode 100644 index 000000000..77e602c8a --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Proto/ordering.proto @@ -0,0 +1,39 @@ +syntax = "proto3"; + +option csharp_namespace = "GrpcOrdering"; + +package OrderingApi; + +service OrderingGrpc { + rpc CreateOrderDraftFromBasketData(CreateOrderDraftCommand) returns (OrderDraftDTO) {} +} + +message CreateOrderDraftCommand { + string buyerId = 1; + repeated BasketItem items = 2; +} + + +message BasketItem { + string id = 1; + int32 productId = 2; + string productName = 3; + double unitPrice = 4; + double oldUnitPrice = 5; + int32 quantity = 6; + string pictureUrl = 7; +} + +message OrderDraftDTO { + double total = 1; + repeated OrderItemDTO orderItems = 2; +} +message OrderItemDTO { + int32 productId = 1; + string productName = 2; + double unitPrice = 3; + double discount = 4; + int32 units = 5; + string pictureUrl = 6; +} + diff --git a/src/Services/Ordering/Ordering.API/Startup.cs b/src/Services/Ordering/Ordering.API/Startup.cs index 8be92a453..ee4c04641 100644 --- a/src/Services/Ordering/Ordering.API/Startup.cs +++ b/src/Services/Ordering/Ordering.API/Startup.cs @@ -7,13 +7,13 @@ using global::Ordering.API.Application.IntegrationEvents.Events; using global::Ordering.API.Infrastructure.Filters; using global::Ordering.API.Infrastructure.Middlewares; + using GrpcOrdering; + using HealthChecks.UI.Client; using Infrastructure.AutofacModules; using Infrastructure.Filters; using Infrastructure.Services; - using Microsoft.ApplicationInsights.Extensibility; - using Microsoft.ApplicationInsights.ServiceFabric; - using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; + using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.ServiceBus; @@ -24,20 +24,20 @@ using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus; using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF; using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services; + using Microsoft.eShopOnContainers.Services.Ordering.API.Controllers; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; + using Microsoft.OpenApi.Models; using Ordering.Infrastructure; using RabbitMQ.Client; - using Swashbuckle.AspNetCore.Swagger; using System; using System.Collections.Generic; using System.Data.Common; using System.IdentityModel.Tokens.Jwt; + using System.IO; using System.Reflection; - using HealthChecks.UI.Client; - using Microsoft.AspNetCore.Diagnostics.HealthChecks; - using Microsoft.Extensions.Diagnostics.HealthChecks; public class Startup { @@ -48,9 +48,15 @@ public IConfiguration Configuration { get; } - public IServiceProvider ConfigureServices(IServiceCollection services) + public virtual IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddApplicationInsights(Configuration) + services + .AddGrpc(options => + { + options.EnableDetailedErrors = true; + }) + .Services + .AddApplicationInsights(Configuration) .AddCustomMvc() .AddHealthChecks(Configuration) .AddCustomDbContext(Configuration) @@ -59,7 +65,6 @@ .AddCustomConfiguration(Configuration) .AddEventBus(Configuration) .AddCustomAuthentication(Configuration); - //configure autofac var container = new ContainerBuilder(); @@ -72,7 +77,7 @@ } - public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) { //loggerFactory.AddAzureWebAppDiagnostics(); //loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace); @@ -86,21 +91,39 @@ app.UseCors("CorsPolicy"); - app.UseHealthChecks("/liveness", new HealthCheckOptions - { - Predicate = r => r.Name.Contains("self") - }); + app.UseRouting(); + ConfigureAuth(app); - app.UseHealthChecks("/hc", new HealthCheckOptions() + app.UseEndpoints(endpoints => { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + endpoints.MapGrpcService(); + endpoints.MapDefaultControllerRoute(); + endpoints.MapControllers(); + endpoints.MapGet("/_proto/", async ctx => + { + ctx.Response.ContentType = "text/plain"; + using var fs = new FileStream(Path.Combine(env.ContentRootPath, "Proto", "basket.proto"), FileMode.Open, FileAccess.Read); + using var sr = new StreamReader(fs); + while (!sr.EndOfStream) + { + var line = await sr.ReadLineAsync(); + if (line != "/* >>" || line != "<< */") + { + await ctx.Response.WriteAsync(line); + } + } + }); + endpoints.MapHealthChecks("/hc", new HealthCheckOptions() + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + endpoints.MapHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = r => r.Name.Contains("self") + }); }); - ConfigureAuth(app); - - app.UseMvcWithDefaultRoute(); - app.UseSwagger() .UseSwaggerUI(c => { @@ -133,6 +156,7 @@ } app.UseAuthentication(); + app.UseAuthorization(); } } @@ -141,19 +165,7 @@ public static IServiceCollection AddApplicationInsights(this IServiceCollection services, IConfiguration configuration) { services.AddApplicationInsightsTelemetry(configuration); - var orchestratorType = configuration.GetValue("OrchestratorType"); - - if (orchestratorType?.ToUpper() == "K8S") - { - // Enable K8s telemetry initializer - services.AddApplicationInsightsKubernetesEnricher(); - } - if (orchestratorType?.ToUpper() == "SF") - { - // Enable SF telemetry initializer - services.AddSingleton((serviceProvider) => - new FabricTelemetryInitializer()); - } + services.AddApplicationInsightsKubernetesEnricher(); return services; } @@ -161,13 +173,15 @@ public static IServiceCollection AddCustomMvc(this IServiceCollection services) { // Add framework services. - services.AddMvc(options => + services.AddControllers(options => { options.Filters.Add(typeof(HttpGlobalExceptionFilter)); }) - .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) - .AddControllersAsServices(); //Injecting Controllers themselves thru DI - //For further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services + // Added for functional tests + .AddApplicationPart(typeof(OrdersController).Assembly) + .AddNewtonsoftJson() + .SetCompatibilityVersion(CompatibilityVersion.Version_3_0) + ; services.AddCors(options => { @@ -224,7 +238,7 @@ sqlServerOptionsAction: sqlOptions => { sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); - sqlOptions.EnableRetryOnFailure(maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); + sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); }); }, ServiceLifetime.Scoped //Showing explicitly that the DbContext is shared across the HTTP request scope (graph of objects started in the HTTP request) @@ -237,7 +251,7 @@ { sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); //Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency - sqlOptions.EnableRetryOnFailure(maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); + sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); }); }); @@ -249,23 +263,26 @@ services.AddSwaggerGen(options => { options.DescribeAllEnumsAsStrings(); - options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info + options.SwaggerDoc("v1", new OpenApiInfo { - Title = "Ordering HTTP API", + Title = "eShopOnContainers - Ordering HTTP API", Version = "v1", - Description = "The Ordering Service HTTP API", - TermsOfService = "Terms Of Service" + Description = "The Ordering Service HTTP API" }); - - options.AddSecurityDefinition("oauth2", new OAuth2Scheme + options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme { - Type = "oauth2", - Flow = "implicit", - AuthorizationUrl = $"{configuration.GetValue("IdentityUrlExternal")}/connect/authorize", - TokenUrl = $"{configuration.GetValue("IdentityUrlExternal")}/connect/token", - Scopes = new Dictionary() + Type = SecuritySchemeType.OAuth2, + Flows = new OpenApiOAuthFlows() { - { "orders", "Ordering API" } + Implicit = new OpenApiOAuthFlow() + { + AuthorizationUrl = new Uri($"{configuration.GetValue("IdentityUrlExternal")}/connect/authorize"), + TokenUrl = new Uri($"{configuration.GetValue("IdentityUrlExternal")}/connect/token"), + Scopes = new Dictionary() + { + { "orders", "Ordering API" } + } + } } }); @@ -407,8 +424,8 @@ services.AddAuthentication(options => { - options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultAuthenticateScheme = AspNetCore.Authentication.JwtBearer.JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = AspNetCore.Authentication.JwtBearer.JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(options => { diff --git a/src/Services/Ordering/Ordering.API/appsettings.json b/src/Services/Ordering/Ordering.API/appsettings.json index f74c312b1..4ef8f6ac4 100644 --- a/src/Services/Ordering/Ordering.API/appsettings.json +++ b/src/Services/Ordering/Ordering.API/appsettings.json @@ -16,6 +16,7 @@ }, "AzureServiceBusEnabled": false, "SubscriptionClientName": "Ordering", + "GracePeriodTime": "1", "CheckUpdateTime": "30000", "ApplicationInsights": { "InstrumentationKey": "" diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/Configuration/BackgroundTaskSettings.cs b/src/Services/Ordering/Ordering.BackgroundTasks/BackgroundTaskSettings.cs similarity index 73% rename from src/Services/Ordering/Ordering.BackgroundTasks/Configuration/BackgroundTaskSettings.cs rename to src/Services/Ordering/Ordering.BackgroundTasks/BackgroundTaskSettings.cs index 2b42f6084..5171e7724 100644 --- a/src/Services/Ordering/Ordering.BackgroundTasks/Configuration/BackgroundTaskSettings.cs +++ b/src/Services/Ordering/Ordering.BackgroundTasks/BackgroundTaskSettings.cs @@ -1,4 +1,4 @@ -namespace Ordering.BackgroundTasks.Configuration +namespace Ordering.BackgroundTasks { public class BackgroundTaskSettings { @@ -9,5 +9,7 @@ public int GracePeriodTime { get; set; } public int CheckUpdateTime { get; set; } + + public string SubscriptionClientName { get; set; } } } diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile b/src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile index ce0aeacde..dfbab9484 100644 --- a/src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile +++ b/src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile @@ -1,55 +1,21 @@ -FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base +FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base WORKDIR /app EXPOSE 80 -FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build WORKDIR /src -# Keep the project list and command dotnet restore identical in all Dockfiles to maximize image cache utilization -COPY eShopOnContainers-ServicesAndWebApps.sln . -COPY docker-compose.dcproj /src/ -COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/ -COPY src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj src/ApiGateways/Mobile.Bff.Shopping/aggregator/ -COPY src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj src/ApiGateways/Web.Bff.Shopping/aggregator/ -COPY src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj src/BuildingBlocks/Devspaces.Support/ -COPY src/BuildingBlocks/EventBus/EventBus/EventBus.csproj src/BuildingBlocks/EventBus/EventBus/ -COPY src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj src/BuildingBlocks/EventBus/EventBus.Tests/ -COPY src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj src/BuildingBlocks/EventBus/EventBusRabbitMQ/ -COPY src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj src/BuildingBlocks/EventBus/EventBusServiceBus/ -COPY src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj src/BuildingBlocks/EventBus/IntegrationEventLogEF/ -COPY src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj src/BuildingBlocks/WebHostCustomization/WebHost.Customization/ -COPY src/Services/Basket/Basket.API/Basket.API.csproj src/Services/Basket/Basket.API/ -COPY src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj src/Services/Basket/Basket.FunctionalTests/ -COPY src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj src/Services/Basket/Basket.UnitTests/ -COPY src/Services/Catalog/Catalog.API/Catalog.API.csproj src/Services/Catalog/Catalog.API/ -COPY src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj src/Services/Catalog/Catalog.FunctionalTests/ -COPY src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj src/Services/Catalog/Catalog.UnitTests/ -COPY src/Services/Identity/Identity.API/Identity.API.csproj src/Services/Identity/Identity.API/ -COPY src/Services/Location/Locations.API/Locations.API.csproj src/Services/Location/Locations.API/ -COPY src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj src/Services/Location/Locations.FunctionalTests/ -COPY src/Services/Marketing/Marketing.API/Marketing.API.csproj src/Services/Marketing/Marketing.API/ -COPY src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj src/Services/Marketing/Marketing.FunctionalTests/ -COPY src/Services/Ordering/Ordering.API/Ordering.API.csproj src/Services/Ordering/Ordering.API/ -COPY src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj src/Services/Ordering/Ordering.BackgroundTasks/ -COPY src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj src/Services/Ordering/Ordering.Domain/ -COPY src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj src/Services/Ordering/Ordering.FunctionalTests/ -COPY src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj src/Services/Ordering/Ordering.Infrastructure/ -COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/ -COPY src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj src/Services/Ordering/Ordering.UnitTests/ -COPY src/Services/Payment/Payment.API/Payment.API.csproj src/Services/Payment/Payment.API/ -COPY src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj src/Services/Webhooks/Webhooks.API/ -COPY src/Web/WebhookClient/WebhookClient.csproj src/Web/WebhookClient/ -COPY src/Web/WebMVC/WebMVC.csproj src/Web/WebMVC/ -COPY src/Web/WebSPA/WebSPA.csproj src/Web/WebSPA/ -COPY src/Web/WebStatus/WebStatus.csproj src/Web/WebStatus/ -COPY test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj test/ServicesTests/Application.FunctionalTests/ -COPY test/ServicesTests/LoadTest/LoadTest.csproj test/ServicesTests/LoadTest/ +COPY scripts scripts/ + +COPY ApiGateways/*/*/*.csproj csproj-files/ +COPY BuildingBlocks/*/*/*.csproj csproj-files/ +COPY Services/*/*/*.csproj csproj-files/ +COPY Web/*/*.csproj csproj-files/ -RUN dotnet restore eShopOnContainers-ServicesAndWebApps.sln COPY . . -WORKDIR /src/src/Services/Ordering/Ordering.BackgroundTasks -RUN dotnet publish --no-restore -c Release -o /app +WORKDIR /src/Services/Ordering/Ordering.BackgroundTasks +RUN dotnet publish -c Release -o /app FROM build AS publish diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile.develop b/src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile.develop deleted file mode 100644 index 5f5d002db..000000000 --- a/src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile.develop +++ /dev/null @@ -1,18 +0,0 @@ -FROM microsoft/dotnet:2.2-sdk -ARG BUILD_CONFIGURATION=Debug -ENV ASPNETCORE_ENVIRONMENT=Development -ENV DOTNET_USE_POLLING_FILE_WATCHER=true -EXPOSE 80 - -WORKDIR /src -COPY ["src/BuildingBlocks/EventBus/EventBus/EventBus.csproj", "src/BuildingBlocks/EventBus/EventBus/"] -COPY ["src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "src/BuildingBlocks/EventBus/EventBusRabbitMQ/"] -COPY ["src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "src/BuildingBlocks/EventBus/EventBusServiceBus/"] -COPY ["src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj", "src/Services/Ordering/Ordering.BackgroundTasks/"] - -RUN dotnet restore src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj -COPY . . -WORKDIR /src/src/Services/Ordering/Ordering.BackgroundTasks -RUN dotnet build --no-restore -c $BUILD_CONFIGURATION - -ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"] \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/IntegrationEvents/GracePeriodConfirmedIntegrationEvent.cs b/src/Services/Ordering/Ordering.BackgroundTasks/Events/GracePeriodConfirmedIntegrationEvent.cs similarity index 64% rename from src/Services/Ordering/Ordering.BackgroundTasks/IntegrationEvents/GracePeriodConfirmedIntegrationEvent.cs rename to src/Services/Ordering/Ordering.BackgroundTasks/Events/GracePeriodConfirmedIntegrationEvent.cs index df008ad90..8fe92df76 100644 --- a/src/Services/Ordering/Ordering.BackgroundTasks/IntegrationEvents/GracePeriodConfirmedIntegrationEvent.cs +++ b/src/Services/Ordering/Ordering.BackgroundTasks/Events/GracePeriodConfirmedIntegrationEvent.cs @@ -1,7 +1,7 @@ -using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; - -namespace Ordering.BackgroundTasks.IntegrationEvents +namespace Ordering.BackgroundTasks.Events { + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + public class GracePeriodConfirmedIntegrationEvent : IntegrationEvent { public int OrderId { get; } diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/Extensions/CustomExtensionMethods.cs b/src/Services/Ordering/Ordering.BackgroundTasks/Extensions/CustomExtensionMethods.cs new file mode 100644 index 000000000..751ae71ee --- /dev/null +++ b/src/Services/Ordering/Ordering.BackgroundTasks/Extensions/CustomExtensionMethods.cs @@ -0,0 +1,142 @@ +using Autofac; +using Microsoft.Azure.ServiceBus; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Microsoft.Extensions.Logging; +using RabbitMQ.Client; +using Serilog; + +namespace Ordering.BackgroundTasks.Extensions +{ + public static class CustomExtensionMethods + { + public static IServiceCollection AddCustomHealthCheck(this IServiceCollection services, IConfiguration configuration) + { + var hcBuilder = services.AddHealthChecks(); + + hcBuilder.AddCheck("self", () => HealthCheckResult.Healthy()); + + hcBuilder.AddSqlServer( + configuration["ConnectionString"], + name: "OrderingTaskDB-check", + tags: new string[] { "orderingtaskdb" }); + + if (configuration.GetValue("AzureServiceBusEnabled")) + { + hcBuilder.AddAzureServiceBusTopic( + configuration["EventBusConnection"], + topicName: "eshop_event_bus", + name: "orderingtask-servicebus-check", + tags: new string[] { "servicebus" }); + } + else + { + hcBuilder.AddRabbitMQ( + $"amqp://{configuration["EventBusConnection"]}", + name: "orderingtask-rabbitmqbus-check", + tags: new string[] { "rabbitmqbus" }); + } + + return services; + } + + public static IServiceCollection AddEventBus(this IServiceCollection services, IConfiguration configuration) + { + var subscriptionClientName = configuration["SubscriptionClientName"]; + + if (configuration.GetValue("AzureServiceBusEnabled")) + { + services.AddSingleton(sp => + { + var logger = sp.GetRequiredService>(); + + var serviceBusConnectionString = configuration["EventBusConnection"]; + var serviceBusConnection = new ServiceBusConnectionStringBuilder(serviceBusConnectionString); + + return new DefaultServiceBusPersisterConnection(serviceBusConnection, logger); + }); + + services.AddSingleton(sp => + { + var serviceBusPersisterConnection = sp.GetRequiredService(); + var iLifetimeScope = sp.GetRequiredService(); + var logger = sp.GetRequiredService>(); + var eventBusSubcriptionsManager = sp.GetRequiredService(); + + return new EventBusServiceBus(serviceBusPersisterConnection, logger, eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); + }); + } + else + { + services.AddSingleton(sp => + { + var logger = sp.GetRequiredService>(); + + var factory = new ConnectionFactory() + { + HostName = configuration["EventBusConnection"], + DispatchConsumersAsync = true + }; + + if (!string.IsNullOrEmpty(configuration["EventBusUserName"])) + { + factory.UserName = configuration["EventBusUserName"]; + } + + if (!string.IsNullOrEmpty(configuration["EventBusPassword"])) + { + factory.Password = configuration["EventBusPassword"]; + } + + var retryCount = 5; + + if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"])) + { + retryCount = int.Parse(configuration["EventBusRetryCount"]); + } + + return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount); + }); + + services.AddSingleton(sp => + { + var rabbitMQPersistentConnection = sp.GetRequiredService(); + var iLifetimeScope = sp.GetRequiredService(); + var logger = sp.GetRequiredService>(); + var eventBusSubcriptionsManager = sp.GetRequiredService(); + + var retryCount = 5; + + if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"])) + { + retryCount = int.Parse(configuration["EventBusRetryCount"]); + } + + return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount); + }); + } + + services.AddSingleton(); + + return services; + } + + public static ILoggingBuilder UseSerilog(this ILoggingBuilder builder, IConfiguration configuration) + { + Log.Logger = new LoggerConfiguration() + .MinimumLevel.Verbose() + .Enrich.WithProperty("ApplicationContext", "BackgroundTasks") + .Enrich.FromLogContext() + .WriteTo.Console() + .ReadFrom.Configuration(configuration) + .CreateLogger(); + + return builder; + } + } +} diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj b/src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj index 219f1f1c2..5e9a6eb83 100644 --- a/src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj +++ b/src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj @@ -1,34 +1,32 @@ - + - netcoreapp2.2 - $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; - ..\..\..\..\docker-compose.dcproj + $(NetCoreTargetVersion) + dotnet-Ordering.BackgroundTasks-9D3E1DD6-405B-447F-8AAB-1708B36D260E + false + Linux + $(LangVersion) - - - - - - - - - - + + + - - - - - - - - - - - + + + + + + + + + + + + + + @@ -36,5 +34,4 @@ - diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/Program.cs b/src/Services/Ordering/Ordering.BackgroundTasks/Program.cs index 7a429742e..152cd79a7 100644 --- a/src/Services/Ordering/Ordering.BackgroundTasks/Program.cs +++ b/src/Services/Ordering/Ordering.BackgroundTasks/Program.cs @@ -1,76 +1,35 @@ -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; +using Autofac.Extensions.DependencyInjection; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Ordering.BackgroundTasks.Extensions; +using Ordering.BackgroundTasks.Tasks; using Serilog; -using System; using System.IO; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; namespace Ordering.BackgroundTasks { public class Program { - public static readonly string Namespace = typeof(Program).Namespace; - public static readonly string AppName = Namespace; - - public static int Main(string[] args) + public static void Main(string[] args) { - var configuration = GetConfiguration(); - - Log.Logger = CreateSerilogLogger(configuration); - - try - { - Log.Information("Configuring web host ({ApplicationContext})...", AppName); - var host = BuildWebHost(configuration, args); - - Log.Information("Starting web host ({ApplicationContext})...", AppName); - host.Run(); - - return 0; - } - catch (Exception ex) - { - Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName); - return 1; - } - finally - { - Log.CloseAndFlush(); - } + CreateHostBuilder(args).Run(); } - private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) => - WebHost.CreateDefaultBuilder(args) - .CaptureStartupErrors(false) + public static IWebHost CreateHostBuilder(string[] args) => + WebHost.CreateDefaultBuilder(args) + .ConfigureAppConfiguration((host, builder) => + { + builder.SetBasePath(Directory.GetCurrentDirectory()); + builder.AddJsonFile("appsettings.json", optional: true); + builder.AddJsonFile($"appsettings.{host.HostingEnvironment.EnvironmentName}.json", optional: true); + builder.AddEnvironmentVariables(); + builder.AddCommandLine(args); + }) + .ConfigureLogging((host, builder) => builder.UseSerilog(host.Configuration).AddSerilog()) .UseStartup() - .UseConfiguration(configuration) - .UseSerilog() .Build(); - - private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration) - { - var seqServerUrl = configuration["Serilog:SeqServerUrl"]; - var logstashUrl = configuration["Serilog:LogstashgUrl"]; - return new LoggerConfiguration() - .MinimumLevel.Verbose() - .Enrich.WithProperty("ApplicationContext", AppName) - .Enrich.FromLogContext() - .WriteTo.Console() - .WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl) - .WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://logstash:8080" : logstashUrl) - .ReadFrom.Configuration(configuration) - .CreateLogger(); - } - - private static IConfiguration GetConfiguration() - { - var builder = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) - .AddEnvironmentVariables(); - - return builder.Build(); - } } } diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/Properties/launchSettings.json b/src/Services/Ordering/Ordering.BackgroundTasks/Properties/launchSettings.json index 6d60a7d28..e2d987f50 100644 --- a/src/Services/Ordering/Ordering.BackgroundTasks/Properties/launchSettings.json +++ b/src/Services/Ordering/Ordering.BackgroundTasks/Properties/launchSettings.json @@ -1,29 +1,13 @@ { - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:5161/", - "sslPort": 0 - } - }, "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "launchUrl": "api/values", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, "Ordering.BackgroundTasks": { "commandName": "Project", - "launchBrowser": true, - "launchUrl": "api/values", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "http://localhost:5162/" + "DOTNET_ENVIRONMENT": "Development" + } + }, + "Docker": { + "commandName": "Docker" } } -} +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/Startup.cs b/src/Services/Ordering/Ordering.BackgroundTasks/Startup.cs index 9d6a78e38..1f35b711c 100644 --- a/src/Services/Ordering/Ordering.BackgroundTasks/Startup.cs +++ b/src/Services/Ordering/Ordering.BackgroundTasks/Startup.cs @@ -1,26 +1,17 @@ -using Autofac; -using Autofac.Extensions.DependencyInjection; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Azure.ServiceBus; -using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; -using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; -using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; -using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Ordering.BackgroundTasks.Configuration; -using Ordering.BackgroundTasks.Tasks; -using RabbitMQ.Client; -using System; -using HealthChecks.UI.Client; -using Microsoft.AspNetCore.Diagnostics.HealthChecks; -using Microsoft.Extensions.Diagnostics.HealthChecks; - -namespace Ordering.BackgroundTasks +namespace Ordering.BackgroundTasks { + using Autofac; + using Autofac.Extensions.DependencyInjection; + using Microsoft.AspNetCore.Builder; + using Microsoft.AspNetCore.Diagnostics.HealthChecks; + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Logging; + using Ordering.BackgroundTasks.Extensions; + using Ordering.BackgroundTasks.Tasks; + using System; + using HealthChecks.UI.Client; + public class Startup { public Startup(IConfiguration configuration) @@ -30,168 +21,37 @@ namespace Ordering.BackgroundTasks public IConfiguration Configuration { get; } - // This method gets called by the runtime. Use this method to add services to the container. - public IServiceProvider ConfigureServices(IServiceCollection services) + public virtual IServiceProvider ConfigureServices(IServiceCollection services) { - //add health check for this service - services.AddCustomHealthCheck(Configuration); - - //configure settings - - services.Configure(Configuration); - services.AddOptions(); - - //configure background task - - services.AddSingleton(); - - //configure event bus related services - - if (Configuration.GetValue("AzureServiceBusEnabled")) - { - services.AddSingleton(sp => - { - var logger = sp.GetRequiredService>(); - - var serviceBusConnectionString = Configuration["EventBusConnection"]; - var serviceBusConnection = new ServiceBusConnectionStringBuilder(serviceBusConnectionString); - - return new DefaultServiceBusPersisterConnection(serviceBusConnection, logger); - }); - } - else - { - services.AddSingleton(sp => - { - var logger = sp.GetRequiredService>(); - - - var factory = new ConnectionFactory() - { - HostName = Configuration["EventBusConnection"], - DispatchConsumersAsync = true - }; - - if (!string.IsNullOrEmpty(Configuration["EventBusUserName"])) - { - factory.UserName = Configuration["EventBusUserName"]; - } - - if (!string.IsNullOrEmpty(Configuration["EventBusPassword"])) - { - factory.Password = Configuration["EventBusPassword"]; - } - - var retryCount = 5; - if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"])) - { - retryCount = int.Parse(Configuration["EventBusRetryCount"]); - } + services.AddCustomHealthCheck(this.Configuration) + .Configure(this.Configuration) + .AddOptions() + .AddHostedService() + .AddEventBus(this.Configuration) + .AddAutofac(container => container.Populate(services)); - return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount); - }); - } - - RegisterEventBus(services); - - //create autofac based service provider var container = new ContainerBuilder(); container.Populate(services); - return new AutofacServiceProvider(container.Build()); } - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app) + public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { - app.UseHealthChecks("/hc", new HealthCheckOptions() + app.UseRouting(); + app.UseEndpoints(endpoints => { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - - app.UseHealthChecks("/liveness", new HealthCheckOptions - { - Predicate = r => r.Name.Contains("self") - }); - } - - - private void RegisterEventBus(IServiceCollection services) - { - var subscriptionClientName = Configuration["SubscriptionClientName"]; - - if (Configuration.GetValue("AzureServiceBusEnabled")) - { - services.AddSingleton(sp => + endpoints.MapHealthChecks("/hc", new HealthCheckOptions() { - var serviceBusPersisterConnection = sp.GetRequiredService(); - var iLifetimeScope = sp.GetRequiredService(); - var logger = sp.GetRequiredService>(); - var eventBusSubcriptionsManager = sp.GetRequiredService(); - - return new EventBusServiceBus(serviceBusPersisterConnection, logger, - eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse }); - } - else - { - services.AddSingleton(sp => + endpoints.MapHealthChecks("/liveness", new HealthCheckOptions { - var rabbitMQPersistentConnection = sp.GetRequiredService(); - var iLifetimeScope = sp.GetRequiredService(); - var logger = sp.GetRequiredService>(); - var eventBusSubcriptionsManager = sp.GetRequiredService(); - - var retryCount = 5; - if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"])) - { - retryCount = int.Parse(Configuration["EventBusRetryCount"]); - } - - return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount); + Predicate = r => r.Name.Contains("self") }); - } - - services.AddSingleton(); - } - } - - public static class CustomExtensionMethods - { - public static IServiceCollection AddCustomHealthCheck(this IServiceCollection services, IConfiguration configuration) - { - var hcBuilder = services.AddHealthChecks(); - - hcBuilder.AddCheck("self", () => HealthCheckResult.Healthy()); - - hcBuilder - .AddSqlServer( - configuration["ConnectionString"], - name: "OrderingTaskDB-check", - tags: new string[] { "orderingtaskdb" }); - - if (configuration.GetValue("AzureServiceBusEnabled")) - { - hcBuilder - .AddAzureServiceBusTopic( - configuration["EventBusConnection"], - topicName: "eshop_event_bus", - name: "orderingtask-servicebus-check", - tags: new string[] { "servicebus" }); - } - else - { - hcBuilder - .AddRabbitMQ( - $"amqp://{configuration["EventBusConnection"]}", - name: "orderingtask-rabbitmqbus-check", - tags: new string[] { "rabbitmqbus" }); - } - - return services; + }); } } } diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/Tasks/GracePeriodManagerTask.cs b/src/Services/Ordering/Ordering.BackgroundTasks/Tasks/GracePeriodManagerTask.cs index 328fb95c4..f70fdeb06 100644 --- a/src/Services/Ordering/Ordering.BackgroundTasks/Tasks/GracePeriodManagerTask.cs +++ b/src/Services/Ordering/Ordering.BackgroundTasks/Tasks/GracePeriodManagerTask.cs @@ -3,8 +3,7 @@ using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Ordering.BackgroundTasks.Configuration; -using Ordering.BackgroundTasks.IntegrationEvents; +using Ordering.BackgroundTasks.Events; using System; using System.Collections.Generic; using System.Data.SqlClient; @@ -13,22 +12,17 @@ using System.Threading.Tasks; namespace Ordering.BackgroundTasks.Tasks { - public class GracePeriodManagerService - : BackgroundService + public class GracePeriodManagerService : BackgroundService { private readonly ILogger _logger; private readonly BackgroundTaskSettings _settings; private readonly IEventBus _eventBus; - public GracePeriodManagerService( - IOptions settings, - IEventBus eventBus, - ILogger logger) + public GracePeriodManagerService(IOptions settings, IEventBus eventBus, ILogger logger) { _settings = settings?.Value ?? throw new ArgumentNullException(nameof(settings)); _eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - } protected override async Task ExecuteAsync(CancellationToken stoppingToken) @@ -61,8 +55,6 @@ namespace Ordering.BackgroundTasks.Tasks { var confirmGracePeriodEvent = new GracePeriodConfirmedIntegrationEvent(orderId); - _logger.LogInformation("----- Publishing integration event: {IntegrationEventId} from {AppName} - ({@IntegrationEvent})", confirmGracePeriodEvent.Id, Program.AppName, confirmGracePeriodEvent); - _eventBus.Publish(confirmGracePeriodEvent); } } @@ -80,7 +72,7 @@ namespace Ordering.BackgroundTasks.Tasks @"SELECT Id FROM [ordering].[orders] WHERE DATEDIFF(minute, [OrderDate], GETDATE()) >= @GracePeriodTime AND [OrderStatusId] = 1", - new { GracePeriodTime = _settings.GracePeriodTime }); + new { _settings.GracePeriodTime }); } catch (SqlException exception) { diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/appsettings.Development.json b/src/Services/Ordering/Ordering.BackgroundTasks/appsettings.Development.json index fa8ce71a9..e203e9407 100644 --- a/src/Services/Ordering/Ordering.BackgroundTasks/appsettings.Development.json +++ b/src/Services/Ordering/Ordering.BackgroundTasks/appsettings.Development.json @@ -1,6 +1,5 @@ -{ +{ "Logging": { - "IncludeScopes": false, "LogLevel": { "Default": "Debug", "System": "Information", diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/appsettings.json b/src/Services/Ordering/Ordering.BackgroundTasks/appsettings.json index 51250be9d..88e5d6858 100644 --- a/src/Services/Ordering/Ordering.BackgroundTasks/appsettings.json +++ b/src/Services/Ordering/Ordering.BackgroundTasks/appsettings.json @@ -1,4 +1,4 @@ -{ +{ "ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;", "Serilog": { "SeqServerUrl": null, diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/azds.yaml b/src/Services/Ordering/Ordering.BackgroundTasks/azds.yaml deleted file mode 100644 index e92eca09f..000000000 --- a/src/Services/Ordering/Ordering.BackgroundTasks/azds.yaml +++ /dev/null @@ -1,56 +0,0 @@ -kind: helm-release -apiVersion: 1.1 -build: - context: ..\..\..\.. - dockerfile: Dockerfile -install: - chart: ../../../../k8s/helm/ordering-backgroundtasks - set: - replicaCount: 1 - image: - tag: $(tag) - pullPolicy: Never - ingress: - annotations: - kubernetes.io/ingress.class: traefik-azds - hosts: - - $(spacePrefix)eshop$(hostSuffix) - inf: - k8s: - dns: $(spacePrefix)eshop$(hostSuffix) - values: - - values.dev.yaml? - - secrets.dev.yaml? - - inf.yaml - - app.yaml -configurations: - develop: - build: - useGitIgnore: true - dockerfile: Dockerfile.develop - args: - BUILD_CONFIGURATION: ${BUILD_CONFIGURATION:-Debug} - container: - sync: - - '**/Pages/**' - - '**/Views/**' - - '**/wwwroot/**' - - '!**/*.{sln,csproj}' - command: - - dotnet - - run - - --no-restore - - --no-build - - --no-launch-profile - - -c - - ${BUILD_CONFIGURATION:-Debug} - iterate: - processesToKill: - - dotnet - - vsdbg - buildCommands: - - - dotnet - - build - - --no-restore - - -c - - ${BUILD_CONFIGURATION:-Debug} diff --git a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Address.cs b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Address.cs index 9576940df..b552f5546 100644 --- a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Address.cs +++ b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Address.cs @@ -12,7 +12,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O public String Country { get; private set; } public String ZipCode { get; private set; } - private Address() { } + public Address() { } public Address(string street, string city, string state, string country, string zipcode) { diff --git a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs index 7da025d3a..b5639ac50 100644 --- a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs +++ b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs @@ -18,7 +18,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O // Address is a Value Object pattern example persisted as EF Core 2.0 owned entity public Address Address { get; private set; } - public int? GetBuyerId => _buyerId; + public int? GetBuyerId { get { return this._buyerId; } } private int? _buyerId; public OrderStatus OrderStatus { get; private set; } @@ -26,7 +26,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O private string _description; - + // Draft orders have this set to true. Currently we don't check anywhere the draft status of an Order, but we could do it if needed private bool _isDraft; @@ -46,7 +46,8 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O return order; } - protected Order() { + protected Order() + { _orderItems = new List(); _isDraft = false; } diff --git a/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj b/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj index 177dda0f9..0574427f0 100644 --- a/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj +++ b/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj @@ -1,13 +1,13 @@  - netstandard2.0 + $(NetStandardTargetVersion) - - - + + + diff --git a/src/Services/Ordering/Ordering.FunctionalTests/AutoAuthorizeMiddleware.cs b/src/Services/Ordering/Ordering.FunctionalTests/AutoAuthorizeMiddleware.cs index 5b7d4301e..a1f77b75d 100644 --- a/src/Services/Ordering/Ordering.FunctionalTests/AutoAuthorizeMiddleware.cs +++ b/src/Services/Ordering/Ordering.FunctionalTests/AutoAuthorizeMiddleware.cs @@ -21,6 +21,7 @@ namespace Ordering.FunctionalTests identity.AddClaim(new Claim("sub", IDENTITY_ID)); identity.AddClaim(new Claim("unique_name", IDENTITY_ID)); + identity.AddClaim(new Claim(ClaimTypes.Name, IDENTITY_ID)); httpContext.User.AddIdentity(identity); diff --git a/src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj b/src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj index 375a292fc..05668125f 100644 --- a/src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj +++ b/src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj @@ -1,7 +1,7 @@  - netcoreapp2.2 + $(NetCoreTargetVersion) false @@ -17,11 +17,9 @@ - - - - - + + + all runtime; build; native; contentfiles; analyzers diff --git a/src/Services/Ordering/Ordering.FunctionalTests/OrderingTestStartup.cs b/src/Services/Ordering/Ordering.FunctionalTests/OrderingTestStartup.cs index d68dd7c3a..9d1975cb7 100644 --- a/src/Services/Ordering/Ordering.FunctionalTests/OrderingTestStartup.cs +++ b/src/Services/Ordering/Ordering.FunctionalTests/OrderingTestStartup.cs @@ -1,6 +1,9 @@ -using Microsoft.AspNetCore.Builder; +using System; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Routing; using Microsoft.eShopOnContainers.Services.Ordering.API; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; namespace Ordering.FunctionalTests { @@ -10,6 +13,13 @@ namespace Ordering.FunctionalTests { } + public override IServiceProvider ConfigureServices(IServiceCollection services) + { + // Added to avoid the Authorize data annotation in test environment. + // Property "SuppressCheckForUnhandledSecurityMetadata" in appsettings.json + services.Configure(Configuration); + return base.ConfigureServices(services); + } protected override void ConfigureAuth(IApplicationBuilder app) { if (Configuration["isTest"] == bool.TrueString.ToLowerInvariant()) diff --git a/src/Services/Ordering/Ordering.FunctionalTests/appsettings.json b/src/Services/Ordering/Ordering.FunctionalTests/appsettings.json index 70f1af3c0..07bb1638a 100644 --- a/src/Services/Ordering/Ordering.FunctionalTests/appsettings.json +++ b/src/Services/Ordering/Ordering.FunctionalTests/appsettings.json @@ -6,5 +6,6 @@ "EventBusConnection": "localhost", "CheckUpdateTime": "30000", "GracePeriodTime": "1", - "SubscriptionClientName": "Ordering" + "SubscriptionClientName": "Ordering", + "SuppressCheckForUnhandledSecurityMetadata":true } diff --git a/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/OrderEntityTypeConfiguration.cs b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/OrderEntityTypeConfiguration.cs index d4eb1fb9a..9bfccd64c 100644 --- a/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/OrderEntityTypeConfiguration.cs +++ b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/OrderEntityTypeConfiguration.cs @@ -21,34 +21,62 @@ namespace Ordering.Infrastructure.EntityConfigurations .ForSqlServerUseSequenceHiLo("orderseq", OrderingContext.DEFAULT_SCHEMA); //Address value object persisted as owned entity type supported since EF Core 2.0 - orderConfiguration.OwnsOne(o => o.Address); + orderConfiguration + .OwnsOne(o => o.Address, a => + { + a.WithOwner(); + }); + + orderConfiguration + .Property("_buyerId") + .UsePropertyAccessMode(PropertyAccessMode.Field) + .HasColumnName("BuyerId") + .IsRequired(false); + + orderConfiguration + .Property("_orderDate") + .UsePropertyAccessMode(PropertyAccessMode.Field) + .HasColumnName("OrderDate") + .IsRequired(); + + orderConfiguration + .Property("_orderStatusId") + // .HasField("_orderStatusId") + .UsePropertyAccessMode(PropertyAccessMode.Field) + .HasColumnName("OrderStatusId") + .IsRequired(); + + orderConfiguration + .Property("_paymentMethodId") + .UsePropertyAccessMode(PropertyAccessMode.Field) + .HasColumnName("PaymentMethodId") + .IsRequired(false); - orderConfiguration.Property("OrderDate").IsRequired(); - orderConfiguration.Property("BuyerId").IsRequired(false); - orderConfiguration.Property("OrderStatusId").IsRequired(); - orderConfiguration.Property("PaymentMethodId").IsRequired(false); orderConfiguration.Property("Description").IsRequired(false); var navigation = orderConfiguration.Metadata.FindNavigation(nameof(Order.OrderItems)); - + // DDD Patterns comment: //Set as field (New since EF 1.1) to access the OrderItem collection property through its field navigation.SetPropertyAccessMode(PropertyAccessMode.Field); orderConfiguration.HasOne() .WithMany() - .HasForeignKey("PaymentMethodId") + // .HasForeignKey("PaymentMethodId") + .HasForeignKey("_paymentMethodId") .IsRequired(false) .OnDelete(DeleteBehavior.Restrict); orderConfiguration.HasOne() .WithMany() .IsRequired(false) - .HasForeignKey("BuyerId"); + // .HasForeignKey("BuyerId"); + .HasForeignKey("_buyerId"); orderConfiguration.HasOne(o => o.OrderStatus) .WithMany() - .HasForeignKey("OrderStatusId"); + // .HasForeignKey("OrderStatusId"); + .HasForeignKey("_orderStatusId"); } } } diff --git a/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/OrderItemEntityTypeConfiguration.cs b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/OrderItemEntityTypeConfiguration.cs index ca16eddad..e4100eb0d 100644 --- a/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/OrderItemEntityTypeConfiguration.cs +++ b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/OrderItemEntityTypeConfiguration.cs @@ -22,22 +22,37 @@ namespace Ordering.Infrastructure.EntityConfigurations orderItemConfiguration.Property("OrderId") .IsRequired(); - orderItemConfiguration.Property("Discount") + orderItemConfiguration + .Property("_discount") + .UsePropertyAccessMode(PropertyAccessMode.Field) + .HasColumnName("Discount") .IsRequired(); orderItemConfiguration.Property("ProductId") .IsRequired(); - orderItemConfiguration.Property("ProductName") + orderItemConfiguration + .Property("_productName") + .UsePropertyAccessMode(PropertyAccessMode.Field) + .HasColumnName("ProductName") .IsRequired(); - orderItemConfiguration.Property("UnitPrice") + orderItemConfiguration + .Property("_unitPrice") + .UsePropertyAccessMode(PropertyAccessMode.Field) + .HasColumnName("UnitPrice") .IsRequired(); - orderItemConfiguration.Property("Units") + orderItemConfiguration + .Property("_units") + .UsePropertyAccessMode(PropertyAccessMode.Field) + .HasColumnName("Units") .IsRequired(); - orderItemConfiguration.Property("PictureUrl") + orderItemConfiguration + .Property("_pictureUrl") + .UsePropertyAccessMode(PropertyAccessMode.Field) + .HasColumnName("PictureUrl") .IsRequired(false); } } diff --git a/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/PaymentMethodEntityTypeConfiguration.cs b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/PaymentMethodEntityTypeConfiguration.cs index 871c2057e..8343deb3b 100644 --- a/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/PaymentMethodEntityTypeConfiguration.cs +++ b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/PaymentMethodEntityTypeConfiguration.cs @@ -23,27 +23,43 @@ namespace Ordering.Infrastructure.EntityConfigurations paymentConfiguration.Property("BuyerId") .IsRequired(); - paymentConfiguration.Property("CardHolderName") + paymentConfiguration + .Property("_cardHolderName") + .UsePropertyAccessMode(PropertyAccessMode.Field) + .HasColumnName("CardHolderName") .HasMaxLength(200) .IsRequired(); - paymentConfiguration.Property("Alias") + paymentConfiguration + .Property("_alias") + .UsePropertyAccessMode(PropertyAccessMode.Field) + .HasColumnName("Alias") .HasMaxLength(200) .IsRequired(); - paymentConfiguration.Property("CardNumber") + paymentConfiguration + .Property("_cardNumber") + .UsePropertyAccessMode(PropertyAccessMode.Field) + .HasColumnName("CardNumber") .HasMaxLength(25) .IsRequired(); - paymentConfiguration.Property("Expiration") + paymentConfiguration + .Property("_expiration") + .UsePropertyAccessMode(PropertyAccessMode.Field) + .HasColumnName("Expiration") + .HasMaxLength(25) .IsRequired(); - paymentConfiguration.Property("CardTypeId") + paymentConfiguration + .Property("_cardTypeId") + .UsePropertyAccessMode(PropertyAccessMode.Field) + .HasColumnName("CardTypeId") .IsRequired(); paymentConfiguration.HasOne(p => p.CardType) .WithMany() - .HasForeignKey("CardTypeId"); + .HasForeignKey("_cardTypeId"); } } } diff --git a/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj b/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj index 21f2ff38c..22bfb2a56 100644 --- a/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj +++ b/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj @@ -1,7 +1,7 @@  - netstandard2.0 + $(NetStandardTargetVersion) @@ -9,9 +9,9 @@ - - - + + + diff --git a/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs b/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs index 40fd9be00..d7991b81c 100644 --- a/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs +++ b/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs @@ -27,7 +27,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure private readonly IMediator _mediator; private IDbContextTransaction _currentTransaction; - private OrderingContext(DbContextOptions options) : base(options) { } + public OrderingContext(DbContextOptions options) : base(options) { } public IDbContextTransaction GetCurrentTransaction() => _currentTransaction; @@ -137,15 +137,16 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure return Task.CompletedTask; } - public Task Send(IRequest request, CancellationToken cancellationToken = default(CancellationToken)) + public Task Publish(object notification, CancellationToken cancellationToken = default) { - return Task.FromResult(default(TResponse)); + return Task.CompletedTask; } - public Task Send(IRequest request, CancellationToken cancellationToken = default(CancellationToken)) + public Task Send(IRequest request, CancellationToken cancellationToken = default(CancellationToken)) { - return Task.CompletedTask; + return Task.FromResult(default(TResponse)); } + } } } diff --git a/src/Services/Ordering/Ordering.Infrastructure/Repositories/OrderRepository.cs b/src/Services/Ordering/Ordering.Infrastructure/Repositories/OrderRepository.cs index 4aaf738af..f2e13577c 100644 --- a/src/Services/Ordering/Ordering.Infrastructure/Repositories/OrderRepository.cs +++ b/src/Services/Ordering/Ordering.Infrastructure/Repositories/OrderRepository.cs @@ -3,6 +3,7 @@ using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.Order using Microsoft.eShopOnContainers.Services.Ordering.Domain.Seedwork; using Ordering.Domain.Exceptions; using System; +using System.Linq; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositories @@ -28,20 +29,28 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositor public Order Add(Order order) { return _context.Orders.Add(order).Entity; - + } public async Task GetAsync(int orderId) { - var order = await _context.Orders.FindAsync(orderId); + var order = await _context + .Orders + .Include(x => x.Address) + .FirstOrDefaultAsync(o => o.Id == orderId); + if (order == null) + { + order = _context + .Orders + .Local + .FirstOrDefault(o => o.Id == orderId); + } if (order != null) { await _context.Entry(order) .Collection(i => i.OrderItems).LoadAsync(); await _context.Entry(order) .Reference(i => i.OrderStatus).LoadAsync(); - await _context.Entry(order) - .Reference(i => i.Address).LoadAsync(); } return order; diff --git a/src/Services/Ordering/Ordering.SignalrHub/Dockerfile b/src/Services/Ordering/Ordering.SignalrHub/Dockerfile index 49e882921..657b1060f 100644 --- a/src/Services/Ordering/Ordering.SignalrHub/Dockerfile +++ b/src/Services/Ordering/Ordering.SignalrHub/Dockerfile @@ -1,55 +1,20 @@ -FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base +FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base WORKDIR /app EXPOSE 80 -FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build WORKDIR /src -# Keep the project list and command dotnet restore identical in all Dockfiles to maximize image cache utilization -COPY eShopOnContainers-ServicesAndWebApps.sln . -COPY docker-compose.dcproj /src/ -COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/ -COPY src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj src/ApiGateways/Mobile.Bff.Shopping/aggregator/ -COPY src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj src/ApiGateways/Web.Bff.Shopping/aggregator/ -COPY src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj src/BuildingBlocks/Devspaces.Support/ -COPY src/BuildingBlocks/EventBus/EventBus/EventBus.csproj src/BuildingBlocks/EventBus/EventBus/ -COPY src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj src/BuildingBlocks/EventBus/EventBus.Tests/ -COPY src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj src/BuildingBlocks/EventBus/EventBusRabbitMQ/ -COPY src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj src/BuildingBlocks/EventBus/EventBusServiceBus/ -COPY src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj src/BuildingBlocks/EventBus/IntegrationEventLogEF/ -COPY src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj src/BuildingBlocks/WebHostCustomization/WebHost.Customization/ -COPY src/Services/Basket/Basket.API/Basket.API.csproj src/Services/Basket/Basket.API/ -COPY src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj src/Services/Basket/Basket.FunctionalTests/ -COPY src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj src/Services/Basket/Basket.UnitTests/ -COPY src/Services/Catalog/Catalog.API/Catalog.API.csproj src/Services/Catalog/Catalog.API/ -COPY src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj src/Services/Catalog/Catalog.FunctionalTests/ -COPY src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj src/Services/Catalog/Catalog.UnitTests/ -COPY src/Services/Identity/Identity.API/Identity.API.csproj src/Services/Identity/Identity.API/ -COPY src/Services/Location/Locations.API/Locations.API.csproj src/Services/Location/Locations.API/ -COPY src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj src/Services/Location/Locations.FunctionalTests/ -COPY src/Services/Marketing/Marketing.API/Marketing.API.csproj src/Services/Marketing/Marketing.API/ -COPY src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj src/Services/Marketing/Marketing.FunctionalTests/ -COPY src/Services/Ordering/Ordering.API/Ordering.API.csproj src/Services/Ordering/Ordering.API/ -COPY src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj src/Services/Ordering/Ordering.BackgroundTasks/ -COPY src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj src/Services/Ordering/Ordering.Domain/ -COPY src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj src/Services/Ordering/Ordering.FunctionalTests/ -COPY src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj src/Services/Ordering/Ordering.Infrastructure/ -COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/ -COPY src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj src/Services/Ordering/Ordering.UnitTests/ -COPY src/Services/Payment/Payment.API/Payment.API.csproj src/Services/Payment/Payment.API/ -COPY src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj src/Services/Webhooks/Webhooks.API/ -COPY src/Web/WebhookClient/WebhookClient.csproj src/Web/WebhookClient/ -COPY src/Web/WebMVC/WebMVC.csproj src/Web/WebMVC/ -COPY src/Web/WebSPA/WebSPA.csproj src/Web/WebSPA/ -COPY src/Web/WebStatus/WebStatus.csproj src/Web/WebStatus/ -COPY test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj test/ServicesTests/Application.FunctionalTests/ -COPY test/ServicesTests/LoadTest/LoadTest.csproj test/ServicesTests/LoadTest/ +COPY scripts scripts/ -RUN dotnet restore eShopOnContainers-ServicesAndWebApps.sln +COPY ApiGateways/*/*/*.csproj csproj-files/ +COPY BuildingBlocks/*/*/*.csproj csproj-files/ +COPY Services/*/*/*.csproj csproj-files/ +COPY Web/*/*.csproj csproj-files/ COPY . . -WORKDIR /src/src/Services/Ordering/Ordering.SignalrHub -RUN dotnet publish --no-restore -c Release -o /app +WORKDIR /src/Services/Ordering/Ordering.SignalrHub +RUN dotnet publish -c Release -o /app FROM build AS publish diff --git a/src/Services/Ordering/Ordering.SignalrHub/Dockerfile.develop b/src/Services/Ordering/Ordering.SignalrHub/Dockerfile.develop index d96223149..d55d319b1 100644 --- a/src/Services/Ordering/Ordering.SignalrHub/Dockerfile.develop +++ b/src/Services/Ordering/Ordering.SignalrHub/Dockerfile.develop @@ -1,4 +1,4 @@ -FROM microsoft/dotnet:2.2-sdk +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster ARG BUILD_CONFIGURATION=Debug ENV ASPNETCORE_ENVIRONMENT=Development ENV DOTNET_USE_POLLING_FILE_WATCHER=true diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToAwaitingValidationIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToAwaitingValidationIntegrationEventHandler.cs index 0e2665232..7a99d898c 100644 --- a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToAwaitingValidationIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToAwaitingValidationIntegrationEventHandler.cs @@ -27,8 +27,6 @@ namespace Ordering.SignalrHub.IntegrationEvents { using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) { - _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); - await _hubContext.Clients .Group(@event.BuyerName) .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus }); diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToCancelledIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToCancelledIntegrationEventHandler.cs index 6257bb237..15d2cce47 100644 --- a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToCancelledIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToCancelledIntegrationEventHandler.cs @@ -28,8 +28,6 @@ namespace Ordering.SignalrHub.IntegrationEvents.EventHandling { using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) { - _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); - await _hubContext.Clients .Group(@event.BuyerName) .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus }); diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs index 836e02d3c..0d70edcbf 100644 --- a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs @@ -26,8 +26,6 @@ namespace Ordering.SignalrHub.IntegrationEvents.EventHandling { using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) { - _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); - await _hubContext.Clients .Group(@event.BuyerName) .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus }); diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToShippedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToShippedIntegrationEventHandler.cs index 5b08d08b4..782ee1a11 100644 --- a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToShippedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToShippedIntegrationEventHandler.cs @@ -28,8 +28,6 @@ namespace Ordering.SignalrHub.IntegrationEvents.EventHandling { using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) { - _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); - await _hubContext.Clients .Group(@event.BuyerName) .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus }); diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs index 348627716..364c1c307 100644 --- a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs @@ -29,8 +29,6 @@ namespace Ordering.SignalrHub.IntegrationEvents.EventHandling { using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) { - _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); - await _hubContext.Clients .Group(@event.BuyerName) .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus }); diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToSubmittedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToSubmittedIntegrationEventHandler.cs index 422bc4a7a..30183ef77 100644 --- a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToSubmittedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToSubmittedIntegrationEventHandler.cs @@ -29,8 +29,6 @@ namespace Ordering.SignalrHub.IntegrationEvents.EventHandling { using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) { - _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); - await _hubContext.Clients .Group(@event.BuyerName) .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus }); diff --git a/src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj b/src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj index 60eca2aef..b64c881a8 100644 --- a/src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj +++ b/src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj @@ -1,8 +1,11 @@  - netcoreapp2.2 + $(NetCoreTargetVersion) ..\..\..\..\docker-compose.dcproj + false + true + $(LangVersion) @@ -10,27 +13,27 @@ - - + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/src/Services/Ordering/Ordering.SignalrHub/Startup.cs b/src/Services/Ordering/Ordering.SignalrHub/Startup.cs index edcc80521..472644781 100644 --- a/src/Services/Ordering/Ordering.SignalrHub/Startup.cs +++ b/src/Services/Ordering/Ordering.SignalrHub/Startup.cs @@ -1,7 +1,9 @@ using Autofac; using Autofac.Extensions.DependencyInjection; +using HealthChecks.UI.Client; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.Azure.ServiceBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; @@ -9,6 +11,7 @@ using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; using Ordering.SignalrHub.AutofacModules; using Ordering.SignalrHub.IntegrationEvents; @@ -17,9 +20,6 @@ using Ordering.SignalrHub.IntegrationEvents.Events; using RabbitMQ.Client; using System; using System.IdentityModel.Tokens.Jwt; -using HealthChecks.UI.Client; -using Microsoft.AspNetCore.Diagnostics.HealthChecks; -using Microsoft.Extensions.Diagnostics.HealthChecks; namespace Ordering.SignalrHub { @@ -109,7 +109,7 @@ namespace Ordering.SignalrHub RegisterEventBus(services); services.AddOptions(); - + //configure autofac var container = new ContainerBuilder(); container.RegisterModule(new ApplicationModule()); @@ -127,31 +127,31 @@ namespace Ordering.SignalrHub //loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace); var pathBase = Configuration["PATH_BASE"]; + if (!string.IsNullOrEmpty(pathBase)) { loggerFactory.CreateLogger().LogDebug("Using PATH BASE '{pathBase}'", pathBase); app.UsePathBase(pathBase); } - app.UseHealthChecks("/hc", new HealthCheckOptions() - { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - - app.UseHealthChecks("/liveness", new HealthCheckOptions - { - Predicate = r => r.Name.Contains("self") - }); - app.UseCors("CorsPolicy"); + app.UseRouting(); app.UseAuthentication(); + app.UseAuthorization(); - app.UseSignalR(routes => + app.UseEndpoints(endpoints => { - routes.MapHub("/notificationhub", options => - options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransports.All); + endpoints.MapHealthChecks("/hc", new HealthCheckOptions() + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + endpoints.MapHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = r => r.Name.Contains("self") + }); + endpoints.MapHub("/notificationhub", options => options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransports.All); }); ConfigureEventBus(app); diff --git a/src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj b/src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj index dc67e5b63..5b7ed2060 100644 --- a/src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj +++ b/src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj @@ -1,16 +1,18 @@  - netcoreapp2.2 - + $(NetCoreTargetVersion) + false false - - - - + + + + + + all runtime; build; native; contentfiles; analyzers diff --git a/src/Services/Payment/Payment.API/Dockerfile b/src/Services/Payment/Payment.API/Dockerfile index 724077312..6f3c1b1db 100644 --- a/src/Services/Payment/Payment.API/Dockerfile +++ b/src/Services/Payment/Payment.API/Dockerfile @@ -1,55 +1,20 @@ -FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base +FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base WORKDIR /app EXPOSE 80 -FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build WORKDIR /src -# Keep the project list and command dotnet restore identical in all Dockfiles to maximize image cache utilization -COPY eShopOnContainers-ServicesAndWebApps.sln . -COPY docker-compose.dcproj /src/ -COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/ -COPY src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj src/ApiGateways/Mobile.Bff.Shopping/aggregator/ -COPY src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj src/ApiGateways/Web.Bff.Shopping/aggregator/ -COPY src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj src/BuildingBlocks/Devspaces.Support/ -COPY src/BuildingBlocks/EventBus/EventBus/EventBus.csproj src/BuildingBlocks/EventBus/EventBus/ -COPY src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj src/BuildingBlocks/EventBus/EventBus.Tests/ -COPY src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj src/BuildingBlocks/EventBus/EventBusRabbitMQ/ -COPY src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj src/BuildingBlocks/EventBus/EventBusServiceBus/ -COPY src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj src/BuildingBlocks/EventBus/IntegrationEventLogEF/ -COPY src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj src/BuildingBlocks/WebHostCustomization/WebHost.Customization/ -COPY src/Services/Basket/Basket.API/Basket.API.csproj src/Services/Basket/Basket.API/ -COPY src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj src/Services/Basket/Basket.FunctionalTests/ -COPY src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj src/Services/Basket/Basket.UnitTests/ -COPY src/Services/Catalog/Catalog.API/Catalog.API.csproj src/Services/Catalog/Catalog.API/ -COPY src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj src/Services/Catalog/Catalog.FunctionalTests/ -COPY src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj src/Services/Catalog/Catalog.UnitTests/ -COPY src/Services/Identity/Identity.API/Identity.API.csproj src/Services/Identity/Identity.API/ -COPY src/Services/Location/Locations.API/Locations.API.csproj src/Services/Location/Locations.API/ -COPY src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj src/Services/Location/Locations.FunctionalTests/ -COPY src/Services/Marketing/Marketing.API/Marketing.API.csproj src/Services/Marketing/Marketing.API/ -COPY src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj src/Services/Marketing/Marketing.FunctionalTests/ -COPY src/Services/Ordering/Ordering.API/Ordering.API.csproj src/Services/Ordering/Ordering.API/ -COPY src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj src/Services/Ordering/Ordering.BackgroundTasks/ -COPY src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj src/Services/Ordering/Ordering.Domain/ -COPY src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj src/Services/Ordering/Ordering.FunctionalTests/ -COPY src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj src/Services/Ordering/Ordering.Infrastructure/ -COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/ -COPY src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj src/Services/Ordering/Ordering.UnitTests/ -COPY src/Services/Payment/Payment.API/Payment.API.csproj src/Services/Payment/Payment.API/ -COPY src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj src/Services/Webhooks/Webhooks.API/ -COPY src/Web/WebhookClient/WebhookClient.csproj src/Web/WebhookClient/ -COPY src/Web/WebMVC/WebMVC.csproj src/Web/WebMVC/ -COPY src/Web/WebSPA/WebSPA.csproj src/Web/WebSPA/ -COPY src/Web/WebStatus/WebStatus.csproj src/Web/WebStatus/ -COPY test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj test/ServicesTests/Application.FunctionalTests/ -COPY test/ServicesTests/LoadTest/LoadTest.csproj test/ServicesTests/LoadTest/ +COPY scripts scripts/ -RUN dotnet restore eShopOnContainers-ServicesAndWebApps.sln +COPY ApiGateways/*/*/*.csproj csproj-files/ +COPY BuildingBlocks/*/*/*.csproj csproj-files/ +COPY Services/*/*/*.csproj csproj-files/ +COPY Web/*/*.csproj csproj-files/ COPY . . -WORKDIR /src/src/Services/Payment/Payment.API -RUN dotnet publish --no-restore -c Release -o /app +WORKDIR /src/Services/Payment/Payment.API +RUN dotnet publish -c Release -o /app FROM build AS publish diff --git a/src/Services/Payment/Payment.API/Dockerfile.develop b/src/Services/Payment/Payment.API/Dockerfile.develop index 4b959f4b3..0b671a94f 100644 --- a/src/Services/Payment/Payment.API/Dockerfile.develop +++ b/src/Services/Payment/Payment.API/Dockerfile.develop @@ -1,19 +1,19 @@ -FROM microsoft/dotnet:2.2-sdk +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster ARG BUILD_CONFIGURATION=Debug ENV ASPNETCORE_ENVIRONMENT=Development ENV DOTNET_USE_POLLING_FILE_WATCHER=true EXPOSE 80 WORKDIR /src -COPY ["src/BuildingBlocks/EventBus/EventBus/EventBus.csproj", "src/BuildingBlocks/EventBus/EventBus/"] -COPY ["src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "src/BuildingBlocks/EventBus/EventBusRabbitMQ/"] -COPY ["src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "src/BuildingBlocks/EventBus/EventBusServiceBus/"] -COPY ["src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj", "src/BuildingBlocks/EventBus/IntegrationEventLogEF/"] -COPY ["src/Services/Payment/Payment.API/Payment.API.csproj", "src/Services/Payment/Payment.API/"] +COPY ["BuildingBlocks/EventBus/EventBus/EventBus.csproj", "BuildingBlocks/EventBus/EventBus/"] +COPY ["BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "BuildingBlocks/EventBus/EventBusRabbitMQ/"] +COPY ["BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "BuildingBlocks/EventBus/EventBusServiceBus/"] +COPY ["BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj", "BuildingBlocks/EventBus/IntegrationEventLogEF/"] +COPY ["Services/Payment/Payment.API/Payment.API.csproj", "Services/Payment/Payment.API/"] -RUN dotnet restore src/Services/Payment/Payment.API/Payment.API.csproj +RUN dotnet restore Services/Payment/Payment.API/Payment.API.csproj COPY . . -WORKDIR /src/src/Services/Payment/Payment.API +WORKDIR /src/Services/Payment/Payment.API RUN dotnet build --no-restore -c $BUILD_CONFIGURATION ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"] \ No newline at end of file diff --git a/src/Services/Payment/Payment.API/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs b/src/Services/Payment/Payment.API/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs index 5921529b2..aa03587a5 100644 --- a/src/Services/Payment/Payment.API/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs +++ b/src/Services/Payment/Payment.API/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs @@ -31,8 +31,6 @@ { using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) { - _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); - IntegrationEvent orderPaymentIntegrationEvent; //Business feature comment: @@ -50,8 +48,6 @@ orderPaymentIntegrationEvent = new OrderPaymentFailedIntegrationEvent(@event.OrderId); } - _logger.LogInformation("----- Publishing integration event: {IntegrationEventId} from {AppName} - ({@IntegrationEvent})", orderPaymentIntegrationEvent.Id, Program.AppName, orderPaymentIntegrationEvent); - _eventBus.Publish(orderPaymentIntegrationEvent); await Task.CompletedTask; diff --git a/src/Services/Payment/Payment.API/Payment.API.csproj b/src/Services/Payment/Payment.API/Payment.API.csproj index 33dec6db4..497349a66 100644 --- a/src/Services/Payment/Payment.API/Payment.API.csproj +++ b/src/Services/Payment/Payment.API/Payment.API.csproj @@ -1,30 +1,31 @@  - netcoreapp2.2 + $(NetCoreTargetVersion) ..\..\..\..\docker-compose.dcproj $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + true + $(LangVersion) - - + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/src/Services/Payment/Payment.API/Startup.cs b/src/Services/Payment/Payment.API/Startup.cs index 39bb78f91..77b8d55fd 100644 --- a/src/Services/Payment/Payment.API/Startup.cs +++ b/src/Services/Payment/Payment.API/Startup.cs @@ -1,9 +1,8 @@ using Autofac; using Autofac.Extensions.DependencyInjection; -using Microsoft.ApplicationInsights.Extensibility; -using Microsoft.ApplicationInsights.ServiceFabric; +using HealthChecks.UI.Client; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.Azure.ServiceBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; @@ -11,14 +10,12 @@ using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; using Payment.API.IntegrationEvents.EventHandling; using Payment.API.IntegrationEvents.Events; using RabbitMQ.Client; using System; -using HealthChecks.UI.Client; -using Microsoft.AspNetCore.Diagnostics.HealthChecks; -using Microsoft.Extensions.Diagnostics.HealthChecks; namespace Payment.API { @@ -80,7 +77,7 @@ namespace Payment.API return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount); }); - } + } RegisterEventBus(services); @@ -90,7 +87,7 @@ namespace Payment.API } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { //loggerFactory.AddAzureWebAppDiagnostics(); //loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace); @@ -101,37 +98,27 @@ namespace Payment.API app.UsePathBase(pathBase); } + ConfigureEventBus(app); - app.UseHealthChecks("/hc", new HealthCheckOptions() - { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - - app.UseHealthChecks("/liveness", new HealthCheckOptions + app.UseRouting(); + app.UseEndpoints(endpoints => { - Predicate = r => r.Name.Contains("self") + endpoints.MapHealthChecks("/hc", new HealthCheckOptions() + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + endpoints.MapHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = r => r.Name.Contains("self") + }); }); - - ConfigureEventBus(app); } private void RegisterAppInsights(IServiceCollection services) { services.AddApplicationInsightsTelemetry(Configuration); - var orchestratorType = Configuration.GetValue("OrchestratorType"); - - if (orchestratorType?.ToUpper() == "K8S") - { - // Enable K8s telemetry initializer - services.AddApplicationInsightsKubernetesEnricher(); - } - if (orchestratorType?.ToUpper() == "SF") - { - // Enable SF telemetry initializer - services.AddSingleton((serviceProvider) => - new FabricTelemetryInitializer()); - } + services.AddApplicationInsightsKubernetesEnricher(); } private void RegisterEventBus(IServiceCollection services) @@ -145,7 +132,7 @@ namespace Payment.API var serviceBusPersisterConnection = sp.GetRequiredService(); var iLifetimeScope = sp.GetRequiredService(); var logger = sp.GetRequiredService>(); - var eventBusSubcriptionsManager = sp.GetRequiredService(); + var eventBusSubcriptionsManager = sp.GetRequiredService(); return new EventBusServiceBus(serviceBusPersisterConnection, logger, eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); diff --git a/src/Services/Webhooks/Webhooks.API/Dockerfile b/src/Services/Webhooks/Webhooks.API/Dockerfile index 5f306dae4..ad6893664 100644 --- a/src/Services/Webhooks/Webhooks.API/Dockerfile +++ b/src/Services/Webhooks/Webhooks.API/Dockerfile @@ -1,55 +1,20 @@ -FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base +FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base WORKDIR /app EXPOSE 80 -FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build WORKDIR /src -# Keep the project list and command dotnet restore identical in all Dockfiles to maximize image cache utilization -COPY eShopOnContainers-ServicesAndWebApps.sln . -COPY docker-compose.dcproj /src/ -COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/ -COPY src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj src/ApiGateways/Mobile.Bff.Shopping/aggregator/ -COPY src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj src/ApiGateways/Web.Bff.Shopping/aggregator/ -COPY src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj src/BuildingBlocks/Devspaces.Support/ -COPY src/BuildingBlocks/EventBus/EventBus/EventBus.csproj src/BuildingBlocks/EventBus/EventBus/ -COPY src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj src/BuildingBlocks/EventBus/EventBus.Tests/ -COPY src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj src/BuildingBlocks/EventBus/EventBusRabbitMQ/ -COPY src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj src/BuildingBlocks/EventBus/EventBusServiceBus/ -COPY src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj src/BuildingBlocks/EventBus/IntegrationEventLogEF/ -COPY src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj src/BuildingBlocks/WebHostCustomization/WebHost.Customization/ -COPY src/Services/Basket/Basket.API/Basket.API.csproj src/Services/Basket/Basket.API/ -COPY src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj src/Services/Basket/Basket.FunctionalTests/ -COPY src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj src/Services/Basket/Basket.UnitTests/ -COPY src/Services/Catalog/Catalog.API/Catalog.API.csproj src/Services/Catalog/Catalog.API/ -COPY src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj src/Services/Catalog/Catalog.FunctionalTests/ -COPY src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj src/Services/Catalog/Catalog.UnitTests/ -COPY src/Services/Identity/Identity.API/Identity.API.csproj src/Services/Identity/Identity.API/ -COPY src/Services/Location/Locations.API/Locations.API.csproj src/Services/Location/Locations.API/ -COPY src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj src/Services/Location/Locations.FunctionalTests/ -COPY src/Services/Marketing/Marketing.API/Marketing.API.csproj src/Services/Marketing/Marketing.API/ -COPY src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj src/Services/Marketing/Marketing.FunctionalTests/ -COPY src/Services/Ordering/Ordering.API/Ordering.API.csproj src/Services/Ordering/Ordering.API/ -COPY src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj src/Services/Ordering/Ordering.BackgroundTasks/ -COPY src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj src/Services/Ordering/Ordering.Domain/ -COPY src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj src/Services/Ordering/Ordering.FunctionalTests/ -COPY src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj src/Services/Ordering/Ordering.Infrastructure/ -COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/ -COPY src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj src/Services/Ordering/Ordering.UnitTests/ -COPY src/Services/Payment/Payment.API/Payment.API.csproj src/Services/Payment/Payment.API/ -COPY src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj src/Services/Webhooks/Webhooks.API/ -COPY src/Web/WebhookClient/WebhookClient.csproj src/Web/WebhookClient/ -COPY src/Web/WebMVC/WebMVC.csproj src/Web/WebMVC/ -COPY src/Web/WebSPA/WebSPA.csproj src/Web/WebSPA/ -COPY src/Web/WebStatus/WebStatus.csproj src/Web/WebStatus/ -COPY test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj test/ServicesTests/Application.FunctionalTests/ -COPY test/ServicesTests/LoadTest/LoadTest.csproj test/ServicesTests/LoadTest/ +COPY scripts scripts/ -RUN dotnet restore eShopOnContainers-ServicesAndWebApps.sln +COPY ApiGateways/*/*/*.csproj csproj-files/ +COPY BuildingBlocks/*/*/*.csproj csproj-files/ +COPY Services/*/*/*.csproj csproj-files/ +COPY Web/*/*.csproj csproj-files/ COPY . . -WORKDIR /src/src/Services/Webhooks/Webhooks.API -RUN dotnet publish --no-restore -c Release -o /app +WORKDIR /src/Services/Webhooks/Webhooks.API +RUN dotnet publish -c Release -o /app FROM build AS publish diff --git a/src/Services/Webhooks/Webhooks.API/Dockerfile.develop b/src/Services/Webhooks/Webhooks.API/Dockerfile.develop index 3cc1084f9..9dbc57a1f 100644 --- a/src/Services/Webhooks/Webhooks.API/Dockerfile.develop +++ b/src/Services/Webhooks/Webhooks.API/Dockerfile.develop @@ -1,4 +1,4 @@ -FROM microsoft/dotnet:2.2-sdk +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster ARG BUILD_CONFIGURATION=Debug ENV ASPNETCORE_ENVIRONMENT=Development ENV DOTNET_USE_POLLING_FILE_WATCHER=true @@ -6,17 +6,17 @@ EXPOSE 80 WORKDIR /src -COPY ["src/BuildingBlocks/EventBus/EventBus/EventBus.csproj", "src/BuildingBlocks/EventBus/EventBus/"] -COPY ["src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "src/BuildingBlocks/EventBus/EventBusRabbitMQ/"] -COPY ["src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "src/BuildingBlocks/EventBus/EventBusServiceBus/"] -COPY ["src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj", "src/BuildingBlocks/EventBus/IntegrationEventLogEF/"] -COPY ["src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj", "src/BuildingBlocks/WebHostCustomization/WebHost.Customization/"] -COPY ["src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj", "src/BuildingBlocks/Devspaces.Support/"] -COPY ["src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj", "src/Services/Webhooks/Webhooks.API/"] +COPY ["BuildingBlocks/EventBus/EventBus/EventBus.csproj", "BuildingBlocks/EventBus/EventBus/"] +COPY ["BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "BuildingBlocks/EventBus/EventBusRabbitMQ/"] +COPY ["BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "BuildingBlocks/EventBus/EventBusServiceBus/"] +COPY ["BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj", "BuildingBlocks/EventBus/IntegrationEventLogEF/"] +COPY ["BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj", "BuildingBlocks/WebHostCustomization/WebHost.Customization/"] +COPY ["BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj", "BuildingBlocks/Devspaces.Support/"] +COPY ["Services/Webhooks/Webhooks.API/Webhooks.API.csproj", "Services/Webhooks/Webhooks.API/"] -RUN dotnet restore src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj -nowarn:msb3202,nu1503 +RUN dotnet restore Services/Webhooks/Webhooks.API/Webhooks.API.csproj -nowarn:msb3202,nu1503 COPY . . -WORKDIR "/src/src/Services/Webhooks/Webhooks.API" +WORKDIR "/src/Services/Webhooks/Webhooks.API" RUN dotnet build --no-restore -c $BUILD_CONFIGURATION ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"] \ No newline at end of file diff --git a/src/Services/Webhooks/Webhooks.API/Infrastructure/AuthorizeCheckOperationFilter.cs b/src/Services/Webhooks/Webhooks.API/Infrastructure/AuthorizeCheckOperationFilter.cs index 920f2ac8e..487a59981 100644 --- a/src/Services/Webhooks/Webhooks.API/Infrastructure/AuthorizeCheckOperationFilter.cs +++ b/src/Services/Webhooks/Webhooks.API/Infrastructure/AuthorizeCheckOperationFilter.cs @@ -1,16 +1,14 @@ using Microsoft.AspNetCore.Authorization; -using Swashbuckle.AspNetCore.Swagger; +using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; -using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; namespace Webhooks.API.Infrastructure { public class AuthorizeCheckOperationFilter : IOperationFilter { - public void Apply(Operation operation, OperationFilterContext context) + public void Apply(OpenApiOperation operation, OperationFilterContext context) { // Check for authorize attribute var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType().Any() || @@ -18,16 +16,21 @@ namespace Webhooks.API.Infrastructure if (!hasAuthorize) return; - operation.Responses.TryAdd("401", new Response { Description = "Unauthorized" }); - operation.Responses.TryAdd("403", new Response { Description = "Forbidden" }); + operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" }); + operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" }); - operation.Security = new List>> + var oAuthScheme = new OpenApiSecurityScheme { - new Dictionary> - { - { "oauth2", new [] { "webhooksapi" } } - } + Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } }; + + operation.Security = new List + { + new OpenApiSecurityRequirement + { + [ oAuthScheme ] = new [] { "webhooksapi" } + } + }; } } } diff --git a/src/Services/Webhooks/Webhooks.API/Startup.cs b/src/Services/Webhooks/Webhooks.API/Startup.cs index f1a89d329..5859e9e12 100644 --- a/src/Services/Webhooks/Webhooks.API/Startup.cs +++ b/src/Services/Webhooks/Webhooks.API/Startup.cs @@ -1,23 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Data.Common; -using System.IdentityModel.Tokens.Jwt; -using System.Linq; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using Autofac; +using Autofac; using Autofac.Extensions.DependencyInjection; using Devspaces.Support; using HealthChecks.UI.Client; -using Microsoft.ApplicationInsights.Extensibility; -using Microsoft.ApplicationInsights.ServiceFabric; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; -using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.ServiceBus; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; @@ -30,8 +18,14 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; +using Microsoft.OpenApi.Models; using RabbitMQ.Client; -using Swashbuckle.AspNetCore.Swagger; +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.IdentityModel.Tokens.Jwt; +using System.Reflection; +using System.Threading; using Webhooks.API.Infrastructure; using Webhooks.API.IntegrationEvents; using Webhooks.API.Services; @@ -52,7 +46,7 @@ namespace Webhooks.API { services .AddAppInsight(Configuration) - .AddCustomMVC(Configuration) + .AddCustomRouting(Configuration) .AddCustomDbContext(Configuration) .AddSwagger(Configuration) .AddCustomHealthCheck(Configuration) @@ -84,22 +78,25 @@ namespace Webhooks.API app.UsePathBase(pathBase); } - app.UseHealthChecks("/hc", new HealthCheckOptions() - { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - - app.UseHealthChecks("/liveness", new HealthCheckOptions - { - Predicate = r => r.Name.Contains("self") - }); - app.UseCors("CorsPolicy"); ConfigureAuth(app); - app.UseMvcWithDefaultRoute(); + app.UseRouting(); + app.UseEndpoints(endpoints => + { + endpoints.MapDefaultControllerRoute(); + endpoints.MapControllers(); + endpoints.MapHealthChecks("/hc", new HealthCheckOptions() + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + endpoints.MapHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = r => r.Name.Contains("self") + }); + }); app.UseSwagger() .UseSwaggerUI(c => @@ -138,31 +135,17 @@ namespace Webhooks.API public static IServiceCollection AddAppInsight(this IServiceCollection services, IConfiguration configuration) { services.AddApplicationInsightsTelemetry(configuration); - var orchestratorType = configuration.GetValue("OrchestratorType"); - - if (orchestratorType?.ToUpper() == "K8S") - { - // Enable K8s telemetry initializer - services.AddApplicationInsightsKubernetesEnricher(); - } - if (orchestratorType?.ToUpper() == "SF") - { - // Enable SF telemetry initializer - services.AddSingleton((serviceProvider) => - new FabricTelemetryInitializer()); - } + services.AddApplicationInsightsKubernetesEnricher(); return services; } - public static IServiceCollection AddCustomMVC(this IServiceCollection services, IConfiguration configuration) + public static IServiceCollection AddCustomRouting(this IServiceCollection services, IConfiguration configuration) { - services.AddMvc(options => + services.AddControllers(options => { options.Filters.Add(typeof(HttpGlobalExceptionFilter)); - }) - .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) - .AddControllersAsServices(); + }); services.AddCors(options => { @@ -179,14 +162,15 @@ namespace Webhooks.API public static IServiceCollection AddCustomDbContext(this IServiceCollection services, IConfiguration configuration) { - services.AddDbContext(options => + services.AddEntityFrameworkSqlServer() + .AddDbContext(options => { options.UseSqlServer(configuration["ConnectionString"], sqlServerOptionsAction: sqlOptions => { sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); //Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency - sqlOptions.EnableRetryOnFailure(maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); + sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); }); // Changing default behavior when client evaluation occurs to throw. @@ -203,23 +187,27 @@ namespace Webhooks.API services.AddSwaggerGen(options => { options.DescribeAllEnumsAsStrings(); - options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info + options.SwaggerDoc("v1", new OpenApiInfo { Title = "eShopOnContainers - Webhooks HTTP API", Version = "v1", - Description = "The Webhooks Microservice HTTP API. This is a simple webhooks CRUD registration entrypoint", - TermsOfService = "Terms Of Service" + Description = "The Webhooks Microservice HTTP API. This is a simple webhooks CRUD registration entrypoint" }); - options.AddSecurityDefinition("oauth2", new OAuth2Scheme + options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme { - Type = "oauth2", - Flow = "implicit", - AuthorizationUrl = $"{configuration.GetValue("IdentityUrlExternal")}/connect/authorize", - TokenUrl = $"{configuration.GetValue("IdentityUrlExternal")}/connect/token", - Scopes = new Dictionary() + Type = SecuritySchemeType.OAuth2, + Flows = new OpenApiOAuthFlows() { - { "webhooks", "Webhooks API" } + Implicit = new OpenApiOAuthFlow() + { + AuthorizationUrl = new Uri($"{configuration.GetValue("IdentityUrlExternal")}/connect/authorize"), + TokenUrl = new Uri($"{configuration.GetValue("IdentityUrlExternal")}/connect/token"), + Scopes = new Dictionary() + { + { "webhooks", "Webhooks API" } + } + } } }); diff --git a/src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj b/src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj index 7fddfe4c9..1e9b44858 100644 --- a/src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj +++ b/src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj @@ -1,27 +1,30 @@  - netcoreapp2.2 + $(NetCoreTargetVersion) InProcess Linux + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + true + $(LangVersion) - + - - - - - - - - - - - + + + + + + + + + + - + diff --git a/src/Web/WebMVC/Controllers/AccountController.cs b/src/Web/WebMVC/Controllers/AccountController.cs index f4562b169..dfd4984c5 100644 --- a/src/Web/WebMVC/Controllers/AccountController.cs +++ b/src/Web/WebMVC/Controllers/AccountController.cs @@ -1,17 +1,16 @@ -using System.Security.Claims; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Http.Authentication; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authentication.OpenIdConnect; -using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.Extensions.Logging; using System; +using System.Security.Claims; +using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.WebMVC.Controllers { - [Authorize] + [Authorize(AuthenticationSchemes = "OpenIdConnect")] public class AccountController : Controller { private readonly ILogger _logger; @@ -21,14 +20,11 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } - [Authorize] - public async Task SignIn(string returnUrl) + [Authorize(AuthenticationSchemes = "OpenIdConnect")] public async Task SignIn(string returnUrl) { var user = User as ClaimsPrincipal; var token = await HttpContext.GetTokenAsync("access_token"); - _logger.LogInformation("----- User {@User} authenticated into {AppName}", user, Program.AppName); - if (token != null) { ViewData["access_token"] = token; diff --git a/src/Web/WebMVC/Controllers/CampaignsController.cs b/src/Web/WebMVC/Controllers/CampaignsController.cs index d26e60f94..cf210318b 100644 --- a/src/Web/WebMVC/Controllers/CampaignsController.cs +++ b/src/Web/WebMVC/Controllers/CampaignsController.cs @@ -12,7 +12,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers using ViewModels; using ViewModels.Pagination; - [Authorize] + [Authorize(AuthenticationSchemes = "OpenIdConnect")] public class CampaignsController : Controller { private readonly ICampaignService _campaignService; diff --git a/src/Web/WebMVC/Controllers/CartController.cs b/src/Web/WebMVC/Controllers/CartController.cs index 30ac77e8b..78cec5670 100644 --- a/src/Web/WebMVC/Controllers/CartController.cs +++ b/src/Web/WebMVC/Controllers/CartController.cs @@ -2,14 +2,13 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.eShopOnContainers.WebMVC.Services; using Microsoft.eShopOnContainers.WebMVC.ViewModels; -using Polly.CircuitBreaker; using System; using System.Collections.Generic; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.WebMVC.Controllers { - [Authorize] + [Authorize(AuthenticationSchemes = "OpenIdConnect")] public class CartController : Controller { private readonly IBasketService _basketSvc; @@ -32,16 +31,15 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers return View(vm); } - catch (BrokenCircuitException) + catch (Exception ex) { - // Catch error when Basket.api is in circuit-opened mode - HandleBrokenCircuitException(); + HandleException(ex); } return View(); } - + [HttpPost] public async Task Index(Dictionary quantities, string action) { @@ -54,10 +52,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers return RedirectToAction("Create", "Order"); } } - catch (BrokenCircuitException) + catch (Exception ex) { - // Catch error when Basket.api is in circuit-opened mode - HandleBrokenCircuitException(); + HandleException(ex); } return View(); @@ -72,20 +69,20 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers var user = _appUserParser.Parse(HttpContext.User); await _basketSvc.AddItemToBasket(user, productDetails.Id); } - return RedirectToAction("Index", "Catalog"); + return RedirectToAction("Index", "Catalog"); } - catch (BrokenCircuitException) + catch (Exception ex) { // Catch error when Basket.api is in circuit-opened mode - HandleBrokenCircuitException(); + HandleException(ex); } return RedirectToAction("Index", "Catalog", new { errorMsg = ViewBag.BasketInoperativeMsg }); } - private void HandleBrokenCircuitException() + private void HandleException(Exception ex) { - ViewBag.BasketInoperativeMsg = "Basket Service is inoperative, please try later on. (Business Msg Due to Circuit-Breaker)"; + ViewBag.BasketInoperativeMsg = $"Basket Service is inoperative {ex.GetType().Name} - {ex.Message}"; } } } diff --git a/src/Web/WebMVC/Controllers/OrderController.cs b/src/Web/WebMVC/Controllers/OrderController.cs index cb5234e3c..f308d0bdc 100644 --- a/src/Web/WebMVC/Controllers/OrderController.cs +++ b/src/Web/WebMVC/Controllers/OrderController.cs @@ -2,12 +2,12 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.eShopOnContainers.WebMVC.Services; using Microsoft.eShopOnContainers.WebMVC.ViewModels; -using Polly.CircuitBreaker; +using System; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.WebMVC.Controllers { - [Authorize] + [Authorize(AuthenticationSchemes = "OpenIdConnect")] public class OrderController : Controller { private IOrderingService _orderSvc; @@ -47,9 +47,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers return RedirectToAction("Index"); } } - catch (BrokenCircuitException) + catch (Exception ex) { - ModelState.AddModelError("Error", "It was not possible to create a new order, please try later on. (Business Msg Due to Circuit-Breaker)"); + ModelState.AddModelError("Error", $"It was not possible to create a new order, please try later on ({ex.GetType().Name} - {ex.Message})"); } return View("Create", model); diff --git a/src/Web/WebMVC/Controllers/OrderManagementController.cs b/src/Web/WebMVC/Controllers/OrderManagementController.cs index 7d61b0221..a488dc4ae 100644 --- a/src/Web/WebMVC/Controllers/OrderManagementController.cs +++ b/src/Web/WebMVC/Controllers/OrderManagementController.cs @@ -10,7 +10,7 @@ using Microsoft.AspNetCore.Authorization; namespace WebMVC.Controllers { - [Authorize] + [Authorize(AuthenticationSchemes = "OpenIdConnect")] public class OrderManagementController : Controller { private IOrderingService _orderSvc; diff --git a/src/Web/WebMVC/Dockerfile b/src/Web/WebMVC/Dockerfile index 989d89b16..76e3b5c77 100644 --- a/src/Web/WebMVC/Dockerfile +++ b/src/Web/WebMVC/Dockerfile @@ -1,55 +1,20 @@ -FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base +FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base WORKDIR /app EXPOSE 80 -FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build WORKDIR /src -# Keep the project list and command dotnet restore identical in all Dockfiles to maximize image cache utilization -COPY eShopOnContainers-ServicesAndWebApps.sln . -COPY docker-compose.dcproj /src/ -COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/ -COPY src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj src/ApiGateways/Mobile.Bff.Shopping/aggregator/ -COPY src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj src/ApiGateways/Web.Bff.Shopping/aggregator/ -COPY src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj src/BuildingBlocks/Devspaces.Support/ -COPY src/BuildingBlocks/EventBus/EventBus/EventBus.csproj src/BuildingBlocks/EventBus/EventBus/ -COPY src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj src/BuildingBlocks/EventBus/EventBus.Tests/ -COPY src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj src/BuildingBlocks/EventBus/EventBusRabbitMQ/ -COPY src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj src/BuildingBlocks/EventBus/EventBusServiceBus/ -COPY src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj src/BuildingBlocks/EventBus/IntegrationEventLogEF/ -COPY src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj src/BuildingBlocks/WebHostCustomization/WebHost.Customization/ -COPY src/Services/Basket/Basket.API/Basket.API.csproj src/Services/Basket/Basket.API/ -COPY src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj src/Services/Basket/Basket.FunctionalTests/ -COPY src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj src/Services/Basket/Basket.UnitTests/ -COPY src/Services/Catalog/Catalog.API/Catalog.API.csproj src/Services/Catalog/Catalog.API/ -COPY src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj src/Services/Catalog/Catalog.FunctionalTests/ -COPY src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj src/Services/Catalog/Catalog.UnitTests/ -COPY src/Services/Identity/Identity.API/Identity.API.csproj src/Services/Identity/Identity.API/ -COPY src/Services/Location/Locations.API/Locations.API.csproj src/Services/Location/Locations.API/ -COPY src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj src/Services/Location/Locations.FunctionalTests/ -COPY src/Services/Marketing/Marketing.API/Marketing.API.csproj src/Services/Marketing/Marketing.API/ -COPY src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj src/Services/Marketing/Marketing.FunctionalTests/ -COPY src/Services/Ordering/Ordering.API/Ordering.API.csproj src/Services/Ordering/Ordering.API/ -COPY src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj src/Services/Ordering/Ordering.BackgroundTasks/ -COPY src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj src/Services/Ordering/Ordering.Domain/ -COPY src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj src/Services/Ordering/Ordering.FunctionalTests/ -COPY src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj src/Services/Ordering/Ordering.Infrastructure/ -COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/ -COPY src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj src/Services/Ordering/Ordering.UnitTests/ -COPY src/Services/Payment/Payment.API/Payment.API.csproj src/Services/Payment/Payment.API/ -COPY src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj src/Services/Webhooks/Webhooks.API/ -COPY src/Web/WebhookClient/WebhookClient.csproj src/Web/WebhookClient/ -COPY src/Web/WebMVC/WebMVC.csproj src/Web/WebMVC/ -COPY src/Web/WebSPA/WebSPA.csproj src/Web/WebSPA/ -COPY src/Web/WebStatus/WebStatus.csproj src/Web/WebStatus/ -COPY test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj test/ServicesTests/Application.FunctionalTests/ -COPY test/ServicesTests/LoadTest/LoadTest.csproj test/ServicesTests/LoadTest/ +COPY scripts scripts/ -RUN dotnet restore eShopOnContainers-ServicesAndWebApps.sln +COPY ApiGateways/*/*/*.csproj csproj-files/ +COPY BuildingBlocks/*/*/*.csproj csproj-files/ +COPY Services/*/*/*.csproj csproj-files/ +COPY Web/*/*.csproj csproj-files/ COPY . . -WORKDIR /src/src/Web/WebMVC -RUN dotnet publish --no-restore -c Release -o /app +WORKDIR /src/Web/WebMVC +RUN dotnet publish -c Release -o /app FROM build AS publish diff --git a/src/Web/WebMVC/Dockerfile.develop b/src/Web/WebMVC/Dockerfile.develop index 6ff9cc869..0e4a5dc81 100644 --- a/src/Web/WebMVC/Dockerfile.develop +++ b/src/Web/WebMVC/Dockerfile.develop @@ -1,15 +1,15 @@ -FROM microsoft/dotnet:2.2-sdk +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster ARG BUILD_CONFIGURATION=Debug ENV ASPNETCORE_ENVIRONMENT=Development ENV DOTNET_USE_POLLING_FILE_WATCHER=true EXPOSE 80 WORKDIR /src -COPY ["src/Web/WebMVC/WebMVC.csproj", "src/Web/WebMVC/"] -COPY ["src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj", "src/BuildingBlocks/Devspaces.Support/"] -RUN dotnet restore "src/Web/WebMVC/WebMVC.csproj" +COPY ["Web/WebMVC/WebMVC.csproj", "Web/WebMVC/"] +COPY ["BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj", "BuildingBlocks/Devspaces.Support/"] +RUN dotnet restore "Web/WebMVC/WebMVC.csproj" COPY . . -WORKDIR "/src/src/Web/WebMVC" +WORKDIR "/src/Web/WebMVC" RUN dotnet build --no-restore "WebMVC.csproj" -c $BUILD_CONFIGURATION ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"] \ No newline at end of file diff --git a/src/Web/WebMVC/Infrastructure/WebContextSeed.cs b/src/Web/WebMVC/Infrastructure/WebContextSeed.cs index c34730ac1..bc4165c0a 100644 --- a/src/Web/WebMVC/Infrastructure/WebContextSeed.cs +++ b/src/Web/WebMVC/Infrastructure/WebContextSeed.cs @@ -2,8 +2,8 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.eShopOnContainers.WebMVC; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Serilog; using System; using System.IO; using System.IO.Compression; @@ -13,9 +13,9 @@ namespace WebMVC.Infrastructure { public class WebContextSeed { - public static void Seed(IApplicationBuilder applicationBuilder, IHostingEnvironment env, ILoggerFactory loggerFactory) + public static void Seed(IApplicationBuilder applicationBuilder, IHostingEnvironment env) { - var log = loggerFactory.CreateLogger(); + var log = Serilog.Log.Logger; var settings = (AppSettings)applicationBuilder .ApplicationServices.GetRequiredService>().Value; @@ -39,7 +39,7 @@ namespace WebMVC.Infrastructure string overrideCssFile = Path.Combine(contentRootPath, "Setup", "override.css"); if (!File.Exists(overrideCssFile)) { - log.LogError("Override css file '{FileName}' does not exists.", overrideCssFile); + log.Error("Override css file '{FileName}' does not exists.", overrideCssFile); return; } @@ -48,7 +48,7 @@ namespace WebMVC.Infrastructure } catch (Exception ex) { - log.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); + log.Error(ex, "EXCEPTION ERROR: {Message}", ex.Message); } } @@ -59,7 +59,7 @@ namespace WebMVC.Infrastructure string imagesZipFile = Path.Combine(contentRootPath, "Setup", "images.zip"); if (!File.Exists(imagesZipFile)) { - log.LogError("Zip file '{ZipFileName}' does not exists.", imagesZipFile); + log.Error("Zip file '{ZipFileName}' does not exists.", imagesZipFile); return; } @@ -81,14 +81,14 @@ namespace WebMVC.Infrastructure } else { - log.LogWarning("Skipped file '{FileName}' in zipfile '{ZipFileName}'", entry.Name, imagesZipFile); + log.Warning("Skipped file '{FileName}' in zipfile '{ZipFileName}'", entry.Name, imagesZipFile); } } } } catch ( Exception ex ) { - log.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); + log.Error(ex, "EXCEPTION ERROR: {Message}", ex.Message); } } diff --git a/src/Web/WebMVC/Program.cs b/src/Web/WebMVC/Program.cs index a80d0514b..5a149ab44 100644 --- a/src/Web/WebMVC/Program.cs +++ b/src/Web/WebMVC/Program.cs @@ -53,15 +53,18 @@ namespace Microsoft.eShopOnContainers.WebMVC { var seqServerUrl = configuration["Serilog:SeqServerUrl"]; var logstashUrl = configuration["Serilog:LogstashgUrl"]; - return new LoggerConfiguration() - .MinimumLevel.Verbose() + var cfg = new LoggerConfiguration() + .ReadFrom.Configuration(configuration) .Enrich.WithProperty("ApplicationContext", AppName) .Enrich.FromLogContext() - .WriteTo.Console() - .WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl) - .WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://logstash:8080" : logstashUrl) - .ReadFrom.Configuration(configuration) - .CreateLogger(); + .WriteTo.Console(); + if (!string.IsNullOrWhiteSpace(seqServerUrl)) { + cfg.WriteTo.Seq(seqServerUrl); + } + if (!string.IsNullOrWhiteSpace(logstashUrl)) { + cfg.WriteTo.Http(logstashUrl); + } + return cfg.CreateLogger(); } private static IConfiguration GetConfiguration() diff --git a/src/Web/WebMVC/Services/BasketService.cs b/src/Web/WebMVC/Services/BasketService.cs index dd0a50feb..8e72ef249 100644 --- a/src/Web/WebMVC/Services/BasketService.cs +++ b/src/Web/WebMVC/Services/BasketService.cs @@ -1,4 +1,5 @@ using Microsoft.eShopOnContainers.WebMVC.ViewModels; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; using System.Collections.Generic; @@ -14,26 +15,27 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services { private readonly IOptions _settings; private readonly HttpClient _apiClient; + private readonly ILogger _logger; private readonly string _basketByPassUrl; private readonly string _purchaseUrl; - private readonly string _bffUrl; - - public BasketService(HttpClient httpClient, IOptions settings) + public BasketService(HttpClient httpClient, IOptions settings, ILogger logger) { _apiClient = httpClient; _settings = settings; + _logger =logger; - _basketByPassUrl = $"{_settings.Value.PurchaseUrl}/api/v1/b/basket"; + _basketByPassUrl = $"{_settings.Value.PurchaseUrl}/b/api/v1/basket"; _purchaseUrl = $"{_settings.Value.PurchaseUrl}/api/v1"; } public async Task GetBasket(ApplicationUser user) { var uri = API.Basket.GetBasket(_basketByPassUrl, user.Id); - - var responseString = await _apiClient.GetStringAsync(uri); - + _logger.LogDebug($"[GetBasket] -> Calling {uri} to get the basket"); + var response = await _apiClient.GetAsync(uri); + _logger.LogDebug($"[GetBasket] -> response code {response.StatusCode}"); + var responseString = await response.Content.ReadAsStringAsync(); return string.IsNullOrEmpty(responseString) ? new Basket() { BuyerId = user.Id } : JsonConvert.DeserializeObject(responseString); @@ -57,6 +59,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services var uri = API.Basket.CheckoutBasket(_basketByPassUrl); var basketContent = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json"); + _logger.LogInformation("Uri chechout {uri}", uri); + var response = await _apiClient.PostAsync(uri, basketContent); response.EnsureSuccessStatusCode(); diff --git a/src/Web/WebMVC/Services/CampaignService.cs b/src/Web/WebMVC/Services/CampaignService.cs index 6521fd4ae..d768c51fd 100644 --- a/src/Web/WebMVC/Services/CampaignService.cs +++ b/src/Web/WebMVC/Services/CampaignService.cs @@ -21,7 +21,7 @@ _httpClient = httpClient; _logger = logger; - _remoteServiceBaseUrl = $"{_settings.Value.MarketingUrl}/api/v1/m/campaigns/"; + _remoteServiceBaseUrl = $"{_settings.Value.MarketingUrl}/m/api/v1/campaigns/"; } public async Task GetCampaigns(int pageSize, int pageIndex) diff --git a/src/Web/WebMVC/Services/CatalogService.cs b/src/Web/WebMVC/Services/CatalogService.cs index d4899b453..40d3644f4 100644 --- a/src/Web/WebMVC/Services/CatalogService.cs +++ b/src/Web/WebMVC/Services/CatalogService.cs @@ -25,7 +25,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services _settings = settings; _logger = logger; - _remoteServiceBaseUrl = $"{_settings.Value.PurchaseUrl}/api/v1/c/catalog/"; + _remoteServiceBaseUrl = $"{_settings.Value.PurchaseUrl}/c/api/v1/catalog/"; } public async Task GetCatalogItems(int page, int take, int? brand, int? type) diff --git a/src/Web/WebMVC/Services/OrderingService.cs b/src/Web/WebMVC/Services/OrderingService.cs index 489946db5..b5ad13386 100644 --- a/src/Web/WebMVC/Services/OrderingService.cs +++ b/src/Web/WebMVC/Services/OrderingService.cs @@ -22,7 +22,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services _httpClient = httpClient; _settings = settings; - _remoteServiceBaseUrl = $"{settings.Value.PurchaseUrl}/api/v1/o/orders"; + _remoteServiceBaseUrl = $"{settings.Value.PurchaseUrl}/o/api/v1/orders"; } async public Task GetOrder(ApplicationUser user, string id) diff --git a/src/Web/WebMVC/Startup.cs b/src/Web/WebMVC/Startup.cs index 52a311369..bfba90662 100644 --- a/src/Web/WebMVC/Startup.cs +++ b/src/Web/WebMVC/Startup.cs @@ -1,9 +1,7 @@ using Devspaces.Support; using HealthChecks.UI.Client; -using Microsoft.ApplicationInsights.Extensibility; -using Microsoft.ApplicationInsights.ServiceFabric; using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.AspNetCore.Authentication.OpenIdConnect; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Diagnostics.HealthChecks; @@ -16,8 +14,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; -using Polly; -using Polly.Extensions.Http; +using Microsoft.IdentityModel.Logging; using StackExchange.Redis; using System; using System.IdentityModel.Tokens.Jwt; @@ -40,29 +37,25 @@ namespace Microsoft.eShopOnContainers.WebMVC // This method gets called by the runtime. Use this method to add services to the IoC container. public void ConfigureServices(IServiceCollection services) { - services.AddAppInsight(Configuration) - .AddHealthChecks(Configuration) - .AddCustomMvc(Configuration) - .AddDevspaces() - .AddHttpClientServices(Configuration) - //.AddHttpClientLogging(Configuration) //Opt-in HttpClientLogging config - .AddCustomAuthentication(Configuration); + services.AddControllersWithViews() + .Services + .AddAppInsight(Configuration) + .AddHealthChecks(Configuration) + .AddCustomMvc(Configuration) + .AddDevspaces() + .AddHttpClientServices(Configuration); + + IdentityModelEventSource.ShowPII = true; // Caution! Do NOT use in production: https://aka.ms/IdentityModel/PII + + services.AddControllers(); + + services.AddCustomAuthentication(Configuration); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + public void Configure(IApplicationBuilder app, IHostingEnvironment env) { - JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); - - //loggerFactory.AddAzureWebAppDiagnostics(); - //loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace); - - app.UseHealthChecks("/hc", new HealthCheckOptions() - { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub"); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); @@ -70,43 +63,44 @@ namespace Microsoft.eShopOnContainers.WebMVC else { app.UseExceptionHandler("/Error"); - app.UseHsts(); } var pathBase = Configuration["PATH_BASE"]; + if (!string.IsNullOrEmpty(pathBase)) { - loggerFactory.CreateLogger().LogDebug("Using PATH BASE '{PathBase}'", pathBase); app.UsePathBase(pathBase); } - app.UseHealthChecks("/liveness", new HealthCheckOptions - { - Predicate = r => r.Name.Contains("self") - }); - - app.UseSession(); app.UseStaticFiles(); + app.UseSession(); if (Configuration.GetValue("UseLoadTest")) { app.UseMiddleware(); } - app.UseAuthentication(); + WebContextSeed.Seed(app, env); - WebContextSeed.Seed(app, env, loggerFactory); + app.UseRouting(); + + app.UseAuthentication(); + app.UseAuthorization(); - app.UseHttpsRedirection(); - app.UseMvc(routes => + app.UseEndpoints(endpoints => { - routes.MapRoute( - name: "default", - template: "{controller=Catalog}/{action=Index}/{id?}"); - - routes.MapRoute( - name: "defaultError", - template: "{controller=Error}/{action=Error}"); + endpoints.MapControllerRoute("default", "{controller=Catalog}/{action=Index}/{id?}"); + endpoints.MapControllerRoute("defaultError", "{controller=Error}/{action=Error}"); + endpoints.MapControllers(); + endpoints.MapHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = r => r.Name.Contains("self") + }); + endpoints.MapHealthChecks("/hc", new HealthCheckOptions() + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); }); } } @@ -117,20 +111,7 @@ namespace Microsoft.eShopOnContainers.WebMVC public static IServiceCollection AddAppInsight(this IServiceCollection services, IConfiguration configuration) { services.AddApplicationInsightsTelemetry(configuration); - var orchestratorType = configuration.GetValue("OrchestratorType"); - - if (orchestratorType?.ToUpper() == "K8S") - { - // Enable K8s telemetry initializer - services.AddApplicationInsightsKubernetesEnricher(); - } - - if (orchestratorType?.ToUpper() == "SF") - { - // Enable SF telemetry initializer - services.AddSingleton((serviceProvider) => - new FabricTelemetryInitializer()); - } + services.AddApplicationInsightsKubernetesEnricher(); return services; } @@ -139,10 +120,8 @@ namespace Microsoft.eShopOnContainers.WebMVC { services.AddHealthChecks() .AddCheck("self", () => HealthCheckResult.Healthy()) - .AddUrlGroup(new Uri(configuration["PurchaseUrlHC"]), name: "purchaseapigw-check", tags: new string[] { "purchaseapigw" }) - .AddUrlGroup(new Uri(configuration["MarketingUrlHC"]), name: "marketingapigw-check", tags: new string[] { "marketingapigw" }) - .AddUrlGroup(new Uri(configuration["IdentityUrlHC"]), name: "identityapi-check", tags: new string[] { "identityapi" }); - + .AddUrlGroup(new Uri(configuration["IdentityUrlHC"]), name: "identityapi-check", tags: new string[] { "identityapi" }); + return services; } @@ -150,11 +129,8 @@ namespace Microsoft.eShopOnContainers.WebMVC { services.AddOptions(); services.Configure(configuration); - - services.AddMvc() - .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); - services.AddSession(); + services.AddDistributedMemoryCache(); if (configuration.GetValue("IsClusterEnv") == bool.TrueString) { @@ -164,10 +140,11 @@ namespace Microsoft.eShopOnContainers.WebMVC }) .PersistKeysToRedis(ConnectionMultiplexer.Connect(configuration["DPConnectionString"]), "DataProtection-Keys"); } + return services; } - // Adds all Http client services (like Service-Agents) using resilient Http requests based on HttpClient factory and Polly's policies + // Adds all Http client services public static IServiceCollection AddHttpClientServices(this IServiceCollection services, IConfiguration configuration) { services.AddSingleton(); @@ -183,32 +160,22 @@ namespace Microsoft.eShopOnContainers.WebMVC services.AddHttpClient() .SetHandlerLifetime(TimeSpan.FromMinutes(5)) //Sample. Default lifetime is 2 minutes .AddHttpMessageHandler() - .AddPolicyHandler(GetRetryPolicy()) - .AddPolicyHandler(GetCircuitBreakerPolicy()) .AddDevspacesSupport(); services.AddHttpClient() - .AddPolicyHandler(GetRetryPolicy()) - .AddPolicyHandler(GetCircuitBreakerPolicy()) .AddDevspacesSupport(); services.AddHttpClient() .AddHttpMessageHandler() .AddHttpMessageHandler() - .AddPolicyHandler(GetRetryPolicy()) - .AddPolicyHandler(GetCircuitBreakerPolicy()) .AddDevspacesSupport(); services.AddHttpClient() .AddHttpMessageHandler() - .AddPolicyHandler(GetRetryPolicy()) - .AddPolicyHandler(GetCircuitBreakerPolicy()) .AddDevspacesSupport(); services.AddHttpClient() .AddHttpMessageHandler() - .AddPolicyHandler(GetRetryPolicy()) - .AddPolicyHandler(GetCircuitBreakerPolicy()) .AddDevspacesSupport(); //add custom application services @@ -217,21 +184,6 @@ namespace Microsoft.eShopOnContainers.WebMVC return services; } - public static IServiceCollection AddHttpClientLogging(this IServiceCollection services, IConfiguration configuration) - { - services.AddLogging(b => - { - b.AddFilter((category, level) => true); // Spam the world with logs. - - // Add console logger so we can see all the logging produced by the client by default. - b.AddConsole(c => c.IncludeScopes = true); - - // Add console logger - b.AddDebug(); - }); - - return services; - } public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) { @@ -245,9 +197,9 @@ namespace Microsoft.eShopOnContainers.WebMVC services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) - .AddCookie(setup=>setup.ExpireTimeSpan = TimeSpan.FromMinutes(sessionCookieLifetime)) + .AddCookie(setup => setup.ExpireTimeSpan = TimeSpan.FromMinutes(sessionCookieLifetime)) .AddOpenIdConnect(options => { options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; @@ -266,25 +218,10 @@ namespace Microsoft.eShopOnContainers.WebMVC options.Scope.Add("marketing"); options.Scope.Add("locations"); options.Scope.Add("webshoppingagg"); - options.Scope.Add("orders.signalrhub"); + options.Scope.Add("orders.signalrhub"); }); return services; } - - static IAsyncPolicy GetRetryPolicy() - { - return HttpPolicyExtensions - .HandleTransientHttpError() - .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound) - .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); - - } - static IAsyncPolicy GetCircuitBreakerPolicy() - { - return HttpPolicyExtensions - .HandleTransientHttpError() - .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)); - } } } diff --git a/src/Web/WebMVC/ViewComponents/Cart.cs b/src/Web/WebMVC/ViewComponents/Cart.cs index 05c7dac50..6cd8bf2d5 100644 --- a/src/Web/WebMVC/ViewComponents/Cart.cs +++ b/src/Web/WebMVC/ViewComponents/Cart.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Polly.CircuitBreaker; namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents { @@ -25,9 +24,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents vm.ItemsCount = itemsInCart; return View(vm); } - catch (BrokenCircuitException) + catch { - // Catch error when Basket.api is in circuit-opened mode ViewBag.IsBasketInoperative = true; } diff --git a/src/Web/WebMVC/ViewComponents/CartList.cs b/src/Web/WebMVC/ViewComponents/CartList.cs index 60fe863d4..88d1f9abb 100644 --- a/src/Web/WebMVC/ViewComponents/CartList.cs +++ b/src/Web/WebMVC/ViewComponents/CartList.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Polly.CircuitBreaker; namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents { @@ -23,10 +22,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents vm = await GetItemsAsync(user); return View(vm); } - catch (BrokenCircuitException) + catch (Exception ex) { - // Catch error when Basket.api is in circuit-opened mode - ViewBag.BasketInoperativeMsg = "Basket Service is inoperative, please try later on. (Business Msg Due to Circuit-Breaker)"; + ViewBag.BasketInoperativeMsg = $"Basket Service is inoperative, please try later on. ({ex.GetType().Name} - {ex.Message}))"; } return View(vm); diff --git a/src/Web/WebMVC/WebMVC.csproj b/src/Web/WebMVC/WebMVC.csproj index e2e8096ef..f6d02d0cd 100644 --- a/src/Web/WebMVC/WebMVC.csproj +++ b/src/Web/WebMVC/WebMVC.csproj @@ -1,10 +1,13 @@  - netcoreapp2.2 + $(NetCoreTargetVersion) aspnet-Microsoft.eShopOnContainers-946ae052-8305-4a99-965b-ec8636ddbae3 ..\..\..\docker-compose.dcproj 3.0 + false + true + $(LangVersion) @@ -19,37 +22,27 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/src/Web/WebMVC/appsettings.Development.json b/src/Web/WebMVC/appsettings.Development.json new file mode 100644 index 000000000..a96c927e8 --- /dev/null +++ b/src/Web/WebMVC/appsettings.Development.json @@ -0,0 +1,7 @@ +{ + "Serilog": { + "MinimumLevel": { + "Default": "Debug" + } + } +} diff --git a/src/Web/WebMVC/appsettings.json b/src/Web/WebMVC/appsettings.json index affc61f93..436baedb6 100644 --- a/src/Web/WebMVC/appsettings.json +++ b/src/Web/WebMVC/appsettings.json @@ -15,12 +15,7 @@ "SeqServerUrl": null, "LogstashgUrl": null, "MinimumLevel": { - "Default": "Information", - "Override": { - "Microsoft": "Warning", - "Microsoft.eShopOnContainers": "Information", - "System": "Warning" - } + "Default": "Information" } }, "ApplicationInsights": { diff --git a/src/Web/WebSPA/Client/modules/basket/basket.service.ts b/src/Web/WebSPA/Client/modules/basket/basket.service.ts index 1e08fa780..171c745c1 100644 --- a/src/Web/WebSPA/Client/modules/basket/basket.service.ts +++ b/src/Web/WebSPA/Client/modules/basket/basket.service.ts @@ -1,17 +1,17 @@ -import { Injectable } from '@angular/core'; -import { Response } from '@angular/http'; -import { Router } from '@angular/router'; +import { Injectable } from '@angular/core'; +import { Response } from '@angular/http'; +import { Router } from '@angular/router'; -import { DataService } from '../shared/services/data.service'; -import { SecurityService } from '../shared/services/security.service'; +import { DataService } from '../shared/services/data.service'; +import { SecurityService } from '../shared/services/security.service'; import { IBasket } from '../shared/models/basket.model'; import { IOrder } from '../shared/models/order.model'; import { IBasketCheckout } from '../shared/models/basketCheckout.model'; -import { BasketWrapperService } from '../shared/services/basket.wrapper.service'; -import { ConfigurationService } from '../shared/services/configuration.service'; -import { StorageService } from '../shared/services/storage.service'; +import { BasketWrapperService } from '../shared/services/basket.wrapper.service'; +import { ConfigurationService } from '../shared/services/configuration.service'; +import { StorageService } from '../shared/services/storage.service'; -import { Observable, Observer, Subject } from 'rxjs'; +import { Observable, Observer, Subject } from 'rxjs'; import { map, catchError } from 'rxjs/operators'; @Injectable() @@ -26,16 +26,16 @@ export class BasketService { //observable that is fired when the basket is dropped private basketDropedSource = new Subject(); basketDroped$ = this.basketDropedSource.asObservable(); - + constructor(private service: DataService, private authService: SecurityService, private basketEvents: BasketWrapperService, private router: Router, private configurationService: ConfigurationService, private storageService: StorageService) { this.basket.items = []; - + // Init: if (this.authService.IsAuthorized) { if (this.authService.UserData) { this.basket.buyerId = this.authService.UserData.sub; if (this.configurationService.isReady) { - this.basketUrl = this.configurationService.serverSettings.purchaseUrl; + this.basketUrl = this.configurationService.serverSettings.purchaseUrl; this.purchaseUrl = this.configurationService.serverSettings.purchaseUrl; this.loadData(); } @@ -53,7 +53,7 @@ export class BasketService { this.dropBasket(); }); } - + addItemToBasket(item): Observable { this.basket.items.push(item); return this.setBasket(this.basket); @@ -68,7 +68,7 @@ export class BasketService { } setBasketCheckout(basketCheckout): Observable { - let url = this.basketUrl + '/api/v1/b/basket/checkout'; + let url = this.basketUrl + '/b/api/v1/basket/checkout'; return this.service.postWithId(url, basketCheckout).pipe(map((response: any) => { this.basketEvents.orderCreated(); return true; @@ -76,14 +76,14 @@ export class BasketService { } getBasket(): Observable { - let url = this.basketUrl + '/api/v1/b/basket/' + this.basket.buyerId; + let url = this.basketUrl + '/b/api/v1/basket/' + this.basket.buyerId; return this.service.get(url).pipe(map((response: any) => { if (response.status === 204) { return null; } return response; })); - } + } mapBasketInfoCheckout(order: IOrder): IBasketCheckout { let basketCheckout = {}; @@ -102,10 +102,10 @@ export class BasketService { basketCheckout.expiration = order.expiration; return basketCheckout; - } + } dropBasket() { - this.basket.items = []; + this.basket.items = []; this.basketDropedSource.next(); } diff --git a/src/Web/WebSPA/Client/modules/campaigns/campaigns.service.ts b/src/Web/WebSPA/Client/modules/campaigns/campaigns.service.ts index 6014bf07a..87efa96b7 100644 --- a/src/Web/WebSPA/Client/modules/campaigns/campaigns.service.ts +++ b/src/Web/WebSPA/Client/modules/campaigns/campaigns.service.ts @@ -29,7 +29,7 @@ export class CampaignsService { } getCampaigns(pageIndex: number, pageSize: number): Observable { - let url = this.marketingUrl + '/api/v1/m/campaigns/user'; + let url = this.marketingUrl + '/m/api/v1/campaigns/user'; url = url + '?pageIndex=' + pageIndex + '&pageSize=' + pageSize; return this.service.get(url).pipe(map((response: any) => { @@ -38,7 +38,7 @@ export class CampaignsService { } getCampaign(id: number): Observable { - let url = this.marketingUrl + '/api/v1/m/campaigns/' + id; + let url = this.marketingUrl + '/m/api/v1/campaigns/' + id; return this.service.get(url).pipe(map((response: any) => { return response; diff --git a/src/Web/WebSPA/Client/modules/catalog/catalog.service.ts b/src/Web/WebSPA/Client/modules/catalog/catalog.service.ts index 2054e0adf..186731543 100644 --- a/src/Web/WebSPA/Client/modules/catalog/catalog.service.ts +++ b/src/Web/WebSPA/Client/modules/catalog/catalog.service.ts @@ -18,9 +18,9 @@ export class CatalogService { constructor(private service: DataService, private configurationService: ConfigurationService) { this.configurationService.settingsLoaded$.subscribe(x => { - this.catalogUrl = this.configurationService.serverSettings.purchaseUrl + '/api/v1/c/catalog/items'; - this.brandUrl = this.configurationService.serverSettings.purchaseUrl + '/api/v1/c/catalog/catalogbrands'; - this.typesUrl = this.configurationService.serverSettings.purchaseUrl + '/api/v1/c/catalog/catalogtypes'; + this.catalogUrl = this.configurationService.serverSettings.purchaseUrl + '/c/api/v1/catalog/items'; + this.brandUrl = this.configurationService.serverSettings.purchaseUrl + '/c/api/v1/catalog/catalogbrands'; + this.typesUrl = this.configurationService.serverSettings.purchaseUrl + '/c/api/v1/catalog/catalogtypes'; }); } diff --git a/src/Web/WebSPA/Client/modules/orders/orders.service.ts b/src/Web/WebSPA/Client/modules/orders/orders.service.ts index fc7ecd6f2..c7f27ee7d 100644 --- a/src/Web/WebSPA/Client/modules/orders/orders.service.ts +++ b/src/Web/WebSPA/Client/modules/orders/orders.service.ts @@ -25,7 +25,7 @@ export class OrdersService { } getOrders(): Observable { - let url = this.ordersUrl + '/api/v1/o/orders'; + let url = this.ordersUrl + '/o/api/v1/orders'; return this.service.get(url).pipe(map((response: any) => { return response; @@ -33,7 +33,7 @@ export class OrdersService { } getOrder(id: number): Observable { - let url = this.ordersUrl + '/api/v1/o/orders/' + id; + let url = this.ordersUrl + '/o/api/v1/orders/' + id; return this.service.get(url).pipe(map((response: any) => { return response; diff --git a/src/Web/WebSPA/Client/modules/shared/models/basketItem.model.ts b/src/Web/WebSPA/Client/modules/shared/models/basketItem.model.ts index 44c5716a5..000b00f30 100644 --- a/src/Web/WebSPA/Client/modules/shared/models/basketItem.model.ts +++ b/src/Web/WebSPA/Client/modules/shared/models/basketItem.model.ts @@ -1,6 +1,6 @@ export interface IBasketItem { id: string; - productId: string; + productId: number; productName: string; unitPrice: number; oldUnitPrice: number; diff --git a/src/Web/WebSPA/Client/modules/shared/models/catalogItem.model.ts b/src/Web/WebSPA/Client/modules/shared/models/catalogItem.model.ts index bf4c7ea70..fcbaa80f9 100644 --- a/src/Web/WebSPA/Client/modules/shared/models/catalogItem.model.ts +++ b/src/Web/WebSPA/Client/modules/shared/models/catalogItem.model.ts @@ -1,5 +1,5 @@ export interface ICatalogItem { - id: string; + id: number; name: string; description: string; price: number; diff --git a/src/Web/WebSPA/Dockerfile b/src/Web/WebSPA/Dockerfile index 99d99a0bc..62454aacb 100644 --- a/src/Web/WebSPA/Dockerfile +++ b/src/Web/WebSPA/Dockerfile @@ -1,63 +1,30 @@ ARG NODE_IMAGE=node:8.11 -FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base +FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base WORKDIR /app EXPOSE 80 FROM ${NODE_IMAGE} as node-build WORKDIR /web -COPY src/Web/WebSPA . +COPY Web/WebSPA/package.json . +COPY Web/WebSPA/package-lock.json . RUN npm install +COPY Web/WebSPA . RUN npm run build:prod -FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build WORKDIR /src -# Keep the project list and command dotnet restore identical in all Dockfiles to maximize image cache utilization -COPY eShopOnContainers-ServicesAndWebApps.sln . -COPY docker-compose.dcproj /src/ -COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/ -COPY src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj src/ApiGateways/Mobile.Bff.Shopping/aggregator/ -COPY src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj src/ApiGateways/Web.Bff.Shopping/aggregator/ -COPY src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj src/BuildingBlocks/Devspaces.Support/ -COPY src/BuildingBlocks/EventBus/EventBus/EventBus.csproj src/BuildingBlocks/EventBus/EventBus/ -COPY src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj src/BuildingBlocks/EventBus/EventBus.Tests/ -COPY src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj src/BuildingBlocks/EventBus/EventBusRabbitMQ/ -COPY src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj src/BuildingBlocks/EventBus/EventBusServiceBus/ -COPY src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj src/BuildingBlocks/EventBus/IntegrationEventLogEF/ -COPY src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj src/BuildingBlocks/WebHostCustomization/WebHost.Customization/ -COPY src/Services/Basket/Basket.API/Basket.API.csproj src/Services/Basket/Basket.API/ -COPY src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj src/Services/Basket/Basket.FunctionalTests/ -COPY src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj src/Services/Basket/Basket.UnitTests/ -COPY src/Services/Catalog/Catalog.API/Catalog.API.csproj src/Services/Catalog/Catalog.API/ -COPY src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj src/Services/Catalog/Catalog.FunctionalTests/ -COPY src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj src/Services/Catalog/Catalog.UnitTests/ -COPY src/Services/Identity/Identity.API/Identity.API.csproj src/Services/Identity/Identity.API/ -COPY src/Services/Location/Locations.API/Locations.API.csproj src/Services/Location/Locations.API/ -COPY src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj src/Services/Location/Locations.FunctionalTests/ -COPY src/Services/Marketing/Marketing.API/Marketing.API.csproj src/Services/Marketing/Marketing.API/ -COPY src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj src/Services/Marketing/Marketing.FunctionalTests/ -COPY src/Services/Ordering/Ordering.API/Ordering.API.csproj src/Services/Ordering/Ordering.API/ -COPY src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj src/Services/Ordering/Ordering.BackgroundTasks/ -COPY src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj src/Services/Ordering/Ordering.Domain/ -COPY src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj src/Services/Ordering/Ordering.FunctionalTests/ -COPY src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj src/Services/Ordering/Ordering.Infrastructure/ -COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/ -COPY src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj src/Services/Ordering/Ordering.UnitTests/ -COPY src/Services/Payment/Payment.API/Payment.API.csproj src/Services/Payment/Payment.API/ -COPY src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj src/Services/Webhooks/Webhooks.API/ -COPY src/Web/WebhookClient/WebhookClient.csproj src/Web/WebhookClient/ -COPY src/Web/WebMVC/WebMVC.csproj src/Web/WebMVC/ -COPY src/Web/WebSPA/WebSPA.csproj src/Web/WebSPA/ -COPY src/Web/WebStatus/WebStatus.csproj src/Web/WebStatus/ -COPY test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj test/ServicesTests/Application.FunctionalTests/ -COPY test/ServicesTests/LoadTest/LoadTest.csproj test/ServicesTests/LoadTest/ +COPY scripts scripts/ -RUN dotnet restore eShopOnContainers-ServicesAndWebApps.sln +COPY ApiGateways/*/*/*.csproj csproj-files/ +COPY BuildingBlocks/*/*/*.csproj csproj-files/ +COPY Services/*/*/*.csproj csproj-files/ +COPY Web/*/*.csproj csproj-files/ COPY . . -COPY --from=node-build /web/wwwroot /src/src/Web/WebSPA/wwwroot/ -WORKDIR /src/src/Web/WebSPA -RUN dotnet publish --no-restore -c Release -o /app +COPY --from=node-build /web/wwwroot /src/Web/WebSPA/wwwroot/ +WORKDIR /src/Web/WebSPA +RUN dotnet publish -c Release -o /app FROM build AS publish diff --git a/src/Web/WebSPA/Startup.cs b/src/Web/WebSPA/Startup.cs index 7a418c432..367d494ba 100644 --- a/src/Web/WebSPA/Startup.cs +++ b/src/Web/WebSPA/Startup.cs @@ -1,22 +1,18 @@ using eShopOnContainers.WebSPA; -using Microsoft.ApplicationInsights.Extensibility; -using Microsoft.ApplicationInsights.ServiceFabric; +using HealthChecks.UI.Client; using Microsoft.AspNetCore.Antiforgery; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; -using Newtonsoft.Json.Serialization; using StackExchange.Redis; using System; using System.IO; using WebSPA.Infrastructure; -using HealthChecks.UI.Client; -using Microsoft.AspNetCore.Diagnostics.HealthChecks; -using Microsoft.Extensions.Diagnostics.HealthChecks; namespace eShopConContainers.WebSPA { @@ -29,11 +25,8 @@ namespace eShopConContainers.WebSPA public IConfiguration Configuration { get; } - private IHostingEnvironment _hostingEnv; - public Startup(IHostingEnvironment env) + public Startup() { - _hostingEnv = env; - var localPath = new Uri(Configuration["ASPNETCORE_URLS"])?.LocalPath ?? "/"; Configuration["BaseUrl"] = localPath; } @@ -46,9 +39,7 @@ namespace eShopConContainers.WebSPA services.AddHealthChecks() .AddCheck("self", () => HealthCheckResult.Healthy()) - .AddUrlGroup(new Uri(Configuration["PurchaseUrlHC"]), name: "purchaseapigw-check", tags: new string[] { "purchaseapigw" }) - .AddUrlGroup(new Uri(Configuration["MarketingUrlHC"]), name: "marketingapigw-check", tags: new string[] { "marketingapigw" }) - .AddUrlGroup(new Uri(Configuration["IdentityUrlHC"]), name: "identityapi-check", tags: new string[] { "identityapi" }); + .AddUrlGroup(new Uri(Configuration["IdentityUrlHC"]), name: "identityapi-check", tags: new string[] { "identityapi" }); services.Configure(Configuration); @@ -62,16 +53,13 @@ namespace eShopConContainers.WebSPA } services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN"); - - services.AddMvc() - .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) + services.AddControllers() .AddJsonOptions(options => { - options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); + options.JsonSerializerOptions.PropertyNameCaseInsensitive = true; }); } - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IAntiforgery antiforgery) { @@ -81,23 +69,7 @@ namespace eShopConContainers.WebSPA { app.UseDeveloperExceptionPage(); } - else - { - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); - } - - app.UseHealthChecks("/liveness", new HealthCheckOptions - { - Predicate = r => r.Name.Contains("self") - }); - - app.UseHealthChecks("/hc", new HealthCheckOptions() - { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - + // Configure XSRF middleware, This pattern is for SPA style applications where XSRF token is added on Index page // load and passed back token on every subsequent async request // app.Use(async (context, next) => @@ -114,6 +86,7 @@ namespace eShopConContainers.WebSPA WebContextSeed.Seed(app, env, loggerFactory); var pathBase = Configuration["PATH_BASE"]; + if (!string.IsNullOrEmpty(pathBase)) { loggerFactory.CreateLogger().LogDebug("Using PATH BASE '{pathBase}'", pathBase); @@ -128,34 +101,35 @@ namespace eShopConContainers.WebSPA // Rewrite request to use app root if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value) && !context.Request.Path.Value.StartsWith("/api")) { - context.Request.Path = "/index.html"; + context.Request.Path = "/index.html"; context.Response.StatusCode = 200; // Make sure we update the status code, otherwise it returns 404 await next(); } }); - + app.UseDefaultFiles(); app.UseStaticFiles(); - - app.UseMvcWithDefaultRoute(); + app.UseRouting(); + app.UseEndpoints(endpoints => + { + endpoints.MapDefaultControllerRoute(); + endpoints.MapControllers(); + endpoints.MapHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = r => r.Name.Contains("self") + }); + endpoints.MapHealthChecks("/hc", new HealthCheckOptions() + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + }); } private void RegisterAppInsights(IServiceCollection services) { services.AddApplicationInsightsTelemetry(Configuration); - var orchestratorType = Configuration.GetValue("OrchestratorType"); - - if (orchestratorType?.ToUpper() == "K8S") - { - // Enable K8s telemetry initializer - services.AddApplicationInsightsKubernetesEnricher(); - } - if (orchestratorType?.ToUpper() == "SF") - { - // Enable SF telemetry initializer - services.AddSingleton((serviceProvider) => - new FabricTelemetryInitializer()); - } + services.AddApplicationInsightsKubernetesEnricher(); } } } diff --git a/src/Web/WebSPA/WebSPA.csproj b/src/Web/WebSPA/WebSPA.csproj index 9b1f292fc..a3b247086 100644 --- a/src/Web/WebSPA/WebSPA.csproj +++ b/src/Web/WebSPA/WebSPA.csproj @@ -1,14 +1,16 @@  - netcoreapp2.2 + $(NetCoreTargetVersion) aspnetcorespa-c23d27a4-eb88-4b18-9b77-2a93f3b15119 ..\..\..\docker-compose.dcproj false + true true wwwroot/dist/** $(DefaultItemExcludes);$(GeneratedItemPatterns) 2.9 + $(LangVersion) @@ -86,18 +88,16 @@ - - - - - - - - - - - - + + + + + + + + + + diff --git a/src/Web/WebSPA/appsettings.json b/src/Web/WebSPA/appsettings.json index 4f7694ea2..5a65eecc0 100644 --- a/src/Web/WebSPA/appsettings.json +++ b/src/Web/WebSPA/appsettings.json @@ -6,6 +6,7 @@ "PurchaseUrlHC": "http://localhost:5202/hc", "MarketingUrlHC": "http://localhost:5203/hc", "IdentityUrlHC": "http://localhost:5105/hc", + "SignalrHubUrl":"http://localhost:5202", "UseCustomizationData": true, "IsClusterEnv": "False", "ActivateCampaignDetailFunction": false, diff --git a/src/Web/WebSPA/package.json b/src/Web/WebSPA/package.json index 177bc4ff8..96b725445 100644 --- a/src/Web/WebSPA/package.json +++ b/src/Web/WebSPA/package.json @@ -37,7 +37,7 @@ "@angular/platform-browser-dynamic": "^7.2.10", "@angular/platform-server": "^7.2.10", "@angular/router": "^7.2.10", - "@aspnet/signalr": "1.0.3", + "@aspnet/signalr": "3.0.0-preview6.19307.2", "@ng-bootstrap/ng-bootstrap": "3.3.0", "bootstrap": "4.3.1", "core-js": "^2.5.0", diff --git a/src/Web/WebStatus/Dockerfile b/src/Web/WebStatus/Dockerfile index df4314def..89b03b5f2 100644 --- a/src/Web/WebStatus/Dockerfile +++ b/src/Web/WebStatus/Dockerfile @@ -1,55 +1,14 @@ -FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base +FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base WORKDIR /app EXPOSE 80 -FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build WORKDIR /src -# Keep the project list and command dotnet restore identical in all Dockfiles to maximize image cache utilization -COPY eShopOnContainers-ServicesAndWebApps.sln . -COPY docker-compose.dcproj /src/ -COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/ -COPY src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj src/ApiGateways/Mobile.Bff.Shopping/aggregator/ -COPY src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj src/ApiGateways/Web.Bff.Shopping/aggregator/ -COPY src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj src/BuildingBlocks/Devspaces.Support/ -COPY src/BuildingBlocks/EventBus/EventBus/EventBus.csproj src/BuildingBlocks/EventBus/EventBus/ -COPY src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj src/BuildingBlocks/EventBus/EventBus.Tests/ -COPY src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj src/BuildingBlocks/EventBus/EventBusRabbitMQ/ -COPY src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj src/BuildingBlocks/EventBus/EventBusServiceBus/ -COPY src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj src/BuildingBlocks/EventBus/IntegrationEventLogEF/ -COPY src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj src/BuildingBlocks/WebHostCustomization/WebHost.Customization/ -COPY src/Services/Basket/Basket.API/Basket.API.csproj src/Services/Basket/Basket.API/ -COPY src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj src/Services/Basket/Basket.FunctionalTests/ -COPY src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj src/Services/Basket/Basket.UnitTests/ -COPY src/Services/Catalog/Catalog.API/Catalog.API.csproj src/Services/Catalog/Catalog.API/ -COPY src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj src/Services/Catalog/Catalog.FunctionalTests/ -COPY src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj src/Services/Catalog/Catalog.UnitTests/ -COPY src/Services/Identity/Identity.API/Identity.API.csproj src/Services/Identity/Identity.API/ -COPY src/Services/Location/Locations.API/Locations.API.csproj src/Services/Location/Locations.API/ -COPY src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj src/Services/Location/Locations.FunctionalTests/ -COPY src/Services/Marketing/Marketing.API/Marketing.API.csproj src/Services/Marketing/Marketing.API/ -COPY src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj src/Services/Marketing/Marketing.FunctionalTests/ -COPY src/Services/Ordering/Ordering.API/Ordering.API.csproj src/Services/Ordering/Ordering.API/ -COPY src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj src/Services/Ordering/Ordering.BackgroundTasks/ -COPY src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj src/Services/Ordering/Ordering.Domain/ -COPY src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj src/Services/Ordering/Ordering.FunctionalTests/ -COPY src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj src/Services/Ordering/Ordering.Infrastructure/ -COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/ -COPY src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj src/Services/Ordering/Ordering.UnitTests/ -COPY src/Services/Payment/Payment.API/Payment.API.csproj src/Services/Payment/Payment.API/ -COPY src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj src/Services/Webhooks/Webhooks.API/ -COPY src/Web/WebhookClient/WebhookClient.csproj src/Web/WebhookClient/ -COPY src/Web/WebMVC/WebMVC.csproj src/Web/WebMVC/ -COPY src/Web/WebSPA/WebSPA.csproj src/Web/WebSPA/ -COPY src/Web/WebStatus/WebStatus.csproj src/Web/WebStatus/ -COPY test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj test/ServicesTests/Application.FunctionalTests/ -COPY test/ServicesTests/LoadTest/LoadTest.csproj test/ServicesTests/LoadTest/ - -RUN dotnet restore eShopOnContainers-ServicesAndWebApps.sln COPY . . -WORKDIR /src/src/Web/WebStatus -RUN dotnet publish --no-restore -c Release -o /app +WORKDIR /src/Web/WebStatus +RUN dotnet publish -c Release -o /app FROM build AS publish diff --git a/src/Web/WebStatus/Program.cs b/src/Web/WebStatus/Program.cs index c8c850cfd..efe3f051b 100644 --- a/src/Web/WebStatus/Program.cs +++ b/src/Web/WebStatus/Program.cs @@ -54,7 +54,7 @@ namespace WebStatus .UseSerilog() .Build(); - private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration) + private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration) { var seqServerUrl = configuration["Serilog:SeqServerUrl"]; var logstashUrl = configuration["Serilog:LogstashgUrl"]; diff --git a/src/Web/WebStatus/Startup.cs b/src/Web/WebStatus/Startup.cs index 5b35ee84f..c68239c32 100644 --- a/src/Web/WebStatus/Startup.cs +++ b/src/Web/WebStatus/Startup.cs @@ -1,7 +1,4 @@ -using HealthChecks.UI.Client; -using Microsoft.ApplicationInsights.Extensibility; -using Microsoft.ApplicationInsights.ServiceFabric; -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; @@ -26,14 +23,15 @@ namespace WebStatus { RegisterAppInsights(services); + services.AddControllers(); + services.AddOptions(); services.AddHealthChecks() .AddCheck("self", () => HealthCheckResult.Healthy()); services.AddHealthChecksUI(); - services.AddMvc() - .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); + .SetCompatibilityVersion(CompatibilityVersion.Version_3_0); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -49,8 +47,6 @@ namespace WebStatus else { app.UseExceptionHandler("/Home/Error"); - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); } var pathBase = Configuration["PATH_BASE"]; @@ -59,44 +55,29 @@ namespace WebStatus app.UsePathBase(pathBase); } - app.UseHealthChecks("/liveness", new HealthCheckOptions + app.UseHealthChecksUI(config => { - Predicate = r => r.Name.Contains("self") - }); - - app.UseHealthChecksUI(config => { config.ResourcesPath = string.IsNullOrEmpty(pathBase) ? "/ui/resources" : $"{pathBase}/ui/resources"; - config.UIPath = "/hc-ui"; + config.UIPath = "/hc-ui"; }); - - app.UseStaticFiles(); - app.UseHttpsRedirection(); + app.UseStaticFiles(); - app.UseMvc(routes => + app.UseRouting(); + app.UseEndpoints(endpoints => { - routes.MapRoute( - name: "default", - template: "{controller=Home}/{action=Index}/{id?}"); + endpoints.MapDefaultControllerRoute(); + endpoints.MapHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = r => r.Name.Contains("self") + }); }); } private void RegisterAppInsights(IServiceCollection services) { services.AddApplicationInsightsTelemetry(Configuration); - var orchestratorType = Configuration.GetValue("OrchestratorType"); - - if (orchestratorType?.ToUpper() == "K8S") - { - // Enable K8s telemetry initializer - services.AddApplicationInsightsKubernetesEnricher(); - } - if (orchestratorType?.ToUpper() == "SF") - { - // Enable SF telemetry initializer - services.AddSingleton((serviceProvider) => - new FabricTelemetryInitializer()); - } + services.AddApplicationInsightsKubernetesEnricher(); } } } diff --git a/src/Web/WebStatus/WebStatus.csproj b/src/Web/WebStatus/WebStatus.csproj index 5acc4adb3..7ddadb6f2 100644 --- a/src/Web/WebStatus/WebStatus.csproj +++ b/src/Web/WebStatus/WebStatus.csproj @@ -1,31 +1,31 @@  - netcoreapp2.2 + $(NetCoreTargetVersion) $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; ..\..\..\docker-compose.dcproj + true + $(LangVersion) + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - + Always diff --git a/src/Web/WebStatus/appsettings.Development.json b/src/Web/WebStatus/appsettings.Development.json index 9e0cea9d0..a96c927e8 100644 --- a/src/Web/WebStatus/appsettings.Development.json +++ b/src/Web/WebStatus/appsettings.Development.json @@ -1,87 +1,7 @@ { - "HealthChecksUI": { - "HealthChecks": [ - { - "Name": "Ordering HTTP Check", - "Uri": "http://localhost:5102/hc" - }, - { - "Name": "Ordering HTTP Background Check", - "Uri": "http://localhost:5111/hc" - }, - { - "Name": "Basket HTTP Check", - "Uri": "http://localhost:5103/hc" - }, - { - "Name": "Catalog HTTP Check", - "Uri": "http://localhost:5101/hc" - }, - { - "Name": "Identity HTTP Check", - "Uri": "http://localhost:5105/hc" - }, - { - "Name": "Marketing HTTP Check", - "Uri": "http://localhost:5110/hc" - }, - { - "Name": "Locations HTTP Check", - "Uri": "http://localhost:5109/hc" - }, - { - "Name": "Payments HTTP Check", - "Uri": "http://localhost:5108/hc" - }, - { - "Name": "WebMVC HTTP Check (settings-dev)", - "Uri": "http://localhost:5100/hc" - }, - { - "Name": "WebSPA HTTP Check", - "Uri": "http://localhost:5104/hc" - }, - { - "Name": "SignalR HTTP Check", - "Uri": "http://localhost:5112/hc" - }, - { - "Name": "Mobile Shopping API GW HTTP Check", - "Uri": "http://localhost:5200/hc" - }, - { - "Name": "Mobile Marketing API GW HTTP Check", - "Uri": "http://localhost:5201/hc" - }, - { - "Name": "Web Shopping API GW HTTP Check", - "Uri": "http://localhost:5202/hc" - }, - { - "Name": "Web Marketing API GW HTTP Check", - "Uri": "http://localhost:5203/hc" - }, - { - "Name": "Mobile Shopping Aggregator HTTP Check", - "Uri": "http://localhost:5120/hc" - }, - { - "Name": "Web Shopping Aggregator HTTP Check", - "Uri": "http://localhost:5121/hc" - } - ], - "EvaluationTimeOnSeconds": 10, - "MinimumSecondsBetweenFailureNotifications": 60 - }, "Serilog": { - "SeqServerUrl": "http://localhost:5341/", "MinimumLevel": { - "Default": "Information", - "Override": { - "Microsoft": "Warning", - "Microsoft.eShopOnContainers": "Information", - "System": "Warning" - } + "Default": "Debug" } } } diff --git a/src/Web/WebhookClient/Controllers/AccountController.cs b/src/Web/WebhookClient/Controllers/AccountController.cs index 26fc4074e..461e3261d 100644 --- a/src/Web/WebhookClient/Controllers/AccountController.cs +++ b/src/Web/WebhookClient/Controllers/AccountController.cs @@ -3,9 +3,6 @@ using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using System; -using System.Collections.Generic; -using System.Linq; using System.Security.Claims; using System.Threading.Tasks; diff --git a/src/Web/WebhookClient/Dockerfile b/src/Web/WebhookClient/Dockerfile index 8711bf0c2..f6d81ba0a 100644 --- a/src/Web/WebhookClient/Dockerfile +++ b/src/Web/WebhookClient/Dockerfile @@ -1,56 +1,21 @@ -FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base +FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base WORKDIR /app EXPOSE 80 EXPOSE 443 -FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build +FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build WORKDIR /src -# Keep the project list and command dotnet restore identical in all Dockfiles to maximize image cache utilization -COPY eShopOnContainers-ServicesAndWebApps.sln . -COPY docker-compose.dcproj /src/ -COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/ -COPY src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj src/ApiGateways/Mobile.Bff.Shopping/aggregator/ -COPY src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj src/ApiGateways/Web.Bff.Shopping/aggregator/ -COPY src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj src/BuildingBlocks/Devspaces.Support/ -COPY src/BuildingBlocks/EventBus/EventBus/EventBus.csproj src/BuildingBlocks/EventBus/EventBus/ -COPY src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj src/BuildingBlocks/EventBus/EventBus.Tests/ -COPY src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj src/BuildingBlocks/EventBus/EventBusRabbitMQ/ -COPY src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj src/BuildingBlocks/EventBus/EventBusServiceBus/ -COPY src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj src/BuildingBlocks/EventBus/IntegrationEventLogEF/ -COPY src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj src/BuildingBlocks/WebHostCustomization/WebHost.Customization/ -COPY src/Services/Basket/Basket.API/Basket.API.csproj src/Services/Basket/Basket.API/ -COPY src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj src/Services/Basket/Basket.FunctionalTests/ -COPY src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj src/Services/Basket/Basket.UnitTests/ -COPY src/Services/Catalog/Catalog.API/Catalog.API.csproj src/Services/Catalog/Catalog.API/ -COPY src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj src/Services/Catalog/Catalog.FunctionalTests/ -COPY src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj src/Services/Catalog/Catalog.UnitTests/ -COPY src/Services/Identity/Identity.API/Identity.API.csproj src/Services/Identity/Identity.API/ -COPY src/Services/Location/Locations.API/Locations.API.csproj src/Services/Location/Locations.API/ -COPY src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj src/Services/Location/Locations.FunctionalTests/ -COPY src/Services/Marketing/Marketing.API/Marketing.API.csproj src/Services/Marketing/Marketing.API/ -COPY src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj src/Services/Marketing/Marketing.FunctionalTests/ -COPY src/Services/Ordering/Ordering.API/Ordering.API.csproj src/Services/Ordering/Ordering.API/ -COPY src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj src/Services/Ordering/Ordering.BackgroundTasks/ -COPY src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj src/Services/Ordering/Ordering.Domain/ -COPY src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj src/Services/Ordering/Ordering.FunctionalTests/ -COPY src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj src/Services/Ordering/Ordering.Infrastructure/ -COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/ -COPY src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj src/Services/Ordering/Ordering.UnitTests/ -COPY src/Services/Payment/Payment.API/Payment.API.csproj src/Services/Payment/Payment.API/ -COPY src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj src/Services/Webhooks/Webhooks.API/ -COPY src/Web/WebhookClient/WebhookClient.csproj src/Web/WebhookClient/ -COPY src/Web/WebMVC/WebMVC.csproj src/Web/WebMVC/ -COPY src/Web/WebSPA/WebSPA.csproj src/Web/WebSPA/ -COPY src/Web/WebStatus/WebStatus.csproj src/Web/WebStatus/ -COPY test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj test/ServicesTests/Application.FunctionalTests/ -COPY test/ServicesTests/LoadTest/LoadTest.csproj test/ServicesTests/LoadTest/ +COPY scripts scripts/ -RUN dotnet restore eShopOnContainers-ServicesAndWebApps.sln +COPY ApiGateways/*/*/*.csproj csproj-files/ +COPY BuildingBlocks/*/*/*.csproj csproj-files/ +COPY Services/*/*/*.csproj csproj-files/ +COPY Web/*/*.csproj csproj-files/ COPY . . -WORKDIR /src/src/Web/WebhookClient -RUN dotnet publish --no-restore -c Release -o /app +WORKDIR /src/Web/WebhookClient +RUN dotnet publish -c Release -o /app FROM build AS publish diff --git a/src/Web/WebhookClient/Startup.cs b/src/Web/WebhookClient/Startup.cs index 13ff70362..f93f61a5f 100644 --- a/src/Web/WebhookClient/Startup.cs +++ b/src/Web/WebhookClient/Startup.cs @@ -26,8 +26,7 @@ namespace WebhookClient // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services - .AddSession(opt => + services.AddSession(opt => { opt.Cookie.Name = ".eShopWebhooks.Session"; }) @@ -36,7 +35,10 @@ namespace WebhookClient .AddCustomAuthentication(Configuration) .AddTransient() .AddSingleton() - .AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); + .AddMvc() + .SetCompatibilityVersion(CompatibilityVersion.Version_3_0); + + services.AddControllers(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -69,7 +71,7 @@ namespace WebhookClient var header = context.Request.Headers[HeaderNames.WebHookCheckHeader]; var value = header.FirstOrDefault(); var tokenToValidate = Configuration["Token"]; - if (!validateToken || value == tokenToValidate) + if (!validateToken || value == tokenToValidate) { if (!string.IsNullOrWhiteSpace(tokenToValidate)) { @@ -91,7 +93,11 @@ namespace WebhookClient }); app.UseStaticFiles(); app.UseSession(); - app.UseMvcWithDefaultRoute(); + app.UseRouting(); + app.UseEndpoints(endpoints => + { + endpoints.MapDefaultControllerRoute(); + }); } } diff --git a/src/Web/WebhookClient/WebhookClient.csproj b/src/Web/WebhookClient/WebhookClient.csproj index 895cbac54..95f4b79e8 100644 --- a/src/Web/WebhookClient/WebhookClient.csproj +++ b/src/Web/WebhookClient/WebhookClient.csproj @@ -1,18 +1,21 @@ - + - netcoreapp2.2 + $(NetCoreTargetVersion) InProcess Linux 36215d41-f31a-4aa6-9929-bd67d650e7b5 + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + true + $(LangVersion) - - - - - + + + + diff --git a/src/_build/ReadMe.md b/src/_build/ReadMe.md new file mode 100644 index 000000000..536add60b --- /dev/null +++ b/src/_build/ReadMe.md @@ -0,0 +1 @@ +`Please define why we are using this here.` diff --git a/src/_build/dependencies.props b/src/_build/dependencies.props new file mode 100644 index 000000000..31233baf7 --- /dev/null +++ b/src/_build/dependencies.props @@ -0,0 +1,130 @@ + + + netstandard2.1 + netcoreapp3.0 + 15.8.0 + preview + + + + 2.1.1 + 2.1.1 + + + + 2.9.406 + + + + 0.1.22-pre3 + 0.1.22-pre3 + 3.9.1 + 1.22.0 + 2.23.0 + 0.1.22-pre2 + + 3.0.0-preview8.19405.4 + 1.7.9 + 2.2.0 + 2.2.0 + 2.2.0 + 2.2.0 + 2.2.0 + 2.2.0 + 2.2.22 + 2.2.3 + 2.2.2 + 4.9.2 + 4.2.1 + 1.50.7 + 4.3.0 + 4.5.1 + 4.5.0 + 5.1.0 + 2.6.375 + 5.2.7 + 15.9.20 + 1.0.172 + 3.0.0-preview4-19123-01 + 1.0.2105168 + 3.0.0-preview6-19319-03 + 5.1.0 + 2.2.1 + 2.6.1 + 1.0.2 + 3.0.0-preview4-19123-01 + 3.0.0-preview8.19405.7 + 3.0.0-preview4-19123-01 + 3.0.0-preview4-19123-01 + 3.0.0-alpha1-10670 + 2.2.0-preview2-35157 + 3.0.0-alpha1-34847 + 3.0.0-preview8.19405.7 + 3.0.0-preview8.19405.7 + 2.2.0 + 1.0.0 + 2.2.0 + 3.0.0-preview4-19123-01 + 3.0.0-preview6.19307.2 + 3.0.0-preview8.19405.7 + 3.0.0-preview8.19405.7 + 3.0.0-preview8.19405.7 + 3.0.0-preview4-19123-01 + 3.0.0-preview4-19123-01 + 7.5.0 + 3.0.0 + 4.5.0 + 4.7.0-preview8.19405.3 + 3.0.0-preview8.19405.11 + 3.0.0-preview8.19405.11 + 3.0.0-preview8.19405.11 + 3.0.0-preview8.19405.11 + 3.0.0-preview5.19227.1 + 3.0.0-preview5.19227.1 + 3.0.0-preview5.19227.1 + 3.0.0-preview8.19405.3 + 3.0.0-preview8.19405.7 + 3.0.0-preview8.19405.4 + 2.2.0 + 2.2.0 + 2.2.0 + 2.2.0 + 2.2.0 + 3.0.0-preview8.19405.4 + 16.0.1 + 2.9.0-beta2 + 2.9.0-beta2 + 2.9.0-beta2 + 2.9.0-beta2 + 4.10.1 + 12.0.2 + 3.0.0-preview8.19405.7 + 12.0.1 + 6.0.1 + 3.0.0-preview3.4 + 3.0.0-preview3.4 + 3.0.0-preview3.4 + 3.0.0-preview3.4 + 3.0.0-preview3.4 + 5.0.1 + 3.0.0-dev-00053 + 2.1.3 + 3.1.1-dev-00209 + 3.1.1 + 4.0.0 + 4.2.1 + 1.2.6 + 5.0.0-rc2 + 4.3.0 + 2.4.0 + 2.4.0 + + + + https://github.com/dotnet-architecture/eShopOnContainers/blob/master/LICENSE + https://github.com/dotnet-architecture/eShopOnContainers + https://github.com/dotnet-architecture/eShopOnContainers + Microsoft + + + \ No newline at end of file diff --git a/docker-compose-tests.override.yml b/src/docker-compose-tests.override.yml similarity index 98% rename from docker-compose-tests.override.yml rename to src/docker-compose-tests.override.yml index 8705e703f..cee5c6623 100644 --- a/docker-compose-tests.override.yml +++ b/src/docker-compose-tests.override.yml @@ -6,6 +6,10 @@ services: - "15672:15672" - "5672:5672" + basket-data-test: + ports: + - "6379:6379" + sql-data-test: environment: - SA_PASSWORD=Pass@word @@ -17,10 +21,6 @@ services: ports: - "27017:27017" - basket-data-test: - ports: - - "6379:6379" - identity-api-test: environment: - ASPNETCORE_ENVIRONMENT=Development @@ -90,7 +90,7 @@ services: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - ConnectionString=${ESHOP_AZURE_CATALOG_DB:-Server=sql-data-test;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word} - - PicBaseUrl=${ESHOP_AZURE_STORAGE_CATALOG_URL:-http://localhost:5202/api/v1/c/catalog/items/[0]/pic/} + - PicBaseUrl=${ESHOP_AZURE_STORAGE_CATALOG_URL:-http://localhost:5202/c/api/v1/catalog/items/[0]/pic/} - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq-test} - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} @@ -114,7 +114,7 @@ services: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - ConnectionString=${ESHOP_AZURE_CATALOG_DB:-Server=sql-data-test;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word} - - PicBaseUrl=${ESHOP_AZURE_STORAGE_CATALOG_URL:-http://localhost:5202/api/v1/c/catalog/items/[0]/pic/} + - PicBaseUrl=${ESHOP_AZURE_STORAGE_CATALOG_URL:-http://localhost:5202/c/api/v1/catalog/items/[0]/pic/} - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq-test} - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} diff --git a/docker-compose-tests.yml b/src/docker-compose-tests.yml similarity index 82% rename from docker-compose-tests.yml rename to src/docker-compose-tests.yml index 7794d1a0e..440e3e5c0 100644 --- a/docker-compose-tests.yml +++ b/src/docker-compose-tests.yml @@ -17,7 +17,7 @@ services: image: ${REGISTRY:-eshop}/identity-api-test:${TAG:-latest} build: context: . - dockerfile: src/Services/Identity/Identity.API/Dockerfile + dockerfile: Services/Identity/Identity.API/Dockerfile depends_on: - sql-data-test @@ -25,7 +25,7 @@ services: image: ${REGISTRY:-eshop}/basket-api-test:${TAG:-latest} build: context: . - dockerfile: src/Services/Basket/Basket.API/Dockerfile + dockerfile: Services/Basket/Basket.API/Dockerfile target: functionaltest depends_on: - basket-data-test @@ -38,7 +38,7 @@ services: image: ${REGISTRY:-eshop}/basket-api-test:${TAG:-latest} build: context: . - dockerfile: src/Services/Basket/Basket.API/Dockerfile + dockerfile: Services/Basket/Basket.API/Dockerfile target: unittest depends_on: - basket-data-test @@ -51,7 +51,7 @@ services: image: ${REGISTRY:-eshop}/catalog-api-test:${TAG:-latest} build: context: . - dockerfile: src/Services/Catalog/Catalog.API/Dockerfile + dockerfile: Services/Catalog/Catalog.API/Dockerfile target: functionaltest depends_on: - sql-data-test @@ -63,7 +63,7 @@ services: image: ${REGISTRY:-eshop}/catalog-api-test:${TAG:-latest} build: context: . - dockerfile: src/Services/Catalog/Catalog.API/Dockerfile + dockerfile: Services/Catalog/Catalog.API/Dockerfile target: unittest depends_on: - sql-data-test @@ -75,7 +75,7 @@ services: image: ${REGISTRY:-eshop}/ordering-api-test:${TAG:-latest} build: context: . - dockerfile: src/Services/Ordering/Ordering.API/Dockerfile + dockerfile: Services/Ordering/Ordering.API/Dockerfile target: functionaltest depends_on: - sql-data-test @@ -87,7 +87,7 @@ services: image: ${REGISTRY:-eshop}/ordering-api-test:${TAG:-latest} build: context: . - dockerfile: src/Services/Ordering/Ordering.API/Dockerfile + dockerfile: Services/Ordering/Ordering.API/Dockerfile target: unittest depends_on: - sql-data-test @@ -99,7 +99,7 @@ services: image: ${REGISTRY:-eshop}/marketing-api-test:${TAG:-latest} build: context: . - dockerfile: src/Services/Marketing/Marketing.API/Dockerfile + dockerfile: Services/Marketing/Marketing.API/Dockerfile target: functionaltest depends_on: - sql-data-test @@ -113,7 +113,7 @@ services: image: ${REGISTRY:-eshop}/payment-api-test:${TAG:-latest} build: context: . - dockerfile: src/Services/Payment/Payment.API/Dockerfile + dockerfile: Services/Payment/Payment.API/Dockerfile depends_on: - rabbitmq-test @@ -121,7 +121,7 @@ services: image: ${REGISTRY:-eshop}/locations-api-test:${TAG:-latest} build: context: . - dockerfile: src/Services/Location/Locations.API/Dockerfile + dockerfile: Services/Location/Locations.API/Dockerfile target: functionaltest depends_on: - nosql-data-test diff --git a/docker-compose-windows.prod.yml b/src/docker-compose-windows.prod.yml similarity index 77% rename from docker-compose-windows.prod.yml rename to src/docker-compose-windows.prod.yml index ead977f29..e38767a03 100644 --- a/docker-compose-windows.prod.yml +++ b/src/docker-compose-windows.prod.yml @@ -13,23 +13,23 @@ version: '3.4' services: - basket.api: + basket-api: environment: - ASPNETCORE_ENVIRONMENT=Production - ASPNETCORE_URLS=http://0.0.0.0:80 - ConnectionString=${ESHOP_AZURE_REDIS_BASKET_DB:-basket.data} - - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. + - identityUrl=http://identity-api #Local: You need to open your local dev-machine firewall at range 5100-5110. - IdentityUrlExternal=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - AzureServiceBusEnabled=False ports: - "5103:5103" - catalog.api: + catalog-api: environment: - ASPNETCORE_ENVIRONMENT=Production - ASPNETCORE_URLS=http://0.0.0.0:80 - - ConnectionString=${ESHOP_AZURE_CATALOG_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word} + - ConnectionString=${ESHOP_AZURE_CATALOG_DB:-Server=sqldata;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word} - PicBaseUrl=${ESHOP_AZURE_STORAGE_CATALOG:-http://localhost:5101/api/v1/catalog/items/[0]/pic/} #Local: You need to open your local dev-machine firewall at range 5100-5110. - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - AzureStorageAccountName=${ESHOP_AZURE_STORAGE_CATALOG_NAME} @@ -40,13 +40,13 @@ services: ports: - "5101:80" - identity.api: + identity-api: environment: - ASPNETCORE_ENVIRONMENT=Production - ASPNETCORE_URLS=http://0.0.0.0:80 - SpaClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5104 - XamarinCallback=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105/xamarincallback - - ConnectionStrings__DefaultConnection=${ESHOP_AZURE_IDENTITY_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word} + - ConnectionStrings__DefaultConnection=${ESHOP_AZURE_IDENTITY_DB:-Server=sqldata;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word} - MvcClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5100 #Local: You need to open your local dev-machine firewall at range 5100-5110. - LocationApiClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5109 - MarketingApiClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5110 @@ -56,30 +56,30 @@ services: ports: - "5105:80" - ordering.api: + ordering-api: environment: - ASPNETCORE_ENVIRONMENT=Production - ASPNETCORE_URLS=http://0.0.0.0:80 - - ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word} - - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. + - ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sqldata;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word} + - identityUrl=http://identity-api #Local: You need to open your local dev-machine firewall at range 5100-5110. - IdentityUrlExternal=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - UseCustomizationData=True - AzureServiceBusEnabled=False ports: - "5102:80" - + ordering.backgroundtasks: environment: - ASPNETCORE_ENVIRONMENT=Production - ASPNETCORE_URLS=http://0.0.0.0:80 - - ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word} + - ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sqldata;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word} - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - UseCustomizationData=True - AzureServiceBusEnabled=False ports: - "5111:80" - + webspa: environment: - ASPNETCORE_ENVIRONMENT=Production @@ -89,11 +89,11 @@ services: - IdentityUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: You need to open your host's firewall at range 5100-5110. - BasketUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5103 - MarketingUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5110 - - CatalogUrlHC=http://catalog.api/hc - - OrderingUrlHC=http://ordering.api/hc - - IdentityUrlHC=http://identity.api/hc #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser. - - BasketUrlHC=http://basket.api/hc - - MarketingUrlHC=http://marketing.api/hc + - CatalogUrlHC=http://catalog-api/hc + - OrderingUrlHC=http://ordering-api/hc + - IdentityUrlHC=http://identity-api/hc #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser. + - BasketUrlHC=http://basket-api/hc + - MarketingUrlHC=http://marketing-api/hc - UseCustomizationData=True ports: - "5104:80" @@ -102,24 +102,24 @@ services: environment: - ASPNETCORE_ENVIRONMENT=Production - ASPNETCORE_URLS=http://0.0.0.0:80 - - CatalogUrl=http://catalog.api - - OrderingUrl=http://ordering.api + - CatalogUrl=http://catalog-api + - OrderingUrl=http://ordering-api - IdentityUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser. - - BasketUrl=http://basket.api - - MarketingUrl=http://marketing.api + - BasketUrl=http://basket-api + - MarketingUrl=http://marketing-api - UseCustomizationData=True #Remote: Use ${ESHOP_EXTERNAL_DNS_NAME_OR_IP} if using external IP or DNS name from browser. ports: - "5100:80" - marketing.api: + marketing-api: environment: - ASPNETCORE_ENVIRONMENT=Production - ASPNETCORE_URLS=http://0.0.0.0:80 - - ConnectionString=${ESHOP_AZURE_MARKETING_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word} - - MongoConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosql.data} + - ConnectionString=${ESHOP_AZURE_MARKETING_DB:-Server=sqldata;Database=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word} + - MongoConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosqldata} - MongoDatabase=MarketingDb - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. + - identityUrl=http://identity-api #Local: You need to open your local dev-machine firewall at range 5100-5110. - IdentityUrlExternal=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 - CampaignDetailFunctionUri=${ESHOP_AZUREFUNC_CAMPAIGN_DETAILS_URI} - PicBaseUrl=${ESHOP_AZURE_STORAGE_MARKETING:-http://localhost:5110/api/v1/campaigns/[0]/pic/} @@ -130,14 +130,14 @@ services: ports: - "5110:80" - sql.data: + sqldata: environment: - MSSQL_SA_PASSWORD=Pass@word - ACCEPT_EULA=Y ports: - "5433:1433" - nosql.data: + nosqldata: ports: - "27017:27017" @@ -145,19 +145,19 @@ services: environment: - ASPNETCORE_ENVIRONMENT=Production - ASPNETCORE_URLS=http://0.0.0.0:80 - - CatalogUrl=http://catalog.api/hc - - OrderingUrl=http://ordering.api/hc - - BasketUrl=http://basket.api/hc - - IdentityUrl=http://identity.api/hc - - LocationsUrl=http://locations.api/hc - - MarketingUrl=http://marketing.api/hc + - CatalogUrl=http://catalog-api/hc + - OrderingUrl=http://ordering-api/hc + - BasketUrl=http://basket-api/hc + - IdentityUrl=http://identity-api/hc + - LocationsUrl=http://locations-api/hc + - MarketingUrl=http://marketing-api/hc - mvc=http://webmvc/hc - spa=http://webspa/hc ports: - "5107:80" - payment.api: + payment-api: environment: - ASPNETCORE_ENVIRONMENT=Production - ASPNETCORE_URLS=http://0.0.0.0:5108 @@ -166,13 +166,13 @@ services: ports: - "5108:80" - locations.api: + locations-api: environment: - ASPNETCORE_ENVIRONMENT=Production - ASPNETCORE_URLS=http://0.0.0.0:80 - - ConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosql.data} + - ConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosqldata} - Database=LocationsDb - - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. + - identityUrl=http://identity-api #Local: You need to open your local dev-machine firewall at range 5100-5110. - IdentityUrlExternal=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - AzureServiceBusEnabled=False diff --git a/docker-compose.dcproj b/src/docker-compose.dcproj similarity index 100% rename from docker-compose.dcproj rename to src/docker-compose.dcproj diff --git a/docker-compose.elk.yml b/src/docker-compose.elk.yml similarity index 100% rename from docker-compose.elk.yml rename to src/docker-compose.elk.yml diff --git a/docker-compose.override.windows.yml b/src/docker-compose.override.windows.yml similarity index 91% rename from docker-compose.override.windows.yml rename to src/docker-compose.override.windows.yml index dcaac7c45..89b26092a 100644 --- a/docker-compose.override.windows.yml +++ b/src/docker-compose.override.windows.yml @@ -22,37 +22,37 @@ version: '3.4' # docker-compose -f docker-compose-windows.yml -f docker-compose.override.yml -f docker-compose.override.windows.yml up services: - basket.api: + basket-api: environment: - EventBusUserName=admin - EventBusPassword=password - catalog.api: + catalog-api: environment: - EventBusUserName=admin - EventBusPassword=password - ordering.api: + ordering-api: environment: - EventBusUserName=admin - EventBusPassword=password - ordering.backgroundtasks: + ordering-backgroundtasks: environment: - EventBusUserName=admin - EventBusPassword=password - payment.api: + payment-api: environment: - EventBusUserName=admin - EventBusPassword=password - locations.api: + locations-api: environment: - EventBusUserName=admin - EventBusPassword=password - ordering.signalrhub: + ordering-signalrhub: environment: - EventBusUserName=admin - EventBusPassword=password diff --git a/src/docker-compose.override.yml b/src/docker-compose.override.yml new file mode 100644 index 000000000..564ff4eb9 --- /dev/null +++ b/src/docker-compose.override.yml @@ -0,0 +1,389 @@ +version: '3.4' + +# The default docker-compose.override file can use the "localhost" as the external name for testing web apps within the same dev machine. +# The ESHOP_EXTERNAL_DNS_NAME_OR_IP environment variable is taken, by default, from the ".env" file defined like: +# ESHOP_EXTERNAL_DNS_NAME_OR_IP=localhost +# but values present in the environment vars at runtime will always override those defined inside the .env file +# An external IP or DNS name has to be used (instead localhost and the 10.0.75.1 IP) when testing the Web apps and the Xamarin apps from remote machines/devices using the same WiFi, for instance. + +services: + seq: + environment: + - ACCEPT_EULA=Y + ports: + - "5340:80" + + sqldata: + environment: + - SA_PASSWORD=Pass@word + - ACCEPT_EULA=Y + ports: + - "5433:1433" + volumes: + - eshop-sqldata:/var/opt/mssql + + nosqldata: + ports: + - "27017:27017" + volumes: + - eshop-nosqldata:/data/db + + basketdata: + ports: + - "6379:6379" + volumes: + - eshop-basketdata:/data + rabbitmq: + ports: + - "15672:15672" + - "5672:5672" + + identity-api: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - SpaClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5104 + - XamarinCallback=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105/xamarincallback + - ConnectionString=${ESHOP_AZURE_IDENTITY_DB:-Server=sqldata;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word} + - MvcClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5100 + - LocationApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5109 + - MarketingApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5110 + - BasketApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5103 + - OrderingApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5102 + - MobileShoppingAggClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5120 + - WebShoppingAggClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5121 + - WebhooksApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5113 + - WebhooksWebClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5114 + - UseCustomizationData=True + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + ports: + - "5105:80" + + basket-api: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - ConnectionString=${ESHOP_AZURE_REDIS_BASKET_DB:-basketdata} + - identityUrl=http://identity-api + - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 + - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} + - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} + - AzureServiceBusEnabled=False + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + - UseLoadTest=${USE_LOADTEST:-False} + - PATH_BASE=/basket-api + - GRPC_PORT=81 + - PORT=80 + ports: + - "5103:80" + - "9103:81" + + catalog-api: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ConnectionString=${ESHOP_AZURE_CATALOG_DB:-Server=sqldata;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word} + - PicBaseUrl=${ESHOP_AZURE_STORAGE_CATALOG_URL:-http://localhost:5202/c/api/v1/catalog/items/[0]/pic/} #Local: You need to open your local dev-machine firewall at range 5100-5110. + - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} + - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} + - AzureStorageAccountName=${ESHOP_AZURE_STORAGE_CATALOG_NAME} + - AzureStorageAccountKey=${ESHOP_AZURE_STORAGE_CATALOG_KEY} + - UseCustomizationData=True + - AzureServiceBusEnabled=False + - AzureStorageEnabled=False + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + - GRPC_PORT=81 + - PORT=80 + - PATH_BASE=/catalog-api + ports: + - "5101:80" + - "9101:81" + + ordering-api: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sqldata;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word} + - identityUrl=http://identity-api + - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 + - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} + - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} + - UseCustomizationData=True + - AzureServiceBusEnabled=False + - CheckUpdateTime=30000 + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + - UseLoadTest=${USE_LOADTEST:-False} + - Serilog__MinimumLevel__Override__Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ=Verbose + - Serilog__MinimumLevel__Override__ordering-api=Verbose + - PATH_BASE=/ordering-api + - GRPC_PORT=81 + - PORT=80 + ports: + - "5102:80" + - "9102:81" + + ordering-backgroundtasks: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sqldata;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word} + - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} + - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} + - UseCustomizationData=True + - AzureServiceBusEnabled=False + - CheckUpdateTime=30000 + - GracePeriodTime=1 + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + - UseLoadTest=${USE_LOADTEST:-False} + - Serilog__MinimumLevel__Override__Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ=Verbose + ports: + - "5111:80" + + marketing-api: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - ConnectionString=${ESHOP_AZURE_MARKETING_DB:-Server=sqldata;Database=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word} + - MongoConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosqldata} + - MongoDatabase=MarketingDb + - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} + - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} + - identityUrl=http://identity-api + - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 + - CampaignDetailFunctionUri=${ESHOP_AZUREFUNC_CAMPAIGN_DETAILS_URI} + - PicBaseUrl=${ESHOP_AZURE_STORAGE_MARKETING_URL:-http://localhost:5110/api/v1/campaigns/[0]/pic/} + - AzureStorageAccountName=${ESHOP_AZURE_STORAGE_MARKETING_NAME} + - AzureStorageAccountKey=${ESHOP_AZURE_STORAGE_MARKETING_KEY} + - AzureServiceBusEnabled=False + - AzureStorageEnabled=False + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + - UseLoadTest=${USE_LOADTEST:-False} + - PATH_BASE=/marketing-api + ports: + - "5110:80" + + payment-api: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} + - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} + - AzureServiceBusEnabled=False + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + - Serilog__MinimumLevel__Override__payment-api.IntegrationEvents.EventHandling=Verbose + - Serilog__MinimumLevel__Override__Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ=Verbose + ports: + - "5108:80" + + locations-api: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - ConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosqldata} + - Database=LocationsDb + - identityUrl=http://identity-api + - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 + - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} + - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} + - AzureServiceBusEnabled=False + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + - UseLoadTest=${USE_LOADTEST:-False} + - PATH_BASE=/locations-api + ports: + - "5109:80" + + webhooks-api: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - ConnectionString=${ESHOP_AZURE_WEBHOOKS_DB:-Server=sqldata;Database=Microsoft.eShopOnContainers.Services.WebhooksDb;User Id=sa;Password=Pass@word} + - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} + - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} + - IdentityUrl=http://identity-api + - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 + ports: + - "5113:80" + + mobileshoppingapigw: + volumes: + - ./ApiGateways/Envoy/config/mobilemarketing:/etc/envoy + ports: + - "5200:80" + - "15200:8001" + + mobilemarketingapigw: + volumes: + - ./ApiGateways/Envoy/config/mobileshopping:/etc/envoy + ports: + - "5201:80" + - "15201:8001" + + webshoppingapigw: + volumes: + - ./ApiGateways/Envoy/config/webshopping:/etc/envoy + ports: + - "5202:80" + - "15202:8001" + + webmarketingapigw: + volumes: + - ./ApiGateways/Envoy/config/webmarketing:/etc/envoy + ports: + - "5203:80" + - "15203:8001" + + mobileshoppingagg: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - urls__basket=http://basket-api + - urls__catalog=http://catalog-api + - urls__orders=http://ordering-api + - urls__identity=http://identity-api + - urls__grpcBasket=http://basket-api:81 + - urls__grpcCatalog=http://catalog-api:81 + - urls__grpcOrdering=http://ordering-api:81 + - CatalogUrlHC=http://catalog-api/hc + - OrderingUrlHC=http://ordering-api/hc + - IdentityUrlHC=http://identity-api/hc + - BasketUrlHC=http://basket-api/hc + - MarketingUrlHC=http://marketing-api/hc + - PaymentUrlHC=http://payment-api/hc + - LocationUrlHC=http://locations-api/hc + - IdentityUrlExternal=http://10.0.75.1:5105 + ports: + - "5120:80" + + webshoppingagg: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - urls__basket=http://basket-api + - urls__catalog=http://catalog-api + - urls__orders=http://ordering-api + - urls__identity=http://identity-api + - urls__grpcBasket=http://basket-api:81 + - urls__grpcCatalog=http://catalog-api:81 + - urls__grpcOrdering=http://ordering-api:81 + - CatalogUrlHC=http://catalog-api/hc + - OrderingUrlHC=http://ordering-api/hc + - IdentityUrlHC=http://identity-api/hc + - BasketUrlHC=http://basket-api/hc + - MarketingUrlHC=http://marketing-api/hc + - PaymentUrlHC=http://payment-api/hc + - LocationUrlHC=http://locations-api/hc + - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 + ports: + - "5121:80" + + ordering-signalrhub: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} + - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} + - AzureServiceBusEnabled=False + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + - identityUrl=http://identity-api + ports: + - "5112:80" + + webstatus: + environment: + - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_URLS=http://0.0.0.0:80 + - HealthChecks-UI__HealthChecks__0__Name=WebMVC HTTP Check + - HealthChecks-UI__HealthChecks__0__Uri=http://webmvc/hc + - HealthChecks-UI__HealthChecks__1__Name=WebSPA HTTP Check + - HealthChecks-UI__HealthChecks__1__Uri=http://webspa/hc + - HealthChecks-UI__HealthChecks__2__Name=Web Shopping Aggregator GW HTTP Check + - HealthChecks-UI__HealthChecks__2__Uri=http://webshoppingagg/hc + - HealthChecks-UI__HealthChecks__3__Name=Mobile Shopping Aggregator HTTP Check + - HealthChecks-UI__HealthChecks__3__Uri=http://mobileshoppingagg/hc + - HealthChecks-UI__HealthChecks__4__Name=Ordering HTTP Check + - HealthChecks-UI__HealthChecks__4__Uri=http://ordering-api/hc + - HealthChecks-UI__HealthChecks__5__Name=Basket HTTP Check + - HealthChecks-UI__HealthChecks__5__Uri=http://basket-api/hc + - HealthChecks-UI__HealthChecks__6__Name=Catalog HTTP Check + - HealthChecks-UI__HealthChecks__6__Uri=http://catalog-api/hc + - HealthChecks-UI__HealthChecks__7__Name=Identity HTTP Check + - HealthChecks-UI__HealthChecks__7__Uri=http://identity-api/hc + - HealthChecks-UI__HealthChecks__8__Name=Marketing HTTP Check + - HealthChecks-UI__HealthChecks__8__Uri=http://marketing-api/hc + - HealthChecks-UI__HealthChecks__9__Name=Locations HTTP Check + - HealthChecks-UI__HealthChecks__9__Uri=http://locations-api/hc + - HealthChecks-UI__HealthChecks__10__Name=Payments HTTP Check + - HealthChecks-UI__HealthChecks__10__Uri=http://payment-api/hc + - HealthChecks-UI__HealthChecks__11__Name=Ordering SignalRHub HTTP Check + - HealthChecks-UI__HealthChecks__11__Uri=http://ordering-signalrhub/hc + - HealthChecks-UI__HealthChecks__12__Name=Ordering HTTP Background Check + - HealthChecks-UI__HealthChecks__12__Uri=http://ordering-backgroundtasks/hc + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + ports: + - "5107:80" + + webspa: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - IdentityUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 + - PurchaseUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5202 + - MarketingUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5203 + - IdentityUrlHC=http://identity-api/hc + - UseCustomizationData=True + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + - SignalrHubUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5202 + ports: + - "5104:80" + + webmvc: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - PurchaseUrl=http://webshoppingapigw + - IdentityUrl=http://10.0.75.1:5105 + - MarketingUrl=http://webmarketingapigw + - SignalrHubUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5202 + - IdentityUrlHC=http://identity-api/hc + - UseCustomizationData=True + - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} + - OrchestratorType=${ORCHESTRATOR_TYPE} + - UseLoadTest=${USE_LOADTEST:-False} + ports: + - "5100:80" + + webhooks-client: + environment: + - ASPNETCORE_URLS=http://0.0.0.0:80 + - Token=6168DB8D-DC58-4094-AF24-483278923590 # Webhooks are registered with this token (any value is valid) but the client won't check it + - IdentityUrl=http://10.0.75.1:5105 + - CallBackUrl=http://localhost:5114 + - WebhooksUrl=http://webhooks-api + - SelfUrl=http://webhooks-client/ + ports: + - "5114:80" +volumes: + eshop-sqldata: + external: false + eshop-nosqldata: + external: false + eshop-basketdata: + external: false + diff --git a/docker-compose.prod.yml b/src/docker-compose.prod.yml similarity index 80% rename from docker-compose.prod.yml rename to src/docker-compose.prod.yml index 4bf465565..7548a4154 100644 --- a/docker-compose.prod.yml +++ b/src/docker-compose.prod.yml @@ -15,12 +15,12 @@ version: '3.4' services: - basket.api: + basket-api: environment: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - ConnectionString=${ESHOP_AZURE_REDIS_BASKET_DB:-basket.data} - - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. + - identityUrl=http://identity-api #Local: You need to open your local dev-machine firewall at range 5100-5110. - IdentityUrlExternal=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} @@ -33,11 +33,11 @@ services: ports: - "80" # The API Gateway redirects and access through the internal port (80). - catalog.api: + catalog-api: environment: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - - ConnectionString=${ESHOP_AZURE_CATALOG_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word} + - ConnectionString=${ESHOP_AZURE_CATALOG_DB:-Server=sqldata;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word} - PicBaseUrl=${ESHOP_AZURE_STORAGE_CATALOG_URL:-http://localhost:5101/api/v1/catalog/items/[0]/pic/} #Local: You need to open your local dev-machine firewall at range 5100-5110. - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} @@ -52,13 +52,13 @@ services: ports: - "80" # The API Gateway redirects and access through the internal port (80). - identity.api: + identity-api: environment: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - SpaClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5104 - XamarinCallback=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105/xamarincallback #localhost do not work for UWP login, so we have to use "external" IP always - - ConnectionString=${ESHOP_AZURE_IDENTITY_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word} + - ConnectionString=${ESHOP_AZURE_IDENTITY_DB:-Server=sqldata;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word} - MvcClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5100 #Local: You need to open your local dev-machine firewall at range 5100-5110. - LocationApiClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5109 - MarketingApiClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5110 @@ -72,12 +72,12 @@ services: ports: - "5105:80" - ordering.api: + ordering-api: environment: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - - ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word} - - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. + - ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sqldata;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word} + - identityUrl=http://identity-api #Local: You need to open your local dev-machine firewall at range 5100-5110. - IdentityUrlExternal=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} @@ -91,12 +91,11 @@ services: ports: - "80" # The API Gateway redirects and access through the internal port (80). - ordering.backgroundtasks: environment: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - - ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word} + - ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sqldata;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word} - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} @@ -110,17 +109,17 @@ services: ports: - "5111:80" - marketing.api: + marketing-api: environment: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - - ConnectionString=${ESHOP_AZURE_MARKETING_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word} - - MongoConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosql.data} + - ConnectionString=${ESHOP_AZURE_MARKETING_DB:-Server=sqldata;Database=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word} + - MongoConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosqldata} - MongoDatabase=MarketingDb - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} - - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. + - identityUrl=http://identity-api #Local: You need to open your local dev-machine firewall at range 5100-5110. - IdentityUrlExternal=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 - CampaignDetailFunctionUri=${ESHOP_AZUREFUNC_CAMPAIGN_DETAILS_URI} - PicBaseUrl=${ESHOP_AZURE_STORAGE_MARKETING_URL:-http://localhost:5110/api/v1/campaigns/[0]/pic/} @@ -141,12 +140,12 @@ services: - IdentityUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105. - PurchaseUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5202 - MarketingUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5203 - - CatalogUrlHC=http://catalog.api/hc - - OrderingUrlHC=http://ordering.api/hc - - IdentityUrlHC=http://identity.api/hc #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser. - - BasketUrlHC=http://basket.api/hc - - MarketingUrlHC=http://marketing.api/hc - - PaymentUrlHC=http://payment.api/hc + - CatalogUrlHC=http://catalog-api/hc + - OrderingUrlHC=http://ordering-api/hc + - IdentityUrlHC=http://identity-api/hc #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser. + - BasketUrlHC=http://basket-api/hc + - MarketingUrlHC=http://marketing-api/hc + - PaymentUrlHC=http://payment-api/hc - UseCustomizationData=True - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} - OrchestratorType=${ORCHESTRATOR_TYPE} @@ -160,12 +159,12 @@ services: - PurchaseUrl=http://webshoppingapigw - IdentityUrl=http://10.0.75.1:5105 # Local Mac: Use http://docker.for.mac.localhost:5105 || Local Windows: Use 10.0.75.1 in a "Docker for Windows" environment, if using "localhost" from browser. || #Remote access: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP} if using external IP or DNS name from browser. - MarketingUrl=http://webmarketingapigw - - CatalogUrlHC=http://catalog.api/hc - - OrderingUrlHC=http://ordering.api/hc - - IdentityUrlHC=http://identity.api/hc #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser. - - BasketUrlHC=http://basket.api/hc - - MarketingUrlHC=http://marketing.api/hc - - PaymentUrlHC=http://payment.api/hc + - CatalogUrlHC=http://catalog-api/hc + - OrderingUrlHC=http://ordering-api/hc + - IdentityUrlHC=http://identity-api/hc #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser. + - BasketUrlHC=http://basket-api/hc + - MarketingUrlHC=http://marketing-api/hc + - PaymentUrlHC=http://payment-api/hc - UseCustomizationData=True - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} - OrchestratorType=${ORCHESTRATOR_TYPE} @@ -177,14 +176,13 @@ services: environment: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - - CatalogUrl=http://catalog.api/hc - - OrderingUrl=http://ordering.api/hc - - OrderingBackgroundTasksUrl=http://ordering.backgroundtasks/hc - - BasketUrl=http://basket.api/hc - - IdentityUrl=http://identity.api/hc - - LocationsUrl=http://locations.api/hc - - MarketingUrl=http://marketing.api/hc - - PaymentUrl=http://payment.api/hc + - CatalogUrl=http://catalog-api/hc + - OrderingUrl=http://ordering-api/hc + - BasketUrl=http://basket-api/hc + - IdentityUrl=http://identity-api/hc + - LocationsUrl=http://locations-api/hc + - MarketingUrl=http://marketing-api/hc + - PaymentUrl=http://payment-api/hc - mvc=http://webmvc/hc - spa=http://webspa/hc - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} @@ -192,7 +190,7 @@ services: ports: - "5107:80" - payment.api: + payment-api: environment: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 @@ -205,13 +203,13 @@ services: ports: - "80" # The API Gateway redirects and access through the internal port (80). - locations.api: + locations-api: environment: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - - ConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosql.data} + - ConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosqldata} - Database=LocationsDb - - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. + - identityUrl=http://identity-api #Local: You need to open your local dev-machine firewall at range 5100-5110. - IdentityUrlExternal=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} @@ -223,14 +221,14 @@ services: ports: - "80" # The API Gateway redirects and access through the internal port (80). - sql.data: + sqldata: environment: - SA_PASSWORD=Pass@word - ACCEPT_EULA=Y ports: - "5433:1433" # Important: In a production environment your should remove the external port - nosql.data: + nosqldata: ports: - "27017:27017" # Important: In a production environment your should remove the external port @@ -246,50 +244,50 @@ services: mobileshoppingapigw: environment: - ASPNETCORE_ENVIRONMENT=Development - - IdentityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. + - IdentityUrl=http://identity-api #Local: You need to open your local dev-machine firewall at range 5100-5110. ports: - "5200:80" # Important: In a production environment your should remove the external port (5200) kept here for microservice debugging purposes. # The API Gateway redirects and access through the internal port (80). volumes: - - ./src/ApiGateways/Mobile.Bff.Shopping/apigw:/app/configuration + - ./ApiGateways/Mobile.Bff.Shopping/apigw:/app/configuration mobilemarketingapigw: environment: - ASPNETCORE_ENVIRONMENT=Development - - IdentityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. + - IdentityUrl=http://identity-api #Local: You need to open your local dev-machine firewall at range 5100-5110. ports: - "5201:80" # Important: In a production environment your should remove the external port (5201) kept here for microservice debugging purposes. # The API Gateway redirects and access through the internal port (80). volumes: - - ./src/ApiGateways/Mobile.Bff.Marketing/apigw:/app/configuration + - ./ApiGateways/Mobile.Bff.Marketing/apigw:/app/configuration webshoppingapigw: environment: - ASPNETCORE_ENVIRONMENT=Development - - IdentityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. + - IdentityUrl=http://identity-api #Local: You need to open your local dev-machine firewall at range 5100-5110. ports: - "5202:80" # Important: In a production environment your should remove the external port (5202) kept here for microservice debugging purposes. # The API Gateway redirects and access through the internal port (80). volumes: - - ./src/ApiGateways/Web.Bff.Shopping/apigw:/app/configuration + - ./ApiGateways/Web.Bff.Shopping/apigw:/app/configuration webmarketingapigw: environment: - ASPNETCORE_ENVIRONMENT=Development - - IdentityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. + - IdentityUrl=http://identity-api #Local: You need to open your local dev-machine firewall at range 5100-5110. ports: - "5203:80" # Important: In a production environment your should remove the external port (5203) kept here for microservice debugging purposes. # The API Gateway redirects and access through the internal port (80). volumes: - - ./src/ApiGateways/Web.Bff.Marketing/apigw:/app/configuration + - ./ApiGateways/Web.Bff.Marketing/apigw:/app/configuration mobileshoppingagg: environment: - ASPNETCORE_ENVIRONMENT=Development - - urls__basket=http://basket.api - - urls__catalog=http://catalog.api - - urls__orders=http://ordering.api - - urls__identity=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. + - urls__basket=http://basket-api + - urls__catalog=http://catalog-api + - urls__orders=http://ordering-api + - urls__identity=http://identity-api #Local: You need to open your local dev-machine firewall at range 5100-5110. ports: - "80" # Important: In a production environment your should remove the external port (5120) kept here for microservice debugging purposes. # The API Gateway redirects and access through the internal port (80). @@ -297,10 +295,10 @@ services: webshoppingagg: environment: - ASPNETCORE_ENVIRONMENT=Development - - urls__basket=http://basket.api - - urls__catalog=http://catalog.api - - urls__orders=http://ordering.api - - urls__identity=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. + - urls__basket=http://basket-api + - urls__catalog=http://catalog-api + - urls__orders=http://ordering-api + - urls__identity=http://identity-api #Local: You need to open your local dev-machine firewall at range 5100-5110. ports: - "80" # Important: In a production environment your should remove the external port (5121) kept here for microservice debugging purposes. # The API Gateway redirects and access through the internal port (80). diff --git a/docker-compose.windows.yml b/src/docker-compose.windows.yml similarity index 91% rename from docker-compose.windows.yml rename to src/docker-compose.windows.yml index b7499f061..44aba924f 100644 --- a/docker-compose.windows.yml +++ b/src/docker-compose.windows.yml @@ -5,10 +5,10 @@ version: '3.4' services: - sql.data: + sqldata: image: microsoft/mssql-server-windows-developer - nosql.data: + nosqldata: image: mongo:windowsservercore basket.data: @@ -17,7 +17,7 @@ services: rabbitmq: image: spring2/rabbitmq - identity.api: + identity-api: build: args: NODE_IMAGE: stefanscherer/node-windows:10 diff --git a/src/docker-compose.yml b/src/docker-compose.yml new file mode 100644 index 000000000..97245790f --- /dev/null +++ b/src/docker-compose.yml @@ -0,0 +1,192 @@ +version: '3.4' + +services: + + seq: + image: datalust/seq:latest + + sqldata: + image: microsoft/mssql-server-linux:2017-latest + + nosqldata: + image: mongo + + basketdata: + image: redis:alpine + + rabbitmq: + image: rabbitmq:3-management-alpine + + identity-api: + image: ${REGISTRY:-eshop}/identity.api:${PLATFORM:-linux}-${TAG:-latest} + build: + context: . + dockerfile: Services/Identity/Identity.API/Dockerfile + depends_on: + - sqldata + + basket-api: + image: ${REGISTRY:-eshop}/basket.api:${PLATFORM:-linux}-${TAG:-latest} + build: + context: . + dockerfile: Services/Basket/Basket.API/Dockerfile + depends_on: + - basketdata + - identity-api + - rabbitmq + + catalog-api: + image: ${REGISTRY:-eshop}/catalog.api:${PLATFORM:-linux}-${TAG:-latest} + build: + context: . + dockerfile: Services/Catalog/Catalog.API/Dockerfile + depends_on: + - sqldata + - rabbitmq + + ordering-api: + image: ${REGISTRY:-eshop}/ordering.api:${PLATFORM:-linux}-${TAG:-latest} + build: + context: . + dockerfile: Services/Ordering/Ordering.API/Dockerfile + depends_on: + - sqldata + - rabbitmq + + ordering-backgroundtasks: + image: ${REGISTRY:-eshop}/ordering.backgroundtasks:${PLATFORM:-linux}-${TAG:-latest} + build: + context: . + dockerfile: Services/Ordering/Ordering.BackgroundTasks/Dockerfile + depends_on: + - sqldata + - rabbitmq + + marketing-api: + image: ${REGISTRY:-eshop}/marketing.api:${PLATFORM:-linux}-${TAG:-latest} + build: + context: . + dockerfile: Services/Marketing/Marketing.API/Dockerfile + depends_on: + - sqldata + - nosqldata + - identity-api + - rabbitmq + + payment-api: + image: ${REGISTRY:-eshop}/payment.api:${PLATFORM:-linux}-${TAG:-latest} + build: + context: . + dockerfile: Services/Payment/Payment.API/Dockerfile + depends_on: + - rabbitmq + + locations-api: + image: ${REGISTRY:-eshop}/locations.api:${PLATFORM:-linux}-${TAG:-latest} + build: + context: . + dockerfile: Services/Location/Locations.API/Dockerfile + depends_on: + - nosqldata + - rabbitmq + + webhooks-api: + image: ${REGISTRY:-eshop}/webhooks.api:${PLATFORM:-linux}-${TAG:-latest} + build: + context: . + dockerfile: Services/Webhooks/Webhooks.API/Dockerfile + depends_on: + - sqldata + + mobileshoppingapigw: + image: envoyproxy/envoy:v1.11.1 + + mobilemarketingapigw: + image: envoyproxy/envoy:v1.11.1 + + mobileshoppingagg: + image: ${REGISTRY:-eshop}/mobileshoppingagg:${PLATFORM:-linux}-${TAG:-latest} + build: + context: . + dockerfile: ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile + depends_on: + - nosqldata + - sqldata + - identity-api + - rabbitmq + - ordering-api + - marketing-api + - catalog-api + - basket-api + + webshoppingagg: + image: ${REGISTRY:-eshop}/webshoppingagg:${PLATFORM:-linux}-${TAG:-latest} + build: + context: . + dockerfile: ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile + depends_on: + - nosqldata + - sqldata + - identity-api + - rabbitmq + - ordering-api + - marketing-api + - catalog-api + - basket-api + + ordering-signalrhub: + image: ${REGISTRY:-eshop}/ordering.signalrhub:${PLATFORM:-linux}-${TAG:-latest} + build: + context: . + dockerfile: Services/Ordering/Ordering.SignalrHub/Dockerfile + depends_on: + - nosqldata + - sqldata + - identity-api + - rabbitmq + - ordering-api + - marketing-api + - catalog-api + - basket-api + + webstatus: + image: ${REGISTRY:-eshop}/webstatus:${PLATFORM:-linux}-${TAG:-latest} + build: + context: . + dockerfile: Web/WebStatus/Dockerfile + + webspa: + image: ${REGISTRY:-eshop}/webspa:${PLATFORM:-linux}-${TAG:-latest} + build: + context: . + dockerfile: Web/WebSPA/Dockerfile + args: + NODE_IMAGE: ${NODE_IMAGE:-node:8.11} +# depends_on: +# - webshoppingagg +# - webshoppingapigw +# - webmarketingapigw + + webmvc: + image: ${REGISTRY:-eshop}/webmvc:${PLATFORM:-linux}-${TAG:-latest} + build: + context: . + dockerfile: Web/WebMVC/Dockerfile + depends_on: + - webshoppingagg + - webshoppingapigw + - webmarketingapigw + + webhooks-client: + image: ${REGISTRY:-eshop}/webhooks.client:${PLATFORM:-linux}-${TAG:-latest} + build: + context: . + dockerfile: Web/WebhookClient/Dockerfile + depends_on: + - webhooks-api + + webshoppingapigw: + image: envoyproxy/envoy:v1.11.1 + + webmarketingapigw: + image: envoyproxy/envoy:v1.11.1 diff --git a/eShopOnContainers-ServicesAndWebApps.sln b/src/eShopOnContainers-ServicesAndWebApps.sln similarity index 89% rename from eShopOnContainers-ServicesAndWebApps.sln rename to src/eShopOnContainers-ServicesAndWebApps.sln index 882bca09f..c41d22d92 100644 --- a/eShopOnContainers-ServicesAndWebApps.sln +++ b/src/eShopOnContainers-ServicesAndWebApps.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27130.2027 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29020.237 MinimumVisualStudioVersion = 10.0.40219.1 Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FEA0C318-FFED-4D39-8781-265718CA43DD}" EndProject @@ -30,99 +30,91 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ServicesTests", "ServicesTe EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Identity", "Identity", "{24CD3B53-141E-4A07-9B0D-796641E1CF78}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Basket.API", "src\Services\Basket\Basket.API\Basket.API.csproj", "{2110CBB0-3B38-4EE4-A743-DF6968D80D90}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Basket.API", "Services\Basket\Basket.API\Basket.API.csproj", "{2110CBB0-3B38-4EE4-A743-DF6968D80D90}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Catalog.API", "src\Services\Catalog\Catalog.API\Catalog.API.csproj", "{42681D9D-750A-4DF7-BD9F-9292CFD5C253}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Catalog.API", "Services\Catalog\Catalog.API\Catalog.API.csproj", "{42681D9D-750A-4DF7-BD9F-9292CFD5C253}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.API", "src\Services\Ordering\Ordering.API\Ordering.API.csproj", "{231226CE-690B-4979-8870-9A79D80928E2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.API", "Services\Ordering\Ordering.API\Ordering.API.csproj", "{231226CE-690B-4979-8870-9A79D80928E2}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.Domain", "src\Services\Ordering\Ordering.Domain\Ordering.Domain.csproj", "{F5598DCB-6DDE-4661-AD9D-A55612DA7E76}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.Domain", "Services\Ordering\Ordering.Domain\Ordering.Domain.csproj", "{F5598DCB-6DDE-4661-AD9D-A55612DA7E76}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebMVC", "src\Web\WebMVC\WebMVC.csproj", "{F0333D8E-0B27-42B7-B2C6-78F3657624E2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebMVC", "Web\WebMVC\WebMVC.csproj", "{F0333D8E-0B27-42B7-B2C6-78F3657624E2}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.Infrastructure", "src\Services\Ordering\Ordering.Infrastructure\Ordering.Infrastructure.csproj", "{95F1F07C-4D92-4742-BD07-E5B805AAB651}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.Infrastructure", "Services\Ordering\Ordering.Infrastructure\Ordering.Infrastructure.csproj", "{95F1F07C-4D92-4742-BD07-E5B805AAB651}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Identity.API", "src\Services\Identity\Identity.API\Identity.API.csproj", "{A579E108-5445-403D-A407-339AC4D1611B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Identity.API", "Services\Identity\Identity.API\Identity.API.csproj", "{A579E108-5445-403D-A407-339AC4D1611B}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebSPA", "src\Web\WebSPA\WebSPA.csproj", "{F16E3C6A-1C94-4EAB-BE91-099618060B68}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebSPA", "Web\WebSPA\WebSPA.csproj", "{F16E3C6A-1C94-4EAB-BE91-099618060B68}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BuildingBlocks", "BuildingBlocks", "{DB0EFB20-B024-4E5E-A75C-52143C131D25}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EventBus", "EventBus", "{807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBus", "src\BuildingBlocks\EventBus\EventBus\EventBus.csproj", "{0044B293-1DCC-4224-B948-00CF6DC7F510}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBus", "BuildingBlocks\EventBus\EventBus\EventBus.csproj", "{0044B293-1DCC-4224-B948-00CF6DC7F510}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBusRabbitMQ", "src\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj", "{8088F3FC-6787-45FA-A924-816EC81CBFAC}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBusRabbitMQ", "BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj", "{8088F3FC-6787-45FA-A924-816EC81CBFAC}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationEventLogEF", "src\BuildingBlocks\EventBus\IntegrationEventLogEF\IntegrationEventLogEF.csproj", "{9EE28E45-1533-472B-8267-56C48855BA0E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationEventLogEF", "BuildingBlocks\EventBus\IntegrationEventLogEF\IntegrationEventLogEF.csproj", "{9EE28E45-1533-472B-8267-56C48855BA0E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebStatus", "src\Web\WebStatus\WebStatus.csproj", "{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebStatus", "Web\WebStatus\WebStatus.csproj", "{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Location", "Location", "{41139F64-4046-4F16-96B7-D941D96FA9C6}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Locations.API", "src\Services\Location\Locations.API\Locations.API.csproj", "{E7581357-FC34-474C-B8F5-307EE3CE05EF}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Locations.API", "Services\Location\Locations.API\Locations.API.csproj", "{E7581357-FC34-474C-B8F5-307EE3CE05EF}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Marketing", "Marketing", "{A5260DE0-1FDD-467E-9CC1-A028AB081CEE}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Marketing.API", "src\Services\Marketing\Marketing.API\Marketing.API.csproj", "{DF395F85-B010-465D-857A-7EBCC512C0C2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Marketing.API", "Services\Marketing\Marketing.API\Marketing.API.csproj", "{DF395F85-B010-465D-857A-7EBCC512C0C2}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBusServiceBus", "src\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj", "{69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBusServiceBus", "BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj", "{69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebHost", "WebHost", "{1815B651-941C-466B-AE33-D1D7EEB8F77F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebHost.Customization", "src\BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj", "{15F4B3AA-89B6-4A0D-9051-414305974781}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebHost.Customization", "BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj", "{15F4B3AA-89B6-4A0D-9051-414305974781}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ApiGateways", "ApiGateways", "{77849D35-37D4-4802-81DC-9477B2775A40}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ApiGw-Base", "ApiGw-Base", "{EC91ADE9-3D66-4AB2-9FB4-2B585E1F3531}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mobile.Bff.Marketing", "Mobile.Bff.Marketing", "{DB813A36-11BA-41FE-B258-CA9A7152247B}" ProjectSection(SolutionItems) = preProject - src\ApiGateways\Mobile.Bff.Marketing\apigw\configuration.json = src\ApiGateways\Mobile.Bff.Marketing\apigw\configuration.json + ApiGateways\Mobile.Bff.Marketing\apigw\configuration.json = ApiGateways\Mobile.Bff.Marketing\apigw\configuration.json EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mobile.Bff.Shopping", "Mobile.Bff.Shopping", "{0189E4FB-6E2B-4F2E-9B1D-5473D23FC6DB}" ProjectSection(SolutionItems) = preProject - src\ApiGateways\Mobile.Bff.Shopping\apigw\configuration.json = src\ApiGateways\Mobile.Bff.Shopping\apigw\configuration.json + ApiGateways\Mobile.Bff.Shopping\apigw\configuration.json = ApiGateways\Mobile.Bff.Shopping\apigw\configuration.json EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web.Bff.Marketing", "Web.Bff.Marketing", "{F8F0921C-EE5D-4AED-A4D6-5BF5FAE02CB5}" ProjectSection(SolutionItems) = preProject - src\ApiGateways\Web.Bff.Marketing\apigw\configuration.json = src\ApiGateways\Web.Bff.Marketing\apigw\configuration.json + ApiGateways\Web.Bff.Marketing\apigw\configuration.json = ApiGateways\Web.Bff.Marketing\apigw\configuration.json EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web.Bff.Shopping", "Web.Bff.Shopping", "{28C0F5C8-4849-4035-80AB-45639424E73F}" ProjectSection(SolutionItems) = preProject - src\ApiGateways\Web.Bff.Shopping\apigw\configuration.json = src\ApiGateways\Web.Bff.Shopping\apigw\configuration.json + ApiGateways\Web.Bff.Shopping\apigw\configuration.json = ApiGateways\Web.Bff.Shopping\apigw\configuration.json EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OcelotApiGw", "src\ApiGateways\ApiGw-Base\OcelotApiGw.csproj", "{3F79558C-485D-49E1-BD3E-E12538D3D308}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mobile.Shopping.HttpAggregator", "src\ApiGateways\Mobile.Bff.Shopping\aggregator\Mobile.Shopping.HttpAggregator.csproj", "{BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Web.Shopping.HttpAggregator", "src\ApiGateways\Web.Bff.Shopping\aggregator\Web.Shopping.HttpAggregator.csproj", "{AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mobile.Shopping.HttpAggregator", "ApiGateways\Mobile.Bff.Shopping\aggregator\Mobile.Shopping.HttpAggregator.csproj", "{BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.BackgroundTasks", "src\Services\Ordering\Ordering.BackgroundTasks\Ordering.BackgroundTasks.csproj", "{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Web.Shopping.HttpAggregator", "ApiGateways\Web.Bff.Shopping\aggregator\Web.Shopping.HttpAggregator.csproj", "{AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.SignalrHub", "src\Services\Ordering\Ordering.SignalrHub\Ordering.SignalrHub.csproj", "{E1D2B260-4E7F-4A88-BC13-9910F7C44623}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.SignalrHub", "Services\Ordering\Ordering.SignalrHub\Ordering.SignalrHub.csproj", "{E1D2B260-4E7F-4A88-BC13-9910F7C44623}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Basket.UnitTests", "src\Services\Basket\Basket.UnitTests\Basket.UnitTests.csproj", "{9D9CE4E4-1DD0-4961-861F-219731DE06CE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Basket.UnitTests", "Services\Basket\Basket.UnitTests\Basket.UnitTests.csproj", "{9D9CE4E4-1DD0-4961-861F-219731DE06CE}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Catalog.UnitTests", "src\Services\Catalog\Catalog.UnitTests\Catalog.UnitTests.csproj", "{791961C7-3F3E-434E-B2BA-B4D6B5E222B0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Catalog.UnitTests", "Services\Catalog\Catalog.UnitTests\Catalog.UnitTests.csproj", "{791961C7-3F3E-434E-B2BA-B4D6B5E222B0}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Basket.FunctionalTests", "src\Services\Basket\Basket.FunctionalTests\Basket.FunctionalTests.csproj", "{3F6202D0-2842-4C2F-98E1-9462709EAFBE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Basket.FunctionalTests", "Services\Basket\Basket.FunctionalTests\Basket.FunctionalTests.csproj", "{3F6202D0-2842-4C2F-98E1-9462709EAFBE}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.UnitTests", "src\Services\Ordering\Ordering.UnitTests\Ordering.UnitTests.csproj", "{B1182FD9-C245-4018-8412-C66F290C7F4C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.UnitTests", "Services\Ordering\Ordering.UnitTests\Ordering.UnitTests.csproj", "{B1182FD9-C245-4018-8412-C66F290C7F4C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Catalog.FunctionalTests", "src\Services\Catalog\Catalog.FunctionalTests\Catalog.FunctionalTests.csproj", "{38107691-A437-461D-A85C-ACD3AC7ACFAB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Catalog.FunctionalTests", "Services\Catalog\Catalog.FunctionalTests\Catalog.FunctionalTests.csproj", "{38107691-A437-461D-A85C-ACD3AC7ACFAB}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Locations.FunctionalTests", "src\Services\Location\Locations.FunctionalTests\Locations.FunctionalTests.csproj", "{16F463AA-9CF6-44DC-B18C-7310CCF663FF}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Locations.FunctionalTests", "Services\Location\Locations.FunctionalTests\Locations.FunctionalTests.csproj", "{16F463AA-9CF6-44DC-B18C-7310CCF663FF}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.FunctionalTests", "src\Services\Ordering\Ordering.FunctionalTests\Ordering.FunctionalTests.csproj", "{DA7D3E03-D0B6-4591-8143-779D3E9F3F30}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.FunctionalTests", "Services\Ordering\Ordering.FunctionalTests\Ordering.FunctionalTests.csproj", "{DA7D3E03-D0B6-4591-8143-779D3E9F3F30}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Marketing.FunctionalTests", "src\Services\Marketing\Marketing.FunctionalTests\Marketing.FunctionalTests.csproj", "{94176D9B-9CAA-4762-8D12-1621E240EE34}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LoadTest", "test\ServicesTests\LoadTest\LoadTest.csproj", "{969E793C-C413-490E-9C9D-B2B46DA5AF32}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Marketing.FunctionalTests", "Services\Marketing\Marketing.FunctionalTests\Marketing.FunctionalTests.csproj", "{94176D9B-9CAA-4762-8D12-1621E240EE34}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Application.FunctionalTests", "test\ServicesTests\Application.FunctionalTests\Application.FunctionalTests.csproj", "{639BB197-D112-47A7-A44A-471DDB0FA1AE}" EndProject @@ -138,17 +130,32 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{120CABB3 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Payment", "Payment", "{C61C5CFE-4876-4A46-A96E-5BBF596A984A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Payment.API", "src\Services\Payment\Payment.API\Payment.API.csproj", "{0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Payment.API", "Services\Payment\Payment.API\Payment.API.csproj", "{0AB40131-8AD7-436F-9C6B-EDA59CFA3A84}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Webhooks", "Webhooks", "{E0AA11C4-2873-461D-8F82-53392530FB7A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Webhooks.API", "src\Services\Webhooks\Webhooks.API\Webhooks.API.csproj", "{84E2016E-0435-44C6-8020-3D288AA38B2C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Webhooks.API", "Services\Webhooks\Webhooks.API\Webhooks.API.csproj", "{84E2016E-0435-44C6-8020-3D288AA38B2C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebhookClient", "src\Web\WebhookClient\WebhookClient.csproj", "{766D7E92-6AF0-476C-ADD5-282BF4D8C576}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebhookClient", "Web\WebhookClient\WebhookClient.csproj", "{766D7E92-6AF0-476C-ADD5-282BF4D8C576}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Devspace.Support", "Devspace.Support", "{68F5041D-51F2-4630-94B6-B49789F5E51A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Devspaces.Support", "src\BuildingBlocks\Devspaces.Support\Devspaces.Support.csproj", "{56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Devspaces.Support", "BuildingBlocks\Devspaces.Support\Devspaces.Support.csproj", "{56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Envoy", "Envoy", "{882A8F3A-C61F-4C44-86DD-A5A258714BF2}" + ProjectSection(SolutionItems) = preProject + ApiGateways\Envoy\Dockerfile = ApiGateways\Envoy\Dockerfile + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "config", "config", "{3ABEEE8C-35E0-4185-9825-C44326151F5B}" + ProjectSection(SolutionItems) = preProject + ApiGateways\Envoy\config\catalog.proto = ApiGateways\Envoy\config\catalog.proto + ApiGateways\Envoy\config\catalog.proto-descriptor.pb = ApiGateways\Envoy\config\catalog.proto-descriptor.pb + ApiGateways\Envoy\Dockerfile = ApiGateways\Envoy\Dockerfile + ApiGateways\Envoy\config\envoy.yaml = ApiGateways\Envoy\config\envoy.yaml + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.BackgroundTasks", "Services\Ordering\Ordering.BackgroundTasks\Ordering.BackgroundTasks.csproj", "{D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -884,54 +891,6 @@ Global {15F4B3AA-89B6-4A0D-9051-414305974781}.Release|x64.Build.0 = Release|Any CPU {15F4B3AA-89B6-4A0D-9051-414305974781}.Release|x86.ActiveCfg = Release|Any CPU {15F4B3AA-89B6-4A0D-9051-414305974781}.Release|x86.Build.0 = Release|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|ARM.Build.0 = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|iPhone.Build.0 = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|x64.ActiveCfg = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|x64.Build.0 = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|x86.ActiveCfg = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|x86.Build.0 = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|ARM.ActiveCfg = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|ARM.Build.0 = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|iPhone.Build.0 = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|x64.ActiveCfg = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|x64.Build.0 = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|x86.ActiveCfg = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|x86.Build.0 = Debug|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|Any CPU.Build.0 = Release|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|ARM.ActiveCfg = Release|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|ARM.Build.0 = Release|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|iPhone.ActiveCfg = Release|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|iPhone.Build.0 = Release|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|x64.ActiveCfg = Release|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|x64.Build.0 = Release|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|x86.ActiveCfg = Release|Any CPU - {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|x86.Build.0 = Release|Any CPU {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU @@ -1028,54 +987,6 @@ Global {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|x64.Build.0 = Release|Any CPU {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|x86.ActiveCfg = Release|Any CPU {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|x86.Build.0 = Release|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|ARM.Build.0 = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|iPhone.Build.0 = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|x64.ActiveCfg = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|x64.Build.0 = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|x86.ActiveCfg = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|x86.Build.0 = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|ARM.ActiveCfg = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|ARM.Build.0 = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|iPhone.Build.0 = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|x64.ActiveCfg = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|x64.Build.0 = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|x86.ActiveCfg = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|x86.Build.0 = Debug|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|Any CPU.Build.0 = Release|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|ARM.ActiveCfg = Release|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|ARM.Build.0 = Release|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|iPhone.ActiveCfg = Release|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|iPhone.Build.0 = Release|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|x64.ActiveCfg = Release|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|x64.Build.0 = Release|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|x86.ActiveCfg = Release|Any CPU - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|x86.Build.0 = Release|Any CPU {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU @@ -1508,54 +1419,6 @@ Global {94176D9B-9CAA-4762-8D12-1621E240EE34}.Release|x64.Build.0 = Release|Any CPU {94176D9B-9CAA-4762-8D12-1621E240EE34}.Release|x86.ActiveCfg = Release|Any CPU {94176D9B-9CAA-4762-8D12-1621E240EE34}.Release|x86.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|ARM.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|x64.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Ad-Hoc|x86.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|Any CPU.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|ARM.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|ARM.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|iPhone.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|x64.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|x64.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|x86.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.AppStore|x86.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|Any CPU.Build.0 = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|ARM.ActiveCfg = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|ARM.Build.0 = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|iPhone.Build.0 = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|x64.ActiveCfg = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|x64.Build.0 = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|x86.ActiveCfg = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Debug|x86.Build.0 = Debug|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|Any CPU.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|Any CPU.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|ARM.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|ARM.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|iPhone.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|iPhone.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|x64.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|x64.Build.0 = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|x86.ActiveCfg = Release|Any CPU - {969E793C-C413-490E-9C9D-B2B46DA5AF32}.Release|x86.Build.0 = Release|Any CPU {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {639BB197-D112-47A7-A44A-471DDB0FA1AE}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU @@ -1796,6 +1659,54 @@ Global {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|x64.Build.0 = Release|Any CPU {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|x86.ActiveCfg = Release|Any CPU {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|x86.Build.0 = Release|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.AppStore|ARM.Build.0 = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.AppStore|iPhone.Build.0 = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.AppStore|x64.ActiveCfg = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.AppStore|x64.Build.0 = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.AppStore|x86.ActiveCfg = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.AppStore|x86.Build.0 = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Debug|ARM.ActiveCfg = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Debug|ARM.Build.0 = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Debug|iPhone.Build.0 = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Debug|x64.ActiveCfg = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Debug|x64.Build.0 = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Debug|x86.ActiveCfg = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Debug|x86.Build.0 = Debug|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Release|Any CPU.Build.0 = Release|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Release|ARM.ActiveCfg = Release|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Release|ARM.Build.0 = Release|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Release|iPhone.ActiveCfg = Release|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Release|iPhone.Build.0 = Release|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Release|x64.ActiveCfg = Release|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Release|x64.Build.0 = Release|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Release|x86.ActiveCfg = Release|Any CPU + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1830,15 +1741,12 @@ Global {1815B651-941C-466B-AE33-D1D7EEB8F77F} = {DB0EFB20-B024-4E5E-A75C-52143C131D25} {15F4B3AA-89B6-4A0D-9051-414305974781} = {1815B651-941C-466B-AE33-D1D7EEB8F77F} {77849D35-37D4-4802-81DC-9477B2775A40} = {932D8224-11F6-4D07-B109-DA28AD288A63} - {EC91ADE9-3D66-4AB2-9FB4-2B585E1F3531} = {77849D35-37D4-4802-81DC-9477B2775A40} {DB813A36-11BA-41FE-B258-CA9A7152247B} = {77849D35-37D4-4802-81DC-9477B2775A40} {0189E4FB-6E2B-4F2E-9B1D-5473D23FC6DB} = {77849D35-37D4-4802-81DC-9477B2775A40} {F8F0921C-EE5D-4AED-A4D6-5BF5FAE02CB5} = {77849D35-37D4-4802-81DC-9477B2775A40} {28C0F5C8-4849-4035-80AB-45639424E73F} = {77849D35-37D4-4802-81DC-9477B2775A40} - {3F79558C-485D-49E1-BD3E-E12538D3D308} = {EC91ADE9-3D66-4AB2-9FB4-2B585E1F3531} {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0} = {0189E4FB-6E2B-4F2E-9B1D-5473D23FC6DB} {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1} = {28C0F5C8-4849-4035-80AB-45639424E73F} - {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B} {E1D2B260-4E7F-4A88-BC13-9910F7C44623} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B} {9D9CE4E4-1DD0-4961-861F-219731DE06CE} = {2751AC5C-D148-4D7A-AE8F-149B47C9A82D} {791961C7-3F3E-434E-B2BA-B4D6B5E222B0} = {5FB21302-3973-4992-962A-6F87F5EC99FD} @@ -1848,7 +1756,6 @@ Global {16F463AA-9CF6-44DC-B18C-7310CCF663FF} = {C3F6ED48-E26D-4D57-970F-B82E69467BA1} {DA7D3E03-D0B6-4591-8143-779D3E9F3F30} = {120CABB3-0FEA-4B40-B4B5-2D3041798C80} {94176D9B-9CAA-4762-8D12-1621E240EE34} = {32EE4736-7534-47EC-BAAD-C00AF3130F80} - {969E793C-C413-490E-9C9D-B2B46DA5AF32} = {EF0337F2-ED00-4643-89FD-EE10863F1870} {639BB197-D112-47A7-A44A-471DDB0FA1AE} = {EF0337F2-ED00-4643-89FD-EE10863F1870} {2751AC5C-D148-4D7A-AE8F-149B47C9A82D} = {BF3EF4F3-E4F5-41DA-9D2D-57223687D1A8} {5FB21302-3973-4992-962A-6F87F5EC99FD} = {326A7FB3-5295-468C-A4FE-67DCB823E1E5} @@ -1862,6 +1769,9 @@ Global {766D7E92-6AF0-476C-ADD5-282BF4D8C576} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04} {68F5041D-51F2-4630-94B6-B49789F5E51A} = {DB0EFB20-B024-4E5E-A75C-52143C131D25} {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35} = {68F5041D-51F2-4630-94B6-B49789F5E51A} + {882A8F3A-C61F-4C44-86DD-A5A258714BF2} = {77849D35-37D4-4802-81DC-9477B2775A40} + {3ABEEE8C-35E0-4185-9825-C44326151F5B} = {882A8F3A-C61F-4C44-86DD-A5A258714BF2} + {D4DBA4A3-E4A5-4D9D-8ACF-F38F7D506191} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {25728519-5F0F-4973-8A64-0A81EB4EA8D9} diff --git a/package-lock.json b/src/package-lock.json similarity index 100% rename from package-lock.json rename to src/package-lock.json diff --git a/scripts/restore-packages b/src/scripts/restore-packages similarity index 100% rename from scripts/restore-packages rename to src/scripts/restore-packages diff --git a/scripts/restore-packages.cmd b/src/scripts/restore-packages.cmd similarity index 100% rename from scripts/restore-packages.cmd rename to src/scripts/restore-packages.cmd diff --git a/test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj b/test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj index 2184e977c..96ef8f046 100644 --- a/test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj +++ b/test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj @@ -1,7 +1,7 @@  - netcoreapp2.2 + $(NetCoreTargetVersion) true false false @@ -67,13 +67,13 @@ - - - + + + + all runtime; build; native; contentfiles; analyzers - diff --git a/test/ServicesTests/LoadTest/Basket.API/AddBasket.webtest b/test/ServicesTests/LoadTest/Basket.API/AddBasket.webtest deleted file mode 100644 index 756a1ed82..000000000 --- a/test/ServicesTests/LoadTest/Basket.API/AddBasket.webtest +++ /dev/null @@ -1,32 +0,0 @@ - - - - - -
-
- - ewAiAEIAdQB5AGUAcgBJAGQAIgA6ACIAewB7AEwAbwBjAGEAbABUAGUAcwB0AFMAZQB0AHQAaQBuAGcAcwAuAFUAcwBlAHIALgBpAGQAfQB9ACIAfQA= - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Basket.API/Checkout.webtest b/test/ServicesTests/LoadTest/Basket.API/Checkout.webtest deleted file mode 100644 index 95f43ec73..000000000 --- a/test/ServicesTests/LoadTest/Basket.API/Checkout.webtest +++ /dev/null @@ -1,42 +0,0 @@ - - - - - -
-
-
- - ewAiAEMAaQB0AHkAIgA6ACIAYwBpAHQAeQAiACwAIgBTAHQAcgBlAGUAdAAiADoAIgBzAHQAcgBlAGUAdAAiACwAIgBTAHQAYQB0AGUAIgA6ACIAcwB0AGEAdABlACIALAAiAEMAbwB1AG4AdAByAHkAIgA6ACIAYwBvAHUAdAByAHkAIgAsACIAWgBpAHAAQwBvAGQAZQAiADoAIgB6AGkAcABjAG8AZABlACIALAAiAEMAYQByAGQATgB1AG0AYgBlAHIAIgA6ACIAQwBhAHIAZABOAHUAbQBiAGUAcgAiACwAIgBDAGEAcgBkAEgAbwBsAGQAZQByAE4AYQBtAGUAIgA6ACIAQwBhAHIAZABIAG8AbABkAGUAcgBOAGEAbQBlACIALAAiAEMAYQByAGQARQB4AHAAaQByAGEAdABpAG8AbgAiADoAIgAyADAAMQA3AC0AMAA2AC0AMwAwAFQAMQAyADoAMgA1ADoAMwAxAC4AOAA3ADQANwAyADIANwBaACIALAAiAEMAYQByAGQAUwBlAGMAdQByAGkAdAB5AE4AdQBtAGIAZQByACIAOgAiADEAMgAzADQAIgAsACIAQwBhAHIAZABUAHkAcABlAEkAZAAiADoAMQAsACIAQgB1AHkAZQByACIAOgAiAEIAdQB5AGUAcgAiACwAIgBSAGUAcQB1AGUAcwB0AEkAZAAiADoAIgBlAGIAOAAwADAAMwA2ADQALQBiADQAZQAxAC0ANAA2AGUAYgAtADkAMgAzADUALQBlADgAYwA0ADcANAA3AGQAYQAyAGQANAAiAH0A - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Basket.API/DeleteBasket.webtest b/test/ServicesTests/LoadTest/Basket.API/DeleteBasket.webtest deleted file mode 100644 index c472bbefc..000000000 --- a/test/ServicesTests/LoadTest/Basket.API/DeleteBasket.webtest +++ /dev/null @@ -1,31 +0,0 @@ - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Basket.API/GetBasket.webtest b/test/ServicesTests/LoadTest/Basket.API/GetBasket.webtest deleted file mode 100644 index 8af000753..000000000 --- a/test/ServicesTests/LoadTest/Basket.API/GetBasket.webtest +++ /dev/null @@ -1,31 +0,0 @@ - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Basket.loadtest b/test/ServicesTests/LoadTest/Basket.loadtest deleted file mode 100644 index 63a682a5d..000000000 --- a/test/ServicesTests/LoadTest/Basket.loadtest +++ /dev/null @@ -1,467 +0,0 @@ - - - - - - - - - - - - - - - -
-
-
-
- - - - - - -
-
-
-
-
- - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Campaigns.loadtest b/test/ServicesTests/LoadTest/Campaigns.loadtest deleted file mode 100644 index 0e1fa2fb3..000000000 --- a/test/ServicesTests/LoadTest/Campaigns.loadtest +++ /dev/null @@ -1,467 +0,0 @@ - - - - - - - - - - - - - - - -
-
-
-
- - - - - - -
-
-
-
-
- - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Catalog.API/GetCatalogBrands.webtest b/test/ServicesTests/LoadTest/Catalog.API/GetCatalogBrands.webtest deleted file mode 100644 index 0cb8085e9..000000000 --- a/test/ServicesTests/LoadTest/Catalog.API/GetCatalogBrands.webtest +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Catalog.API/GetCatalogFiltered.webtest b/test/ServicesTests/LoadTest/Catalog.API/GetCatalogFiltered.webtest deleted file mode 100644 index 24d81ec9b..000000000 --- a/test/ServicesTests/LoadTest/Catalog.API/GetCatalogFiltered.webtest +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Catalog.API/GetCatalogTypes.webtest b/test/ServicesTests/LoadTest/Catalog.API/GetCatalogTypes.webtest deleted file mode 100644 index 1f5bcc6f6..000000000 --- a/test/ServicesTests/LoadTest/Catalog.API/GetCatalogTypes.webtest +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Catalog.API/GetItem.webtest b/test/ServicesTests/LoadTest/Catalog.API/GetItem.webtest deleted file mode 100644 index 80cd01d01..000000000 --- a/test/ServicesTests/LoadTest/Catalog.API/GetItem.webtest +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Catalog.API/GetItemPic.webtest b/test/ServicesTests/LoadTest/Catalog.API/GetItemPic.webtest deleted file mode 100644 index 7c552eac5..000000000 --- a/test/ServicesTests/LoadTest/Catalog.API/GetItemPic.webtest +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Catalog.API/GetItems.loadtest b/test/ServicesTests/LoadTest/Catalog.API/GetItems.loadtest deleted file mode 100644 index 5b8da9703..000000000 --- a/test/ServicesTests/LoadTest/Catalog.API/GetItems.loadtest +++ /dev/null @@ -1,443 +0,0 @@ - - - - - - - - - - - - - -
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Catalog.API/GetItems.webtest b/test/ServicesTests/LoadTest/Catalog.API/GetItems.webtest deleted file mode 100644 index f9a99ea56..000000000 --- a/test/ServicesTests/LoadTest/Catalog.API/GetItems.webtest +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Catalog.API/GetItemsByName.webtest b/test/ServicesTests/LoadTest/Catalog.API/GetItemsByName.webtest deleted file mode 100644 index 5b575eaf5..000000000 --- a/test/ServicesTests/LoadTest/Catalog.API/GetItemsByName.webtest +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Catalog.loadtest b/test/ServicesTests/LoadTest/Catalog.loadtest deleted file mode 100644 index ec522dc5e..000000000 --- a/test/ServicesTests/LoadTest/Catalog.loadtest +++ /dev/null @@ -1,471 +0,0 @@ - - - - - - - - - - - - - - - - - - - -
-
-
-
- - - - - - -
-
-
-
-
- - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Identity.API/Login.webtest b/test/ServicesTests/LoadTest/Identity.API/Login.webtest deleted file mode 100644 index 15bd5d5f1..000000000 --- a/test/ServicesTests/LoadTest/Identity.API/Login.webtest +++ /dev/null @@ -1,84 +0,0 @@ - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Identity.API/Logout.webtest b/test/ServicesTests/LoadTest/Identity.API/Logout.webtest deleted file mode 100644 index add2ee744..000000000 --- a/test/ServicesTests/LoadTest/Identity.API/Logout.webtest +++ /dev/null @@ -1,23 +0,0 @@ - - - - - -
- - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/LoadTest.csproj b/test/ServicesTests/LoadTest/LoadTest.csproj deleted file mode 100644 index 830d7cb61..000000000 --- a/test/ServicesTests/LoadTest/LoadTest.csproj +++ /dev/null @@ -1,188 +0,0 @@ - - - Debug - AnyCPU - - - 2.0 - {969E793C-C413-490E-9C9D-B2B46DA5AF32} - Library - Properties - LoadTest - LoadTest - v4.5.2 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - WebTest - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages - False - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - False - - - - - - - - - False - - - - - - - - Designer - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - PreserveNewest - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - PreserveNewest - - - Always - - - Always - - - PreserveNewest - - - PreserveNewest - - - Always - - - Always - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - - - - False - - - False - - - False - - - False - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Local.testsettings b/test/ServicesTests/LoadTest/Local.testsettings deleted file mode 100644 index 4e1e6ab7f..000000000 --- a/test/ServicesTests/LoadTest/Local.testsettings +++ /dev/null @@ -1,13 +0,0 @@ - - - These are default test settings for a local test run. - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Location.API/CreateOrUpdateUserLocation.webtest b/test/ServicesTests/LoadTest/Location.API/CreateOrUpdateUserLocation.webtest deleted file mode 100644 index d005c1c32..000000000 --- a/test/ServicesTests/LoadTest/Location.API/CreateOrUpdateUserLocation.webtest +++ /dev/null @@ -1,32 +0,0 @@ - - - - - -
-
- - ewAiAEwAbwBuAGcAaQB0AHUAZABlACIAOgAtADEAMgAxAC4AMAA0ADAAMwA2ACwAIgBMAGEAdABpAHQAdQBkAGUAIgA6ADQAOAAuADAAOQAxADYAMwAxAH0A - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Location.API/GetAllLocations.webtest b/test/ServicesTests/LoadTest/Location.API/GetAllLocations.webtest deleted file mode 100644 index 86dc545f2..000000000 --- a/test/ServicesTests/LoadTest/Location.API/GetAllLocations.webtest +++ /dev/null @@ -1,31 +0,0 @@ - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Location.API/GetLocation.webtest b/test/ServicesTests/LoadTest/Location.API/GetLocation.webtest deleted file mode 100644 index 72614cdf9..000000000 --- a/test/ServicesTests/LoadTest/Location.API/GetLocation.webtest +++ /dev/null @@ -1,34 +0,0 @@ - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Location.API/GetUserLocation.webtest b/test/ServicesTests/LoadTest/Location.API/GetUserLocation.webtest deleted file mode 100644 index 403c0ae1a..000000000 --- a/test/ServicesTests/LoadTest/Location.API/GetUserLocation.webtest +++ /dev/null @@ -1,39 +0,0 @@ - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Locations.loadtest b/test/ServicesTests/LoadTest/Locations.loadtest deleted file mode 100644 index 84a77fd5e..000000000 --- a/test/ServicesTests/LoadTest/Locations.loadtest +++ /dev/null @@ -1,468 +0,0 @@ - - - - - - - - - - - - - - - - -
-
-
-
- - - - - - -
-
-
-
-
- - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Marketing.API/GetAllCampaigns.webtest b/test/ServicesTests/LoadTest/Marketing.API/GetAllCampaigns.webtest deleted file mode 100644 index 63383876e..000000000 --- a/test/ServicesTests/LoadTest/Marketing.API/GetAllCampaigns.webtest +++ /dev/null @@ -1,31 +0,0 @@ - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Marketing.API/GetCampaign.webtest b/test/ServicesTests/LoadTest/Marketing.API/GetCampaign.webtest deleted file mode 100644 index c8a0623bf..000000000 --- a/test/ServicesTests/LoadTest/Marketing.API/GetCampaign.webtest +++ /dev/null @@ -1,34 +0,0 @@ - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Marketing.API/GetUserCampaigns.webtest b/test/ServicesTests/LoadTest/Marketing.API/GetUserCampaigns.webtest deleted file mode 100644 index aaf392ab2..000000000 --- a/test/ServicesTests/LoadTest/Marketing.API/GetUserCampaigns.webtest +++ /dev/null @@ -1,31 +0,0 @@ - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/OrderProducts.loadtest b/test/ServicesTests/LoadTest/OrderProducts.loadtest deleted file mode 100644 index 70457f327..000000000 --- a/test/ServicesTests/LoadTest/OrderProducts.loadtest +++ /dev/null @@ -1,476 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - - - - - -
-
-
-
-
- - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Ordering.API/CancelOrder.webtest b/test/ServicesTests/LoadTest/Ordering.API/CancelOrder.webtest deleted file mode 100644 index 5f1a2204a..000000000 --- a/test/ServicesTests/LoadTest/Ordering.API/CancelOrder.webtest +++ /dev/null @@ -1,33 +0,0 @@ - - - - - -
-
- - ewAiAE8AcgBkAGUAcgBOAHUAbQBiAGUAcgAiADoAIAAxAH0A - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Ordering.API/GetAllOrders.webtest b/test/ServicesTests/LoadTest/Ordering.API/GetAllOrders.webtest deleted file mode 100644 index 614f2bd1f..000000000 --- a/test/ServicesTests/LoadTest/Ordering.API/GetAllOrders.webtest +++ /dev/null @@ -1,31 +0,0 @@ - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Ordering.API/GetCardTypes.webtest b/test/ServicesTests/LoadTest/Ordering.API/GetCardTypes.webtest deleted file mode 100644 index 28c40c85e..000000000 --- a/test/ServicesTests/LoadTest/Ordering.API/GetCardTypes.webtest +++ /dev/null @@ -1,31 +0,0 @@ - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Ordering.API/GetOrder.webtest b/test/ServicesTests/LoadTest/Ordering.API/GetOrder.webtest deleted file mode 100644 index d81388995..000000000 --- a/test/ServicesTests/LoadTest/Ordering.API/GetOrder.webtest +++ /dev/null @@ -1,34 +0,0 @@ - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Ordering.API/ShipOrder.webtest b/test/ServicesTests/LoadTest/Ordering.API/ShipOrder.webtest deleted file mode 100644 index 36a778855..000000000 --- a/test/ServicesTests/LoadTest/Ordering.API/ShipOrder.webtest +++ /dev/null @@ -1,34 +0,0 @@ - - - - - -
-
-
- - ewAiAE8AcgBkAGUAcgBOAHUAbQBiAGUAcgAiADoAIAAxAH0A - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/Properties/AssemblyInfo.cs b/test/ServicesTests/LoadTest/Properties/AssemblyInfo.cs deleted file mode 100644 index 91e6827da..000000000 --- a/test/ServicesTests/LoadTest/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("LoadTest")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("LoadTest")] -[assembly: AssemblyCopyright("Copyright © 2017")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("969e793c-c413-490e-9c9d-b2b46da5af32")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/test/ServicesTests/LoadTest/WebMVC/AddProducts.webtest b/test/ServicesTests/LoadTest/WebMVC/AddProducts.webtest deleted file mode 100644 index 060148a1f..000000000 --- a/test/ServicesTests/LoadTest/WebMVC/AddProducts.webtest +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/WebMVC/CatalogFilter.webtest b/test/ServicesTests/LoadTest/WebMVC/CatalogFilter.webtest deleted file mode 100644 index 1385cbf37..000000000 --- a/test/ServicesTests/LoadTest/WebMVC/CatalogFilter.webtest +++ /dev/null @@ -1,104 +0,0 @@ - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/WebMVC/CreateNewOrder.webtest b/test/ServicesTests/LoadTest/WebMVC/CreateNewOrder.webtest deleted file mode 100644 index 7a59ee50b..000000000 --- a/test/ServicesTests/LoadTest/WebMVC/CreateNewOrder.webtest +++ /dev/null @@ -1,204 +0,0 @@ - - - - - -
-
- - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/app.config b/test/ServicesTests/LoadTest/app.config deleted file mode 100644 index b7037fc22..000000000 --- a/test/ServicesTests/LoadTest/app.config +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/ServicesTests/LoadTest/readme.md b/test/ServicesTests/LoadTest/readme.md deleted file mode 100644 index 42022fd7d..000000000 --- a/test/ServicesTests/LoadTest/readme.md +++ /dev/null @@ -1,84 +0,0 @@ -# Load Testing settings - -This folder contains files needed to run load tests locally or on a Kubernetes / Service Fabric cluster. - -

- -

- -## Set a local environment - -Modify the **app.config** file in the LoadTest project directory and set the following service urls. - -``` - - - - - - - - - -``` - -Modify the **.env** file and set the following config property as shown bellow. - -``` -USE_LOADTEST=True -``` -## Set a Service Fabric environment - -Modify the **app.config** file in the LoadTest project directory and set the following service urls. - -``` - - - - - - - - - -``` - -Modify the **ServiceManifest.xml** files of the eShop SF Services and set the **UseLoadTest** environment variable to True. This setting enables the load tests to bypass authorization in api services. - -

- -

- -Deploy the SF services. **PLEASE** Read our [SF deployment guide for Linux](./../../../deploy/az/servicefabric/LinuxContainers/readme.md) And [SF deployment guide for Windows](./../../../deploy/az/servicefabric/WindowsContainers/readme.md) to know about how to deploy eshop on SF. - -## Set a Kubernetes environment - -Modify the **app.config** file in the LoadTest project directory and set the following service urls. - -``` - - - - - - - - - -``` - -Modify the **conf_local.yml** file in the K8s directory and set the **EnableLoadTest** environment variable to True. This setting enables the load tests to bypass authorization in api services. - -

- -

- -Deploy the kubernetes services. **PLEASE** Read our [k8s deployment guide](./../../../k8s/README.k8s.md) to know about how to deploy eshop on Kubernetes. - -## Run Load Tests - -Open the load test you want to perform ***.loadtest** files and click the Run Load test button. - -

- -

\ No newline at end of file