From 514142a3c7721611ed66f5612d981493f26404ff Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Wed, 21 Jun 2017 12:58:55 +0200 Subject: [PATCH 01/86] global.json set to 2.0.0-preview1-005977 dcproj update --- docker-compose.dcproj | 8 +- docker-compose.vs.debug.yml | 166 ---------------------------------- docker-compose.vs.release.yml | 112 ----------------------- global.json | 2 +- 4 files changed, 3 insertions(+), 285 deletions(-) delete mode 100644 docker-compose.vs.debug.yml delete mode 100644 docker-compose.vs.release.yml diff --git a/docker-compose.dcproj b/docker-compose.dcproj index f7f04c5b4..23547b577 100644 --- a/docker-compose.dcproj +++ b/docker-compose.dcproj @@ -5,6 +5,8 @@ True http://localhost:5100 webmvc + Linux + 2.0 @@ -14,12 +16,6 @@ docker-compose.yml - - docker-compose.yml - - - docker-compose.yml - \ No newline at end of file diff --git a/docker-compose.vs.debug.yml b/docker-compose.vs.debug.yml deleted file mode 100644 index b0c792d32..000000000 --- a/docker-compose.vs.debug.yml +++ /dev/null @@ -1,166 +0,0 @@ -version: '3' - -services: - basket.api: - image: eshop/basket.api:dev - build: - args: - source: ${DOCKER_BUILD_SOURCE} - environment: - - DOTNET_USE_POLLING_FILE_WATCHER=1 - volumes: - - ./src/Services/Basket/Basket.API:/app - - ~/.nuget/packages:/root/.nuget/packages:ro - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - - catalog.api: - image: eshop/catalog.api:dev - build: - args: - source: ${DOCKER_BUILD_SOURCE} - environment: - - DOTNET_USE_POLLING_FILE_WATCHER=1 - volumes: - - ./src/Services/Catalog/Catalog.API:/app - - ~/.nuget/packages:/root/.nuget/packages:ro - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - - identity.api: - image: eshop/identity.api:dev - build: - args: - source: ${DOCKER_BUILD_SOURCE} - environment: - - DOTNET_USE_POLLING_FILE_WATCHER=1 - volumes: - - ./src/Services/Identity/Identity.API:/app - - ~/.nuget/packages:/root/.nuget/packages:ro - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - - ordering.api: - image: eshop/ordering.api:dev - build: - args: - source: ${DOCKER_BUILD_SOURCE} - environment: - - DOTNET_USE_POLLING_FILE_WATCHER=1 - volumes: - - ./src/Services/Ordering/Ordering.API:/app - - ~/.nuget/packages:/root/.nuget/packages:ro - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - - marketing.api: - image: eshop/marketing.api:dev - build: - args: - source: ${DOCKER_BUILD_SOURCE} - environment: - - DOTNET_USE_POLLING_FILE_WATCHER=1 - volumes: - - ./src/Services/Marketing/Marketing.API:/app - - ~/.nuget/packages:/root/.nuget/packages:ro - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - - - webspa: - image: eshop/webspa:dev - build: - args: - source: ${DOCKER_BUILD_SOURCE} - environment: - - DOTNET_USE_POLLING_FILE_WATCHER=1 - volumes: - - ./src/Web/WebSPA:/app - - ~/.nuget/packages:/root/.nuget/packages:ro - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - - webmvc: - image: eshop/webmvc:dev - build: - args: - source: ${DOCKER_BUILD_SOURCE} - environment: - - DOTNET_USE_POLLING_FILE_WATCHER=1 - volumes: - - ./src/Web/WebMVC:/app - - ~/.nuget/packages:/root/.nuget/packages:ro - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - - webstatus: - image: eshop/webstatus:dev - build: - args: - source: ${DOCKER_BUILD_SOURCE} - environment: - - DOTNET_USE_POLLING_FILE_WATCHER=1 - volumes: - - ./src/Web/WebStatus:/app - - ~/.nuget/packages:/root/.nuget/packages:ro - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - - payment.api: - image: eshop/payment.api:dev - build: - args: - source: ${DOCKER_BUILD_SOURCE} - environment: - - DOTNET_USE_POLLING_FILE_WATCHER=1 - volumes: - - ./src/Services/Payment/Payment.API:/app - - ~/.nuget/packages:/root/.nuget/packages:ro - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - - graceperiodmanager: - image: eshop/graceperiodmanager:dev - build: - args: - source: ${DOCKER_BUILD_SOURCE} - volumes: - - ./src/Services/GracePeriod/GracePeriodManager:/app - - ~/.nuget/packages:/root/.nuget/packages:ro - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - - locations.api: - image: eshop/locations.api:dev - build: - args: - source: ${DOCKER_BUILD_SOURCE} - environment: - - DOTNET_USE_POLLING_FILE_WATCHER=1 - volumes: - - ./src/Services/Location/Locations.API:/app - - ~/.nuget/packages:/root/.nuget/packages:ro - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" diff --git a/docker-compose.vs.release.yml b/docker-compose.vs.release.yml deleted file mode 100644 index 6aac3f799..000000000 --- a/docker-compose.vs.release.yml +++ /dev/null @@ -1,112 +0,0 @@ -version: '3' - -services: - basket.api: - build: - args: - source: ${DOCKER_BUILD_SOURCE} - volumes: - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - - catalog.api: - build: - args: - source: ${DOCKER_BUILD_SOURCE} - volumes: - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - - identity.api: - build: - args: - source: ${DOCKER_BUILD_SOURCE} - volumes: - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - - ordering.api: - build: - args: - source: ${DOCKER_BUILD_SOURCE} - volumes: - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - - marketing.api: - build: - args: - source: ${DOCKER_BUILD_SOURCE} - volumes: - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - - webspa: - build: - args: - source: ${DOCKER_BUILD_SOURCE} - volumes: - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - - webmvc: - build: - args: - source: ${DOCKER_BUILD_SOURCE} - volumes: - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - - webstatus: - build: - args: - source: ${DOCKER_BUILD_SOURCE} - volumes: - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - - payment.api: - build: - args: - source: ${DOCKER_BUILD_SOURCE} - volumes: - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - - graceperiodmanager: - build: - args: - source: ${DOCKER_BUILD_SOURCE} - volumes: - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - - locations.api: - build: - args: - source: ${DOCKER_BUILD_SOURCE} - volumes: - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" diff --git a/global.json b/global.json index 38fed7db6..6c30ddc76 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version":"1.0.4" + "version":"2.0.0-preview1-005977" } } \ No newline at end of file From 56902a554970e9ff8eda5ed770f58bee028902ca Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Wed, 21 Jun 2017 19:03:48 +0200 Subject: [PATCH 02/86] [WIP] Projects & Dockerfile migrated to 2.0 Lots of things to address yet, because nuget packages are still on 1.1 --- cli-windows/build-bits.ps1 | 7 ++++++- .../DataProtection/DataProtection.csproj | 2 +- .../EventBus/EventBus.Tests/EventBus.Tests.csproj | 2 +- .../EventBus/EventBus/EventBus.csproj | 2 +- .../EventBusRabbitMQ/EventBusRabbitMQ.csproj | 2 +- src/Services/Basket/Basket.API/Basket.API.csproj | 2 +- src/Services/Basket/Basket.API/Dockerfile | 2 +- .../Catalog/Catalog.API/Catalog.API.csproj | 2 +- src/Services/Catalog/Catalog.API/Dockerfile | 2 +- .../GracePeriod/GracePeriodManager/Dockerfile | 2 +- .../GracePeriodManager/GracePeriodManager.csproj | 2 +- .../Location/Locations.API/Locations.API.csproj | 2 +- src/Services/Marketing/Marketing.API/Dockerfile | 2 +- .../Marketing/Marketing.API/Marketing.API.csproj | 3 ++- src/Services/Ordering/Ordering.API/Dockerfile | 2 +- .../Ordering/Ordering.API/Ordering.API.csproj | 2 +- .../Ordering.Domain/Ordering.Domain.csproj | 3 ++- .../Ordering.Domain/SeedWork/Enumeration.cs | 2 +- .../Ordering.Infrastructure.csproj | 2 +- .../Payment/Payment.API/Payment.API.csproj | 2 +- src/Web/WebMVC/Dockerfile | 2 +- src/Web/WebMVC/Startup.cs | 5 +++-- src/Web/WebMVC/WebMVC.csproj | 4 +--- src/Web/WebSPA/Dockerfile | 2 +- src/Web/WebSPA/WebSPA.csproj | 5 +---- src/Web/WebStatus/Dockerfile | 2 +- src/Web/WebStatus/WebStatus.csproj | 14 +++----------- .../FunctionalTests/FunctionalTests.csproj | 2 +- .../IntegrationTests/IntegrationTests.csproj | 2 +- test/Services/UnitTest/UnitTest.csproj | 2 +- 30 files changed, 41 insertions(+), 46 deletions(-) diff --git a/cli-windows/build-bits.ps1 b/cli-windows/build-bits.ps1 index 26651da5b..9533ee25e 100644 --- a/cli-windows/build-bits.ps1 +++ b/cli-windows/build-bits.ps1 @@ -14,7 +14,12 @@ $projectPaths = @{Path="$rootPath\src\Services\Identity\Identity.API";Prj="Identity.API.csproj"}, @{Path="$rootPath\src\Services\Catalog\Catalog.API";Prj="Catalog.API.csproj"}, @{Path="$rootPath\src\Services\Ordering\Ordering.API";Prj="Ordering.API.csproj"}, - @{Path="$rootPath\src\Services\Basket\Basket.API";Prj="Basket.API.csproj"} + @{Path="$rootPath\src\Services\GracePeriod\GracePeriodManager";Prj="GracePeriodManager.csproj"}, + @{Path="$rootPath\src\Services\Basket\Basket.API";Prj="Basket.API.csproj"}, + @{Path="$rootPath\src\Services\Identity\Identity.API";Prj="Identity.API.csproj"}, + @{Path="$rootPath\src\Services\Location\Location.API";Prj="Locations.API.csproj"}, + @{Path="$rootPath\src\Services\Marketing\Marketing.API";Prj="Marketing.API.csproj"}, + @{Path="$rootPath\src\Services\Payment\Payment.API";Prj="Payment.API.csproj"}, @{Path="$rootPath\src\Web\WebStatus";Prj="WebStatus.csproj"} $projectPaths | foreach { diff --git a/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj b/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj index bfe61a85a..c5266d0a9 100644 --- a/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj +++ b/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj @@ -1,7 +1,7 @@  - netcoreapp1.1 + netstandard1.5 Microsoft.eShopOnContainers.BuildingBlocks diff --git a/src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj b/src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj index 1387a74dd..8589f6035 100644 --- a/src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj +++ b/src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp1.1 + netstandard1.5 diff --git a/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj b/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj index 37aeb8d1f..723b22b64 100644 --- a/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj +++ b/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj @@ -1,7 +1,7 @@  - netcoreapp1.1 + netstandard1.5 Microsoft.eShopOnContainers.BuildingBlocks.EventBus diff --git a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj index d7e3a58d8..d59c999c1 100644 --- a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj +++ b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj @@ -1,7 +1,7 @@  - netcoreapp1.1 + netstandard1.5 Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ diff --git a/src/Services/Basket/Basket.API/Basket.API.csproj b/src/Services/Basket/Basket.API/Basket.API.csproj index 5287dcc96..6e5c66b61 100644 --- a/src/Services/Basket/Basket.API/Basket.API.csproj +++ b/src/Services/Basket/Basket.API/Basket.API.csproj @@ -1,7 +1,7 @@  - netcoreapp1.1 + netcoreapp2.0 1.1.2 Exe $(PackageTargetFallback);netstandard1.6.1;dnxcore50;portable-net451+win8 diff --git a/src/Services/Basket/Basket.API/Dockerfile b/src/Services/Basket/Basket.API/Dockerfile index c81c776b0..2e7395520 100644 --- a/src/Services/Basket/Basket.API/Dockerfile +++ b/src/Services/Basket/Basket.API/Dockerfile @@ -1,4 +1,4 @@ -FROM microsoft/aspnetcore:1.1.2 +FROM microsoft/aspnetcore:2.0 ARG source WORKDIR /app EXPOSE 80 diff --git a/src/Services/Catalog/Catalog.API/Catalog.API.csproj b/src/Services/Catalog/Catalog.API/Catalog.API.csproj index 8f30f7ca3..140a7a552 100644 --- a/src/Services/Catalog/Catalog.API/Catalog.API.csproj +++ b/src/Services/Catalog/Catalog.API/Catalog.API.csproj @@ -1,7 +1,7 @@  - netcoreapp1.1 + netcoreapp2.0 portable true Catalog.API diff --git a/src/Services/Catalog/Catalog.API/Dockerfile b/src/Services/Catalog/Catalog.API/Dockerfile index 61c8e8839..0f5d934d2 100644 --- a/src/Services/Catalog/Catalog.API/Dockerfile +++ b/src/Services/Catalog/Catalog.API/Dockerfile @@ -1,4 +1,4 @@ -FROM microsoft/aspnetcore:1.1.2 +FROM microsoft/aspnetcore:2.0 ARG source WORKDIR /app EXPOSE 80 diff --git a/src/Services/GracePeriod/GracePeriodManager/Dockerfile b/src/Services/GracePeriod/GracePeriodManager/Dockerfile index 37971fde2..7a4f21a64 100644 --- a/src/Services/GracePeriod/GracePeriodManager/Dockerfile +++ b/src/Services/GracePeriod/GracePeriodManager/Dockerfile @@ -1,4 +1,4 @@ -FROM microsoft/aspnetcore:1.1.2 +FROM microsoft/aspnetcore:2.0 ARG source WORKDIR /app COPY ${source:-obj/Docker/publish} . diff --git a/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj b/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj index d057a6b54..ab9a44f2e 100644 --- a/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj +++ b/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp1.1 + netcoreapp2.0 1.1.2 diff --git a/src/Services/Location/Locations.API/Locations.API.csproj b/src/Services/Location/Locations.API/Locations.API.csproj index b9ef671dc..e78661ba0 100644 --- a/src/Services/Location/Locations.API/Locations.API.csproj +++ b/src/Services/Location/Locations.API/Locations.API.csproj @@ -1,7 +1,7 @@  - netcoreapp1.1 + netcoreapp2.0 ..\..\..\..\docker-compose.dcproj Microsoft.eShopOnContainers.Services.Locations.API aspnet-Locations.API-20161122013619 diff --git a/src/Services/Marketing/Marketing.API/Dockerfile b/src/Services/Marketing/Marketing.API/Dockerfile index 54a79a5e4..bae6435ed 100644 --- a/src/Services/Marketing/Marketing.API/Dockerfile +++ b/src/Services/Marketing/Marketing.API/Dockerfile @@ -1,4 +1,4 @@ -FROM microsoft/aspnetcore:1.1.2 +FROM microsoft/aspnetcore:2.0 ARG source WORKDIR /app EXPOSE 80 diff --git a/src/Services/Marketing/Marketing.API/Marketing.API.csproj b/src/Services/Marketing/Marketing.API/Marketing.API.csproj index 4a6e2d4ea..85d9370ce 100644 --- a/src/Services/Marketing/Marketing.API/Marketing.API.csproj +++ b/src/Services/Marketing/Marketing.API/Marketing.API.csproj @@ -1,13 +1,14 @@  - netcoreapp1.1 + netcoreapp2.0 1.1.2 Exe ..\..\..\..\docker-compose.dcproj Microsoft.eShopOnContainers.Services.Marketing.API portable-net45+win8 aspnet-Marketing.API-20161122013619 + diff --git a/src/Services/Ordering/Ordering.API/Dockerfile b/src/Services/Ordering/Ordering.API/Dockerfile index 09564ae9a..c7386bb43 100644 --- a/src/Services/Ordering/Ordering.API/Dockerfile +++ b/src/Services/Ordering/Ordering.API/Dockerfile @@ -1,4 +1,4 @@ -FROM microsoft/aspnetcore:1.1.2 +FROM microsoft/aspnetcore:2.0 ARG source WORKDIR /app EXPOSE 80 diff --git a/src/Services/Ordering/Ordering.API/Ordering.API.csproj b/src/Services/Ordering/Ordering.API/Ordering.API.csproj index 96b4f6627..71c2ea251 100644 --- a/src/Services/Ordering/Ordering.API/Ordering.API.csproj +++ b/src/Services/Ordering/Ordering.API/Ordering.API.csproj @@ -1,7 +1,7 @@  - netcoreapp1.1 + netcoreapp2.0 1.1.2 Exe aspnet-Ordering.API-20161122013547 diff --git a/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj b/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj index 528f5e27a..c6cb205c3 100644 --- a/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj +++ b/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj @@ -1,7 +1,7 @@  - netstandard1.6.1 + netstandard1.4 Ordering.Domain Ordering.Domain 1.6.1 @@ -14,6 +14,7 @@ + diff --git a/src/Services/Ordering/Ordering.Domain/SeedWork/Enumeration.cs b/src/Services/Ordering/Ordering.Domain/SeedWork/Enumeration.cs index ec8dfd968..ecf248be9 100644 --- a/src/Services/Ordering/Ordering.Domain/SeedWork/Enumeration.cs +++ b/src/Services/Ordering/Ordering.Domain/SeedWork/Enumeration.cs @@ -29,7 +29,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.SeedWork public static IEnumerable GetAll() where T : Enumeration, new() { var type = typeof(T); - var fields = type.GetTypeInfo().GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly); + var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly); foreach (var info in fields) { diff --git a/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj b/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj index 43ba7ecd1..6f460108f 100644 --- a/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj +++ b/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj @@ -1,7 +1,7 @@  - netstandard1.6.1 + netstandard1.4 Ordering.Infrastructure Ordering.Infrastructure 1.6.1 diff --git a/src/Services/Payment/Payment.API/Payment.API.csproj b/src/Services/Payment/Payment.API/Payment.API.csproj index dc8aad80d..bb873d1c8 100644 --- a/src/Services/Payment/Payment.API/Payment.API.csproj +++ b/src/Services/Payment/Payment.API/Payment.API.csproj @@ -1,7 +1,7 @@  - netcoreapp1.1 + netcoreapp2.0 ..\..\..\..\docker-compose.dcproj portable-net45+win8 diff --git a/src/Web/WebMVC/Dockerfile b/src/Web/WebMVC/Dockerfile index 16a9c99df..729620bb9 100644 --- a/src/Web/WebMVC/Dockerfile +++ b/src/Web/WebMVC/Dockerfile @@ -1,4 +1,4 @@ -FROM microsoft/aspnetcore:1.1.2 +FROM microsoft/aspnetcore:2.0 ARG source WORKDIR /app EXPOSE 80 diff --git a/src/Web/WebMVC/Startup.cs b/src/Web/WebMVC/Startup.cs index 8147f6720..bcdbbcc21 100644 --- a/src/Web/WebMVC/Startup.cs +++ b/src/Web/WebMVC/Startup.cs @@ -1,4 +1,6 @@ -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Authentication.OpenIdConnect; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.eShopOnContainers.BuildingBlocks; @@ -116,7 +118,6 @@ namespace Microsoft.eShopOnContainers.WebMVC var oidcOptions = new OpenIdConnectOptions { - AuthenticationScheme = "oidc", SignInScheme = "Cookies", Authority = identityUrl.ToString(), PostLogoutRedirectUri = callBackUrl.ToString(), diff --git a/src/Web/WebMVC/WebMVC.csproj b/src/Web/WebMVC/WebMVC.csproj index 48925ab34..b6a866c12 100644 --- a/src/Web/WebMVC/WebMVC.csproj +++ b/src/Web/WebMVC/WebMVC.csproj @@ -1,9 +1,7 @@  - netcoreapp1.1 - 1.1.2 - Exe + netcoreapp2.0 aspnet-Microsoft.eShopOnContainers-946ae052-8305-4a99-965b-ec8636ddbae3 $(PackageTargetFallback);dotnet5.6;portable-net45+win8 ..\..\..\docker-compose.dcproj diff --git a/src/Web/WebSPA/Dockerfile b/src/Web/WebSPA/Dockerfile index b954fac87..f08724dd8 100644 --- a/src/Web/WebSPA/Dockerfile +++ b/src/Web/WebSPA/Dockerfile @@ -1,4 +1,4 @@ -FROM microsoft/aspnetcore:1.1.2 +FROM microsoft/aspnetcore:2.0 ARG source WORKDIR /app EXPOSE 80 diff --git a/src/Web/WebSPA/WebSPA.csproj b/src/Web/WebSPA/WebSPA.csproj index c4bc8e8d5..9b64a5fe7 100644 --- a/src/Web/WebSPA/WebSPA.csproj +++ b/src/Web/WebSPA/WebSPA.csproj @@ -1,10 +1,7 @@  - netcoreapp1.1 - 1.1.2 - Exe - eShopOnContainers.WebSPA + netcoreapp2.0 aspnetcorespa-c23d27a4-eb88-4b18-9b77-2a93f3b15119 $(PackageTargetFallback);dotnet5.6;portable-net45+win8 ..\..\..\docker-compose.dcproj diff --git a/src/Web/WebStatus/Dockerfile b/src/Web/WebStatus/Dockerfile index 729a46123..8d9b70884 100644 --- a/src/Web/WebStatus/Dockerfile +++ b/src/Web/WebStatus/Dockerfile @@ -1,4 +1,4 @@ -FROM microsoft/aspnetcore:1.1.2 +FROM microsoft/aspnetcore:2.0 ARG source WORKDIR /app EXPOSE 80 diff --git a/src/Web/WebStatus/WebStatus.csproj b/src/Web/WebStatus/WebStatus.csproj index b845fdcc3..3a5a8c633 100644 --- a/src/Web/WebStatus/WebStatus.csproj +++ b/src/Web/WebStatus/WebStatus.csproj @@ -1,23 +1,15 @@  - netcoreapp1.1.2 - 1.1.2 - - - + netcoreapp2.0 $(PackageTargetFallback);portable-net45+win8+wp8+wpa81; ..\..\..\docker-compose.dcproj + - - - - - - + diff --git a/test/Services/FunctionalTests/FunctionalTests.csproj b/test/Services/FunctionalTests/FunctionalTests.csproj index ef5561595..1bf5db148 100644 --- a/test/Services/FunctionalTests/FunctionalTests.csproj +++ b/test/Services/FunctionalTests/FunctionalTests.csproj @@ -1,7 +1,7 @@  - netcoreapp1.1 + netcoreapp2.0 true $(PackageTargetFallback);netstandard1.6.1;dnxcore50;portable-net451+win8 false diff --git a/test/Services/IntegrationTests/IntegrationTests.csproj b/test/Services/IntegrationTests/IntegrationTests.csproj index 689b801bc..8578b7adf 100644 --- a/test/Services/IntegrationTests/IntegrationTests.csproj +++ b/test/Services/IntegrationTests/IntegrationTests.csproj @@ -1,7 +1,7 @@  - netcoreapp1.1 + netcoreapp2.0 FunctionalTests FunctionalTests true diff --git a/test/Services/UnitTest/UnitTest.csproj b/test/Services/UnitTest/UnitTest.csproj index 2cf0dfbb0..e5a1cb835 100644 --- a/test/Services/UnitTest/UnitTest.csproj +++ b/test/Services/UnitTest/UnitTest.csproj @@ -1,7 +1,7 @@  - netcoreapp1.1 + netcoreapp2.0 true $(PackageTargetFallback);netstandard1.6.1;dnxcore50;portable-net451+win8 false From 5d383dbaad4db1bfe57b876f2cb681409873f992 Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Wed, 21 Jun 2017 19:10:12 +0200 Subject: [PATCH 03/86] GracePeriodManager nuget updated --- .../GracePeriodManager.csproj | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj b/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj index ab9a44f2e..08f3542fa 100644 --- a/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj +++ b/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj @@ -9,15 +9,15 @@ - - - - - - - - - + + + + + + + + + From b050ba5c944d942fa15b81b931a87618774ba556 Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Wed, 21 Jun 2017 19:16:59 +0200 Subject: [PATCH 04/86] DataProtection.csproj nuget updated --- .../DataProtection/DataProtection/DataProtection.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj b/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj index c5266d0a9..ab35dab8e 100644 --- a/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj +++ b/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj @@ -6,7 +6,7 @@ - + From 7fd5647bae65bfe9784f9edae9346b464d0e3b97 Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Wed, 21 Jun 2017 19:19:58 +0200 Subject: [PATCH 05/86] EventBus.csproj nuget updated --- src/BuildingBlocks/EventBus/EventBus/EventBus.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj b/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj index 723b22b64..1fc8e48cf 100644 --- a/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj +++ b/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj @@ -10,7 +10,7 @@ - + \ No newline at end of file From ea129609d580631c284a81df29bec5b372339960 Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Wed, 21 Jun 2017 19:33:24 +0200 Subject: [PATCH 06/86] Basket.API nuget updated --- .../Basket/Basket.API/Basket.API.csproj | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/Services/Basket/Basket.API/Basket.API.csproj b/src/Services/Basket/Basket.API/Basket.API.csproj index 6e5c66b61..d2e8d5173 100644 --- a/src/Services/Basket/Basket.API/Basket.API.csproj +++ b/src/Services/Basket/Basket.API/Basket.API.csproj @@ -2,8 +2,6 @@ netcoreapp2.0 - 1.1.2 - Exe $(PackageTargetFallback);netstandard1.6.1;dnxcore50;portable-net451+win8 ..\..\..\..\docker-compose.dcproj @@ -21,19 +19,19 @@ - - - - - - - - - - + + + + + + + + + + - - + + From 4069a3a048109c3dc116e7cee0f942ae6ca0d4f0 Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Wed, 21 Jun 2017 19:36:33 +0200 Subject: [PATCH 07/86] Catalog.API nuget updated --- .../Catalog/Catalog.API/Catalog.API.csproj | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/src/Services/Catalog/Catalog.API/Catalog.API.csproj b/src/Services/Catalog/Catalog.API/Catalog.API.csproj index 140a7a552..5cd6691ab 100644 --- a/src/Services/Catalog/Catalog.API/Catalog.API.csproj +++ b/src/Services/Catalog/Catalog.API/Catalog.API.csproj @@ -5,10 +5,8 @@ portable true Catalog.API - Exe Catalog.API aspnet-Catalog.API-20161122013618 - 1.1.2 $(PackageTargetFallback);dotnet5.6;portable-net45+win8 ..\..\..\..\docker-compose.dcproj @@ -30,25 +28,25 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + From 4303cbae89d6fe2e93fa72f1e6d4db71d55d29bc Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Wed, 21 Jun 2017 19:39:47 +0200 Subject: [PATCH 08/86] Locations.API nuget updated --- .../Locations.API/Locations.API.csproj | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/Services/Location/Locations.API/Locations.API.csproj b/src/Services/Location/Locations.API/Locations.API.csproj index e78661ba0..01cb58ec5 100644 --- a/src/Services/Location/Locations.API/Locations.API.csproj +++ b/src/Services/Location/Locations.API/Locations.API.csproj @@ -11,25 +11,25 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + From 706423cc8d4d88c3bbfdd980315ae1874fe1f0a9 Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Wed, 21 Jun 2017 19:43:02 +0200 Subject: [PATCH 09/86] Marketing.API nuget updated --- .../Marketing.API/Marketing.API.csproj | 56 +++++++++---------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/src/Services/Marketing/Marketing.API/Marketing.API.csproj b/src/Services/Marketing/Marketing.API/Marketing.API.csproj index 85d9370ce..b8af9107a 100644 --- a/src/Services/Marketing/Marketing.API/Marketing.API.csproj +++ b/src/Services/Marketing/Marketing.API/Marketing.API.csproj @@ -2,8 +2,6 @@ netcoreapp2.0 - 1.1.2 - Exe ..\..\..\..\docker-compose.dcproj Microsoft.eShopOnContainers.Services.Marketing.API portable-net45+win8 @@ -20,33 +18,33 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + From 3c2ce4d7a7a4b5089c2a19bca62accafdd8a67fe Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Wed, 21 Jun 2017 19:48:13 +0200 Subject: [PATCH 10/86] Ordering.API nuget update --- .../Ordering/Ordering.API/Ordering.API.csproj | 46 +++++++++---------- .../Ordering.Domain/Ordering.Domain.csproj | 2 +- .../Ordering.Infrastructure.csproj | 6 +-- 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/Services/Ordering/Ordering.API/Ordering.API.csproj b/src/Services/Ordering/Ordering.API/Ordering.API.csproj index 71c2ea251..80c3d9068 100644 --- a/src/Services/Ordering/Ordering.API/Ordering.API.csproj +++ b/src/Services/Ordering/Ordering.API/Ordering.API.csproj @@ -2,8 +2,6 @@ netcoreapp2.0 - 1.1.2 - Exe aspnet-Ordering.API-20161122013547 $(PackageTargetFallback);netstandard1.6.1;dnxcore50;portable-net451+win8 ..\..\..\..\docker-compose.dcproj @@ -30,35 +28,35 @@ - + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - + - - + + diff --git a/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj b/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj index c6cb205c3..9ccbf60eb 100644 --- a/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj +++ b/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj b/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj index 6f460108f..ef785364f 100644 --- a/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj +++ b/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj @@ -16,9 +16,9 @@ - - - + + + From 17dc20077d2fcab4d69babc90b6d7e9911196218 Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Wed, 21 Jun 2017 19:50:01 +0200 Subject: [PATCH 11/86] Payment.API nuget updated --- .../Payment/Payment.API/Payment.API.csproj | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Services/Payment/Payment.API/Payment.API.csproj b/src/Services/Payment/Payment.API/Payment.API.csproj index bb873d1c8..1bbb9696b 100644 --- a/src/Services/Payment/Payment.API/Payment.API.csproj +++ b/src/Services/Payment/Payment.API/Payment.API.csproj @@ -11,15 +11,15 @@ - - - - - - - - - + + + + + + + + + From 286b8e4344b144e8644a17dc5a8bf461abbe38d5 Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Wed, 21 Jun 2017 19:57:36 +0200 Subject: [PATCH 12/86] Unwanted fwk reference in GracePeriodManager --- .../GracePeriod/GracePeriodManager/GracePeriodManager.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj b/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj index 08f3542fa..f239692b7 100644 --- a/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj +++ b/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj @@ -3,7 +3,6 @@ Exe netcoreapp2.0 - 1.1.2 From 6b466a2c664291bf6c6c69775062d331fdcdb51c Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Thu, 22 Jun 2017 16:15:58 +0200 Subject: [PATCH 13/86] Fixing NetStandard.Library versions --- .../DataProtection/DataProtection/DataProtection.csproj | 1 + src/Services/Location/Locations.API/Dockerfile | 2 +- src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj | 2 +- .../Ordering.Infrastructure/Ordering.Infrastructure.csproj | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj b/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj index ab35dab8e..69b23a145 100644 --- a/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj +++ b/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj @@ -3,6 +3,7 @@ netstandard1.5 Microsoft.eShopOnContainers.BuildingBlocks + 2.0.0-preview1-25301-01 diff --git a/src/Services/Location/Locations.API/Dockerfile b/src/Services/Location/Locations.API/Dockerfile index 3d00f01a9..5a5edb3e7 100644 --- a/src/Services/Location/Locations.API/Dockerfile +++ b/src/Services/Location/Locations.API/Dockerfile @@ -1,4 +1,4 @@ -FROM microsoft/aspnetcore:1.1 +FROM microsoft/aspnetcore:2.0 ARG source WORKDIR /app EXPOSE 80 diff --git a/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj b/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj index 9ccbf60eb..187dc56fc 100644 --- a/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj +++ b/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj @@ -3,8 +3,8 @@ netstandard1.4 Ordering.Domain + 2.0.0-preview1-25301-01 Ordering.Domain - 1.6.1 $(PackageTargetFallback);dnxcore50 false false diff --git a/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj b/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj index ef785364f..ea8d8c29b 100644 --- a/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj +++ b/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj @@ -4,7 +4,7 @@ netstandard1.4 Ordering.Infrastructure Ordering.Infrastructure - 1.6.1 + 2.0.0-preview1-25301-01 $(PackageTargetFallback);dnxcore50 false false From 0a1f14f1f185812cdf56ec44c3acbd1a809f3c5e Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Thu, 22 Jun 2017 16:19:54 +0200 Subject: [PATCH 14/86] WebSPA nuget update --- src/Web/WebSPA/Startup.cs | 6 ------ src/Web/WebSPA/WebSPA.csproj | 42 ++++++++++++++++++------------------ 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/src/Web/WebSPA/Startup.cs b/src/Web/WebSPA/Startup.cs index d9e9d093b..53406422f 100644 --- a/src/Web/WebSPA/Startup.cs +++ b/src/Web/WebSPA/Startup.cs @@ -27,12 +27,6 @@ namespace eShopConContainers.WebSPA .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) .AddEnvironmentVariables(); - if (env.IsDevelopment()) - { - // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709 - builder.AddUserSecrets(); - } - Configuration = builder.Build(); var localPath = new Uri(Configuration["ASPNETCORE_URLS"])?.LocalPath ?? "/"; diff --git a/src/Web/WebSPA/WebSPA.csproj b/src/Web/WebSPA/WebSPA.csproj index 9b64a5fe7..c598d700e 100644 --- a/src/Web/WebSPA/WebSPA.csproj +++ b/src/Web/WebSPA/WebSPA.csproj @@ -25,29 +25,29 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + All - - + + From bbc682d6a9925a40cde76182683f9bd0ee162686 Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Thu, 22 Jun 2017 16:22:41 +0200 Subject: [PATCH 15/86] WebMVC nuget update --- src/Web/WebMVC/WebMVC.csproj | 40 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Web/WebMVC/WebMVC.csproj b/src/Web/WebMVC/WebMVC.csproj index b6a866c12..89077d5e9 100644 --- a/src/Web/WebMVC/WebMVC.csproj +++ b/src/Web/WebMVC/WebMVC.csproj @@ -27,29 +27,29 @@ --> - - - - - - - - - - - - - + + + + + + + + + + + + + - + All - - - - - - + + + + + + From fdd9a367190748fe4f9beff76500d2b4f5d89299 Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Thu, 22 Jun 2017 16:55:57 +0200 Subject: [PATCH 16/86] MVC auth updated to 2.0.0 --- .../WebMVC/Controllers/AccountController.cs | 5 +- src/Web/WebMVC/Services/BasketService.cs | 2 +- src/Web/WebMVC/Services/CampaignService.cs | 2 +- src/Web/WebMVC/Services/OrderingService.cs | 2 +- src/Web/WebMVC/Startup.cs | 58 +++++++++---------- 5 files changed, 33 insertions(+), 36 deletions(-) diff --git a/src/Web/WebMVC/Controllers/AccountController.cs b/src/Web/WebMVC/Controllers/AccountController.cs index a38207d58..c00a94c72 100644 --- a/src/Web/WebMVC/Controllers/AccountController.cs +++ b/src/Web/WebMVC/Controllers/AccountController.cs @@ -22,7 +22,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers public async Task SignIn(string returnUrl) { var user = User as ClaimsPrincipal; - var token = await HttpContext.Authentication.GetTokenAsync("access_token"); + + var token = await HttpContext.GetTokenAsync("access_token"); if (token != null) { @@ -42,7 +43,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers // "Catalog" because UrlHelper doesn't support nameof() for controllers // https://github.com/aspnet/Mvc/issues/5853 var homeUrl = Url.Action(nameof(CatalogController.Index), "Catalog"); - return new SignOutResult("oidc", new AuthenticationProperties { RedirectUri = homeUrl }); + return new SignOutResult("oidc", new AspNetCore.Authentication.AuthenticationProperties { RedirectUri = homeUrl }); } } } diff --git a/src/Web/WebMVC/Services/BasketService.cs b/src/Web/WebMVC/Services/BasketService.cs index 55cec1bb9..fd4bad124 100644 --- a/src/Web/WebMVC/Services/BasketService.cs +++ b/src/Web/WebMVC/Services/BasketService.cs @@ -125,7 +125,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services async Task GetUserTokenAsync() { var context = _httpContextAccesor.HttpContext; - return await context.Authentication.GetTokenAsync("access_token"); + return await context.GetTokenAsync("access_token"); } } } diff --git a/src/Web/WebMVC/Services/CampaignService.cs b/src/Web/WebMVC/Services/CampaignService.cs index e90be9590..dd93e3283 100644 --- a/src/Web/WebMVC/Services/CampaignService.cs +++ b/src/Web/WebMVC/Services/CampaignService.cs @@ -64,7 +64,7 @@ private async Task GetUserTokenAsync() { var context = _httpContextAccesor.HttpContext; - return await context.Authentication.GetTokenAsync("access_token"); + return await context.GetTokenAsync("access_token"); } } } \ No newline at end of file diff --git a/src/Web/WebMVC/Services/OrderingService.cs b/src/Web/WebMVC/Services/OrderingService.cs index d9eba7392..f36f1410d 100644 --- a/src/Web/WebMVC/Services/OrderingService.cs +++ b/src/Web/WebMVC/Services/OrderingService.cs @@ -151,7 +151,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services { var context = _httpContextAccesor.HttpContext; - return await context.Authentication.GetTokenAsync("access_token"); + return await context.GetTokenAsync("access_token"); } } } diff --git a/src/Web/WebMVC/Startup.cs b/src/Web/WebMVC/Startup.cs index bcdbbcc21..7fe05da02 100644 --- a/src/Web/WebMVC/Startup.cs +++ b/src/Web/WebMVC/Startup.cs @@ -26,13 +26,6 @@ namespace Microsoft.eShopOnContainers.WebMVC .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) // Settings for the application .AddEnvironmentVariables(); // override settings with environment variables set in compose. - - if (env.IsDevelopment()) - { - // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709 - builder.AddUserSecrets(); - } - Configuration = builder.Build(); } @@ -84,6 +77,32 @@ namespace Microsoft.eShopOnContainers.WebMVC { services.AddSingleton(); } + + + var identityUrl = Configuration.GetValue("IdentityUrl"); + var callBackUrl = Configuration.GetValue("CallBackUrl"); + // Add Authentication services + services.AddCookieAuthentication(CookieAuthenticationDefaults.AuthenticationScheme); + services.AddOpenIdConnectAuthentication("Oidc", options => + { + options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + options.Authority = identityUrl.ToString(); + options.PostLogoutRedirectUri = callBackUrl.ToString(); + options.ClientId = "mvc"; + options.ClientSecret = "secret"; + options.ResponseType = "code id_token"; + options.SaveTokens = true; + options.GetClaimsFromUserInfoEndpoint = true; + options.RequireHttpsMetadata = false; + options.Scope.Add("openid"); + options.Scope.Add("profile"); + options.Scope.Add("orders"); + options.Scope.Add("basket"); + options.Scope.Add("marketing"); + }); + + services.AddAuthentication(sharedOptions => sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme); + } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -106,32 +125,9 @@ namespace Microsoft.eShopOnContainers.WebMVC app.UseStaticFiles(); - app.UseCookieAuthentication(new CookieAuthenticationOptions - { - AuthenticationScheme = "Cookies", - AutomaticAuthenticate = true, - }); - var identityUrl = Configuration.GetValue("IdentityUrl"); - var callBackUrl = Configuration.GetValue("CallBackUrl"); - var log = loggerFactory.CreateLogger("identity"); - var oidcOptions = new OpenIdConnectOptions - { - SignInScheme = "Cookies", - Authority = identityUrl.ToString(), - PostLogoutRedirectUri = callBackUrl.ToString(), - ClientId = "mvc", - ClientSecret = "secret", - ResponseType = "code id_token", - SaveTokens = true, - GetClaimsFromUserInfoEndpoint = true, - RequireHttpsMetadata = false, - Scope = { "openid", "profile", "orders", "basket", "marketing" } - }; - - //Wait untill identity service is ready on compose. - app.UseOpenIdConnectAuthentication(oidcOptions); + var log = loggerFactory.CreateLogger("identity"); app.UseMvc(routes => { From 340d50fddd9e6ea0e887cb06cb6c2a761baf0146 Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Thu, 22 Jun 2017 16:56:10 +0200 Subject: [PATCH 17/86] WebStatus Nuget updated --- src/Web/WebStatus/WebStatus.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Web/WebStatus/WebStatus.csproj b/src/Web/WebStatus/WebStatus.csproj index 3a5a8c633..409c7362f 100644 --- a/src/Web/WebStatus/WebStatus.csproj +++ b/src/Web/WebStatus/WebStatus.csproj @@ -6,7 +6,7 @@ - + From d6a6416e195fcecde2df5ef6982fde9552b1db3f Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Thu, 22 Jun 2017 16:56:27 +0200 Subject: [PATCH 18/86] Bad folder for Locations.API corrected --- cli-windows/build-bits.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli-windows/build-bits.ps1 b/cli-windows/build-bits.ps1 index 9533ee25e..96caa7f26 100644 --- a/cli-windows/build-bits.ps1 +++ b/cli-windows/build-bits.ps1 @@ -17,7 +17,7 @@ $projectPaths = @{Path="$rootPath\src\Services\GracePeriod\GracePeriodManager";Prj="GracePeriodManager.csproj"}, @{Path="$rootPath\src\Services\Basket\Basket.API";Prj="Basket.API.csproj"}, @{Path="$rootPath\src\Services\Identity\Identity.API";Prj="Identity.API.csproj"}, - @{Path="$rootPath\src\Services\Location\Location.API";Prj="Locations.API.csproj"}, + @{Path="$rootPath\src\Services\Location\Locations.API";Prj="Locations.API.csproj"}, @{Path="$rootPath\src\Services\Marketing\Marketing.API";Prj="Marketing.API.csproj"}, @{Path="$rootPath\src\Services\Payment\Payment.API";Prj="Payment.API.csproj"}, @{Path="$rootPath\src\Web\WebStatus";Prj="WebStatus.csproj"} From eba0a53562d8e0b31155282271da679514708a15 Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Thu, 22 Jun 2017 20:11:36 +0200 Subject: [PATCH 19/86] fixed invalid WebMVC csproj entries --- src/Web/WebMVC/WebMVC.csproj | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/Web/WebMVC/WebMVC.csproj b/src/Web/WebMVC/WebMVC.csproj index 89077d5e9..b8a57a359 100644 --- a/src/Web/WebMVC/WebMVC.csproj +++ b/src/Web/WebMVC/WebMVC.csproj @@ -7,17 +7,6 @@ ..\..\..\docker-compose.dcproj - - - - - - - - - PreserveNewest - - + + diff --git a/src/Services/Identity/Identity.API/Identity.API.csproj b/src/Services/Identity/Identity.API/Identity.API.csproj index d31664a2b..4f175503c 100644 --- a/src/Services/Identity/Identity.API/Identity.API.csproj +++ b/src/Services/Identity/Identity.API/Identity.API.csproj @@ -3,7 +3,6 @@ netcoreapp1.1 1.1.2 - Exe aspnet-eShopOnContainers.Identity-90487118-103c-4ff0-b9da-e5e26f7ab0c5 $(PackageTargetFallback);dotnet5.6;portable-net45+win8 ..\..\..\..\docker-compose.dcproj diff --git a/src/Web/WebMVC/Startup.cs b/src/Web/WebMVC/Startup.cs index 7fe05da02..f07fb21c7 100644 --- a/src/Web/WebMVC/Startup.cs +++ b/src/Web/WebMVC/Startup.cs @@ -83,7 +83,7 @@ namespace Microsoft.eShopOnContainers.WebMVC var callBackUrl = Configuration.GetValue("CallBackUrl"); // Add Authentication services services.AddCookieAuthentication(CookieAuthenticationDefaults.AuthenticationScheme); - services.AddOpenIdConnectAuthentication("Oidc", options => + services.AddOpenIdConnectAuthentication(OpenIdConnectDefaults.AuthenticationScheme, options => { options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.Authority = identityUrl.ToString(); @@ -101,8 +101,11 @@ namespace Microsoft.eShopOnContainers.WebMVC options.Scope.Add("marketing"); }); - services.AddAuthentication(sharedOptions => sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme); - + services.AddAuthentication(options => { + options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; + options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; + }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -125,7 +128,7 @@ namespace Microsoft.eShopOnContainers.WebMVC app.UseStaticFiles(); - + app.UseAuthentication(); var log = loggerFactory.CreateLogger("identity"); From d65a11253516f2a003c094d1752641af9b51811d Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Thu, 29 Jun 2017 18:36:57 +0200 Subject: [PATCH 22/86] References updated to preview-2 code adjustements to work with preview-2 --- cli-windows/build-bits.ps1 | 1 + global.json | 2 +- .../DataProtection/DataProtection.csproj | 2 +- .../EventBusRabbitMQ/EventBusRabbitMQ.csproj | 4 +- .../IntegrationEventLogEF.csproj | 2 +- .../Microsoft.Extensions.HealthChecks.csproj | 2 +- .../Resilience.Http/Resilience.Http.csproj | 4 +- .../Basket/Basket.API/Basket.API.csproj | 22 +++++----- .../Catalog/Catalog.API/Catalog.API.csproj | 38 ++++++++-------- src/Services/Catalog/Catalog.API/Startup.cs | 1 + .../GracePeriodManager.csproj | 18 ++++---- .../Identity/Identity.API/Identity.API.csproj | 5 +-- .../Locations.API/Locations.API.csproj | 24 +++++------ .../Marketing.API/Marketing.API.csproj | 43 +++++++++---------- .../Marketing/Marketing.API/Startup.cs | 1 + .../Ordering/Ordering.API/Ordering.API.csproj | 38 ++++++++-------- .../Ordering.Domain/Ordering.Domain.csproj | 4 +- .../Ordering.Infrastructure.csproj | 11 +++-- .../Payment/Payment.API/Payment.API.csproj | 16 +++---- src/Web/WebMVC/ViewModels/ApplicationUser.cs | 2 +- src/Web/WebMVC/WebMVC.csproj | 39 ++++++++--------- .../WebMonolithic/eShopWeb/eShopWeb.csproj | 1 - src/Web/WebSPA/WebSPA.csproj | 41 ++++++++---------- src/Web/WebStatus/WebStatus.csproj | 6 +-- .../FunctionalTests/FunctionalTests.csproj | 2 +- .../IntegrationTests/IntegrationTests.csproj | 2 +- test/Services/UnitTest/UnitTest.csproj | 2 +- 27 files changed, 162 insertions(+), 171 deletions(-) diff --git a/cli-windows/build-bits.ps1 b/cli-windows/build-bits.ps1 index 96caa7f26..6a5a06d86 100644 --- a/cli-windows/build-bits.ps1 +++ b/cli-windows/build-bits.ps1 @@ -20,6 +20,7 @@ $projectPaths = @{Path="$rootPath\src\Services\Location\Locations.API";Prj="Locations.API.csproj"}, @{Path="$rootPath\src\Services\Marketing\Marketing.API";Prj="Marketing.API.csproj"}, @{Path="$rootPath\src\Services\Payment\Payment.API";Prj="Payment.API.csproj"}, + @{Path="$rootPath\src\Services\GracePeriod\GracePeriodManager";Prj="GracePeriodManager.csproj"}, @{Path="$rootPath\src\Web\WebStatus";Prj="WebStatus.csproj"} $projectPaths | foreach { diff --git a/global.json b/global.json index 6c30ddc76..7d2a1589c 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version":"2.0.0-preview1-005977" + "version":"2.0.0-preview2-006497" } } \ No newline at end of file diff --git a/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj b/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj index a8024b7e5..2f519fc95 100644 --- a/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj +++ b/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj @@ -11,7 +11,7 @@ diff --git a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj index d59c999c1..f033ad159 100644 --- a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj +++ b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj index cc3d51f6a..30225c299 100644 --- a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj +++ b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj @@ -12,7 +12,7 @@ - + diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Microsoft.Extensions.HealthChecks.csproj b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Microsoft.Extensions.HealthChecks.csproj index c0a9c571a..8ef22e156 100644 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Microsoft.Extensions.HealthChecks.csproj +++ b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Microsoft.Extensions.HealthChecks.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/BuildingBlocks/Resilience/Resilience.Http/Resilience.Http.csproj b/src/BuildingBlocks/Resilience/Resilience.Http/Resilience.Http.csproj index e472bb7a5..1f094380c 100644 --- a/src/BuildingBlocks/Resilience/Resilience.Http/Resilience.Http.csproj +++ b/src/BuildingBlocks/Resilience/Resilience.Http/Resilience.Http.csproj @@ -7,8 +7,8 @@ - - + + \ No newline at end of file diff --git a/src/Services/Basket/Basket.API/Basket.API.csproj b/src/Services/Basket/Basket.API/Basket.API.csproj index d2e8d5173..13f2830db 100644 --- a/src/Services/Basket/Basket.API/Basket.API.csproj +++ b/src/Services/Basket/Basket.API/Basket.API.csproj @@ -2,7 +2,7 @@ netcoreapp2.0 - $(PackageTargetFallback);netstandard1.6.1;dnxcore50;portable-net451+win8 + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; ..\..\..\..\docker-compose.dcproj @@ -19,16 +19,16 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/src/Services/Catalog/Catalog.API/Catalog.API.csproj b/src/Services/Catalog/Catalog.API/Catalog.API.csproj index 5cd6691ab..31b600c02 100644 --- a/src/Services/Catalog/Catalog.API/Catalog.API.csproj +++ b/src/Services/Catalog/Catalog.API/Catalog.API.csproj @@ -7,7 +7,7 @@ Catalog.API Catalog.API aspnet-Catalog.API-20161122013618 - $(PackageTargetFallback);dotnet5.6;portable-net45+win8 + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; ..\..\..\..\docker-compose.dcproj @@ -28,24 +28,24 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/src/Services/Catalog/Catalog.API/Startup.cs b/src/Services/Catalog/Catalog.API/Startup.cs index c5784b6a4..39ebf519d 100644 --- a/src/Services/Catalog/Catalog.API/Startup.cs +++ b/src/Services/Catalog/Catalog.API/Startup.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; + using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; diff --git a/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj b/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj index f239692b7..c37a06663 100644 --- a/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj +++ b/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj @@ -8,15 +8,15 @@ - - - - - - - - - + + + + + + + + + diff --git a/src/Services/Identity/Identity.API/Identity.API.csproj b/src/Services/Identity/Identity.API/Identity.API.csproj index 4f175503c..373e47a33 100644 --- a/src/Services/Identity/Identity.API/Identity.API.csproj +++ b/src/Services/Identity/Identity.API/Identity.API.csproj @@ -4,7 +4,7 @@ netcoreapp1.1 1.1.2 aspnet-eShopOnContainers.Identity-90487118-103c-4ff0-b9da-e5e26f7ab0c5 - $(PackageTargetFallback);dotnet5.6;portable-net45+win8 + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; ..\..\..\..\docker-compose.dcproj @@ -34,9 +34,6 @@ - - All - diff --git a/src/Services/Location/Locations.API/Locations.API.csproj b/src/Services/Location/Locations.API/Locations.API.csproj index 01cb58ec5..2ede0db1f 100644 --- a/src/Services/Location/Locations.API/Locations.API.csproj +++ b/src/Services/Location/Locations.API/Locations.API.csproj @@ -13,19 +13,19 @@ - - - - - - + + + + + + - - - - - - + + + + + + diff --git a/src/Services/Marketing/Marketing.API/Marketing.API.csproj b/src/Services/Marketing/Marketing.API/Marketing.API.csproj index b8af9107a..0e886a2ea 100644 --- a/src/Services/Marketing/Marketing.API/Marketing.API.csproj +++ b/src/Services/Marketing/Marketing.API/Marketing.API.csproj @@ -4,7 +4,7 @@ netcoreapp2.0 ..\..\..\..\docker-compose.dcproj Microsoft.eShopOnContainers.Services.Marketing.API - portable-net45+win8 + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; aspnet-Marketing.API-20161122013619 @@ -19,28 +19,27 @@ - - - - - - - + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/src/Services/Marketing/Marketing.API/Startup.cs b/src/Services/Marketing/Marketing.API/Startup.cs index a31055d39..909ca1235 100644 --- a/src/Services/Marketing/Marketing.API/Startup.cs +++ b/src/Services/Marketing/Marketing.API/Startup.cs @@ -23,6 +23,7 @@ using Polly; using System.Threading.Tasks; using System.Data.SqlClient; + using Microsoft.EntityFrameworkCore.Diagnostics; public class Startup { diff --git a/src/Services/Ordering/Ordering.API/Ordering.API.csproj b/src/Services/Ordering/Ordering.API/Ordering.API.csproj index 80c3d9068..13cdad1a0 100644 --- a/src/Services/Ordering/Ordering.API/Ordering.API.csproj +++ b/src/Services/Ordering/Ordering.API/Ordering.API.csproj @@ -3,7 +3,7 @@ netcoreapp2.0 aspnet-Ordering.API-20161122013547 - $(PackageTargetFallback);netstandard1.6.1;dnxcore50;portable-net451+win8 + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; ..\..\..\..\docker-compose.dcproj @@ -32,31 +32,31 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - + diff --git a/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj b/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj index 187dc56fc..2673abf84 100644 --- a/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj +++ b/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj @@ -5,7 +5,7 @@ Ordering.Domain 2.0.0-preview1-25301-01 Ordering.Domain - $(PackageTargetFallback);dnxcore50 + $(AssetTargetFallback);dnxcore50; false false false @@ -14,7 +14,7 @@ - + diff --git a/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj b/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj index ea8d8c29b..f37446084 100644 --- a/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj +++ b/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj @@ -1,11 +1,10 @@  - netstandard1.4 + netstandard2.0 Ordering.Infrastructure Ordering.Infrastructure - 2.0.0-preview1-25301-01 - $(PackageTargetFallback);dnxcore50 + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; false false false @@ -16,9 +15,9 @@ - - - + + + diff --git a/src/Services/Payment/Payment.API/Payment.API.csproj b/src/Services/Payment/Payment.API/Payment.API.csproj index 1bbb9696b..6152a78fa 100644 --- a/src/Services/Payment/Payment.API/Payment.API.csproj +++ b/src/Services/Payment/Payment.API/Payment.API.csproj @@ -3,7 +3,7 @@ netcoreapp2.0 ..\..\..\..\docker-compose.dcproj - portable-net45+win8 + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; @@ -12,14 +12,14 @@ - - - - - + + + + + - - + + diff --git a/src/Web/WebMVC/ViewModels/ApplicationUser.cs b/src/Web/WebMVC/ViewModels/ApplicationUser.cs index 0602a9c95..23016a6db 100644 --- a/src/Web/WebMVC/ViewModels/ApplicationUser.cs +++ b/src/Web/WebMVC/ViewModels/ApplicationUser.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.ComponentModel.DataAnnotations; -using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.AspNetCore.Identity; namespace Microsoft.eShopOnContainers.WebMVC.ViewModels { diff --git a/src/Web/WebMVC/WebMVC.csproj b/src/Web/WebMVC/WebMVC.csproj index b8a57a359..d7f1cabdb 100644 --- a/src/Web/WebMVC/WebMVC.csproj +++ b/src/Web/WebMVC/WebMVC.csproj @@ -3,7 +3,7 @@ netcoreapp2.0 aspnet-Microsoft.eShopOnContainers-946ae052-8305-4a99-965b-ec8636ddbae3 - $(PackageTargetFallback);dotnet5.6;portable-net45+win8 + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; ..\..\..\docker-compose.dcproj @@ -16,29 +16,26 @@ --> - - - - - - - - - - - - - + + + + + + + + + + + + + - - All - - - - - + + + + diff --git a/src/Web/WebMonolithic/eShopWeb/eShopWeb.csproj b/src/Web/WebMonolithic/eShopWeb/eShopWeb.csproj index 749087ce4..cf53a938a 100644 --- a/src/Web/WebMonolithic/eShopWeb/eShopWeb.csproj +++ b/src/Web/WebMonolithic/eShopWeb/eShopWeb.csproj @@ -21,7 +21,6 @@ - diff --git a/src/Web/WebSPA/WebSPA.csproj b/src/Web/WebSPA/WebSPA.csproj index c598d700e..155d65d95 100644 --- a/src/Web/WebSPA/WebSPA.csproj +++ b/src/Web/WebSPA/WebSPA.csproj @@ -3,7 +3,7 @@ netcoreapp2.0 aspnetcorespa-c23d27a4-eb88-4b18-9b77-2a93f3b15119 - $(PackageTargetFallback);dotnet5.6;portable-net45+win8 + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; ..\..\..\docker-compose.dcproj false true @@ -25,29 +25,26 @@ - - - - - - - + + + + + + + - - - - - - - - - - - All - - - + + + + + + + + + + + diff --git a/src/Web/WebStatus/WebStatus.csproj b/src/Web/WebStatus/WebStatus.csproj index 409c7362f..56c5766f5 100644 --- a/src/Web/WebStatus/WebStatus.csproj +++ b/src/Web/WebStatus/WebStatus.csproj @@ -1,15 +1,15 @@  netcoreapp2.0 - $(PackageTargetFallback);portable-net45+win8+wp8+wpa81; + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; ..\..\..\docker-compose.dcproj - + - + diff --git a/test/Services/FunctionalTests/FunctionalTests.csproj b/test/Services/FunctionalTests/FunctionalTests.csproj index 1bf5db148..f9f58a318 100644 --- a/test/Services/FunctionalTests/FunctionalTests.csproj +++ b/test/Services/FunctionalTests/FunctionalTests.csproj @@ -3,7 +3,7 @@ netcoreapp2.0 true - $(PackageTargetFallback);netstandard1.6.1;dnxcore50;portable-net451+win8 + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; false false false diff --git a/test/Services/IntegrationTests/IntegrationTests.csproj b/test/Services/IntegrationTests/IntegrationTests.csproj index 8578b7adf..d787b10fc 100644 --- a/test/Services/IntegrationTests/IntegrationTests.csproj +++ b/test/Services/IntegrationTests/IntegrationTests.csproj @@ -5,7 +5,7 @@ FunctionalTests FunctionalTests true - $(PackageTargetFallback);netstandard1.6.1;dnxcore50;portable-net451+win8 + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; false false false diff --git a/test/Services/UnitTest/UnitTest.csproj b/test/Services/UnitTest/UnitTest.csproj index e5a1cb835..ec396c982 100644 --- a/test/Services/UnitTest/UnitTest.csproj +++ b/test/Services/UnitTest/UnitTest.csproj @@ -3,7 +3,7 @@ netcoreapp2.0 true - $(PackageTargetFallback);netstandard1.6.1;dnxcore50;portable-net451+win8 + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; false false false From 62a14e1006555c398241b4f6e7dec8654c519b10 Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Tue, 11 Jul 2017 10:12:32 +0200 Subject: [PATCH 23/86] Upgrade IntegrationEventLogEF to netcore2 --- .../IntegrationEventLogEF.csproj | 16 ++++++++-------- .../Services/IntegrationEventLogService.cs | 1 + 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj index 30225c299..e1e24b9fe 100644 --- a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj +++ b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj @@ -1,22 +1,22 @@  - netcoreapp1.1 + netcoreapp2.0 Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF - - - - - - + + + + + + - + diff --git a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Services/IntegrationEventLogService.cs b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Services/IntegrationEventLogService.cs index bef74b452..5ac8bb862 100644 --- a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Services/IntegrationEventLogService.cs +++ b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Services/IntegrationEventLogService.cs @@ -6,6 +6,7 @@ using System.Data.Common; using System.Linq; using System.Threading.Tasks; using System; +using Microsoft.EntityFrameworkCore.Diagnostics; namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services { From 2e64a97b4cddaa9e1d5ce2138c2a53f64a7e06f5 Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Wed, 12 Jul 2017 17:28:04 +0200 Subject: [PATCH 24/86] Changes for retrieving all claims under netcore2 --- .../Identity/Identity.API/Configuration/Config.cs | 1 + src/Web/WebMVC/Controllers/AccountController.cs | 13 ++++++++----- src/Web/WebMVC/Startup.cs | 1 + 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Services/Identity/Identity.API/Configuration/Config.cs b/src/Services/Identity/Identity.API/Configuration/Config.cs index bce62b039..a4f804db6 100644 --- a/src/Services/Identity/Identity.API/Configuration/Config.cs +++ b/src/Services/Identity/Identity.API/Configuration/Config.cs @@ -96,6 +96,7 @@ namespace Identity.API.Configuration AllowAccessTokensViaBrowser = false, RequireConsent = false, AllowOfflineAccess = true, + AlwaysIncludeUserClaimsInIdToken = true, RedirectUris = new List { $"{clientsUrl["Mvc"]}/signin-oidc" diff --git a/src/Web/WebMVC/Controllers/AccountController.cs b/src/Web/WebMVC/Controllers/AccountController.cs index c00a94c72..25c42e8d7 100644 --- a/src/Web/WebMVC/Controllers/AccountController.cs +++ b/src/Web/WebMVC/Controllers/AccountController.cs @@ -6,6 +6,8 @@ using Microsoft.eShopOnContainers.WebMVC.Services; using Microsoft.AspNetCore.Http.Authentication; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.OpenIdConnect; +using Microsoft.AspNetCore.Authentication.Cookies; namespace Microsoft.eShopOnContainers.WebMVC.Controllers { @@ -35,15 +37,16 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers return RedirectToAction(nameof(CatalogController.Index), "Catalog"); } - public IActionResult Signout() + public async Task Signout() { - HttpContext.Authentication.SignOutAsync("Cookies"); - HttpContext.Authentication.SignOutAsync("oidc"); - + await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme); + // "Catalog" because UrlHelper doesn't support nameof() for controllers // https://github.com/aspnet/Mvc/issues/5853 var homeUrl = Url.Action(nameof(CatalogController.Index), "Catalog"); - return new SignOutResult("oidc", new AspNetCore.Authentication.AuthenticationProperties { RedirectUri = homeUrl }); + return new SignOutResult(OpenIdConnectDefaults.AuthenticationScheme, + new AspNetCore.Authentication.AuthenticationProperties { RedirectUri = homeUrl }); } } } diff --git a/src/Web/WebMVC/Startup.cs b/src/Web/WebMVC/Startup.cs index 3349d9530..90bc98ac1 100644 --- a/src/Web/WebMVC/Startup.cs +++ b/src/Web/WebMVC/Startup.cs @@ -100,6 +100,7 @@ namespace Microsoft.eShopOnContainers.WebMVC options.Scope.Add("orders"); options.Scope.Add("basket"); options.Scope.Add("marketing"); + options.Scope.Add("locations"); }); services.AddAuthentication(options => { From 2f1f1cd61671db902b411064b64266832b1e0722 Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Thu, 13 Jul 2017 12:34:19 +0200 Subject: [PATCH 25/86] Address as EF Value object --- .../Ordering.Infrastructure/OrderingContext.cs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs b/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs index 0c69fe566..42110a7f7 100644 --- a/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs +++ b/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs @@ -45,7 +45,6 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure { modelBuilder.Entity(ConfigureRequests); - modelBuilder.Entity
(ConfigureAddress); modelBuilder.Entity(ConfigurePayment); modelBuilder.Entity(ConfigureOrder); modelBuilder.Entity(ConfigureOrderItems); @@ -62,19 +61,6 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure requestConfiguration.Property(cr => cr.Time).IsRequired(); } - void ConfigureAddress(EntityTypeBuilder
addressConfiguration) - { - addressConfiguration.ToTable("address", DEFAULT_SCHEMA); - - // DDD Pattern comment: Implementing the Address Id as "Shadow property" - // becuase the Address is a Value-Object (VO) and an Id (Identity) is not desired for a VO - // EF Core just needs the Id so it is capable to store it in a database table - // See: https://docs.microsoft.com/en-us/ef/core/modeling/shadow-properties - addressConfiguration.Property("Id") - .IsRequired(); - - addressConfiguration.HasKey("Id"); - } void ConfigureBuyer(EntityTypeBuilder buyerConfiguration) { @@ -152,6 +138,8 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure orderConfiguration.Property(o => o.Id) .ForSqlServerUseSequenceHiLo("orderseq", DEFAULT_SCHEMA); + orderConfiguration.OwnsOne(o => o.Address); + orderConfiguration.Property("OrderDate").IsRequired(); orderConfiguration.Property("BuyerId").IsRequired(false); orderConfiguration.Property("OrderStatusId").IsRequired(); From eeda5bcb9def94c67fec7961a1895b272d0ed77c Mon Sep 17 00:00:00 2001 From: Eduard Tomas Date: Thu, 13 Jul 2017 13:42:29 +0200 Subject: [PATCH 26/86] Order.Address is a value object. It has no table and no ID --- .../Application/Queries/OrderQueries.cs | 8 +- ...0713111342_AdressAsValueObject.Designer.cs | 251 ++++++++++++++++++ .../20170713111342_AdressAsValueObject.cs | 146 ++++++++++ .../OrderingContextModelSnapshot.cs | 75 +++--- .../OrderingDbContextDesigner.cs | 29 ++ src/Services/Ordering/Ordering.API/Startup.cs | 16 +- .../OrderingContext.cs | 7 + 7 files changed, 485 insertions(+), 47 deletions(-) create mode 100644 src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20170713111342_AdressAsValueObject.Designer.cs create mode 100644 src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20170713111342_AdressAsValueObject.cs create mode 100644 src/Services/Ordering/Ordering.API/Infrastructure/OrderingDbContextDesigner.cs diff --git a/src/Services/Ordering/Ordering.API/Application/Queries/OrderQueries.cs b/src/Services/Ordering/Ordering.API/Application/Queries/OrderQueries.cs index 15036e154..a57c61334 100644 --- a/src/Services/Ordering/Ordering.API/Application/Queries/OrderQueries.cs +++ b/src/Services/Ordering/Ordering.API/Application/Queries/OrderQueries.cs @@ -26,11 +26,11 @@ connection.Open(); var result = await connection.QueryAsync( - @"select o.[Id] as ordernumber,o.OrderDate as date, o.Description as description, os.Name as status, - oi.ProductName as productname, oi.Units as units, oi.UnitPrice as unitprice, oi.PictureUrl as pictureurl, - a.Street as street, a.City as city, a.Country as country, a.State as state, a.ZipCode as zipcode + @"select o.[Id] as ordernumber,o.OrderDate as date, o.Description as description, + o.Address_City as city, o.Address_Country as country, o.Address_State as state, o.Address_Street as street, o.Address_ZipCode as zipcode, + os.Name as status, + oi.ProductName as productname, oi.Units as units, oi.UnitPrice as unitprice, oi.PictureUrl as pictureurl FROM ordering.Orders o - INNER JOIN ordering.Address a ON o.AddressId = a.Id LEFT JOIN ordering.Orderitems oi ON o.Id = oi.orderid LEFT JOIN ordering.orderstatus os on o.OrderStatusId = os.Id WHERE o.Id=@id" diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20170713111342_AdressAsValueObject.Designer.cs b/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20170713111342_AdressAsValueObject.Designer.cs new file mode 100644 index 000000000..6e66bc9b4 --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20170713111342_AdressAsValueObject.Designer.cs @@ -0,0 +1,251 @@ +// +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.eShopOnContainers.Services.Ordering.Infrastructure; +using System; + +namespace Ordering.API.Migrations +{ + [DbContext(typeof(OrderingContext))] + [Migration("20170713111342_AdressAsValueObject")] + partial class AdressAsValueObject + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.0.0-preview2-25794") + .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.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.OrderAggregate.Address", b => + { + b.Property("OrderId"); + + b.Property("City"); + + b.Property("Country"); + + b.Property("State"); + + b.Property("Street"); + + b.Property("ZipCode"); + + b.HasKey("OrderId"); + + b.ToTable("orders","ordering"); + }); + + modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", b => + { + b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer") + .WithMany("PaymentMethods") + .HasForeignKey("BuyerId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.CardType", "CardType") + .WithMany() + .HasForeignKey("CardTypeId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order", b => + { + b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer") + .WithMany() + .HasForeignKey("BuyerId"); + + b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderStatus", "OrderStatus") + .WithMany() + .HasForeignKey("OrderStatusId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod") + .WithMany() + .HasForeignKey("PaymentMethodId") + .OnDelete(DeleteBehavior.Restrict); + }); + + modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderItem", b => + { + b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order") + .WithMany("OrderItems") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", b => + { + b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order") + .WithOne("Address") + .HasForeignKey("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", "OrderId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20170713111342_AdressAsValueObject.cs b/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20170713111342_AdressAsValueObject.cs new file mode 100644 index 000000000..9f5d28d99 --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20170713111342_AdressAsValueObject.cs @@ -0,0 +1,146 @@ +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using System; +using System.Collections.Generic; + +namespace Ordering.API.Migrations +{ + public partial class AdressAsValueObject : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_orders_address_AddressId", + schema: "ordering", + table: "orders"); + + migrationBuilder.DropForeignKey( + name: "FK_orders_paymentmethods_PaymentMethodId", + schema: "ordering", + table: "orders"); + + migrationBuilder.DropTable( + name: "address", + schema: "ordering"); + + migrationBuilder.DropIndex( + name: "IX_orders_AddressId", + schema: "ordering", + table: "orders"); + + migrationBuilder.DropColumn( + name: "AddressId", + schema: "ordering", + table: "orders"); + + migrationBuilder.AddColumn( + name: "Address_City", + schema: "ordering", + table: "orders", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "Address_Country", + schema: "ordering", + table: "orders", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "Address_State", + schema: "ordering", + table: "orders", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "Address_Street", + schema: "ordering", + table: "orders", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "Address_ZipCode", + schema: "ordering", + table: "orders", + type: "nvarchar(max)", + nullable: true); + + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_orders_paymentmethods_PaymentMethodId", + schema: "ordering", + table: "orders"); + + migrationBuilder.DropColumn( + name: "Address_City", + schema: "ordering", + table: "orders"); + + migrationBuilder.DropColumn( + name: "Address_Country", + schema: "ordering", + table: "orders"); + + migrationBuilder.DropColumn( + name: "Address_State", + schema: "ordering", + table: "orders"); + + migrationBuilder.DropColumn( + name: "Address_Street", + schema: "ordering", + table: "orders"); + + migrationBuilder.DropColumn( + name: "Address_ZipCode", + schema: "ordering", + table: "orders"); + + migrationBuilder.AddColumn( + name: "AddressId", + schema: "ordering", + table: "orders", + nullable: true); + + migrationBuilder.CreateTable( + name: "address", + schema: "ordering", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), + City = table.Column(nullable: true), + Country = table.Column(nullable: true), + State = table.Column(nullable: true), + Street = table.Column(nullable: true), + ZipCode = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_address", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_orders_AddressId", + schema: "ordering", + table: "orders", + column: "AddressId"); + + migrationBuilder.AddForeignKey( + name: "FK_orders_address_AddressId", + schema: "ordering", + table: "orders", + column: "AddressId", + principalSchema: "ordering", + principalTable: "address", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + } + } +} diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/OrderingContextModelSnapshot.cs b/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/OrderingContextModelSnapshot.cs index fa342cf31..9e455568d 100644 --- a/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/OrderingContextModelSnapshot.cs +++ b/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/OrderingContextModelSnapshot.cs @@ -1,9 +1,12 @@ -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.eShopOnContainers.Services.Ordering.Infrastructure; +using System; namespace Ordering.API.Migrations { @@ -12,12 +15,13 @@ namespace Ordering.API.Migrations { protected override void BuildModel(ModelBuilder modelBuilder) { +#pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "1.1.1") - .HasAnnotation("SqlServer:Sequence:.orderitemseq", "'orderitemseq', '', '1', '10', '', '', 'Int64', 'False'") - .HasAnnotation("SqlServer:Sequence:ordering.buyerseq", "'buyerseq', 'ordering', '1', '10', '', '', 'Int64', 'False'") - .HasAnnotation("SqlServer:Sequence:ordering.orderseq", "'orderseq', 'ordering', '1', '10', '', '', 'Int64', 'False'") - .HasAnnotation("SqlServer:Sequence:ordering.paymentseq", "'paymentseq', 'ordering', '1', '10', '', '', 'Int64', 'False'") + .HasAnnotation("ProductVersion", "2.0.0-preview2-25794") + .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 => @@ -89,26 +93,6 @@ namespace Ordering.API.Migrations b.ToTable("paymentmethods","ordering"); }); - modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("City"); - - b.Property("Country"); - - b.Property("State"); - - b.Property("Street"); - - b.Property("ZipCode"); - - b.HasKey("Id"); - - b.ToTable("address","ordering"); - }); - modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order", b => { b.Property("Id") @@ -117,8 +101,6 @@ namespace Ordering.API.Migrations .HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering") .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo); - b.Property("AddressId"); - b.Property("BuyerId"); b.Property("Description"); @@ -131,8 +113,6 @@ namespace Ordering.API.Migrations b.HasKey("Id"); - b.HasIndex("AddressId"); - b.HasIndex("BuyerId"); b.HasIndex("OrderStatusId"); @@ -200,6 +180,25 @@ namespace Ordering.API.Migrations b.ToTable("requests","ordering"); }); + modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", b => + { + b.Property("OrderId"); + + b.Property("City"); + + b.Property("Country"); + + b.Property("State"); + + b.Property("Street"); + + b.Property("ZipCode"); + + b.HasKey("OrderId"); + + b.ToTable("orders","ordering"); + }); + modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", b => { b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer") @@ -215,10 +214,6 @@ namespace Ordering.API.Migrations modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order", b => { - b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", "Address") - .WithMany() - .HasForeignKey("AddressId"); - b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer") .WithMany() .HasForeignKey("BuyerId"); @@ -230,7 +225,8 @@ namespace Ordering.API.Migrations b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod") .WithMany() - .HasForeignKey("PaymentMethodId"); + .HasForeignKey("PaymentMethodId") + .OnDelete(DeleteBehavior.Restrict); }); modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderItem", b => @@ -240,6 +236,15 @@ namespace Ordering.API.Migrations .HasForeignKey("OrderId") .OnDelete(DeleteBehavior.Cascade); }); + + modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", b => + { + b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order") + .WithOne("Address") + .HasForeignKey("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", "OrderId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 } } } diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/OrderingDbContextDesigner.cs b/src/Services/Ordering/Ordering.API/Infrastructure/OrderingDbContextDesigner.cs new file mode 100644 index 000000000..5d14c55e6 --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Infrastructure/OrderingDbContextDesigner.cs @@ -0,0 +1,29 @@ +using MediatR; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Design; +using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; +using Microsoft.Extensions.Configuration; +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; + +namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure +{ + public class OrderingDbContextDesigner : IDesignTimeDbContextFactory + { + + + public OrderingContext CreateDbContext(string[] args) + { + var options = new DbContextOptionsBuilder(); + options.UseSqlServer("Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;", + sqlServerOptionsAction: sqlOptions => + { + sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); + }); + return OrderingContext.CreateForEFDesignTools(options.Options); + } + + } +} diff --git a/src/Services/Ordering/Ordering.API/Startup.cs b/src/Services/Ordering/Ordering.API/Startup.cs index 15a966c1a..33fcc0052 100644 --- a/src/Services/Ordering/Ordering.API/Startup.cs +++ b/src/Services/Ordering/Ordering.API/Startup.cs @@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Azure.ServiceBus; using Microsoft.EntityFrameworkCore; + using Microsoft.EntityFrameworkCore.Design; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; @@ -58,11 +59,10 @@ // Add framework services. services.AddMvc(options => { - options.Filters.Add(typeof(HttpGlobalExceptionFilter)); + options.Filters.Add(typeof(HttpGlobalExceptionFilter)); }).AddControllersAsServices(); //Injecting Controllers themselves thru DI //For further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services - services.AddHealthChecks(checks => { var minutes = 1; @@ -72,7 +72,7 @@ } checks.AddSqlCheck("OrderingDb", Configuration["ConnectionString"], TimeSpan.FromMinutes(minutes)); }); - + services.AddEntityFrameworkSqlServer() .AddDbContext(options => { @@ -81,8 +81,8 @@ { sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); sqlOptions.EnableRetryOnFailure(maxRetryCount: 5, 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) ); @@ -113,8 +113,8 @@ services.AddSingleton(); services.AddTransient(); services.AddTransient>( - sp => (DbConnection c) => new IntegrationEventLogService(c)); - + sp => (DbConnection c) => new IntegrationEventLogService(c)); + services.AddTransient(); if (Configuration.GetValue("AzureServiceBusEnabled")) @@ -164,7 +164,7 @@ { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); - + app.UseCors("CorsPolicy"); ConfigureAuth(app); diff --git a/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs b/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs index 42110a7f7..85e2cb0f9 100644 --- a/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs +++ b/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs @@ -33,6 +33,13 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure private readonly IMediator _mediator; + + public static OrderingContext CreateForEFDesignTools(DbContextOptions options) + { + return new OrderingContext(options); + } + + private OrderingContext(DbContextOptions options) : base (options) { } public OrderingContext(DbContextOptions options, IMediator mediator) : base(options) { _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator)); From 26a4701bf4545d1b4d47349e0737b7f0385f7559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ram=C3=B3n=20Tom=C3=A1s?= Date: Tue, 22 Aug 2017 19:47:22 +0200 Subject: [PATCH 27/86] Fix Account Controller unittest --- test/Services/UnitTest/Account/AccountControllerTest.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/test/Services/UnitTest/Account/AccountControllerTest.cs b/test/Services/UnitTest/Account/AccountControllerTest.cs index 0fa4402d3..3a92ed4d4 100644 --- a/test/Services/UnitTest/Account/AccountControllerTest.cs +++ b/test/Services/UnitTest/Account/AccountControllerTest.cs @@ -1,16 +1,9 @@ -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Authentication; using Microsoft.AspNetCore.Mvc; using Microsoft.eShopOnContainers.WebMVC.Controllers; -using Microsoft.eShopOnContainers.WebMVC.Services; -using Microsoft.eShopOnContainers.WebMVC.ViewModels; using Moq; -using System; -using System.Collections.Generic; using System.Security.Claims; -using System.Text; -using System.Threading.Tasks; using Xunit; namespace UnitTest.Account From 8288acf3a4a1d0adef917cb416b8ab42188a97e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ram=C3=B3n=20Tom=C3=A1s?= Date: Tue, 22 Aug 2017 22:36:23 +0200 Subject: [PATCH 28/86] Update projects from netcore 2.0.0 preview to 2.0.0 Fix netcore 2.0.0 breaking changes in authentication middleware --- .../Basket/Basket.API/Basket.API.csproj | 20 ++++----- .../Catalog/Catalog.API/Catalog.API.csproj | 36 ++++++++-------- .../GracePeriodManager.csproj | 18 ++++---- .../Locations.API/Locations.API.csproj | 25 +++++------ .../Marketing.API/Marketing.API.csproj | 40 +++++++++--------- .../Ordering/Ordering.API/Ordering.API.csproj | 34 +++++++-------- .../Ordering.Infrastructure.csproj | 6 +-- .../Payment/Payment.API/Payment.API.csproj | 14 +++---- src/Web/WebMVC/Startup.cs | 42 ++++++++++--------- src/Web/WebMVC/WebMVC.csproj | 35 ++++++++-------- src/Web/WebSPA/WebSPA.csproj | 36 ++++++++-------- src/Web/WebStatus/WebStatus.csproj | 5 +-- 12 files changed, 157 insertions(+), 154 deletions(-) diff --git a/src/Services/Basket/Basket.API/Basket.API.csproj b/src/Services/Basket/Basket.API/Basket.API.csproj index 57a807d3a..584838c8f 100644 --- a/src/Services/Basket/Basket.API/Basket.API.csproj +++ b/src/Services/Basket/Basket.API/Basket.API.csproj @@ -20,16 +20,16 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/src/Services/Catalog/Catalog.API/Catalog.API.csproj b/src/Services/Catalog/Catalog.API/Catalog.API.csproj index 62816baf3..4c1edfa22 100644 --- a/src/Services/Catalog/Catalog.API/Catalog.API.csproj +++ b/src/Services/Catalog/Catalog.API/Catalog.API.csproj @@ -33,24 +33,24 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj b/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj index 567b61662..c376e88f6 100644 --- a/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj +++ b/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj @@ -8,15 +8,15 @@ - - - - - - - - - + + + + + + + + + diff --git a/src/Services/Location/Locations.API/Locations.API.csproj b/src/Services/Location/Locations.API/Locations.API.csproj index ca1f68f2a..3a53ee826 100644 --- a/src/Services/Location/Locations.API/Locations.API.csproj +++ b/src/Services/Location/Locations.API/Locations.API.csproj @@ -13,24 +13,25 @@ - - - - - - + + + + + + - - - - - - + + + + + + + diff --git a/src/Services/Marketing/Marketing.API/Marketing.API.csproj b/src/Services/Marketing/Marketing.API/Marketing.API.csproj index 703f82bc6..71adef034 100644 --- a/src/Services/Marketing/Marketing.API/Marketing.API.csproj +++ b/src/Services/Marketing/Marketing.API/Marketing.API.csproj @@ -19,27 +19,27 @@ - - - - - - - + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/src/Services/Ordering/Ordering.API/Ordering.API.csproj b/src/Services/Ordering/Ordering.API/Ordering.API.csproj index 3f6ce21d4..047579f6d 100644 --- a/src/Services/Ordering/Ordering.API/Ordering.API.csproj +++ b/src/Services/Ordering/Ordering.API/Ordering.API.csproj @@ -36,24 +36,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + diff --git a/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj b/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj index f37446084..fdd0bfa53 100644 --- a/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj +++ b/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj @@ -15,9 +15,9 @@ - - - + + + diff --git a/src/Services/Payment/Payment.API/Payment.API.csproj b/src/Services/Payment/Payment.API/Payment.API.csproj index 9b1442c8e..46f2d81b9 100644 --- a/src/Services/Payment/Payment.API/Payment.API.csproj +++ b/src/Services/Payment/Payment.API/Payment.API.csproj @@ -12,14 +12,14 @@ - - - - - + + + + + - - + + diff --git a/src/Web/WebMVC/Startup.cs b/src/Web/WebMVC/Startup.cs index 0a9bd99e2..315be8973 100644 --- a/src/Web/WebMVC/Startup.cs +++ b/src/Web/WebMVC/Startup.cs @@ -83,26 +83,28 @@ namespace Microsoft.eShopOnContainers.WebMVC var useLoadTest = Configuration.GetValue("UseLoadTest"); var identityUrl = Configuration.GetValue("IdentityUrl"); var callBackUrl = Configuration.GetValue("CallBackUrl"); - // Add Authentication services - services.AddCookieAuthentication(CookieAuthenticationDefaults.AuthenticationScheme); - services.AddOpenIdConnectAuthentication(OpenIdConnectDefaults.AuthenticationScheme, options => - { - options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; - options.Authority = identityUrl.ToString(); - options.PostLogoutRedirectUri = callBackUrl.ToString(); - options.ClientId = useLoadTest ? "mvctest" : "mvc"; - options.ClientSecret = "secret"; - options.ResponseType = useLoadTest ? "code id_token token" : "code id_token"; - options.SaveTokens = true; - options.GetClaimsFromUserInfoEndpoint = true; - options.RequireHttpsMetadata = false; - options.Scope.Add("openid"); - options.Scope.Add("profile"); - options.Scope.Add("orders"); - options.Scope.Add("basket"); - options.Scope.Add("marketing"); - options.Scope.Add("locations"); - }); + + // Add Authentication services + + services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) + .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme) + .AddOpenIdConnect(options => { + options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + options.Authority = identityUrl.ToString(); + options.SignedOutRedirectUri = callBackUrl.ToString(); + options.ClientId = useLoadTest ? "mvctest" : "mvc"; + options.ClientSecret = "secret"; + options.ResponseType = useLoadTest ? "code id_token token" : "code id_token"; + options.SaveTokens = true; + options.GetClaimsFromUserInfoEndpoint = true; + options.RequireHttpsMetadata = false; + options.Scope.Add("openid"); + options.Scope.Add("profile"); + options.Scope.Add("orders"); + options.Scope.Add("basket"); + options.Scope.Add("marketing"); + options.Scope.Add("locations"); + }); services.AddAuthentication(options => { options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; diff --git a/src/Web/WebMVC/WebMVC.csproj b/src/Web/WebMVC/WebMVC.csproj index ddd35c889..e6e11cb99 100644 --- a/src/Web/WebMVC/WebMVC.csproj +++ b/src/Web/WebMVC/WebMVC.csproj @@ -36,26 +36,27 @@ --> - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - + + + + diff --git a/src/Web/WebSPA/WebSPA.csproj b/src/Web/WebSPA/WebSPA.csproj index ca26a394b..1e3b2630a 100644 --- a/src/Web/WebSPA/WebSPA.csproj +++ b/src/Web/WebSPA/WebSPA.csproj @@ -28,26 +28,26 @@ - - - - - - - + + + + + + + - - - - - - - - - - - + + + + + + + + + + + diff --git a/src/Web/WebStatus/WebStatus.csproj b/src/Web/WebStatus/WebStatus.csproj index 56c5766f5..7939b146a 100644 --- a/src/Web/WebStatus/WebStatus.csproj +++ b/src/Web/WebStatus/WebStatus.csproj @@ -5,11 +5,10 @@ ..\..\..\docker-compose.dcproj - - + - + From 58f3b5b274ec76cad93a5b7f3912cbf2cf9ca3c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ram=C3=B3n=20Tom=C3=A1s?= Date: Wed, 23 Aug 2017 00:10:28 +0200 Subject: [PATCH 29/86] Removed GracePeriod microservice and added as a HostService --- docker-compose-windows.override.yml | 8 -- docker-compose-windows.prod.yml | 7 - docker-compose-windows.yml | 9 -- docker-compose.override.yml | 8 -- docker-compose.prod.yml | 8 -- docker-compose.yml | 9 -- eShopOnContainers-ServicesAndWebApps.sln | 56 +------- .../GracePeriodManager/.dockerignore | 3 - .../GracePeriod/GracePeriodManager/Dockerfile | 5 - .../GracePeriodManager/Dockerfile.nanowin | 8 -- .../GracePeriodManager.csproj | 36 ----- .../GracePeriodConfirmedIntegrationEvent.cs | 11 -- .../GracePeriod/GracePeriodManager/Program.cs | 130 ------------------ .../Services/IManagerService.cs | 7 - .../GracePeriodManager/appsettings.json | 15 -- .../GracePeriodManagerService.cs} | 55 ++++++-- .../GracePeriodManagerSettings.cs} | 7 +- .../HostedServices/HostedService.cs | 48 +++++++ src/Services/Ordering/Ordering.API/Startup.cs | 14 +- .../Ordering.API/graceperiodsettings.json | 6 + 20 files changed, 113 insertions(+), 337 deletions(-) delete mode 100644 src/Services/GracePeriod/GracePeriodManager/.dockerignore delete mode 100644 src/Services/GracePeriod/GracePeriodManager/Dockerfile delete mode 100644 src/Services/GracePeriod/GracePeriodManager/Dockerfile.nanowin delete mode 100644 src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj delete mode 100644 src/Services/GracePeriod/GracePeriodManager/IntegrationEvents/Events/GracePeriodConfirmedIntegrationEvent.cs delete mode 100644 src/Services/GracePeriod/GracePeriodManager/Program.cs delete mode 100644 src/Services/GracePeriod/GracePeriodManager/Services/IManagerService.cs delete mode 100644 src/Services/GracePeriod/GracePeriodManager/appsettings.json rename src/Services/{GracePeriod/GracePeriodManager/Services/ManagerService.cs => Ordering/Ordering.API/Infrastructure/HostedServices/GracePeriodManagerService.cs} (52%) rename src/Services/{GracePeriod/GracePeriodManager/ManagerSettings.cs => Ordering/Ordering.API/Infrastructure/HostedServices/GracePeriodManagerSettings.cs} (68%) create mode 100644 src/Services/Ordering/Ordering.API/Infrastructure/HostedServices/HostedService.cs create mode 100644 src/Services/Ordering/Ordering.API/graceperiodsettings.json diff --git a/docker-compose-windows.override.yml b/docker-compose-windows.override.yml index 4237d9c96..6c791b1a6 100644 --- a/docker-compose-windows.override.yml +++ b/docker-compose-windows.override.yml @@ -137,14 +137,6 @@ services: - AzureStorageEnabled=False ports: - "5110:80" - - graceperiodmanager: - 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} - - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - - AzureServiceBusEnabled=False webstatus: environment: diff --git a/docker-compose-windows.prod.yml b/docker-compose-windows.prod.yml index 5dc00aa9a..d5ea2d1bc 100644 --- a/docker-compose-windows.prod.yml +++ b/docker-compose-windows.prod.yml @@ -118,13 +118,6 @@ services: - AzureStorageEnabled=False ports: - "5110:80" - - graceperiodmanager: - 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} - - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} sql.data: environment: diff --git a/docker-compose-windows.yml b/docker-compose-windows.yml index 6296f5ca7..190b823b6 100644 --- a/docker-compose-windows.yml +++ b/docker-compose-windows.yml @@ -106,15 +106,6 @@ services: ports: - "5672:5672" - graceperiodmanager: - image: eshop/graceperiodmanager:${TAG:-latest} - build: - context: ./src/Services/GracePeriod/GracePeriodManager - dockerfile: Dockerfile.nanowin - depends_on: - - sql.data - - rabbitmq - payment.api: image: eshop/payment.api:${TAG:-latest} build: diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 1a0129ac3..c8375040d 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -82,14 +82,6 @@ services: - AzureStorageEnabled=False ports: - "5110:80" - - graceperiodmanager: - 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} - - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - - AzureServiceBusEnabled=False webspa: environment: diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index cb53a1d00..f768b5872 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -88,14 +88,6 @@ services: ports: - "5110:80" - graceperiodmanager: - 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} - - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - - AzureServiceBusEnabled=False - webspa: environment: - ASPNETCORE_ENVIRONMENT=Production diff --git a/docker-compose.yml b/docker-compose.yml index 253674b57..991a7b28b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -49,15 +49,6 @@ services: - identity.api - rabbitmq - graceperiodmanager: - image: eshop/graceperiodmanager:${TAG:-latest} - build: - context: ./src/Services/GracePeriod/GracePeriodManager - dockerfile: Dockerfile - depends_on: - - sql.data - - rabbitmq - webspa: image: eshop/webspa:${TAG:-latest} build: diff --git a/eShopOnContainers-ServicesAndWebApps.sln b/eShopOnContainers-ServicesAndWebApps.sln index 9dd6308a4..a01ca8a37 100644 --- a/eShopOnContainers-ServicesAndWebApps.sln +++ b/eShopOnContainers-ServicesAndWebApps.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26430.6 +VisualStudioVersion = 15.0.26730.8 MinimumVisualStudioVersion = 10.0.40219.1 Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FEA0C318-FFED-4D39-8781-265718CA43DD}" EndProject @@ -81,8 +81,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Health EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBus.Tests", "src\BuildingBlocks\EventBus\EventBus.Tests\EventBus.Tests.csproj", "{4A980AC4-7205-46BF-8CCB-09E44D700FD4}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GracePeriodManager", "src\Services\GracePeriod\GracePeriodManager\GracePeriodManager.csproj", "{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}" -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}" @@ -1075,54 +1073,6 @@ Global {4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Release|x64.Build.0 = Release|Any CPU {4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Release|x86.ActiveCfg = Release|Any CPU {4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Release|x86.Build.0 = Release|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|x64.Build.0 = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|ARM.ActiveCfg = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|ARM.Build.0 = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|iPhone.Build.0 = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|x64.ActiveCfg = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|x64.Build.0 = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|x86.ActiveCfg = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|x86.Build.0 = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|ARM.ActiveCfg = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|ARM.Build.0 = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|iPhone.Build.0 = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|x64.ActiveCfg = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|x64.Build.0 = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|x86.ActiveCfg = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|x86.Build.0 = Debug|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|Any CPU.Build.0 = Release|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|ARM.ActiveCfg = Release|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|ARM.Build.0 = Release|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|iPhone.ActiveCfg = Release|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|iPhone.Build.0 = Release|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|x64.ActiveCfg = Release|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|x64.Build.0 = Release|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|x86.ActiveCfg = Release|Any CPU - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|x86.Build.0 = Release|Any CPU {E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU @@ -1449,7 +1399,6 @@ Global {22A0F9C1-2D4A-4107-95B7-8459E6688BC5} = {A81ECBC2-6B00-4DCD-8388-469174033379} {4BD76717-3102-4969-8C2C-BAAA3F0263B6} = {A81ECBC2-6B00-4DCD-8388-469174033379} {4A980AC4-7205-46BF-8CCB-09E44D700FD4} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F} - {F6E0F0DD-1400-43C3-B5E0-7CC325728C47} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B} {41139F64-4046-4F16-96B7-D941D96FA9C6} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8} {E7581357-FC34-474C-B8F5-307EE3CE05EF} = {41139F64-4046-4F16-96B7-D941D96FA9C6} {88B22DBB-AA8F-4290-A454-2C109352C345} = {DB0EFB20-B024-4E5E-A75C-52143C131D25} @@ -1460,4 +1409,7 @@ Global {768C887F-C229-4B94-ACD8-0C7F65686524} = {A81ECBC2-6B00-4DCD-8388-469174033379} {969E793C-C413-490E-9C9D-B2B46DA5AF32} = {EF0337F2-ED00-4643-89FD-EE10863F1870} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {25728519-5F0F-4973-8A64-0A81EB4EA8D9} + EndGlobalSection EndGlobal diff --git a/src/Services/GracePeriod/GracePeriodManager/.dockerignore b/src/Services/GracePeriod/GracePeriodManager/.dockerignore deleted file mode 100644 index d8f8175f6..000000000 --- a/src/Services/GracePeriod/GracePeriodManager/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -* -!obj/Docker/publish/* -!obj/Docker/empty/ diff --git a/src/Services/GracePeriod/GracePeriodManager/Dockerfile b/src/Services/GracePeriod/GracePeriodManager/Dockerfile deleted file mode 100644 index 7a4f21a64..000000000 --- a/src/Services/GracePeriod/GracePeriodManager/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM microsoft/aspnetcore:2.0 -ARG source -WORKDIR /app -COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "GracePeriodManager.dll"] \ No newline at end of file diff --git a/src/Services/GracePeriod/GracePeriodManager/Dockerfile.nanowin b/src/Services/GracePeriod/GracePeriodManager/Dockerfile.nanowin deleted file mode 100644 index 9c664f4e4..000000000 --- a/src/Services/GracePeriod/GracePeriodManager/Dockerfile.nanowin +++ /dev/null @@ -1,8 +0,0 @@ -FROM microsoft/dotnet:1.1-runtime-nanoserver -SHELL ["powershell"] -ARG source -WORKDIR /app -RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord -EXPOSE 80 -COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "Basket.API.dll"] diff --git a/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj b/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj deleted file mode 100644 index c376e88f6..000000000 --- a/src/Services/GracePeriod/GracePeriodManager/GracePeriodManager.csproj +++ /dev/null @@ -1,36 +0,0 @@ - - - - Exe - netcoreapp2.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - Dockerfile - - - - \ No newline at end of file diff --git a/src/Services/GracePeriod/GracePeriodManager/IntegrationEvents/Events/GracePeriodConfirmedIntegrationEvent.cs b/src/Services/GracePeriod/GracePeriodManager/IntegrationEvents/Events/GracePeriodConfirmedIntegrationEvent.cs deleted file mode 100644 index fce04cd24..000000000 --- a/src/Services/GracePeriod/GracePeriodManager/IntegrationEvents/Events/GracePeriodConfirmedIntegrationEvent.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace GracePeriodManager.IntegrationEvents.Events -{ - using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; - - public class GracePeriodConfirmedIntegrationEvent : IntegrationEvent - { - public int OrderId { get;} - - public GracePeriodConfirmedIntegrationEvent(int orderId) => OrderId = orderId; - } -} \ No newline at end of file diff --git a/src/Services/GracePeriod/GracePeriodManager/Program.cs b/src/Services/GracePeriod/GracePeriodManager/Program.cs deleted file mode 100644 index 88fb1547e..000000000 --- a/src/Services/GracePeriod/GracePeriodManager/Program.cs +++ /dev/null @@ -1,130 +0,0 @@ -namespace GracePeriodManager -{ - using System.IO; - using System; - using System.Threading.Tasks; - using Autofac.Extensions.DependencyInjection; - using Autofac; - using Microsoft.Extensions.Configuration; - using Microsoft.Extensions.DependencyInjection; - using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; - using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; - using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; - using Microsoft.Extensions.Logging; - using Microsoft.Extensions.Options; - using RabbitMQ.Client; - using Services; - using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus; - using Microsoft.Azure.ServiceBus; - - public class Program - { - public static IConfigurationRoot Configuration { get; set; } - - public static void Main(string[] args) => MainAsync().Wait(); - - static async Task MainAsync() - { - StartUp(); - - IServiceCollection services = new ServiceCollection(); - var serviceProvider = ConfigureServices(services); - - var logger = serviceProvider.GetService(); - Configure(logger); - - var gracePeriodManagerService = serviceProvider - .GetRequiredService(); - var checkUpdateTime = serviceProvider - .GetRequiredService>().Value.CheckUpdateTime; - - while (true) - { - gracePeriodManagerService.CheckConfirmedGracePeriodOrders(); - await Task.Delay(checkUpdateTime); - } - } - - public static void StartUp() - { - var builder = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) - .AddEnvironmentVariables(); - - Configuration = builder.Build(); - } - - public static IServiceProvider ConfigureServices(IServiceCollection services) - { - services.AddLogging() - .AddOptions() - .Configure(Configuration) - .AddSingleton(); - - 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"] - }; - - return new DefaultRabbitMQPersistentConnection(factory, logger); - }); - } - - RegisterEventBus(services); - - var container = new ContainerBuilder(); - container.Populate(services); - return new AutofacServiceProvider(container.Build()); - } - - public static void Configure(ILoggerFactory loggerFactory) - { - loggerFactory - .AddConsole(Configuration.GetSection("Logging")) - .AddConsole(LogLevel.Debug); - } - - private static void RegisterEventBus(IServiceCollection services) - { - if (Configuration.GetValue("AzureServiceBusEnabled")) - { - services.AddSingleton(sp => - { - var serviceBusPersisterConnection = sp.GetRequiredService(); - var iLifetimeScope = sp.GetRequiredService(); - var logger = sp.GetRequiredService>(); - var eventBusSubcriptionsManager = sp.GetRequiredService(); - var subscriptionClientName = Configuration["SubscriptionClientName"]; - - return new EventBusServiceBus(serviceBusPersisterConnection, logger, - eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); - }); - } - else - { - services.AddSingleton(); - } - - services.AddSingleton(); - } - } -} \ No newline at end of file diff --git a/src/Services/GracePeriod/GracePeriodManager/Services/IManagerService.cs b/src/Services/GracePeriod/GracePeriodManager/Services/IManagerService.cs deleted file mode 100644 index 2362ccd00..000000000 --- a/src/Services/GracePeriod/GracePeriodManager/Services/IManagerService.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace GracePeriodManager.Services -{ - public interface IManagerService - { - void CheckConfirmedGracePeriodOrders(); - } -} \ No newline at end of file diff --git a/src/Services/GracePeriod/GracePeriodManager/appsettings.json b/src/Services/GracePeriod/GracePeriodManager/appsettings.json deleted file mode 100644 index 76703a77e..000000000 --- a/src/Services/GracePeriod/GracePeriodManager/appsettings.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Debug", - "System": "Information", - "Microsoft": "Information" - } - }, - "ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;", - "GracePeriodTime": "1", - "CheckUpdateTime": "30000", - "AzureServiceBusEnabled": false, - "SubscriptionClientName": "GracePeriod" -} diff --git a/src/Services/GracePeriod/GracePeriodManager/Services/ManagerService.cs b/src/Services/Ordering/Ordering.API/Infrastructure/HostedServices/GracePeriodManagerService.cs similarity index 52% rename from src/Services/GracePeriod/GracePeriodManager/Services/ManagerService.cs rename to src/Services/Ordering/Ordering.API/Infrastructure/HostedServices/GracePeriodManagerService.cs index 973fda158..58408b2fd 100644 --- a/src/Services/GracePeriod/GracePeriodManager/Services/ManagerService.cs +++ b/src/Services/Ordering/Ordering.API/Infrastructure/HostedServices/GracePeriodManagerService.cs @@ -1,30 +1,56 @@ -namespace GracePeriodManager.Services +namespace Ordering.API.Infrastructure.HostedServices { using Dapper; - using GracePeriodManager.IntegrationEvents.Events; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; + using Ordering.API.Application.IntegrationEvents.Events; + using System; using System.Collections.Generic; using System.Data.SqlClient; + using System.Threading; + using System.Threading.Tasks; - public class ManagerService : IManagerService + public class GracePeriodManagerService + : HostedService { - private readonly ManagerSettings _settings; + private readonly GracePeriodManagerSettings _settings; + private readonly ILogger _logger; private readonly IEventBus _eventBus; - private readonly ILogger _logger; - public ManagerService(IOptions settings, + public GracePeriodManagerService(IOptions settings, IEventBus eventBus, - ILogger logger) + ILogger logger) { - _settings = settings.Value; - _eventBus = eventBus; - _logger = logger; + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus)); + + _settings = settings?.Value ?? throw new ArgumentNullException(nameof(settings)); } - public void CheckConfirmedGracePeriodOrders() + protected override async Task ExecuteAsync(CancellationToken cancellationToken) { + while (true) + { + if (cancellationToken.IsCancellationRequested) + { + break; + } + + CheckConfirmedGracePeriodOrders(); + + await Task.Delay(_settings.CheckUpdateTime, cancellationToken); + + continue; + } + + await Task.CompletedTask; + } + + private void CheckConfirmedGracePeriodOrders() + { + _logger.LogDebug($"Checking confirmed grace period orders"); + var orderIds = GetConfirmedGracePeriodOrders(); foreach (var orderId in orderIds) @@ -37,6 +63,7 @@ private IEnumerable GetConfirmedGracePeriodOrders() { IEnumerable orderIds = new List(); + using (var conn = new SqlConnection(_settings.ConnectionString)) { try @@ -46,16 +73,16 @@ @"SELECT Id FROM [Microsoft.eShopOnContainers.Services.OrderingDb].[ordering].[orders] WHERE DATEDIFF(minute, [OrderDate], GETDATE()) >= @GracePeriodTime AND [OrderStatusId] = 1", - new { GracePeriodTime = _settings.GracePeriodTime }); + new { GracePeriodTime = _settings.GracePeriodTime }); } catch (SqlException exception) { _logger.LogCritical($"FATAL ERROR: Database connections could not be opened: {exception.Message}"); } - + } return orderIds; } } -} \ No newline at end of file +} diff --git a/src/Services/GracePeriod/GracePeriodManager/ManagerSettings.cs b/src/Services/Ordering/Ordering.API/Infrastructure/HostedServices/GracePeriodManagerSettings.cs similarity index 68% rename from src/Services/GracePeriod/GracePeriodManager/ManagerSettings.cs rename to src/Services/Ordering/Ordering.API/Infrastructure/HostedServices/GracePeriodManagerSettings.cs index 44e0b56f7..2997c051d 100644 --- a/src/Services/GracePeriod/GracePeriodManager/ManagerSettings.cs +++ b/src/Services/Ordering/Ordering.API/Infrastructure/HostedServices/GracePeriodManagerSettings.cs @@ -1,6 +1,6 @@ -namespace GracePeriodManager +namespace Ordering.API.Infrastructure.HostedServices { - public class ManagerSettings + public class GracePeriodManagerSettings { public string ConnectionString { get; set; } @@ -9,5 +9,6 @@ public int GracePeriodTime { get; set; } public int CheckUpdateTime { get; set; } + } -} \ No newline at end of file +} diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/HostedServices/HostedService.cs b/src/Services/Ordering/Ordering.API/Infrastructure/HostedServices/HostedService.cs new file mode 100644 index 000000000..98ee4907a --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Infrastructure/HostedServices/HostedService.cs @@ -0,0 +1,48 @@ +using Microsoft.Extensions.Hosting; +using System.Threading; +using System.Threading.Tasks; + +namespace Ordering.API.Infrastructure.HostedServices +{ + public abstract class HostedService : IHostedService + { + // Example untested base class code kindly provided by David Fowler: https://gist.github.com/davidfowl/a7dd5064d9dcf35b6eae1a7953d615e3 + + private Task _executingTask; + private CancellationTokenSource _cts; + + public Task StartAsync(CancellationToken cancellationToken) + { + // Create a linked token so we can trigger cancellation outside of this token's cancellation + _cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + + // Store the task we're executing + _executingTask = ExecuteAsync(_cts.Token); + + // If the task is completed then return it, otherwise it's running + return _executingTask.IsCompleted ? _executingTask : Task.CompletedTask; + } + + public async Task StopAsync(CancellationToken cancellationToken) + { + // Stop called without start + if (_executingTask == null) + { + return; + } + + // Signal cancellation to the executing method + _cts.Cancel(); + + // Wait until the task completes or the stop token triggers + await Task.WhenAny(_executingTask, Task.Delay(-1, cancellationToken)); + + // Throw if cancellation triggered + cancellationToken.ThrowIfCancellationRequested(); + } + + // Derived classes should override this and execute a long running method until + // cancellation is requested + protected abstract Task ExecuteAsync(CancellationToken cancellationToken); + } +} diff --git a/src/Services/Ordering/Ordering.API/Startup.cs b/src/Services/Ordering/Ordering.API/Startup.cs index 37ab2ac29..0d3f779c9 100644 --- a/src/Services/Ordering/Ordering.API/Startup.cs +++ b/src/Services/Ordering/Ordering.API/Startup.cs @@ -6,6 +6,7 @@ using global::Ordering.API.Application.IntegrationEvents; using global::Ordering.API.Application.IntegrationEvents.Events; using global::Ordering.API.Infrastructure.Filters; + using global::Ordering.API.Infrastructure.HostedServices; using Infrastructure; using Infrastructure.AutofacModules; using Infrastructure.Filters; @@ -14,7 +15,6 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Azure.ServiceBus; using Microsoft.EntityFrameworkCore; - using Microsoft.EntityFrameworkCore.Design; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; @@ -24,6 +24,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.HealthChecks; + using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Ordering.Infrastructure; using Polly; @@ -43,6 +44,7 @@ var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("settings.json", optional: true, reloadOnChange: true) + .AddJsonFile("graceperiodsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"settings.{env.EnvironmentName}.json", optional: true); if (env.IsDevelopment()) @@ -65,6 +67,10 @@ options.Filters.Add(typeof(HttpGlobalExceptionFilter)); }).AddControllersAsServices(); //Injecting Controllers themselves thru DI //For further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services + + // Configure GracePeriodManager Hosted Service + services.AddSingleton(); + services.Configure(Configuration); services.AddHealthChecks(checks => { @@ -207,7 +213,7 @@ private void ConfigureEventBus(IApplicationBuilder app) { - var eventBus = app.ApplicationServices.GetRequiredService(); + var eventBus = app.ApplicationServices.GetRequiredService(); eventBus.Subscribe>(); eventBus.Subscribe>(); @@ -232,7 +238,7 @@ { if (Configuration.GetValue("AzureServiceBusEnabled")) { - services.AddSingleton(sp => + services.AddSingleton(sp => { var serviceBusPersisterConnection = sp.GetRequiredService(); var iLifetimeScope = sp.GetRequiredService(); @@ -246,7 +252,7 @@ } else { - services.AddSingleton(); + services.AddSingleton(); } services.AddSingleton(); diff --git a/src/Services/Ordering/Ordering.API/graceperiodsettings.json b/src/Services/Ordering/Ordering.API/graceperiodsettings.json new file mode 100644 index 000000000..1c9d30e5e --- /dev/null +++ b/src/Services/Ordering/Ordering.API/graceperiodsettings.json @@ -0,0 +1,6 @@ +{ + "ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;", + "GracePeriodTime": "1", + "CheckUpdateTime": "30000" +} + From 4161efdd7084449f9047d0fa02184e9266402111 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ram=C3=B3n=20Tom=C3=A1s?= Date: Wed, 23 Aug 2017 16:40:28 +0200 Subject: [PATCH 30/86] Update authentication middleware Update global to sdk 2.0.0 --- global.json | 2 +- src/Web/WebMVC/Startup.cs | 38 ++++++++++++++++++-------------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/global.json b/global.json index 7d2a1589c..bfd985e30 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version":"2.0.0-preview2-006497" + "version":"2.0.0" } } \ No newline at end of file diff --git a/src/Web/WebMVC/Startup.cs b/src/Web/WebMVC/Startup.cs index 315be8973..ebf303f1b 100644 --- a/src/Web/WebMVC/Startup.cs +++ b/src/Web/WebMVC/Startup.cs @@ -86,30 +86,28 @@ namespace Microsoft.eShopOnContainers.WebMVC // Add Authentication services - services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) - .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme) - .AddOpenIdConnect(options => { - options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; - options.Authority = identityUrl.ToString(); - options.SignedOutRedirectUri = callBackUrl.ToString(); - options.ClientId = useLoadTest ? "mvctest" : "mvc"; - options.ClientSecret = "secret"; - options.ResponseType = useLoadTest ? "code id_token token" : "code id_token"; - options.SaveTokens = true; - options.GetClaimsFromUserInfoEndpoint = true; - options.RequireHttpsMetadata = false; - options.Scope.Add("openid"); - options.Scope.Add("profile"); - options.Scope.Add("orders"); - options.Scope.Add("basket"); - options.Scope.Add("marketing"); - options.Scope.Add("locations"); - }); - services.AddAuthentication(options => { options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; + }) + .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme) + .AddOpenIdConnect(options => { + options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + options.Authority = identityUrl.ToString(); + options.SignedOutRedirectUri = callBackUrl.ToString(); + options.ClientId = useLoadTest ? "mvctest" : "mvc"; + options.ClientSecret = "secret"; + options.ResponseType = useLoadTest ? "code id_token token" : "code id_token"; + options.SaveTokens = true; + options.GetClaimsFromUserInfoEndpoint = true; + options.RequireHttpsMetadata = false; + options.Scope.Add("openid"); + options.Scope.Add("profile"); + options.Scope.Add("orders"); + options.Scope.Add("basket"); + options.Scope.Add("marketing"); + options.Scope.Add("locations"); }); } From 2a7dafd97e0f174da8091b6ab4173816c585d2c9 Mon Sep 17 00:00:00 2001 From: Cesar De la Torre Date: Wed, 23 Aug 2017 11:16:26 -0700 Subject: [PATCH 31/86] Fixed Build Container version to microsoft/aspnetcore-build:2.0 (v2.0) --- docker-compose.ci.build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.ci.build.yml b/docker-compose.ci.build.yml index 2a4c88724..7b9838cf4 100644 --- a/docker-compose.ci.build.yml +++ b/docker-compose.ci.build.yml @@ -2,7 +2,7 @@ version: '2.1' services: ci-build: - image: microsoft/aspnetcore-build:1.1.2 + image: microsoft/aspnetcore-build:2.0 volumes: - .:/src - ./cli-linux:/cli-linux From 01469da7d3314367e4ff58ef5cc0affca97bf9ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ram=C3=B3n=20Tom=C3=A1s?= Date: Thu, 24 Aug 2017 15:41:11 +0200 Subject: [PATCH 32/86] Fixed bug Swagger is not working for the services #290 --- src/Services/Basket/Basket.API/Basket.API.csproj | 1 + src/Services/Catalog/Catalog.API/Catalog.API.csproj | 1 + src/Services/Location/Locations.API/Locations.API.csproj | 1 + src/Services/Ordering/Ordering.API/Ordering.API.csproj | 1 + 4 files changed, 4 insertions(+) diff --git a/src/Services/Basket/Basket.API/Basket.API.csproj b/src/Services/Basket/Basket.API/Basket.API.csproj index 584838c8f..c418c56a5 100644 --- a/src/Services/Basket/Basket.API/Basket.API.csproj +++ b/src/Services/Basket/Basket.API/Basket.API.csproj @@ -17,6 +17,7 @@ + diff --git a/src/Services/Catalog/Catalog.API/Catalog.API.csproj b/src/Services/Catalog/Catalog.API/Catalog.API.csproj index 4c1edfa22..3257ea917 100644 --- a/src/Services/Catalog/Catalog.API/Catalog.API.csproj +++ b/src/Services/Catalog/Catalog.API/Catalog.API.csproj @@ -38,6 +38,7 @@ + diff --git a/src/Services/Location/Locations.API/Locations.API.csproj b/src/Services/Location/Locations.API/Locations.API.csproj index 3a53ee826..90588c8f7 100644 --- a/src/Services/Location/Locations.API/Locations.API.csproj +++ b/src/Services/Location/Locations.API/Locations.API.csproj @@ -15,6 +15,7 @@ + diff --git a/src/Services/Ordering/Ordering.API/Ordering.API.csproj b/src/Services/Ordering/Ordering.API/Ordering.API.csproj index 047579f6d..134b65030 100644 --- a/src/Services/Ordering/Ordering.API/Ordering.API.csproj +++ b/src/Services/Ordering/Ordering.API/Ordering.API.csproj @@ -39,6 +39,7 @@ + From 0369d8a9586215e35ea4e449363a27cdc8d8d09d Mon Sep 17 00:00:00 2001 From: Cesar De la Torre Date: Thu, 24 Aug 2017 19:33:08 -0700 Subject: [PATCH 33/86] Workaround (dotnet CLI set with verbosity minimal) so we don't get stdout errors when compiling from the Docker Linux "build containers" when doing the CLI build. Related bug: https://github.com/Microsoft/msbuild/issues/2153#issuecomment-305375162 --- cli-linux/build-bits-linux.sh | 5 ++--- docker-compose.ci.build.yml | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cli-linux/build-bits-linux.sh b/cli-linux/build-bits-linux.sh index 75ace0938..bcb3b9f06 100755 --- a/cli-linux/build-bits-linux.sh +++ b/cli-linux/build-bits-linux.sh @@ -16,7 +16,6 @@ declare -a projectList=( "$path/Services/Location/Locations.API" "$path/Services/Marketing/Marketing.API" "$path/Services/Payment/Payment.API" - "$path/Services/GracePeriod/GracePeriodManager" "$path/Web/WebMVC" "$path/Web/WebStatus" ) @@ -32,9 +31,9 @@ do pushd $path/$project rm -rf obj/Docker/publish echo -e "\e[33m\tRestoring project $project" - dotnet restore + dotnet restore --verbosity minimal echo -e "\e[33m\tBuilding and publishing $project" - dotnet publish -o obj/Docker/publish + dotnet publish -c Release -o obj/Docker/publish --verbosity minimal popd done diff --git a/docker-compose.ci.build.yml b/docker-compose.ci.build.yml index 7b9838cf4..02fe39637 100644 --- a/docker-compose.ci.build.yml +++ b/docker-compose.ci.build.yml @@ -11,7 +11,7 @@ services: # Next line is using the .sln file to compile all the projects. # Sometime there is an issue in msbuild exits the process before finishing building the bits: (https://github.com/Microsoft/msbuild/issues/2153) # Random error: error MSB4017: The build stopped unexpectedly be cause of an unexpected logger failure. - #command: /bin/bash -c "pushd ./src/Web/WebSPA && npm rebuild node-sass && popd && dotnet restore ./eShopOnContainers-ServicesAndWebApps.sln && dotnet publish ./eShopOnContainers-ServicesAndWebApps.sln -c Release -o ./obj/Docker/publish" + #command: /bin/bash -c "pushd ./src/Web/WebSPA && npm rebuild node-sass && popd && dotnet restore ./eShopOnContainers-ServicesAndWebApps.sln --verbosity minimal && dotnet publish ./eShopOnContainers-ServicesAndWebApps.sln -c Release -o ./obj/Docker/publish --verbosity minimal" # NOTE: Using build-bits-linux.sh from Linux build container exits before ending. command: /bin/bash -c "pushd ./src/Web/WebSPA && npm rebuild node-sass && popd && pushd /cli-linux && ./build-bits-linux.sh /src" From fb7217c92982519ad7fdc5c68f0081663ad8b883 Mon Sep 17 00:00:00 2001 From: Cesar De la Torre Date: Fri, 25 Aug 2017 19:39:22 -0700 Subject: [PATCH 34/86] Added aditional script to delete images created by VS --- cli-windows/delete-vs-and-eshop-images.ps1 | 46 ++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 cli-windows/delete-vs-and-eshop-images.ps1 diff --git a/cli-windows/delete-vs-and-eshop-images.ps1 b/cli-windows/delete-vs-and-eshop-images.ps1 new file mode 100644 index 000000000..f37dc6ea4 --- /dev/null +++ b/cli-windows/delete-vs-and-eshop-images.ps1 @@ -0,0 +1,46 @@ + # Delete all containers + Write-Host "Deleting all running containers in the local Docker Host" + docker rm $(docker ps -a -q) -f + +$eShopImagesToDelete = docker images --filter=reference="eshop/*" -q +If (-Not $eShopImagesToDelete) {Write-Host "Not deleting eShop images as there are no eShop images in the current local Docker repo."} +Else +{ + # Delete all eshop images + Write-Host "Deleting eShop images in local Docker repo" + Write-Host $eShopImagesToDelete + docker rmi $(docker images --filter=reference="eshop/*" -q) -f +} + +$VSImagesToDelete = docker images --filter=reference="catalog.api:dev" -q +If (-Not $VSImagesToDelete) {Write-Host "Not deleting VS images as there are no VS images in the current local Docker repo."} +Else +{ + # Delete all eshop images + Write-Host "Deleting images created by VS in local Docker repo" + Write-Host $VSImagesToDelete + docker rmi $(docker images --filter=reference="*:dev" -q) -f + + #docker rmi $(docker images --filter=reference="eshop/payment.api:dev" -q) -f + #docker rmi $(docker images --filter=reference="eshop/webspa:dev" -q) -f + #docker rmi $(docker images --filter=reference="eshop/webmvc:dev" -q) -f + #docker rmi $(docker images --filter=reference="eshop/catalog.api:dev" -q) -f + #docker rmi $(docker images --filter=reference="eshop/marketing.api:dev" -q) -f + #docker rmi $(docker images --filter=reference="eshop/ordering.api:dev" -q) -f + #docker rmi $(docker images --filter=reference="eshop/basket.api:dev" -q) -f + #docker rmi $(docker images --filter=reference="eshop/identity.api:dev" -q) -f + #docker rmi $(docker images --filter=reference="eshop/locations.api:dev" -q) -f + #docker rmi $(docker images --filter=reference="eshop/webstatus:dev" -q) -f +} + +# DELETE ALL IMAGES AND CONTAINERS + +# Delete all containers +# docker rm $(docker ps -a -q) -f + +# Delete all images +# docker rmi $(docker images -q) + +#Filter by image name (Has to be complete, cannot be a wildcard) +#docker ps -q --filter=ancestor=eshop/identity.api:dev + From 8dc176add96bdc15baa78a981cef99bcef3e68c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ram=C3=B3n=20Tom=C3=A1s?= Date: Sat, 26 Aug 2017 22:55:24 +0200 Subject: [PATCH 35/86] Fixed issue #291ordering.api fails after submitting orders --- .../Infrastructure/AutofacModules/ApplicationModule.cs | 7 +++++++ .../Infrastructure/AutofacModules/MediatorModule.cs | 9 ++------- src/Services/Ordering/Ordering.API/Ordering.API.csproj | 2 +- src/Services/Ordering/Ordering.API/Startup.cs | 4 +++- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/AutofacModules/ApplicationModule.cs b/src/Services/Ordering/Ordering.API/Infrastructure/AutofacModules/ApplicationModule.cs index 1e6b4c788..dbda8bc14 100644 --- a/src/Services/Ordering/Ordering.API/Infrastructure/AutofacModules/ApplicationModule.cs +++ b/src/Services/Ordering/Ordering.API/Infrastructure/AutofacModules/ApplicationModule.cs @@ -1,9 +1,12 @@ using Autofac; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; +using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries; using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate; using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency; using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositories; +using System.Reflection; namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.AutofacModules { @@ -38,6 +41,10 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Autof builder.RegisterType() .As() .InstancePerLifetimeScope(); + + builder.RegisterAssemblyTypes(typeof(CreateOrderCommandHandler).GetTypeInfo().Assembly) + .AsClosedTypesOf(typeof(IIntegrationEventHandler<>)); + } } } diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/AutofacModules/MediatorModule.cs b/src/Services/Ordering/Ordering.API/Infrastructure/AutofacModules/MediatorModule.cs index 86e18668b..b23f6812a 100644 --- a/src/Services/Ordering/Ordering.API/Infrastructure/AutofacModules/MediatorModule.cs +++ b/src/Services/Ordering/Ordering.API/Infrastructure/AutofacModules/MediatorModule.cs @@ -21,16 +21,11 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Autof // Register all the Command classes (they implement IAsyncRequestHandler) in assembly holding the Commands builder.RegisterAssemblyTypes(typeof(CreateOrderCommand).GetTypeInfo().Assembly) - .As(o => o.GetInterfaces() - .Where(i => i.IsClosedTypeOf(typeof(IAsyncRequestHandler<,>))) - .Select(i => new KeyedService("IAsyncRequestHandler", i))); + .AsClosedTypesOf(typeof(IAsyncRequestHandler<,>)); // Register all the event classes (they implement IAsyncNotificationHandler) in assembly holding the Commands builder.RegisterAssemblyTypes(typeof(ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler).GetTypeInfo().Assembly) - .As(o => o.GetInterfaces() - .Where(i => i.IsClosedTypeOf(typeof(IAsyncNotificationHandler<>))) - .Select(i => new KeyedService("IAsyncNotificationHandler", i))) - .AsImplementedInterfaces(); + .AsClosedTypesOf(typeof(IAsyncNotificationHandler<>)); builder diff --git a/src/Services/Ordering/Ordering.API/Ordering.API.csproj b/src/Services/Ordering/Ordering.API/Ordering.API.csproj index 134b65030..ce6a77ca6 100644 --- a/src/Services/Ordering/Ordering.API/Ordering.API.csproj +++ b/src/Services/Ordering/Ordering.API/Ordering.API.csproj @@ -34,7 +34,7 @@ - + diff --git a/src/Services/Ordering/Ordering.API/Startup.cs b/src/Services/Ordering/Ordering.API/Startup.cs index 0d3f779c9..3f2bbe43b 100644 --- a/src/Services/Ordering/Ordering.API/Startup.cs +++ b/src/Services/Ordering/Ordering.API/Startup.cs @@ -67,11 +67,13 @@ options.Filters.Add(typeof(HttpGlobalExceptionFilter)); }).AddControllersAsServices(); //Injecting Controllers themselves thru DI //For further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services - + // Configure GracePeriodManager Hosted Service services.AddSingleton(); services.Configure(Configuration); + services.AddTransient(); + services.AddHealthChecks(checks => { var minutes = 1; From 03d5a50a54bbe715359499a50443db8dbe0d1695 Mon Sep 17 00:00:00 2001 From: Igor Sychev Date: Mon, 28 Aug 2017 09:16:21 +0300 Subject: [PATCH 36/86] CLI-Windows using wrong dll names in Dockerfile.nanowin --- src/Services/Location/Locations.API/Dockerfile.nanowin | 2 +- src/Services/Marketing/Marketing.API/Dockerfile.nanowin | 2 +- src/Services/Payment/Payment.API/Dockerfile.nanowin | 2 +- src/Web/WebStatus/Dockerfile.nanowin | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Services/Location/Locations.API/Dockerfile.nanowin b/src/Services/Location/Locations.API/Dockerfile.nanowin index 9c664f4e4..148c6cd98 100644 --- a/src/Services/Location/Locations.API/Dockerfile.nanowin +++ b/src/Services/Location/Locations.API/Dockerfile.nanowin @@ -5,4 +5,4 @@ WORKDIR /app RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord EXPOSE 80 COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "Basket.API.dll"] +ENTRYPOINT ["dotnet", "Locations.API.dll"] diff --git a/src/Services/Marketing/Marketing.API/Dockerfile.nanowin b/src/Services/Marketing/Marketing.API/Dockerfile.nanowin index 9c664f4e4..7c9458ffb 100644 --- a/src/Services/Marketing/Marketing.API/Dockerfile.nanowin +++ b/src/Services/Marketing/Marketing.API/Dockerfile.nanowin @@ -5,4 +5,4 @@ WORKDIR /app RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord EXPOSE 80 COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "Basket.API.dll"] +ENTRYPOINT ["dotnet", "Marketing.API.dll"] diff --git a/src/Services/Payment/Payment.API/Dockerfile.nanowin b/src/Services/Payment/Payment.API/Dockerfile.nanowin index 9c664f4e4..781f354f7 100644 --- a/src/Services/Payment/Payment.API/Dockerfile.nanowin +++ b/src/Services/Payment/Payment.API/Dockerfile.nanowin @@ -5,4 +5,4 @@ WORKDIR /app RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord EXPOSE 80 COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "Basket.API.dll"] +ENTRYPOINT ["dotnet", "Payment.API.dll"] diff --git a/src/Web/WebStatus/Dockerfile.nanowin b/src/Web/WebStatus/Dockerfile.nanowin index 4eaad3b22..96f878c99 100644 --- a/src/Web/WebStatus/Dockerfile.nanowin +++ b/src/Web/WebStatus/Dockerfile.nanowin @@ -5,4 +5,4 @@ WORKDIR /app RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord EXPOSE 80 COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "WebMVC.dll"] +ENTRYPOINT ["dotnet", "WebStatus.dll"] From 4e37f0df271b784227ef77e88ff585e3e00baad2 Mon Sep 17 00:00:00 2001 From: Unai Zorrilla Castro Date: Tue, 29 Aug 2017 10:20:13 +0200 Subject: [PATCH 37/86] Migrate Building Blocks to .NETStandard2.0 and .NETCoreApp2.0. Fix packages references. Update Basket.API to new templates on .NETCoreApp2.0 --- .../DataProtection/DataProtection.csproj | 12 +- .../EventBus.Tests/EventBus.Tests.csproj | 4 +- .../EventBus/EventBus/EventBus.csproj | 2 +- .../EventBusRabbitMQ/EventBusRabbitMQ.cs | 5 +- .../EventBusRabbitMQ/EventBusRabbitMQ.csproj | 12 +- .../DefaultServiceBusPersisterConnection.cs | 1 - .../EventBusServiceBus/EventBusServiceBus.cs | 1 - .../EventBusServiceBus.csproj | 6 +- .../IServiceBusPersisterConnection.cs | 2 +- .../IntegrationEventLogEF.csproj | 15 ++- .../Microsoft.AspNetCore.HealthChecks.csproj | 4 +- ...xtensions.HealthChecks.AzureStorage.csproj | 8 +- ...t.Extensions.HealthChecks.SqlServer.csproj | 4 +- .../Microsoft.Extensions.HealthChecks.csproj | 4 +- .../Resilience.Http/Resilience.Http.csproj | 6 +- .../Basket/Basket.API/Basket.API.csproj | 17 +-- .../Controllers/BasketController.cs | 15 +-- .../Exceptions/BasketDomainException.cs | 3 - .../FailingMiddlewareAppBuilderExtensions.cs | 3 - .../Filters/AuthorizeCheckOperationFilter.cs | 2 - .../Filters/ValidateModelStateFilter.cs | 4 +- .../Middlewares/FailingMiddleware.cs | 1 - .../Middlewares/FailingOptions.cs | 5 +- .../OrderStartedIntegrationEventHandler.cs | 1 - .../UserCheckoutAcceptedIntegrationEvent.cs | 3 - .../Basket/Basket.API/Model/BasketCheckout.cs | 3 - src/Services/Basket/Basket.API/Program.cs | 22 ++-- .../Basket.API/Services/IIdentityService.cs | 7 +- .../Basket.API/Services/IdentityService.cs | 3 - src/Services/Basket/Basket.API/Startup.cs | 105 ++++++++---------- 30 files changed, 109 insertions(+), 171 deletions(-) diff --git a/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj b/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj index 2f519fc95..41281cf54 100644 --- a/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj +++ b/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj @@ -1,19 +1,13 @@  - netstandard1.5 + netstandard2.0 Microsoft.eShopOnContainers.BuildingBlocks - - - + - + \ No newline at end of file diff --git a/src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj b/src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj index 8589f6035..48f96ab59 100644 --- a/src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj +++ b/src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj @@ -1,11 +1,11 @@  - netstandard1.5 + netstandard2.0 - + diff --git a/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj b/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj index 1fc8e48cf..22a2d3091 100644 --- a/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj +++ b/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj @@ -1,7 +1,7 @@  - netstandard1.5 + netstandard2.0 Microsoft.eShopOnContainers.BuildingBlocks.EventBus diff --git a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs index 07a130f22..f438623a6 100644 --- a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs +++ b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs @@ -11,10 +11,7 @@ using RabbitMQ.Client; using RabbitMQ.Client.Events; using RabbitMQ.Client.Exceptions; using System; -using System.Collections.Generic; -using System.Linq; using System.Net.Sockets; -using System.Reflection; using System.Text; using System.Threading.Tasks; @@ -184,7 +181,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ }; channel.BasicConsume(queue: _queueName, - noAck: true, + autoAck: false, consumer: consumer); channel.CallbackException += (sender, ea) => diff --git a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj index f033ad159..6966a57f1 100644 --- a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj +++ b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj @@ -1,17 +1,17 @@  - netstandard1.5 + netstandard2.0 Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ - - + + - - - + + + diff --git a/src/BuildingBlocks/EventBus/EventBusServiceBus/DefaultServiceBusPersisterConnection.cs b/src/BuildingBlocks/EventBus/EventBusServiceBus/DefaultServiceBusPersisterConnection.cs index db1b6b390..a3f563c2f 100644 --- a/src/BuildingBlocks/EventBus/EventBusServiceBus/DefaultServiceBusPersisterConnection.cs +++ b/src/BuildingBlocks/EventBus/EventBusServiceBus/DefaultServiceBusPersisterConnection.cs @@ -1,7 +1,6 @@ using Microsoft.Azure.ServiceBus; using Microsoft.Extensions.Logging; using System; -using System.IO; namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus { diff --git a/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.cs b/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.cs index 1458b7198..03a3d1139 100644 --- a/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.cs +++ b/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.cs @@ -9,7 +9,6 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; - using System.Reflection; using System.Text; using System.Threading.Tasks; diff --git a/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj b/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj index 1db35be68..07c7a7607 100644 --- a/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj +++ b/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj @@ -1,14 +1,14 @@  - netcoreapp1.1 + netstandard2.0 Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus - + - + diff --git a/src/BuildingBlocks/EventBus/EventBusServiceBus/IServiceBusPersisterConnection.cs b/src/BuildingBlocks/EventBus/EventBusServiceBus/IServiceBusPersisterConnection.cs index 283031247..52737cef7 100644 --- a/src/BuildingBlocks/EventBus/EventBusServiceBus/IServiceBusPersisterConnection.cs +++ b/src/BuildingBlocks/EventBus/EventBusServiceBus/IServiceBusPersisterConnection.cs @@ -1,7 +1,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus { - using System; using Microsoft.Azure.ServiceBus; + using System; public interface IServiceBusPersisterConnection : IDisposable { diff --git a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj index e1e24b9fe..8d5c8f0ad 100644 --- a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj +++ b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj @@ -1,22 +1,21 @@  - netcoreapp2.0 + netstandard2.0 Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF - - - - - - + + + + + - + diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/Microsoft.AspNetCore.HealthChecks.csproj b/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/Microsoft.AspNetCore.HealthChecks.csproj index 023554e60..0f6b99f32 100644 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/Microsoft.AspNetCore.HealthChecks.csproj +++ b/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/Microsoft.AspNetCore.HealthChecks.csproj @@ -1,7 +1,7 @@  - netstandard1.3 + netstandard2.0 @@ -9,7 +9,7 @@ - + diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.AzureStorage/Microsoft.Extensions.HealthChecks.AzureStorage.csproj b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.AzureStorage/Microsoft.Extensions.HealthChecks.AzureStorage.csproj index 24d5ce92b..110ef7497 100644 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.AzureStorage/Microsoft.Extensions.HealthChecks.AzureStorage.csproj +++ b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.AzureStorage/Microsoft.Extensions.HealthChecks.AzureStorage.csproj @@ -1,7 +1,7 @@  - netstandard1.3 + netstandard2.0 $(PackageTargetFallback);net46 false false @@ -17,11 +17,11 @@ - + - - + + diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/Microsoft.Extensions.HealthChecks.SqlServer.csproj b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/Microsoft.Extensions.HealthChecks.SqlServer.csproj index 35aacef13..60017a85f 100644 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/Microsoft.Extensions.HealthChecks.SqlServer.csproj +++ b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/Microsoft.Extensions.HealthChecks.SqlServer.csproj @@ -1,7 +1,7 @@  - netstandard1.3 + netstandard2.0 @@ -9,7 +9,7 @@ - + diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Microsoft.Extensions.HealthChecks.csproj b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Microsoft.Extensions.HealthChecks.csproj index 8ef22e156..80e8026b0 100644 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Microsoft.Extensions.HealthChecks.csproj +++ b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Microsoft.Extensions.HealthChecks.csproj @@ -1,7 +1,7 @@  - netstandard1.3 + netstandard2.0 @@ -9,7 +9,7 @@ - + diff --git a/src/BuildingBlocks/Resilience/Resilience.Http/Resilience.Http.csproj b/src/BuildingBlocks/Resilience/Resilience.Http/Resilience.Http.csproj index 1f094380c..e1c32cff2 100644 --- a/src/BuildingBlocks/Resilience/Resilience.Http/Resilience.Http.csproj +++ b/src/BuildingBlocks/Resilience/Resilience.Http/Resilience.Http.csproj @@ -1,14 +1,14 @@  - netstandard1.4 + netstandard2.0 Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http - + - + \ No newline at end of file diff --git a/src/Services/Basket/Basket.API/Basket.API.csproj b/src/Services/Basket/Basket.API/Basket.API.csproj index c418c56a5..8864c9d06 100644 --- a/src/Services/Basket/Basket.API/Basket.API.csproj +++ b/src/Services/Basket/Basket.API/Basket.API.csproj @@ -16,24 +16,9 @@ + - - - - - - - - - - - - - - - - diff --git a/src/Services/Basket/Basket.API/Controllers/BasketController.cs b/src/Services/Basket/Basket.API/Controllers/BasketController.cs index 9219cfad3..dff9ba54a 100644 --- a/src/Services/Basket/Basket.API/Controllers/BasketController.cs +++ b/src/Services/Basket/Basket.API/Controllers/BasketController.cs @@ -1,15 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.eShopOnContainers.Services.Basket.API.Model; +using Basket.API.IntegrationEvents.Events; +using Basket.API.Model; using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; -using Basket.API.IntegrationEvents.Events; +using Microsoft.eShopOnContainers.Services.Basket.API.Model; using Microsoft.eShopOnContainers.Services.Basket.API.Services; -using Basket.API.Model; +using System; +using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers { diff --git a/src/Services/Basket/Basket.API/Infrastructure/Exceptions/BasketDomainException.cs b/src/Services/Basket/Basket.API/Infrastructure/Exceptions/BasketDomainException.cs index 199409ecc..e0f2df6fa 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Exceptions/BasketDomainException.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Exceptions/BasketDomainException.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace Basket.API.Infrastructure.Exceptions { diff --git a/src/Services/Basket/Basket.API/Infrastructure/Exceptions/FailingMiddlewareAppBuilderExtensions.cs b/src/Services/Basket/Basket.API/Infrastructure/Exceptions/FailingMiddlewareAppBuilderExtensions.cs index 935bb79a8..a09f32f76 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Exceptions/FailingMiddlewareAppBuilderExtensions.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Exceptions/FailingMiddlewareAppBuilderExtensions.cs @@ -1,8 +1,5 @@ using Microsoft.AspNetCore.Builder; using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace Basket.API.Infrastructure.Middlewares { diff --git a/src/Services/Basket/Basket.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs b/src/Services/Basket/Basket.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs index f27a3c209..7caa9740d 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs @@ -1,10 +1,8 @@ using Microsoft.AspNetCore.Authorization; using Swashbuckle.AspNetCore.Swagger; using Swashbuckle.AspNetCore.SwaggerGen; -using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; namespace Basket.API.Infrastructure.Filters { diff --git a/src/Services/Basket/Basket.API/Infrastructure/Filters/ValidateModelStateFilter.cs b/src/Services/Basket/Basket.API/Infrastructure/Filters/ValidateModelStateFilter.cs index 8ef72edb6..3e4c3e072 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Filters/ValidateModelStateFilter.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Filters/ValidateModelStateFilter.cs @@ -1,6 +1,6 @@ -using System.Linq; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; +using System.Linq; namespace Basket.API.Infrastructure.Filters { diff --git a/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingMiddleware.cs b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingMiddleware.cs index 05acd0d2c..875749b5f 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingMiddleware.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingMiddleware.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Http; using System; -using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; diff --git a/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingOptions.cs b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingOptions.cs index b31207e00..45989832c 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingOptions.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingOptions.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Generic; namespace Basket.API.Infrastructure.Middlewares { diff --git a/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/OrderStartedIntegrationEventHandler.cs b/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/OrderStartedIntegrationEventHandler.cs index f6e7de1b0..19ae1b594 100644 --- a/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/OrderStartedIntegrationEventHandler.cs +++ b/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/OrderStartedIntegrationEventHandler.cs @@ -1,6 +1,5 @@ using Basket.API.IntegrationEvents.Events; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; -using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; using Microsoft.eShopOnContainers.Services.Basket.API.Model; using System; using System.Threading.Tasks; diff --git a/src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs b/src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs index 4c02612c5..e3665451c 100644 --- a/src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs +++ b/src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs @@ -1,9 +1,6 @@ using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; using Microsoft.eShopOnContainers.Services.Basket.API.Model; using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace Basket.API.IntegrationEvents.Events { diff --git a/src/Services/Basket/Basket.API/Model/BasketCheckout.cs b/src/Services/Basket/Basket.API/Model/BasketCheckout.cs index 5241a3672..410700773 100644 --- a/src/Services/Basket/Basket.API/Model/BasketCheckout.cs +++ b/src/Services/Basket/Basket.API/Model/BasketCheckout.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace Basket.API.Model { diff --git a/src/Services/Basket/Basket.API/Program.cs b/src/Services/Basket/Basket.API/Program.cs index 7753ef537..53b6f311f 100644 --- a/src/Services/Basket/Basket.API/Program.cs +++ b/src/Services/Basket/Basket.API/Program.cs @@ -1,7 +1,8 @@ using Basket.API.Infrastructure.Middlewares; +using Microsoft.AspNetCore; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using System.Collections.Generic; +using Microsoft.Extensions.Logging; using System.IO; namespace Microsoft.eShopOnContainers.Services.Basket.API @@ -10,19 +11,24 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API { public static void Main(string[] args) { - var host = new WebHostBuilder() - .UseKestrel() + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) .UseFailing(options => { - options.ConfigPath = "/Failing"; + options.ConfigPath = "/Failing"; }) .UseHealthChecks("/hc") .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() .UseStartup() + .ConfigureLogging((hostingContext, builder) => + { + builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); + builder.AddConsole(); + builder.AddDebug(); + }) .Build(); - - host.Run(); - } } } diff --git a/src/Services/Basket/Basket.API/Services/IIdentityService.cs b/src/Services/Basket/Basket.API/Services/IIdentityService.cs index 8cc7bd848..fe84e23d5 100644 --- a/src/Services/Basket/Basket.API/Services/IIdentityService.cs +++ b/src/Services/Basket/Basket.API/Services/IIdentityService.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Microsoft.eShopOnContainers.Services.Basket.API.Services +namespace Microsoft.eShopOnContainers.Services.Basket.API.Services { public interface IIdentityService { diff --git a/src/Services/Basket/Basket.API/Services/IdentityService.cs b/src/Services/Basket/Basket.API/Services/IdentityService.cs index 08d1ffffa..d187be8d6 100644 --- a/src/Services/Basket/Basket.API/Services/IdentityService.cs +++ b/src/Services/Basket/Basket.API/Services/IdentityService.cs @@ -1,9 +1,6 @@  using Microsoft.AspNetCore.Http; using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Services.Basket.API.Services { diff --git a/src/Services/Basket/Basket.API/Startup.cs b/src/Services/Basket/Basket.API/Startup.cs index 18e21e209..e2a2b6e3e 100644 --- a/src/Services/Basket/Basket.API/Startup.cs +++ b/src/Services/Basket/Basket.API/Startup.cs @@ -6,10 +6,11 @@ using Basket.API.IntegrationEvents.Events; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.Azure.ServiceBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; -using Microsoft.eShopOnContainers.Services.Basket.API.Auth.Server; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus; using Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.EventHandling; using Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Events; using Microsoft.eShopOnContainers.Services.Basket.API.Model; @@ -21,31 +22,22 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using RabbitMQ.Client; using StackExchange.Redis; -using System; -using System.Linq; -using System.Net; -using System.Threading.Tasks; - -using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus; -using Microsoft.Azure.ServiceBus; using Swashbuckle.AspNetCore.Swagger; +using System; using System.Collections.Generic; +using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Services.Basket.API { public class Startup { - public Startup(IHostingEnvironment env) + public Startup(IConfiguration configuration) { - var builder = new ConfigurationBuilder() - .SetBasePath(env.ContentRootPath) - .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) - .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) - .AddEnvironmentVariables(); - Configuration = builder.Build(); + Configuration = configuration; } - public IConfigurationRoot Configuration { get; } + 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) @@ -55,6 +47,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API { options.Filters.Add(typeof(HttpGlobalExceptionFilter)); options.Filters.Add(typeof(ValidateModelStateFilter)); + }).AddControllersAsServices(); services.AddHealthChecks(checks => @@ -66,6 +59,15 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API services.Configure(Configuration); + services.AddAuthentication() + .AddJwtBearer(options => + { + options.Authority = Configuration.GetValue("IdentityUrl"); + options.Audience = "basket"; + options.RequireHttpsMetadata = false; + + }); + //By connecting here we are making sure that our service //cannot start until redis is ready. This might slow down startup, //but given that there is a delay on resolving the ip address @@ -75,7 +77,8 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API services.AddSingleton(sp => { var settings = sp.GetRequiredService>().Value; - ConfigurationOptions configuration = ConfigurationOptions.Parse(settings.ConnectionString, true); + var configuration = ConfigurationOptions.Parse(settings.ConnectionString, true); + configuration.ResolveDns = true; return ConnectionMultiplexer.Connect(configuration); @@ -111,11 +114,10 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API RegisterEventBus(services); - services.AddSwaggerGen(options => { options.DescribeAllEnumsAsStrings(); - options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info + options.SwaggerDoc("v1", new Info { Title = "Basket HTTP API", Version = "v1", @@ -154,9 +156,32 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API 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, IHostingEnvironment env) + { + app.UseStaticFiles(); + app.UseCors("CorsPolicy"); + app.UseAuthentication(); + app.UseMvcWithDefaultRoute(); + + app.UseSwagger() + .UseSwaggerUI(c => + { + c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); + c.ConfigureOAuth2("basketswaggerui", "", "", "Basket Swagger UI"); + }); + + ConfigureEventBus(app); + + } + + private void RegisterEventBus(IServiceCollection services) { if (Configuration.GetValue("AzureServiceBusEnabled")) @@ -169,7 +194,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API var eventBusSubcriptionsManager = sp.GetRequiredService(); var subscriptionClientName = Configuration["SubscriptionClientName"]; - return new EventBusServiceBus(serviceBusPersisterConnection, logger, + return new EventBusServiceBus(serviceBusPersisterConnection, logger, eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); }); } @@ -184,46 +209,10 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API services.AddTransient(); } - // 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) - { - loggerFactory.AddConsole(Configuration.GetSection("Logging")); - loggerFactory.AddDebug(); - - app.UseStaticFiles(); - - // Use frameworks - app.UseCors("CorsPolicy"); - - ConfigureAuth(app); - - app.UseMvcWithDefaultRoute(); - - app.UseSwagger() - .UseSwaggerUI(c => - { - c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); - c.ConfigureOAuth2("basketswaggerui", "", "", "Basket Swagger UI"); - }); - - ConfigureEventBus(app); - - } - - protected virtual void ConfigureAuth(IApplicationBuilder app) - { - var identityUrl = Configuration.GetValue("IdentityUrl"); - app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions - { - Authority = identityUrl.ToString(), - ApiName = "basket", - RequireHttpsMetadata = false - }); - } - - protected virtual void ConfigureEventBus(IApplicationBuilder app) + private void ConfigureEventBus(IApplicationBuilder app) { var eventBus = app.ApplicationServices.GetRequiredService(); + eventBus.Subscribe(); eventBus.Subscribe(); } From 360456f051669f30f6688429308393cdd7fc24b7 Mon Sep 17 00:00:00 2001 From: Unai Zorrilla Castro Date: Tue, 29 Aug 2017 11:01:27 +0200 Subject: [PATCH 38/86] Migrated Marketing.API and Locations.API to .NETCoreApp2.0. Update Startup and Program to new .NETCoreApp2.0 templates --- .../Controllers/HomeController.cs | 6 +- .../Repositories/ILocationsRepository.cs | 2 +- .../Services/LocationsService.cs | 2 +- .../Locations.API/Locations.API.csproj | 22 +------ .../Location/Locations.API/Model/Locations.cs | 2 +- .../Location/Locations.API/Program.cs | 21 ++++-- .../Location/Locations.API/Startup.cs | 57 +++++----------- .../ViewModel/LocationRequest.cs | 7 +- .../Marketing.API/Marketing.API.csproj | 28 +------- .../Marketing/Marketing.API/Program.cs | 21 ++++-- .../Marketing/Marketing.API/Startup.cs | 66 +++++++------------ 11 files changed, 79 insertions(+), 155 deletions(-) diff --git a/src/Services/Location/Locations.API/Controllers/HomeController.cs b/src/Services/Location/Locations.API/Controllers/HomeController.cs index e7cea3cca..15cb07404 100644 --- a/src/Services/Location/Locations.API/Controllers/HomeController.cs +++ b/src/Services/Location/Locations.API/Controllers/HomeController.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; // For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 diff --git a/src/Services/Location/Locations.API/Infrastructure/Repositories/ILocationsRepository.cs b/src/Services/Location/Locations.API/Infrastructure/Repositories/ILocationsRepository.cs index e2d7f9ea2..cd50fa987 100644 --- a/src/Services/Location/Locations.API/Infrastructure/Repositories/ILocationsRepository.cs +++ b/src/Services/Location/Locations.API/Infrastructure/Repositories/ILocationsRepository.cs @@ -1,9 +1,9 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Repositories { using Microsoft.eShopOnContainers.Services.Locations.API.Model; - using ViewModel; using System.Collections.Generic; using System.Threading.Tasks; + using ViewModel; public interface ILocationsRepository { diff --git a/src/Services/Location/Locations.API/Infrastructure/Services/LocationsService.cs b/src/Services/Location/Locations.API/Infrastructure/Services/LocationsService.cs index 81bc16489..771a075d2 100644 --- a/src/Services/Location/Locations.API/Infrastructure/Services/LocationsService.cs +++ b/src/Services/Location/Locations.API/Infrastructure/Services/LocationsService.cs @@ -1,9 +1,9 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Services { - using Microsoft.eShopOnContainers.Services.Locations.API.IntegrationEvents.Events; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Exceptions; using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Repositories; + using Microsoft.eShopOnContainers.Services.Locations.API.IntegrationEvents.Events; using Microsoft.eShopOnContainers.Services.Locations.API.Model; using Microsoft.eShopOnContainers.Services.Locations.API.ViewModel; using System; diff --git a/src/Services/Location/Locations.API/Locations.API.csproj b/src/Services/Location/Locations.API/Locations.API.csproj index 90588c8f7..b1b322708 100644 --- a/src/Services/Location/Locations.API/Locations.API.csproj +++ b/src/Services/Location/Locations.API/Locations.API.csproj @@ -11,22 +11,7 @@ - - - - - - - - - - - - - - - - + @@ -35,10 +20,7 @@ - - - - + diff --git a/src/Services/Location/Locations.API/Model/Locations.cs b/src/Services/Location/Locations.API/Model/Locations.cs index df521b9b7..7c0580fc6 100644 --- a/src/Services/Location/Locations.API/Model/Locations.cs +++ b/src/Services/Location/Locations.API/Model/Locations.cs @@ -1,9 +1,9 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API.Model { using MongoDB.Bson; + using MongoDB.Bson.Serialization.Attributes; using MongoDB.Driver.GeoJsonObjectModel; using System.Collections.Generic; - using MongoDB.Bson.Serialization.Attributes; public class Locations { diff --git a/src/Services/Location/Locations.API/Program.cs b/src/Services/Location/Locations.API/Program.cs index 8a4a486cb..7ebc0ab8a 100644 --- a/src/Services/Location/Locations.API/Program.cs +++ b/src/Services/Location/Locations.API/Program.cs @@ -1,6 +1,8 @@ -using System.IO; +using Microsoft.AspNetCore; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Logging; +using System.IO; namespace Microsoft.eShopOnContainers.Services.Locations.API { @@ -8,14 +10,19 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API { public static void Main(string[] args) { - var host = new WebHostBuilder() - .UseKestrel() + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) .UseHealthChecks("/hc") .UseContentRoot(Directory.GetCurrentDirectory()) .UseStartup() - .Build(); - - host.Run(); - } + .ConfigureLogging((hostingContext, builder) => + { + builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); + builder.AddConsole(); + builder.AddDebug(); + }).Build(); } } diff --git a/src/Services/Location/Locations.API/Startup.cs b/src/Services/Location/Locations.API/Startup.cs index 34fd8cb75..7d235ed0f 100644 --- a/src/Services/Location/Locations.API/Startup.cs +++ b/src/Services/Location/Locations.API/Startup.cs @@ -3,58 +3,51 @@ using Autofac.Extensions.DependencyInjection; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +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.Locations.API.Infrastructure; using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Filters; using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Repositories; using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Services; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.HealthChecks; using Microsoft.Extensions.Logging; using RabbitMQ.Client; -using System.Reflection; +using Swashbuckle.AspNetCore.Swagger; using System; -using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus; -using Microsoft.Azure.ServiceBus; using System.Collections.Generic; -using Swashbuckle.AspNetCore.Swagger; -using Microsoft.Extensions.HealthChecks; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Services.Locations.API { public class Startup { - public IConfigurationRoot Configuration { get; } - - public Startup(IHostingEnvironment env) + public Startup(IConfiguration configuration) { - var builder = new ConfigurationBuilder() - .SetBasePath(env.ContentRootPath) - .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) - .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); - - if (env.IsDevelopment()) - { - builder.AddUserSecrets(typeof(Startup).GetTypeInfo().Assembly); - } - - builder.AddEnvironmentVariables(); - - Configuration = builder.Build(); + Configuration = configuration; } - // This method gets called by the runtime. Use this method to add services to the container. + public IConfiguration Configuration { get; } + public IServiceProvider ConfigureServices(IServiceCollection services) { - // Add framework services. services.AddMvc(options => { options.Filters.Add(typeof(HttpGlobalExceptionFilter)); }).AddControllersAsServices(); + services.AddAuthentication() + .AddJwtBearer(options => + { + options.Authority = Configuration.GetValue("IdentityUrl"); + options.Audience = "locations"; + options.RequireHttpsMetadata = false; + }); + services.Configure(Configuration); if (Configuration.GetValue("AzureServiceBusEnabled")) @@ -143,14 +136,9 @@ 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) { - //Configure logs - - loggerFactory.AddConsole(Configuration.GetSection("Logging")); - loggerFactory.AddDebug(); - app.UseCors("CorsPolicy"); - ConfigureAuth(app); + app.UseAuthentication(); app.UseMvcWithDefaultRoute(); @@ -165,17 +153,6 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API .Wait(); } - protected virtual void ConfigureAuth(IApplicationBuilder app) - { - var identityUrl = Configuration.GetValue("IdentityUrl"); - app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions - { - Authority = identityUrl.ToString(), - ApiName = "locations", - RequireHttpsMetadata = false - }); - } - private void RegisterEventBus(IServiceCollection services) { if (Configuration.GetValue("AzureServiceBusEnabled")) diff --git a/src/Services/Location/Locations.API/ViewModel/LocationRequest.cs b/src/Services/Location/Locations.API/ViewModel/LocationRequest.cs index 8619bfc0f..5301cee87 100644 --- a/src/Services/Location/Locations.API/ViewModel/LocationRequest.cs +++ b/src/Services/Location/Locations.API/ViewModel/LocationRequest.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Microsoft.eShopOnContainers.Services.Locations.API.ViewModel +namespace Microsoft.eShopOnContainers.Services.Locations.API.ViewModel { public class LocationRequest { diff --git a/src/Services/Marketing/Marketing.API/Marketing.API.csproj b/src/Services/Marketing/Marketing.API/Marketing.API.csproj index 71adef034..b834eab2d 100644 --- a/src/Services/Marketing/Marketing.API/Marketing.API.csproj +++ b/src/Services/Marketing/Marketing.API/Marketing.API.csproj @@ -18,28 +18,7 @@ - - - - - - - - - - - - - - - - - - - - - - + @@ -47,10 +26,7 @@ - - - - + diff --git a/src/Services/Marketing/Marketing.API/Program.cs b/src/Services/Marketing/Marketing.API/Program.cs index dbde65b27..197573518 100644 --- a/src/Services/Marketing/Marketing.API/Program.cs +++ b/src/Services/Marketing/Marketing.API/Program.cs @@ -1,21 +1,28 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API { - using System.IO; using AspNetCore.Hosting; + using Microsoft.AspNetCore; + using Microsoft.Extensions.Logging; + using System.IO; public class Program { public static void Main(string[] args) { - var host = new WebHostBuilder() - .UseKestrel() + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) .UseHealthChecks("/hc") .UseContentRoot(Directory.GetCurrentDirectory()) .UseStartup() .UseWebRoot("Pics") - .Build(); - - host.Run(); - } + .ConfigureLogging((hostingContext, builder) => + { + builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); + builder.AddConsole(); + builder.AddDebug(); + }).Build(); } } diff --git a/src/Services/Marketing/Marketing.API/Startup.cs b/src/Services/Marketing/Marketing.API/Startup.cs index e5fa1a451..3a7eab78a 100644 --- a/src/Services/Marketing/Marketing.API/Startup.cs +++ b/src/Services/Marketing/Marketing.API/Startup.cs @@ -1,58 +1,45 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API { - using Autofac; - using Autofac.Extensions.DependencyInjection; - using IntegrationEvents.Events; using AspNetCore.Builder; using AspNetCore.Hosting; using AspNetCore.Http; + using Autofac; + using Autofac.Extensions.DependencyInjection; using Azure.ServiceBus; - using EntityFrameworkCore; - using EntityFrameworkCore.Infrastructure; using BuildingBlocks.EventBus; using BuildingBlocks.EventBus.Abstractions; using BuildingBlocks.EventBusRabbitMQ; using BuildingBlocks.EventBusServiceBus; + using EntityFrameworkCore; + using Extensions.Configuration; + using Extensions.DependencyInjection; + using Extensions.HealthChecks; + using Extensions.Logging; using Infrastructure; using Infrastructure.Filters; using Infrastructure.Repositories; using Infrastructure.Services; - using Extensions.Configuration; - using Extensions.DependencyInjection; - using Extensions.Logging; + using IntegrationEvents.Events; + using Marketing.API.IntegrationEvents.Handlers; + using Microsoft.EntityFrameworkCore.Diagnostics; using Polly; using RabbitMQ.Client; + using Swashbuckle.AspNetCore.Swagger; using System; + using System.Collections.Generic; using System.Data.SqlClient; using System.Reflection; using System.Threading.Tasks; - using Extensions.HealthChecks; - using Marketing.API.IntegrationEvents.Handlers; - using Microsoft.EntityFrameworkCore.Diagnostics; - using Swashbuckle.AspNetCore.Swagger; - using System.Collections.Generic; public class Startup { - public Startup(IHostingEnvironment env) + public Startup(IConfiguration configuration) { - var builder = new ConfigurationBuilder() - .SetBasePath(env.ContentRootPath) - .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) - .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) - .AddEnvironmentVariables(); - - if (env.IsDevelopment()) - { - builder.AddUserSecrets(typeof(Startup).GetTypeInfo().Assembly); - } - - builder.AddEnvironmentVariables(); - - Configuration = builder.Build(); + Configuration = configuration; } - public IConfigurationRoot Configuration { get; } + 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) @@ -65,6 +52,14 @@ services.Configure(Configuration); + services.AddAuthentication() + .AddJwtBearer(options => + { + options.Authority = Configuration.GetValue("IdentityUrl"); + options.Audience = "marketing"; + options.RequireHttpsMetadata = false; + }); + services.AddHealthChecks(checks => { checks.AddValueTaskCheck("HTTP Endpoint", () => new ValueTask(HealthCheckResult.Healthy("Ok"))); @@ -179,7 +174,7 @@ app.UseCors("CorsPolicy"); - ConfigureAuth(app); + app.UseAuthentication(); app.UseMvcWithDefaultRoute(); @@ -198,17 +193,6 @@ ConfigureEventBus(app); } - protected virtual void ConfigureAuth(IApplicationBuilder app) - { - var identityUrl = Configuration.GetValue("IdentityUrl"); - app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions - { - Authority = identityUrl.ToString(), - ApiName = "marketing", - RequireHttpsMetadata = false - }); - } - private void RegisterEventBus(IServiceCollection services) { if (Configuration.GetValue("AzureServiceBusEnabled")) From 0c41218c2c23439c824d9c6549ce42f2f55d8614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ram=C3=B3n=20Tom=C3=A1s?= Date: Tue, 29 Aug 2017 11:02:18 +0200 Subject: [PATCH 39/86] Include aspnetcore.all metapackage --- .../Ordering/Ordering.API/Ordering.API.csproj | 25 ++--------------- src/Services/Ordering/Ordering.API/Program.cs | 16 ++++------- src/Services/Ordering/Ordering.API/Startup.cs | 28 +++++++++++++------ 3 files changed, 29 insertions(+), 40 deletions(-) diff --git a/src/Services/Ordering/Ordering.API/Ordering.API.csproj b/src/Services/Ordering/Ordering.API/Ordering.API.csproj index ce6a77ca6..4b02a4abd 100644 --- a/src/Services/Ordering/Ordering.API/Ordering.API.csproj +++ b/src/Services/Ordering/Ordering.API/Ordering.API.csproj @@ -36,32 +36,13 @@ - - - - - - - - - - - - - - - - - - - + - - - + + diff --git a/src/Services/Ordering/Ordering.API/Program.cs b/src/Services/Ordering/Ordering.API/Program.cs index ba92a2da9..3ee6f6500 100644 --- a/src/Services/Ordering/Ordering.API/Program.cs +++ b/src/Services/Ordering/Ordering.API/Program.cs @@ -1,6 +1,5 @@ -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; -using System.IO; namespace Microsoft.eShopOnContainers.Services.Ordering.API { @@ -8,15 +7,12 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API { public static void Main(string[] args) { - var host = new WebHostBuilder() - .UseKestrel() - .UseHealthChecks("/hc") - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) .UseStartup() .Build(); - - host.Run(); - } } } diff --git a/src/Services/Ordering/Ordering.API/Startup.cs b/src/Services/Ordering/Ordering.API/Startup.cs index 3f2bbe43b..c793a3950 100644 --- a/src/Services/Ordering/Ordering.API/Startup.cs +++ b/src/Services/Ordering/Ordering.API/Startup.cs @@ -11,6 +11,7 @@ using Infrastructure.AutofacModules; using Infrastructure.Filters; using Infrastructure.Services; + using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Azure.ServiceBus; @@ -170,7 +171,7 @@ } RegisterEventBus(services); - + ConfigureAuthService(services); services.AddOptions(); //configure autofac @@ -225,22 +226,33 @@ eventBus.Subscribe>(); } - protected virtual void ConfigureAuth(IApplicationBuilder app) + private void ConfigureAuthService(IServiceCollection services) { var identityUrl = Configuration.GetValue("IdentityUrl"); - app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions + + services.AddAuthentication(options => + { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + + }).AddJwtBearer(options => { - Authority = identityUrl.ToString(), - ApiName = "orders", - RequireHttpsMetadata = false + options.Authority = identityUrl; + options.RequireHttpsMetadata = false; + options.Audience = "orders"; }); } + protected virtual void ConfigureAuth(IApplicationBuilder app) + { + app.UseAuthentication(); + } + private void RegisterEventBus(IServiceCollection services) { if (Configuration.GetValue("AzureServiceBusEnabled")) { - services.AddSingleton(sp => + services.AddSingleton(sp => { var serviceBusPersisterConnection = sp.GetRequiredService(); var iLifetimeScope = sp.GetRequiredService(); @@ -254,7 +266,7 @@ } else { - services.AddSingleton(); + services.AddSingleton(); } services.AddSingleton(); From c4454b005b05e0c5fad673d771c249b8ea5ee73a Mon Sep 17 00:00:00 2001 From: Unai Zorrilla Castro Date: Tue, 29 Aug 2017 11:17:09 +0200 Subject: [PATCH 40/86] Migrated Payment.API to .NETCoreApp2.0. Update Startup and Program to new template. Minor refactorings. Remove unused PaymentController.cs --- .../Marketing/Marketing.API/Startup.cs | 5 +- .../Controllers/PaymentController.cs | 46 ------------------- ...ToStockConfirmedIntegrationEventHandler.cs | 8 ++-- .../Payment/Payment.API/Payment.API.csproj | 12 +---- src/Services/Payment/Payment.API/Program.cs | 22 ++++++--- src/Services/Payment/Payment.API/Startup.cs | 37 ++++++--------- 6 files changed, 38 insertions(+), 92 deletions(-) delete mode 100644 src/Services/Payment/Payment.API/Controllers/PaymentController.cs diff --git a/src/Services/Marketing/Marketing.API/Startup.cs b/src/Services/Marketing/Marketing.API/Startup.cs index 3a7eab78a..952594556 100644 --- a/src/Services/Marketing/Marketing.API/Startup.cs +++ b/src/Services/Marketing/Marketing.API/Startup.cs @@ -167,11 +167,8 @@ } // 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.AddConsole(Configuration.GetSection("Logging")); - loggerFactory.AddDebug(); - app.UseCors("CorsPolicy"); app.UseAuthentication(); diff --git a/src/Services/Payment/Payment.API/Controllers/PaymentController.cs b/src/Services/Payment/Payment.API/Controllers/PaymentController.cs deleted file mode 100644 index 60ccca2a6..000000000 --- a/src/Services/Payment/Payment.API/Controllers/PaymentController.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; - -// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 - -namespace Payment.API.Controllers -{ - [Route("api/v1/[controller]")] - public class PaymentController : Controller - { - // GET: api/values - [HttpGet] - public IEnumerable Get() - { - return new string[] { "value1", "value2" }; - } - - // GET api/values/5 - [HttpGet("{id}")] - public string Get(int id) - { - return "value"; - } - - // POST api/values - [HttpPost] - public void Post([FromBody]string value) - { - } - - // PUT api/values/5 - [HttpPut("{id}")] - public void Put(int id, [FromBody]string value) - { - } - - // DELETE api/values/5 - [HttpDelete("{id}")] - public void Delete(int id) - { - } - } -} diff --git a/src/Services/Payment/Payment.API/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs b/src/Services/Payment/Payment.API/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs index bf2e4c1ca..c70a32093 100644 --- a/src/Services/Payment/Payment.API/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs +++ b/src/Services/Payment/Payment.API/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs @@ -1,10 +1,10 @@ namespace Payment.API.IntegrationEvents.EventHandling { using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; - using System.Threading.Tasks; - using Payment.API.IntegrationEvents.Events; - using Microsoft.Extensions.Options; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + using Microsoft.Extensions.Options; + using Payment.API.IntegrationEvents.Events; + using System.Threading.Tasks; public class OrderStatusChangedToStockConfirmedIntegrationEventHandler : IIntegrationEventHandler @@ -39,6 +39,8 @@ } _eventBus.Publish(orderPaymentIntegrationEvent); + + await Task.CompletedTask; } } } \ No newline at end of file diff --git a/src/Services/Payment/Payment.API/Payment.API.csproj b/src/Services/Payment/Payment.API/Payment.API.csproj index 46f2d81b9..49dd3d149 100644 --- a/src/Services/Payment/Payment.API/Payment.API.csproj +++ b/src/Services/Payment/Payment.API/Payment.API.csproj @@ -11,19 +11,11 @@ - - - - - - - - - + - + diff --git a/src/Services/Payment/Payment.API/Program.cs b/src/Services/Payment/Payment.API/Program.cs index 8ad35dce2..c45d786b9 100644 --- a/src/Services/Payment/Payment.API/Program.cs +++ b/src/Services/Payment/Payment.API/Program.cs @@ -1,6 +1,8 @@ -using System.IO; +using Microsoft.AspNetCore; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Logging; +using System.IO; namespace Payment.API { @@ -8,13 +10,19 @@ namespace Payment.API { public static void Main(string[] args) { - var host = new WebHostBuilder() - .UseKestrel() + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseContentRoot(Directory.GetCurrentDirectory()) .UseStartup() - .Build(); - - host.Run(); - } + .ConfigureLogging((hostingContext, builder) => + { + builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); + builder.AddConsole(); + builder.AddDebug(); + }).Build(); } } diff --git a/src/Services/Payment/Payment.API/Startup.cs b/src/Services/Payment/Payment.API/Startup.cs index 9cba1415d..5e87c4e19 100644 --- a/src/Services/Payment/Payment.API/Startup.cs +++ b/src/Services/Payment/Payment.API/Startup.cs @@ -2,41 +2,38 @@ 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.Logging; -using System; -using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; -using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; -using RabbitMQ.Client; -using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; -using Payment.API.IntegrationEvents.Events; using Payment.API.IntegrationEvents.EventHandling; -using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus; -using Microsoft.Azure.ServiceBus; +using Payment.API.IntegrationEvents.Events; +using RabbitMQ.Client; +using System; namespace Payment.API { public class Startup { - public Startup(IHostingEnvironment env) + public Startup(IConfiguration configuration) { - var builder = new ConfigurationBuilder() - .SetBasePath(env.ContentRootPath) - .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) - .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) - .AddEnvironmentVariables(); - Configuration = builder.Build(); + Configuration = configuration; } - public IConfigurationRoot Configuration { get; } + 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) { // Add framework services. services.AddMvc(); + services.Configure(Configuration); + if (Configuration.GetValue("AzureServiceBusEnabled")) { services.AddSingleton(sp => @@ -84,14 +81,10 @@ 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) - { - loggerFactory.AddConsole(Configuration.GetSection("Logging")); - loggerFactory.AddDebug(); - + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { app.UseMvcWithDefaultRoute(); - app.UseSwagger() .UseSwaggerUI(c => { From 116d5b55bb142b959e9d7607893b2a21f30fdc0b Mon Sep 17 00:00:00 2001 From: Unai Zorrilla Castro Date: Tue, 29 Aug 2017 11:28:21 +0200 Subject: [PATCH 41/86] Updated Startup and Program to use new .NETCoreApp2.0 templates.Minor Refactorings --- .../WebStatus/Controllers/HomeController.cs | 9 +++----- .../HealthCheckBuilderExtensions.cs | 4 ---- src/Web/WebStatus/Program.cs | 22 ++++++++++++------- src/Web/WebStatus/Startup.cs | 18 +++++---------- .../Viewmodels/HealthStatusViewModel.cs | 9 ++++---- .../WebStatus/Viewmodels/NamedCheckResult.cs | 5 +---- 6 files changed, 29 insertions(+), 38 deletions(-) diff --git a/src/Web/WebStatus/Controllers/HomeController.cs b/src/Web/WebStatus/Controllers/HomeController.cs index cd59c44d2..7f139843a 100644 --- a/src/Web/WebStatus/Controllers/HomeController.cs +++ b/src/Web/WebStatus/Controllers/HomeController.cs @@ -1,10 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Options; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.HealthChecks; +using System.Threading.Tasks; using WebStatus.Viewmodels; namespace WebStatus.Controllers @@ -29,6 +25,7 @@ namespace WebStatus.Controllers } ViewBag.RefreshSeconds = 60; + return View(data); } diff --git a/src/Web/WebStatus/Extensions/HealthCheckBuilderExtensions.cs b/src/Web/WebStatus/Extensions/HealthCheckBuilderExtensions.cs index c0655b753..a6076df52 100644 --- a/src/Web/WebStatus/Extensions/HealthCheckBuilderExtensions.cs +++ b/src/Web/WebStatus/Extensions/HealthCheckBuilderExtensions.cs @@ -1,8 +1,5 @@ using Microsoft.Extensions.HealthChecks; using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace WebStatus.Extensions { @@ -17,6 +14,5 @@ namespace WebStatus.Extensions return builder; } - } } diff --git a/src/Web/WebStatus/Program.cs b/src/Web/WebStatus/Program.cs index f0df7ee22..6a895f9e7 100644 --- a/src/Web/WebStatus/Program.cs +++ b/src/Web/WebStatus/Program.cs @@ -1,5 +1,7 @@ -using System.IO; +using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Logging; +using System.IO; namespace WebStatus { @@ -7,14 +9,18 @@ namespace WebStatus { public static void Main(string[] args) { - var host = new WebHostBuilder() - .UseKestrel() + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() .UseStartup() - .Build(); - - host.Run(); - } + .ConfigureLogging((hostingContext, builder) => + { + builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); + builder.AddConsole(); + builder.AddDebug(); + }).Build(); } } diff --git a/src/Web/WebStatus/Startup.cs b/src/Web/WebStatus/Startup.cs index 244f81787..eb559acd9 100644 --- a/src/Web/WebStatus/Startup.cs +++ b/src/Web/WebStatus/Startup.cs @@ -13,22 +13,18 @@ namespace WebStatus { public class Startup { - public Startup(IHostingEnvironment env) + public Startup(IConfiguration configuration) { - var builder = new ConfigurationBuilder() - .SetBasePath(env.ContentRootPath) - .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) - .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) - .AddEnvironmentVariables(); - Configuration = builder.Build(); + Configuration = configuration; } - public IConfigurationRoot Configuration { get; } + public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddOptions(); + // Add framework services. services.AddHealthChecks(checks => { @@ -47,15 +43,13 @@ namespace WebStatus checks.AddUrlCheckIfNotNull(Configuration["mvc"], TimeSpan.FromMinutes(minutes)); checks.AddUrlCheckIfNotNull(Configuration["spa"], TimeSpan.FromMinutes(minutes)); }); + services.AddMvc(); } // 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) { - loggerFactory.AddConsole(Configuration.GetSection("Logging")); - loggerFactory.AddDebug(); - if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); diff --git a/src/Web/WebStatus/Viewmodels/HealthStatusViewModel.cs b/src/Web/WebStatus/Viewmodels/HealthStatusViewModel.cs index d30acc460..08126ce4f 100644 --- a/src/Web/WebStatus/Viewmodels/HealthStatusViewModel.cs +++ b/src/Web/WebStatus/Viewmodels/HealthStatusViewModel.cs @@ -1,22 +1,23 @@ using Microsoft.Extensions.HealthChecks; -using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; namespace WebStatus.Viewmodels { public class HealthStatusViewModel { private readonly CheckStatus _overall; + private readonly Dictionary _results; public CheckStatus OverallStatus => _overall; + public IEnumerable Results => _results.Select(kvp => new NamedCheckResult(kvp.Key, kvp.Value)); + private HealthStatusViewModel() => _results = new Dictionary(); + public HealthStatusViewModel(CheckStatus overall) : this() => _overall = overall; + public void AddResult(string name, IHealthCheckResult result) => _results.Add(name, result); - - } } diff --git a/src/Web/WebStatus/Viewmodels/NamedCheckResult.cs b/src/Web/WebStatus/Viewmodels/NamedCheckResult.cs index e856504c7..f6a9cd316 100644 --- a/src/Web/WebStatus/Viewmodels/NamedCheckResult.cs +++ b/src/Web/WebStatus/Viewmodels/NamedCheckResult.cs @@ -1,14 +1,11 @@ using Microsoft.Extensions.HealthChecks; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace WebStatus.Viewmodels { public class NamedCheckResult { public string Name { get; } + public IHealthCheckResult Result { get; } public NamedCheckResult(string name, IHealthCheckResult result) From acefa6446597d732ba547088ac2d4953cd2ca89f Mon Sep 17 00:00:00 2001 From: Unai Zorrilla Castro Date: Tue, 29 Aug 2017 11:40:23 +0200 Subject: [PATCH 42/86] Updated Program and Startup to new .NETCoreApp2.0 templates. Minor refactorings --- src/Web/WebMVC/Program.cs | 24 +++++++++++++++--------- src/Web/WebMVC/Startup.cs | 14 +++++--------- src/Web/WebMVC/WebMVC.csproj | 27 ++++----------------------- 3 files changed, 24 insertions(+), 41 deletions(-) diff --git a/src/Web/WebMVC/Program.cs b/src/Web/WebMVC/Program.cs index 654ae7677..ec711b2ae 100644 --- a/src/Web/WebMVC/Program.cs +++ b/src/Web/WebMVC/Program.cs @@ -1,4 +1,6 @@ -using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Logging; using System.IO; namespace Microsoft.eShopOnContainers.WebMVC @@ -7,15 +9,19 @@ namespace Microsoft.eShopOnContainers.WebMVC { public static void Main(string[] args) { - var host = new WebHostBuilder() - .UseKestrel() - .UseHealthChecks("/hc") + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() + .UseHealthChecks("/hc") .UseStartup() - .Build(); - - host.Run(); - } + .ConfigureLogging((hostingContext, builder) => + { + builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); + builder.AddConsole(); + builder.AddDebug(); + }).Build(); } } diff --git a/src/Web/WebMVC/Startup.cs b/src/Web/WebMVC/Startup.cs index ebf303f1b..1791e8da1 100644 --- a/src/Web/WebMVC/Startup.cs +++ b/src/Web/WebMVC/Startup.cs @@ -20,17 +20,12 @@ namespace Microsoft.eShopOnContainers.WebMVC { public class Startup { - public Startup(IHostingEnvironment env) + public Startup(IConfiguration configuration) { - var builder = new ConfigurationBuilder() - .SetBasePath(env.ContentRootPath) - .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) // Settings for the application - .AddEnvironmentVariables(); // override settings with environment variables set in compose. - - Configuration = builder.Build(); + Configuration = configuration; } - public IConfigurationRoot Configuration { get; } + public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) @@ -135,7 +130,8 @@ namespace Microsoft.eShopOnContainers.WebMVC app.UseAuthentication(); var log = loggerFactory.CreateLogger("identity"); - WebContextSeed.Seed(app, env, loggerFactory); + + WebContextSeed.Seed(app, env, loggerFactory); app.UseMvc(routes => { diff --git a/src/Web/WebMVC/WebMVC.csproj b/src/Web/WebMVC/WebMVC.csproj index e6e11cb99..7f45a64f9 100644 --- a/src/Web/WebMVC/WebMVC.csproj +++ b/src/Web/WebMVC/WebMVC.csproj @@ -36,27 +36,8 @@ --> - - - - - - - - - - - - - - - - - - - - - + + @@ -66,8 +47,8 @@ - - + + From 364c07a528f2c9d0b3be93127e335cdc953effcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ram=C3=B3n=20Tom=C3=A1s?= Date: Tue, 29 Aug 2017 12:03:20 +0200 Subject: [PATCH 43/86] Included AspnetCore.all metapackage --- ...xtensions.HealthChecks.AzureStorage.csproj | 1 - .../Catalog/Catalog.API/Catalog.API.csproj | 24 ++-------------- src/Services/Catalog/Catalog.API/Program.cs | 28 +++++++++++-------- .../Ordering/Ordering.API/Ordering.API.csproj | 2 +- src/Services/Ordering/Ordering.API/Program.cs | 10 +++++++ src/Web/WebSPA/WebSPA.csproj | 1 + 6 files changed, 31 insertions(+), 35 deletions(-) diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.AzureStorage/Microsoft.Extensions.HealthChecks.AzureStorage.csproj b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.AzureStorage/Microsoft.Extensions.HealthChecks.AzureStorage.csproj index 110ef7497..0007d0be6 100644 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.AzureStorage/Microsoft.Extensions.HealthChecks.AzureStorage.csproj +++ b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.AzureStorage/Microsoft.Extensions.HealthChecks.AzureStorage.csproj @@ -2,7 +2,6 @@ netstandard2.0 - $(PackageTargetFallback);net46 false false false diff --git a/src/Services/Catalog/Catalog.API/Catalog.API.csproj b/src/Services/Catalog/Catalog.API/Catalog.API.csproj index 3257ea917..7f55b6432 100644 --- a/src/Services/Catalog/Catalog.API/Catalog.API.csproj +++ b/src/Services/Catalog/Catalog.API/Catalog.API.csproj @@ -7,7 +7,6 @@ Catalog.API Catalog.API aspnet-Catalog.API-20161122013618 - $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; ..\..\..\..\docker-compose.dcproj @@ -33,32 +32,13 @@ - - - - - - - - - - - - - - - - - - - - + - + diff --git a/src/Services/Catalog/Catalog.API/Program.cs b/src/Services/Catalog/Catalog.API/Program.cs index 93c151cf2..2de3600b9 100644 --- a/src/Services/Catalog/Catalog.API/Program.cs +++ b/src/Services/Catalog/Catalog.API/Program.cs @@ -1,5 +1,6 @@ -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Logging; using System.IO; namespace Microsoft.eShopOnContainers.Services.Catalog.API @@ -8,16 +9,21 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API { public static void Main(string[] args) { - var host = new WebHostBuilder() - .UseKestrel() + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseStartup() .UseHealthChecks("/hc") - .UseIISIntegration() - .UseContentRoot(Directory.GetCurrentDirectory()) + .UseContentRoot(Directory.GetCurrentDirectory()) .UseWebRoot("Pics") - .UseStartup() - .Build(); - - host.Run(); - } + .ConfigureLogging((hostingContext, builder) => + { + builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); + builder.AddConsole(); + builder.AddDebug(); + }) + .Build(); } -} +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Ordering.API.csproj b/src/Services/Ordering/Ordering.API/Ordering.API.csproj index 4b02a4abd..80ea309d8 100644 --- a/src/Services/Ordering/Ordering.API/Ordering.API.csproj +++ b/src/Services/Ordering/Ordering.API/Ordering.API.csproj @@ -46,7 +46,7 @@ - + diff --git a/src/Services/Ordering/Ordering.API/Program.cs b/src/Services/Ordering/Ordering.API/Program.cs index 3ee6f6500..382ba2594 100644 --- a/src/Services/Ordering/Ordering.API/Program.cs +++ b/src/Services/Ordering/Ordering.API/Program.cs @@ -1,5 +1,7 @@ using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Logging; +using System.IO; namespace Microsoft.eShopOnContainers.Services.Ordering.API { @@ -13,6 +15,14 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup() + .UseHealthChecks("/hc") + .UseContentRoot(Directory.GetCurrentDirectory()) + .ConfigureLogging((hostingContext, builder) => + { + builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); + builder.AddConsole(); + builder.AddDebug(); + }) .Build(); } } diff --git a/src/Web/WebSPA/WebSPA.csproj b/src/Web/WebSPA/WebSPA.csproj index 1e3b2630a..e4447a126 100644 --- a/src/Web/WebSPA/WebSPA.csproj +++ b/src/Web/WebSPA/WebSPA.csproj @@ -28,6 +28,7 @@ + From cd78d98436c1b3209838f929dbea3f58cde522e3 Mon Sep 17 00:00:00 2001 From: Unai Zorrilla Castro Date: Tue, 29 Aug 2017 12:12:45 +0200 Subject: [PATCH 44/86] Updated Identity.API to preview version of IdentityServer4, Fix breaking changes. Not well tested --- .../Controllers/AccountController.cs | 28 +++++++------- .../Identity/Identity.API/Identity.API.csproj | 38 ++++--------------- .../Identity.API/Models/ApplicationUser.cs | 6 +-- src/Services/Identity/Identity.API/Program.cs | 24 +++++++----- src/Services/Identity/Identity.API/Startup.cs | 31 +++++---------- src/Web/WebMVC/WebMVC.csproj | 1 - 6 files changed, 47 insertions(+), 81 deletions(-) diff --git a/src/Services/Identity/Identity.API/Controllers/AccountController.cs b/src/Services/Identity/Identity.API/Controllers/AccountController.cs index 641f39522..6b56b3467 100644 --- a/src/Services/Identity/Identity.API/Controllers/AccountController.cs +++ b/src/Services/Identity/Identity.API/Controllers/AccountController.cs @@ -2,26 +2,24 @@ // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. +using Identity.API.Models; +using Identity.API.Models.AccountViewModels; +using Identity.API.Services; using IdentityModel; -using IdentityServer4.Quickstart.UI.Models; +using IdentityServer4.Models; using IdentityServer4.Services; -using Microsoft.AspNetCore.Http.Authentication; +using IdentityServer4.Stores; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; using System; -using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Text.Encodings.Web; using System.Threading.Tasks; -using IdentityServer4.Models; -using IdentityServer4.Stores; -using Identity.API.Services; -using Identity.API.Models; -using Microsoft.Extensions.Logging; -using Microsoft.AspNetCore.Authorization; -using Identity.API.Models.AccountViewModels; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Authentication; + namespace IdentityServer4.Quickstart.UI.Controllers { @@ -194,7 +192,7 @@ namespace IdentityServer4.Quickstart.UI.Controllers try { // hack: try/catch to handle social providers that throw - await HttpContext.Authentication.SignOutAsync(idp, new AuthenticationProperties { RedirectUri = url }); + await HttpContext.SignOutAsync(idp, new AuthenticationProperties { RedirectUri = url }); } catch(Exception ex) { @@ -203,7 +201,7 @@ namespace IdentityServer4.Quickstart.UI.Controllers } // delete authentication cookie - await HttpContext.Authentication.SignOutAsync(); + await HttpContext.SignOutAsync(); // set this so UI rendering sees an anonymous user HttpContext.User = new ClaimsPrincipal(new ClaimsIdentity()); @@ -217,7 +215,7 @@ namespace IdentityServer4.Quickstart.UI.Controllers public async Task DeviceLogOut(string redirectUrl) { // delete authentication cookie - await HttpContext.Authentication.SignOutAsync(); + await HttpContext.SignOutAsync(); // set this so UI rendering sees an anonymous user HttpContext.User = new ClaimsPrincipal(new ClaimsIdentity()); diff --git a/src/Services/Identity/Identity.API/Identity.API.csproj b/src/Services/Identity/Identity.API/Identity.API.csproj index 7c221e858..49f9b4c2e 100644 --- a/src/Services/Identity/Identity.API/Identity.API.csproj +++ b/src/Services/Identity/Identity.API/Identity.API.csproj @@ -1,10 +1,10 @@  - netcoreapp1.1 - 1.1.2 + netcoreapp2.0 + 2.0.0 aspnet-eShopOnContainers.Identity-90487118-103c-4ff0-b9da-e5e26f7ab0c5 - $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + ..\..\..\..\docker-compose.dcproj @@ -16,30 +16,8 @@ - - - - - - - - - - - - All - - - All - - - - - - - - - + + @@ -52,9 +30,9 @@ - - - + + + diff --git a/src/Services/Identity/Identity.API/Models/ApplicationUser.cs b/src/Services/Identity/Identity.API/Models/ApplicationUser.cs index b520c333b..1c1f7bda1 100644 --- a/src/Services/Identity/Identity.API/Models/ApplicationUser.cs +++ b/src/Services/Identity/Identity.API/Models/ApplicationUser.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.AspNetCore.Identity; using System.ComponentModel.DataAnnotations; namespace Identity.API.Models diff --git a/src/Services/Identity/Identity.API/Program.cs b/src/Services/Identity/Identity.API/Program.cs index 2f731c045..9a035bd93 100644 --- a/src/Services/Identity/Identity.API/Program.cs +++ b/src/Services/Identity/Identity.API/Program.cs @@ -1,4 +1,6 @@ -using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Logging; using System.IO; namespace eShopOnContainers.Identity @@ -7,15 +9,19 @@ namespace eShopOnContainers.Identity { public static void Main(string[] args) { - var host = new WebHostBuilder() - .UseKestrel() - .UseHealthChecks("/hc") + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() + .UseHealthChecks("/hc") .UseStartup() - .Build(); - - host.Run(); - } + .ConfigureLogging((hostingContext, builder) => + { + builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); + builder.AddConsole(); + builder.AddDebug(); + }).Build(); } } diff --git a/src/Services/Identity/Identity.API/Startup.cs b/src/Services/Identity/Identity.API/Startup.cs index 5b0a216de..711c4b9c1 100644 --- a/src/Services/Identity/Identity.API/Startup.cs +++ b/src/Services/Identity/Identity.API/Startup.cs @@ -1,4 +1,6 @@ -using Identity.API.Certificate; +using Autofac; +using Autofac.Extensions.DependencyInjection; +using Identity.API.Certificate; using Identity.API.Configuration; using Identity.API.Data; using Identity.API.Models; @@ -9,16 +11,12 @@ using IdentityServer4.Services; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.eShopOnContainers.BuildingBlocks; using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.HealthChecks; -using Identity.API.Certificate; -using Autofac.Extensions.DependencyInjection; -using Autofac; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -30,24 +28,13 @@ namespace eShopOnContainers.Identity { public class Startup { - public Startup(IHostingEnvironment env) + public Startup(IConfiguration configuration) { - var builder = new ConfigurationBuilder() - .SetBasePath(env.ContentRootPath) - .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) - .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); - - if (env.IsDevelopment()) - { - // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709 - builder.AddUserSecrets(); - } - - builder.AddEnvironmentVariables(); - Configuration = builder.Build(); + Configuration = configuration; } - public IConfigurationRoot Configuration { get; } + 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) @@ -136,9 +123,11 @@ namespace eShopOnContainers.Identity await next(); }); - app.UseIdentity(); + // Adds IdentityServer + app.UseAuthentication(); + app.UseIdentityServer(); app.UseMvc(routes => diff --git a/src/Web/WebMVC/WebMVC.csproj b/src/Web/WebMVC/WebMVC.csproj index 7f45a64f9..5e73cdfda 100644 --- a/src/Web/WebMVC/WebMVC.csproj +++ b/src/Web/WebMVC/WebMVC.csproj @@ -37,7 +37,6 @@ - From e20223b6e2376822349a740022d9f8d7ccb3a53b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ram=C3=B3n=20Tom=C3=A1s?= Date: Tue, 29 Aug 2017 12:14:10 +0200 Subject: [PATCH 45/86] Included Aspnetcore.all metapackage --- src/Web/WebSPA/Program.cs | 25 ++++++++++++++++--------- src/Web/WebSPA/Startup.cs | 11 +++++------ src/Web/WebSPA/WebSPA.csproj | 26 +++----------------------- 3 files changed, 24 insertions(+), 38 deletions(-) diff --git a/src/Web/WebSPA/Program.cs b/src/Web/WebSPA/Program.cs index 12c29d8c2..92a6af2da 100644 --- a/src/Web/WebSPA/Program.cs +++ b/src/Web/WebSPA/Program.cs @@ -1,5 +1,7 @@ -using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; using System.IO; +using Microsoft.Extensions.Logging; namespace eShopConContainers.WebSPA { @@ -7,15 +9,20 @@ namespace eShopConContainers.WebSPA { public static void Main(string[] args) { - var host = new WebHostBuilder() - .UseKestrel() + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseStartup() .UseHealthChecks("/hc") .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseStartup() - .Build(); - - host.Run(); - } + .ConfigureLogging((hostingContext, builder) => + { + builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); + builder.AddConsole(); + builder.AddDebug(); + }) + .Build(); } } diff --git a/src/Web/WebSPA/Startup.cs b/src/Web/WebSPA/Startup.cs index 9eed6dc10..22511c135 100644 --- a/src/Web/WebSPA/Startup.cs +++ b/src/Web/WebSPA/Startup.cs @@ -1,16 +1,15 @@ -using System; -using System.IO; +using eShopOnContainers.WebSPA; using Microsoft.AspNetCore.Antiforgery; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; +using Microsoft.eShopOnContainers.BuildingBlocks; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.HealthChecks; +using Microsoft.Extensions.Logging; using Newtonsoft.Json.Serialization; -using eShopOnContainers.WebSPA; -using Microsoft.eShopOnContainers.BuildingBlocks; +using System; +using System.IO; using WebSPA.Infrastructure; namespace eShopConContainers.WebSPA diff --git a/src/Web/WebSPA/WebSPA.csproj b/src/Web/WebSPA/WebSPA.csproj index e4447a126..1efcb89e6 100644 --- a/src/Web/WebSPA/WebSPA.csproj +++ b/src/Web/WebSPA/WebSPA.csproj @@ -3,7 +3,6 @@ netcoreapp2.0 aspnetcorespa-c23d27a4-eb88-4b18-9b77-2a93f3b15119 - $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; ..\..\..\docker-compose.dcproj false true @@ -29,26 +28,7 @@ - - - - - - - - - - - - - - - - - - - @@ -62,9 +42,9 @@ - - - + + + From 6ac34cbdaaf51a8e15dee1ddc36b7a77c1016ff8 Mon Sep 17 00:00:00 2001 From: Unai Zorrilla Castro Date: Tue, 29 Aug 2017 12:48:04 +0200 Subject: [PATCH 46/86] Update functional tests --- src/Services/Basket/Basket.API/Startup.cs | 9 ++++++++- src/Services/Location/Locations.API/Startup.cs | 7 ++++++- src/Services/Marketing/Marketing.API/Startup.cs | 7 ++++++- test/Services/FunctionalTests/FunctionalTests.csproj | 7 +++---- .../Services/Basket/BasketTestsStartup.cs | 3 ++- .../Services/Location/LocationsTestsStartup.cs | 5 ++++- .../Services/Marketing/MarketingTestsStartup.cs | 8 ++++---- 7 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/Services/Basket/Basket.API/Startup.cs b/src/Services/Basket/Basket.API/Startup.cs index e2a2b6e3e..01314b38e 100644 --- a/src/Services/Basket/Basket.API/Startup.cs +++ b/src/Services/Basket/Basket.API/Startup.cs @@ -167,7 +167,9 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API { app.UseStaticFiles(); app.UseCors("CorsPolicy"); - app.UseAuthentication(); + + ConfigureAuth(app); + app.UseMvcWithDefaultRoute(); app.UseSwagger() @@ -216,5 +218,10 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API eventBus.Subscribe(); eventBus.Subscribe(); } + + protected virtual void ConfigureAuth(IApplicationBuilder app) + { + app.UseAuthentication(); + } } } diff --git a/src/Services/Location/Locations.API/Startup.cs b/src/Services/Location/Locations.API/Startup.cs index 7d235ed0f..9c2881f07 100644 --- a/src/Services/Location/Locations.API/Startup.cs +++ b/src/Services/Location/Locations.API/Startup.cs @@ -138,7 +138,7 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API { app.UseCors("CorsPolicy"); - app.UseAuthentication(); + ConfigureAuth(app); app.UseMvcWithDefaultRoute(); @@ -176,5 +176,10 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API services.AddSingleton(); } + + protected virtual void ConfigureAuth(IApplicationBuilder app) + { + app.UseAuthentication(); + } } } diff --git a/src/Services/Marketing/Marketing.API/Startup.cs b/src/Services/Marketing/Marketing.API/Startup.cs index 952594556..76ff4b380 100644 --- a/src/Services/Marketing/Marketing.API/Startup.cs +++ b/src/Services/Marketing/Marketing.API/Startup.cs @@ -171,7 +171,7 @@ { app.UseCors("CorsPolicy"); - app.UseAuthentication(); + ConfigureAuth(app); app.UseMvcWithDefaultRoute(); @@ -243,5 +243,10 @@ } ); } + + protected virtual void ConfigureAuth(IApplicationBuilder app) + { + app.UseAuthentication(); + } } } diff --git a/test/Services/FunctionalTests/FunctionalTests.csproj b/test/Services/FunctionalTests/FunctionalTests.csproj index f9f58a318..99cf123a2 100644 --- a/test/Services/FunctionalTests/FunctionalTests.csproj +++ b/test/Services/FunctionalTests/FunctionalTests.csproj @@ -3,7 +3,7 @@ netcoreapp2.0 true - $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false false false @@ -45,9 +45,8 @@ - - - + + diff --git a/test/Services/FunctionalTests/Services/Basket/BasketTestsStartup.cs b/test/Services/FunctionalTests/Services/Basket/BasketTestsStartup.cs index 2beb73bd1..a6695c12f 100644 --- a/test/Services/FunctionalTests/Services/Basket/BasketTestsStartup.cs +++ b/test/Services/FunctionalTests/Services/Basket/BasketTestsStartup.cs @@ -2,12 +2,13 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.eShopOnContainers.Services.Basket.API; +using Microsoft.Extensions.Configuration; namespace FunctionalTests.Services.Basket { public class BasketTestsStartup : Startup { - public BasketTestsStartup(IHostingEnvironment env) : base(env) + public BasketTestsStartup(IConfiguration configuration) : base(configuration) { } diff --git a/test/Services/FunctionalTests/Services/Location/LocationsTestsStartup.cs b/test/Services/FunctionalTests/Services/Location/LocationsTestsStartup.cs index b80408388..fce808759 100644 --- a/test/Services/FunctionalTests/Services/Location/LocationsTestsStartup.cs +++ b/test/Services/FunctionalTests/Services/Location/LocationsTestsStartup.cs @@ -4,12 +4,13 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.eShopOnContainers.Services.Locations.API; + using Microsoft.Extensions.Configuration; using System.Security.Claims; using System.Threading.Tasks; public class LocationsTestsStartup : Startup { - public LocationsTestsStartup(IHostingEnvironment env) : base(env) + public LocationsTestsStartup(IConfiguration configuration) : base(configuration) { } @@ -28,6 +29,7 @@ class LocationAuthorizeMiddleware { private readonly RequestDelegate _next; + public LocationAuthorizeMiddleware(RequestDelegate rd) { _next = rd; @@ -38,6 +40,7 @@ var identity = new ClaimsIdentity("cookies"); identity.AddClaim(new Claim("sub", "4611ce3f-380d-4db5-8d76-87a8689058ed")); httpContext.User.AddIdentity(identity); + await _next.Invoke(httpContext); } } diff --git a/test/Services/FunctionalTests/Services/Marketing/MarketingTestsStartup.cs b/test/Services/FunctionalTests/Services/Marketing/MarketingTestsStartup.cs index e43db6646..ae5f4453b 100644 --- a/test/Services/FunctionalTests/Services/Marketing/MarketingTestsStartup.cs +++ b/test/Services/FunctionalTests/Services/Marketing/MarketingTestsStartup.cs @@ -1,13 +1,13 @@ namespace FunctionalTests.Services.Marketing { - using Microsoft.eShopOnContainers.Services.Marketing.API; - using Microsoft.AspNetCore.Hosting; - using Microsoft.AspNetCore.Builder; using FunctionalTests.Middleware; + using Microsoft.AspNetCore.Builder; + using Microsoft.eShopOnContainers.Services.Marketing.API; + using Microsoft.Extensions.Configuration; public class MarketingTestsStartup : Startup { - public MarketingTestsStartup(IHostingEnvironment env) : base(env) + public MarketingTestsStartup(IConfiguration configuration) : base(configuration) { } From 9ed7325e0e8925c22c5d8e62bc126801a3ca8b1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ram=C3=B3n=20Tom=C3=A1s?= Date: Tue, 29 Aug 2017 18:11:30 +0200 Subject: [PATCH 47/86] Downgrade Identity.api version due to compatibility issues Updated Test project version Fix issue Idsrv token --- docker-compose.override.yml | 2 + .../DataProtection/DataProtection.csproj | 6 +-- .../Microsoft.AspNetCore.HealthChecks.csproj | 4 +- ...t.Extensions.HealthChecks.SqlServer.csproj | 4 +- .../Microsoft.Extensions.HealthChecks.csproj | 4 +- src/Services/Basket/Basket.API/Startup.cs | 43 +++++++++++++------ src/Services/Catalog/Catalog.API/Startup.cs | 20 ++------- .../Controllers/AccountController.cs | 41 ++++++++++-------- .../Identity/Identity.API/Identity.API.csproj | 38 ++++++++++++---- .../Identity.API/Models/ApplicationUser.cs | 6 ++- src/Services/Identity/Identity.API/Program.cs | 24 ++++------- src/Services/Identity/Identity.API/Startup.cs | 35 +++++++++------ .../Location/Locations.API/Startup.cs | 30 +++++++++---- .../Marketing/Marketing.API/Startup.cs | 32 ++++++++++---- .../GracePeriodManagerService.cs | 5 ++- .../GracePeriodManagerSettings.cs | 14 ------ .../Ordering/Ordering.API/OrderingSettings.cs | 7 +++ src/Services/Ordering/Ordering.API/Startup.cs | 24 +++-------- .../Ordering.API/graceperiodsettings.json | 6 --- .../Ordering/Ordering.API/settings.json | 4 +- src/Web/WebMVC/Startup.cs | 5 +-- src/Web/WebSPA/Startup.cs | 16 +++---- .../Services/Basket/BasketTestsStartup.cs | 3 +- .../Location/LocationsTestsStartup.cs | 3 +- .../Marketing/MarketingTestsStartup.cs | 3 +- .../Services/Ordering/OrderingTestsStartup.cs | 3 +- .../Services/Basket/BasketTestsStartup.cs | 3 +- .../Locations/LocationsTestsStartup.cs | 3 +- .../Marketing/MarketingTestsStartup.cs | 3 +- .../Services/Ordering/OrderingTestsStartup.cs | 3 +- 30 files changed, 225 insertions(+), 169 deletions(-) delete mode 100644 src/Services/Ordering/Ordering.API/Infrastructure/HostedServices/GracePeriodManagerSettings.cs delete mode 100644 src/Services/Ordering/Ordering.API/graceperiodsettings.json diff --git a/docker-compose.override.yml b/docker-compose.override.yml index c8375040d..6870b617f 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -61,6 +61,8 @@ services: - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - UseCustomizationData=True - AzureServiceBusEnabled=False + - GracePeriodTime=1 + - CheckUpdateTime=30000 ports: - "5102:80" diff --git a/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj b/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj index 41281cf54..c5266d0a9 100644 --- a/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj +++ b/src/BuildingBlocks/DataProtection/DataProtection/DataProtection.csproj @@ -1,13 +1,13 @@  - netstandard2.0 + netstandard1.5 Microsoft.eShopOnContainers.BuildingBlocks - + - + \ No newline at end of file diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/Microsoft.AspNetCore.HealthChecks.csproj b/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/Microsoft.AspNetCore.HealthChecks.csproj index 0f6b99f32..023554e60 100644 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/Microsoft.AspNetCore.HealthChecks.csproj +++ b/src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/Microsoft.AspNetCore.HealthChecks.csproj @@ -1,7 +1,7 @@  - netstandard2.0 + netstandard1.3 @@ -9,7 +9,7 @@ - + diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/Microsoft.Extensions.HealthChecks.SqlServer.csproj b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/Microsoft.Extensions.HealthChecks.SqlServer.csproj index 60017a85f..35aacef13 100644 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/Microsoft.Extensions.HealthChecks.SqlServer.csproj +++ b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/Microsoft.Extensions.HealthChecks.SqlServer.csproj @@ -1,7 +1,7 @@  - netstandard2.0 + netstandard1.3 @@ -9,7 +9,7 @@ - + diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Microsoft.Extensions.HealthChecks.csproj b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Microsoft.Extensions.HealthChecks.csproj index 80e8026b0..8ef22e156 100644 --- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Microsoft.Extensions.HealthChecks.csproj +++ b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Microsoft.Extensions.HealthChecks.csproj @@ -1,7 +1,7 @@  - netstandard2.0 + netstandard1.3 @@ -9,7 +9,7 @@ - + diff --git a/src/Services/Basket/Basket.API/Startup.cs b/src/Services/Basket/Basket.API/Startup.cs index e2a2b6e3e..a00477f1e 100644 --- a/src/Services/Basket/Basket.API/Startup.cs +++ b/src/Services/Basket/Basket.API/Startup.cs @@ -3,6 +3,7 @@ using Autofac.Extensions.DependencyInjection; using Basket.API.Infrastructure.Filters; using Basket.API.IntegrationEvents.EventHandling; using Basket.API.IntegrationEvents.Events; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; @@ -25,6 +26,7 @@ using StackExchange.Redis; using Swashbuckle.AspNetCore.Swagger; using System; using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Services.Basket.API @@ -50,6 +52,8 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API }).AddControllersAsServices(); + ConfigureAuthService(services); + services.AddHealthChecks(checks => { checks.AddValueTaskCheck("HTTP Endpoint", () => new ValueTask(HealthCheckResult.Healthy("Ok")), @@ -57,16 +61,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API ); }); - services.Configure(Configuration); - - services.AddAuthentication() - .AddJwtBearer(options => - { - options.Authority = Configuration.GetValue("IdentityUrl"); - options.Audience = "basket"; - options.RequireHttpsMetadata = false; - - }); + services.Configure(Configuration); //By connecting here we are making sure that our service //cannot start until redis is ready. This might slow down startup, @@ -151,7 +146,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API services.AddSingleton(); services.AddTransient(); services.AddTransient(); - + services.AddOptions(); var container = new ContainerBuilder(); @@ -167,7 +162,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API { app.UseStaticFiles(); app.UseCors("CorsPolicy"); - app.UseAuthentication(); + ConfigureAuth(app); app.UseMvcWithDefaultRoute(); app.UseSwagger() @@ -181,6 +176,30 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API } + 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"; + }); + } + + protected virtual void ConfigureAuth(IApplicationBuilder app) + { + app.UseAuthentication(); + } private void RegisterEventBus(IServiceCollection services) { diff --git a/src/Services/Catalog/Catalog.API/Startup.cs b/src/Services/Catalog/Catalog.API/Startup.cs index 7f64e9a88..64754c3ab 100644 --- a/src/Services/Catalog/Catalog.API/Startup.cs +++ b/src/Services/Catalog/Catalog.API/Startup.cs @@ -36,25 +36,13 @@ public class Startup { - public IConfigurationRoot Configuration { get; } - - public Startup(IHostingEnvironment env) + public Startup(IConfiguration configuration) { - var builder = new ConfigurationBuilder() - .SetBasePath(env.ContentRootPath) - .AddJsonFile($"settings.json", optional: false, reloadOnChange: true) - .AddJsonFile($"settings.{env.EnvironmentName}.json", optional: true); - - if (env.IsDevelopment()) - { - builder.AddUserSecrets(typeof(Startup).GetTypeInfo().Assembly); - } - - builder.AddEnvironmentVariables(); - - Configuration = builder.Build(); + Configuration = configuration; } + public IConfiguration Configuration { get; } + public IServiceProvider ConfigureServices(IServiceCollection services) { // Add framework services. diff --git a/src/Services/Identity/Identity.API/Controllers/AccountController.cs b/src/Services/Identity/Identity.API/Controllers/AccountController.cs index 6b56b3467..02b50129f 100644 --- a/src/Services/Identity/Identity.API/Controllers/AccountController.cs +++ b/src/Services/Identity/Identity.API/Controllers/AccountController.cs @@ -2,24 +2,26 @@ // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. -using Identity.API.Models; -using Identity.API.Models.AccountViewModels; -using Identity.API.Services; using IdentityModel; -using IdentityServer4.Models; +using IdentityServer4.Quickstart.UI.Models; using IdentityServer4.Services; -using IdentityServer4.Stores; -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Http.Authentication; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; using System; +using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Text.Encodings.Web; using System.Threading.Tasks; - +using IdentityServer4.Models; +using IdentityServer4.Stores; +using Identity.API.Services; +using Identity.API.Models; +using Microsoft.Extensions.Logging; +using Microsoft.AspNetCore.Authorization; +using Identity.API.Models.AccountViewModels; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Authentication; namespace IdentityServer4.Quickstart.UI.Controllers { @@ -38,12 +40,12 @@ namespace IdentityServer4.Quickstart.UI.Controllers private readonly UserManager _userManager; public AccountController( - + //InMemoryUserLoginService loginService, ILoginService loginService, IIdentityServerInteractionService interaction, IClientStore clientStore, - ILoggerFactory loggerFactory, + ILoggerFactory loggerFactory, UserManager userManager) { _loginService = loginService; @@ -84,7 +86,7 @@ namespace IdentityServer4.Quickstart.UI.Controllers var user = await _loginService.FindByUsername(model.Email); if (await _loginService.ValidateCredentials(user, model.Password)) { - AuthenticationProperties props = null; + AuthenticationProperties props = null; if (model.RememberMe) { props = new AuthenticationProperties @@ -192,16 +194,16 @@ namespace IdentityServer4.Quickstart.UI.Controllers try { // hack: try/catch to handle social providers that throw - await HttpContext.SignOutAsync(idp, new AuthenticationProperties { RedirectUri = url }); + await HttpContext.Authentication.SignOutAsync(idp, new AuthenticationProperties { RedirectUri = url }); } - catch(Exception ex) + catch (Exception ex) { _logger.LogCritical(ex.Message); } } // delete authentication cookie - await HttpContext.SignOutAsync(); + await HttpContext.Authentication.SignOutAsync(); // set this so UI rendering sees an anonymous user HttpContext.User = new ClaimsPrincipal(new ClaimsIdentity()); @@ -215,7 +217,7 @@ namespace IdentityServer4.Quickstart.UI.Controllers public async Task DeviceLogOut(string redirectUrl) { // delete authentication cookie - await HttpContext.SignOutAsync(); + await HttpContext.Authentication.SignOutAsync(); // set this so UI rendering sees an anonymous user HttpContext.User = new ClaimsPrincipal(new ClaimsIdentity()); @@ -238,7 +240,7 @@ namespace IdentityServer4.Quickstart.UI.Controllers // start challenge and roundtrip the return URL var props = new AuthenticationProperties { - RedirectUri = returnUrl, + RedirectUri = returnUrl, Items = { { "scheme", provider } } }; return new ChallengeResult(provider, props); @@ -291,7 +293,8 @@ namespace IdentityServer4.Quickstart.UI.Controllers } } - if (returnUrl != null) { + if (returnUrl != null) + { if (HttpContext.User.Identity.IsAuthenticated) return Redirect(returnUrl); else diff --git a/src/Services/Identity/Identity.API/Identity.API.csproj b/src/Services/Identity/Identity.API/Identity.API.csproj index 49f9b4c2e..7c221e858 100644 --- a/src/Services/Identity/Identity.API/Identity.API.csproj +++ b/src/Services/Identity/Identity.API/Identity.API.csproj @@ -1,10 +1,10 @@  - netcoreapp2.0 - 2.0.0 + netcoreapp1.1 + 1.1.2 aspnet-eShopOnContainers.Identity-90487118-103c-4ff0-b9da-e5e26f7ab0c5 - + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; ..\..\..\..\docker-compose.dcproj @@ -16,8 +16,30 @@ - - + + + + + + + + + + + + All + + + All + + + + + + + + + @@ -30,9 +52,9 @@ - - - + + + diff --git a/src/Services/Identity/Identity.API/Models/ApplicationUser.cs b/src/Services/Identity/Identity.API/Models/ApplicationUser.cs index 1c1f7bda1..b520c333b 100644 --- a/src/Services/Identity/Identity.API/Models/ApplicationUser.cs +++ b/src/Services/Identity/Identity.API/Models/ApplicationUser.cs @@ -1,4 +1,8 @@ -using Microsoft.AspNetCore.Identity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using System.ComponentModel.DataAnnotations; namespace Identity.API.Models diff --git a/src/Services/Identity/Identity.API/Program.cs b/src/Services/Identity/Identity.API/Program.cs index 9a035bd93..2f731c045 100644 --- a/src/Services/Identity/Identity.API/Program.cs +++ b/src/Services/Identity/Identity.API/Program.cs @@ -1,6 +1,4 @@ -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Logging; +using Microsoft.AspNetCore.Hosting; using System.IO; namespace eShopOnContainers.Identity @@ -9,19 +7,15 @@ namespace eShopOnContainers.Identity { public static void Main(string[] args) { - BuildWebHost(args).Run(); - } - - public static IWebHost BuildWebHost(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseContentRoot(Directory.GetCurrentDirectory()) + var host = new WebHostBuilder() + .UseKestrel() .UseHealthChecks("/hc") + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() .UseStartup() - .ConfigureLogging((hostingContext, builder) => - { - builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); - builder.AddConsole(); - builder.AddDebug(); - }).Build(); + .Build(); + + host.Run(); + } } } diff --git a/src/Services/Identity/Identity.API/Startup.cs b/src/Services/Identity/Identity.API/Startup.cs index 711c4b9c1..a07cd69c2 100644 --- a/src/Services/Identity/Identity.API/Startup.cs +++ b/src/Services/Identity/Identity.API/Startup.cs @@ -1,6 +1,4 @@ -using Autofac; -using Autofac.Extensions.DependencyInjection; -using Identity.API.Certificate; +using Identity.API.Certificate; using Identity.API.Configuration; using Identity.API.Data; using Identity.API.Models; @@ -11,12 +9,16 @@ using IdentityServer4.Services; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.eShopOnContainers.BuildingBlocks; using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.HealthChecks; +using Identity.API.Certificate; +using Autofac.Extensions.DependencyInjection; +using Autofac; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -28,17 +30,28 @@ namespace eShopOnContainers.Identity { public class Startup { - public Startup(IConfiguration configuration) + public Startup(IHostingEnvironment env) { - Configuration = configuration; - } + var builder = new ConfigurationBuilder() + .SetBasePath(env.ContentRootPath) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); - public IConfiguration Configuration { get; } + if (env.IsDevelopment()) + { + // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709 + builder.AddUserSecrets(); + } + + builder.AddEnvironmentVariables(); + Configuration = builder.Build(); + } + public IConfigurationRoot Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public IServiceProvider ConfigureServices(IServiceCollection services) - { + { // Add framework services. services.AddDbContext(options => @@ -81,7 +94,7 @@ namespace eShopOnContainers.Identity // Adds IdentityServer services.AddIdentityServer(x => x.IssuerUri = "null") - .AddSigningCredential(Certificate.Get()) + .AddSigningCredential(Certificate.Get()) .AddAspNetIdentity() .AddConfigurationStore(builder => builder.UseSqlServer(connectionString, options => @@ -123,11 +136,9 @@ namespace eShopOnContainers.Identity await next(); }); - + app.UseIdentity(); // Adds IdentityServer - app.UseAuthentication(); - app.UseIdentityServer(); app.UseMvc(routes => diff --git a/src/Services/Location/Locations.API/Startup.cs b/src/Services/Location/Locations.API/Startup.cs index 7d235ed0f..eb2077c8c 100644 --- a/src/Services/Location/Locations.API/Startup.cs +++ b/src/Services/Location/Locations.API/Startup.cs @@ -20,6 +20,7 @@ using RabbitMQ.Client; using Swashbuckle.AspNetCore.Swagger; using System; using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Services.Locations.API @@ -40,13 +41,7 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API options.Filters.Add(typeof(HttpGlobalExceptionFilter)); }).AddControllersAsServices(); - services.AddAuthentication() - .AddJwtBearer(options => - { - options.Authority = Configuration.GetValue("IdentityUrl"); - options.Audience = "locations"; - options.RequireHttpsMetadata = false; - }); + ConfigureAuthService(services); services.Configure(Configuration); @@ -138,7 +133,7 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API { app.UseCors("CorsPolicy"); - app.UseAuthentication(); + ConfigureAuth(app); app.UseMvcWithDefaultRoute(); @@ -153,6 +148,25 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API .Wait(); } + private void ConfigureAuthService(IServiceCollection services) + { + // prevent from mapping "sub" claim to nameidentifier. + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + + services.AddAuthentication() + .AddJwtBearer(options => + { + options.Authority = Configuration.GetValue("IdentityUrl"); + options.Audience = "locations"; + options.RequireHttpsMetadata = false; + }); + } + + protected virtual void ConfigureAuth(IApplicationBuilder app) + { + app.UseAuthentication(); + } + private void RegisterEventBus(IServiceCollection services) { if (Configuration.GetValue("AzureServiceBusEnabled")) diff --git a/src/Services/Marketing/Marketing.API/Startup.cs b/src/Services/Marketing/Marketing.API/Startup.cs index 952594556..15b845337 100644 --- a/src/Services/Marketing/Marketing.API/Startup.cs +++ b/src/Services/Marketing/Marketing.API/Startup.cs @@ -28,6 +28,7 @@ using System; using System.Collections.Generic; using System.Data.SqlClient; + using System.IdentityModel.Tokens.Jwt; using System.Reflection; using System.Threading.Tasks; @@ -52,13 +53,7 @@ services.Configure(Configuration); - services.AddAuthentication() - .AddJwtBearer(options => - { - options.Authority = Configuration.GetValue("IdentityUrl"); - options.Audience = "marketing"; - options.RequireHttpsMetadata = false; - }); + ConfigureAuthService(services); services.AddHealthChecks(checks => { @@ -171,7 +166,7 @@ { app.UseCors("CorsPolicy"); - app.UseAuthentication(); + ConfigureAuth(app); app.UseMvcWithDefaultRoute(); @@ -190,7 +185,21 @@ ConfigureEventBus(app); } - private void RegisterEventBus(IServiceCollection services) + private void ConfigureAuthService(IServiceCollection services) + { + // prevent from mapping "sub" claim to nameidentifier. + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + + services.AddAuthentication() + .AddJwtBearer(options => + { + options.Authority = Configuration.GetValue("IdentityUrl"); + options.Audience = "marketing"; + options.RequireHttpsMetadata = false; + }); + } + + private void RegisterEventBus(IServiceCollection services) { if (Configuration.GetValue("AzureServiceBusEnabled")) { @@ -221,6 +230,11 @@ eventBus.Subscribe(); } + protected virtual void ConfigureAuth(IApplicationBuilder app) + { + app.UseAuthentication(); + } + private async Task WaitForSqlAvailabilityAsync(MarketingContext ctx, ILoggerFactory loggerFactory, IApplicationBuilder app, int retries = 0) { var logger = loggerFactory.CreateLogger(nameof(Startup)); diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/HostedServices/GracePeriodManagerService.cs b/src/Services/Ordering/Ordering.API/Infrastructure/HostedServices/GracePeriodManagerService.cs index 58408b2fd..f38fc8fd8 100644 --- a/src/Services/Ordering/Ordering.API/Infrastructure/HostedServices/GracePeriodManagerService.cs +++ b/src/Services/Ordering/Ordering.API/Infrastructure/HostedServices/GracePeriodManagerService.cs @@ -2,6 +2,7 @@ { using Dapper; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; + using Microsoft.eShopOnContainers.Services.Ordering.API; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Ordering.API.Application.IntegrationEvents.Events; @@ -14,11 +15,11 @@ public class GracePeriodManagerService : HostedService { - private readonly GracePeriodManagerSettings _settings; + private readonly OrderingSettings _settings; private readonly ILogger _logger; private readonly IEventBus _eventBus; - public GracePeriodManagerService(IOptions settings, + public GracePeriodManagerService(IOptions settings, IEventBus eventBus, ILogger logger) { diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/HostedServices/GracePeriodManagerSettings.cs b/src/Services/Ordering/Ordering.API/Infrastructure/HostedServices/GracePeriodManagerSettings.cs deleted file mode 100644 index 2997c051d..000000000 --- a/src/Services/Ordering/Ordering.API/Infrastructure/HostedServices/GracePeriodManagerSettings.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ordering.API.Infrastructure.HostedServices -{ - public class GracePeriodManagerSettings - { - 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/OrderingSettings.cs b/src/Services/Ordering/Ordering.API/OrderingSettings.cs index 8c75ba62d..bfe4d0793 100644 --- a/src/Services/Ordering/Ordering.API/OrderingSettings.cs +++ b/src/Services/Ordering/Ordering.API/OrderingSettings.cs @@ -3,5 +3,12 @@ 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/Startup.cs b/src/Services/Ordering/Ordering.API/Startup.cs index c793a3950..7f22540fa 100644 --- a/src/Services/Ordering/Ordering.API/Startup.cs +++ b/src/Services/Ordering/Ordering.API/Startup.cs @@ -35,30 +35,18 @@ using System.Collections.Generic; using System.Data.Common; using System.Data.SqlClient; + using System.IdentityModel.Tokens.Jwt; using System.Reflection; using System.Threading.Tasks; public class Startup { - public Startup(IHostingEnvironment env) + public Startup(IConfiguration configuration) { - var builder = new ConfigurationBuilder() - .SetBasePath(env.ContentRootPath) - .AddJsonFile("settings.json", optional: true, reloadOnChange: true) - .AddJsonFile("graceperiodsettings.json", optional: true, reloadOnChange: true) - .AddJsonFile($"settings.{env.EnvironmentName}.json", optional: true); - - if (env.IsDevelopment()) - { - builder.AddUserSecrets(typeof(Startup).GetTypeInfo().Assembly); - } - - builder.AddEnvironmentVariables(); - - Configuration = builder.Build(); + Configuration = configuration; } - public IConfigurationRoot Configuration { get; } + public IConfiguration Configuration { get; } public IServiceProvider ConfigureServices(IServiceCollection services) { @@ -71,7 +59,6 @@ // Configure GracePeriodManager Hosted Service services.AddSingleton(); - services.Configure(Configuration); services.AddTransient(); @@ -228,6 +215,9 @@ private void ConfigureAuthService(IServiceCollection services) { + // prevent from mapping "sub" claim to nameidentifier. + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + var identityUrl = Configuration.GetValue("IdentityUrl"); services.AddAuthentication(options => diff --git a/src/Services/Ordering/Ordering.API/graceperiodsettings.json b/src/Services/Ordering/Ordering.API/graceperiodsettings.json deleted file mode 100644 index 1c9d30e5e..000000000 --- a/src/Services/Ordering/Ordering.API/graceperiodsettings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;", - "GracePeriodTime": "1", - "CheckUpdateTime": "30000" -} - diff --git a/src/Services/Ordering/Ordering.API/settings.json b/src/Services/Ordering/Ordering.API/settings.json index aa3499295..d2068fcab 100644 --- a/src/Services/Ordering/Ordering.API/settings.json +++ b/src/Services/Ordering/Ordering.API/settings.json @@ -11,5 +11,7 @@ } }, "AzureServiceBusEnabled": false, - "SubscriptionClientName": "Ordering" + "SubscriptionClientName": "Ordering", + "GracePeriodTime": "1", + "CheckUpdateTime": "30000" } diff --git a/src/Web/WebMVC/Startup.cs b/src/Web/WebMVC/Startup.cs index 1791e8da1..8b10c1ecc 100644 --- a/src/Web/WebMVC/Startup.cs +++ b/src/Web/WebMVC/Startup.cs @@ -82,11 +82,10 @@ namespace Microsoft.eShopOnContainers.WebMVC // Add Authentication services services.AddAuthentication(options => { + options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; - options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; - options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; }) - .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme) + .AddCookie() .AddOpenIdConnect(options => { options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.Authority = identityUrl.ToString(); diff --git a/src/Web/WebSPA/Startup.cs b/src/Web/WebSPA/Startup.cs index 22511c135..1659af537 100644 --- a/src/Web/WebSPA/Startup.cs +++ b/src/Web/WebSPA/Startup.cs @@ -16,24 +16,22 @@ namespace eShopConContainers.WebSPA { public class Startup { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + private IHostingEnvironment _hostingEnv; public Startup(IHostingEnvironment env) { _hostingEnv = env; - var builder = new ConfigurationBuilder() - .SetBasePath(env.ContentRootPath) - .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) - .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) - .AddEnvironmentVariables(); - - Configuration = builder.Build(); - var localPath = new Uri(Configuration["ASPNETCORE_URLS"])?.LocalPath ?? "/"; Configuration["BaseUrl"] = localPath; } - public static IConfigurationRoot Configuration { get; set;} // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) diff --git a/test/Services/FunctionalTests/Services/Basket/BasketTestsStartup.cs b/test/Services/FunctionalTests/Services/Basket/BasketTestsStartup.cs index 2beb73bd1..31d83fddc 100644 --- a/test/Services/FunctionalTests/Services/Basket/BasketTestsStartup.cs +++ b/test/Services/FunctionalTests/Services/Basket/BasketTestsStartup.cs @@ -2,12 +2,13 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.eShopOnContainers.Services.Basket.API; +using Microsoft.Extensions.Configuration; namespace FunctionalTests.Services.Basket { public class BasketTestsStartup : Startup { - public BasketTestsStartup(IHostingEnvironment env) : base(env) + public BasketTestsStartup(IConfiguration env) : base(env) { } diff --git a/test/Services/FunctionalTests/Services/Location/LocationsTestsStartup.cs b/test/Services/FunctionalTests/Services/Location/LocationsTestsStartup.cs index b80408388..679518fb0 100644 --- a/test/Services/FunctionalTests/Services/Location/LocationsTestsStartup.cs +++ b/test/Services/FunctionalTests/Services/Location/LocationsTestsStartup.cs @@ -4,12 +4,13 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.eShopOnContainers.Services.Locations.API; + using Microsoft.Extensions.Configuration; using System.Security.Claims; using System.Threading.Tasks; public class LocationsTestsStartup : Startup { - public LocationsTestsStartup(IHostingEnvironment env) : base(env) + public LocationsTestsStartup(IConfiguration env) : base(env) { } diff --git a/test/Services/FunctionalTests/Services/Marketing/MarketingTestsStartup.cs b/test/Services/FunctionalTests/Services/Marketing/MarketingTestsStartup.cs index e43db6646..14176da67 100644 --- a/test/Services/FunctionalTests/Services/Marketing/MarketingTestsStartup.cs +++ b/test/Services/FunctionalTests/Services/Marketing/MarketingTestsStartup.cs @@ -4,10 +4,11 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Builder; using FunctionalTests.Middleware; + using Microsoft.Extensions.Configuration; public class MarketingTestsStartup : Startup { - public MarketingTestsStartup(IHostingEnvironment env) : base(env) + public MarketingTestsStartup(IConfiguration env) : base(env) { } diff --git a/test/Services/FunctionalTests/Services/Ordering/OrderingTestsStartup.cs b/test/Services/FunctionalTests/Services/Ordering/OrderingTestsStartup.cs index 0d8676f61..46e5fe8c1 100644 --- a/test/Services/FunctionalTests/Services/Ordering/OrderingTestsStartup.cs +++ b/test/Services/FunctionalTests/Services/Ordering/OrderingTestsStartup.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.eShopOnContainers.Services.Ordering.API; +using Microsoft.Extensions.Configuration; using System; using System.Collections.Generic; using System.Text; @@ -10,7 +11,7 @@ namespace FunctionalTests.Services.Ordering { public class OrderingTestsStartup : Startup { - public OrderingTestsStartup(IHostingEnvironment env) : base(env) + public OrderingTestsStartup(IConfiguration env) : base(env) { } diff --git a/test/Services/IntegrationTests/Services/Basket/BasketTestsStartup.cs b/test/Services/IntegrationTests/Services/Basket/BasketTestsStartup.cs index 788c9621d..6bc1bbe6d 100644 --- a/test/Services/IntegrationTests/Services/Basket/BasketTestsStartup.cs +++ b/test/Services/IntegrationTests/Services/Basket/BasketTestsStartup.cs @@ -2,12 +2,13 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.eShopOnContainers.Services.Basket.API; +using Microsoft.Extensions.Configuration; namespace IntegrationTests.Services.Basket { public class BasketTestsStartup : Startup { - public BasketTestsStartup(IHostingEnvironment env) : base(env) + public BasketTestsStartup(IConfiguration env) : base(env) { } diff --git a/test/Services/IntegrationTests/Services/Locations/LocationsTestsStartup.cs b/test/Services/IntegrationTests/Services/Locations/LocationsTestsStartup.cs index 28a51456b..efcc9a3c0 100644 --- a/test/Services/IntegrationTests/Services/Locations/LocationsTestsStartup.cs +++ b/test/Services/IntegrationTests/Services/Locations/LocationsTestsStartup.cs @@ -5,12 +5,13 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.eShopOnContainers.Services.Locations.API; + using Microsoft.Extensions.Configuration; using System.Security.Claims; using System.Threading.Tasks; public class LocationsTestsStartup : Startup { - public LocationsTestsStartup(IHostingEnvironment env) : base(env) + public LocationsTestsStartup(IConfiguration env) : base(env) { } diff --git a/test/Services/IntegrationTests/Services/Marketing/MarketingTestsStartup.cs b/test/Services/IntegrationTests/Services/Marketing/MarketingTestsStartup.cs index b8d337ab2..b2d8ed3dc 100644 --- a/test/Services/IntegrationTests/Services/Marketing/MarketingTestsStartup.cs +++ b/test/Services/IntegrationTests/Services/Marketing/MarketingTestsStartup.cs @@ -4,10 +4,11 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Builder; using IntegrationTests.Middleware; + using Microsoft.Extensions.Configuration; public class MarketingTestsStartup : Startup { - public MarketingTestsStartup(IHostingEnvironment env) : base(env) + public MarketingTestsStartup(IConfiguration env) : base(env) { } diff --git a/test/Services/IntegrationTests/Services/Ordering/OrderingTestsStartup.cs b/test/Services/IntegrationTests/Services/Ordering/OrderingTestsStartup.cs index 72fe91f0e..a5aab6136 100644 --- a/test/Services/IntegrationTests/Services/Ordering/OrderingTestsStartup.cs +++ b/test/Services/IntegrationTests/Services/Ordering/OrderingTestsStartup.cs @@ -5,12 +5,13 @@ using System.Text; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Builder; using IntegrationTests.Middleware; +using Microsoft.Extensions.Configuration; namespace IntegrationTests.Services.Ordering { public class OrderingTestsStartup : Startup { - public OrderingTestsStartup(IHostingEnvironment env) : base(env) + public OrderingTestsStartup(IConfiguration env) : base(env) { } From dc566ea2a18c0a3629c9cf2cfed976f33070fdd8 Mon Sep 17 00:00:00 2001 From: Igor Sychev Date: Wed, 30 Aug 2017 08:46:56 +0300 Subject: [PATCH 48/86] nanowin --- src/Services/Basket/Basket.API/Dockerfile.nanowin | 2 +- src/Services/Catalog/Catalog.API/Dockerfile.nanowin | 2 +- src/Services/Location/Locations.API/Dockerfile.nanowin | 4 ++-- src/Services/Marketing/Marketing.API/Dockerfile.nanowin | 4 ++-- src/Services/Ordering/Ordering.API/Dockerfile.nanowin | 2 +- src/Services/Payment/Payment.API/Dockerfile.nanowin | 4 ++-- src/Web/WebMVC/Dockerfile.nanowin | 2 +- src/Web/WebSPA/Dockerfile.nanowin | 2 +- src/Web/WebStatus/Dockerfile.nanowin | 4 ++-- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Services/Basket/Basket.API/Dockerfile.nanowin b/src/Services/Basket/Basket.API/Dockerfile.nanowin index 9c664f4e4..deab637ef 100644 --- a/src/Services/Basket/Basket.API/Dockerfile.nanowin +++ b/src/Services/Basket/Basket.API/Dockerfile.nanowin @@ -1,4 +1,4 @@ -FROM microsoft/dotnet:1.1-runtime-nanoserver +FROM microsoft/dotnet:2.0-runtime-nanoserver SHELL ["powershell"] ARG source WORKDIR /app diff --git a/src/Services/Catalog/Catalog.API/Dockerfile.nanowin b/src/Services/Catalog/Catalog.API/Dockerfile.nanowin index 193ddaef6..68eb9262d 100644 --- a/src/Services/Catalog/Catalog.API/Dockerfile.nanowin +++ b/src/Services/Catalog/Catalog.API/Dockerfile.nanowin @@ -1,4 +1,4 @@ -FROM microsoft/dotnet:1.1-runtime-nanoserver +FROM microsoft/dotnet:2.0-runtime-nanoserver SHELL ["powershell"] ARG source WORKDIR /app diff --git a/src/Services/Location/Locations.API/Dockerfile.nanowin b/src/Services/Location/Locations.API/Dockerfile.nanowin index 9c664f4e4..59fe001da 100644 --- a/src/Services/Location/Locations.API/Dockerfile.nanowin +++ b/src/Services/Location/Locations.API/Dockerfile.nanowin @@ -1,8 +1,8 @@ -FROM microsoft/dotnet:1.1-runtime-nanoserver +FROM microsoft/dotnet:2.0-runtime-nanoserver SHELL ["powershell"] ARG source WORKDIR /app RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord EXPOSE 80 COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "Basket.API.dll"] +ENTRYPOINT ["dotnet", "Locations.API.dll"] diff --git a/src/Services/Marketing/Marketing.API/Dockerfile.nanowin b/src/Services/Marketing/Marketing.API/Dockerfile.nanowin index 9c664f4e4..33bcd0e82 100644 --- a/src/Services/Marketing/Marketing.API/Dockerfile.nanowin +++ b/src/Services/Marketing/Marketing.API/Dockerfile.nanowin @@ -1,8 +1,8 @@ -FROM microsoft/dotnet:1.1-runtime-nanoserver +FROM microsoft/dotnet:2.0-runtime-nanoserver SHELL ["powershell"] ARG source WORKDIR /app RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord EXPOSE 80 COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "Basket.API.dll"] +ENTRYPOINT ["dotnet", "Marketing.API.dll"] diff --git a/src/Services/Ordering/Ordering.API/Dockerfile.nanowin b/src/Services/Ordering/Ordering.API/Dockerfile.nanowin index 653531d0f..c5dd08a2e 100644 --- a/src/Services/Ordering/Ordering.API/Dockerfile.nanowin +++ b/src/Services/Ordering/Ordering.API/Dockerfile.nanowin @@ -1,4 +1,4 @@ -FROM microsoft/dotnet:1.1-runtime-nanoserver +FROM microsoft/dotnet:2.0-runtime-nanoserver SHELL ["powershell"] ARG source WORKDIR /app diff --git a/src/Services/Payment/Payment.API/Dockerfile.nanowin b/src/Services/Payment/Payment.API/Dockerfile.nanowin index 9c664f4e4..c04327048 100644 --- a/src/Services/Payment/Payment.API/Dockerfile.nanowin +++ b/src/Services/Payment/Payment.API/Dockerfile.nanowin @@ -1,8 +1,8 @@ -FROM microsoft/dotnet:1.1-runtime-nanoserver +FROM microsoft/dotnet:2.0-runtime-nanoserver SHELL ["powershell"] ARG source WORKDIR /app RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord EXPOSE 80 COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "Basket.API.dll"] +ENTRYPOINT ["dotnet", "Payment.API.dll"] diff --git a/src/Web/WebMVC/Dockerfile.nanowin b/src/Web/WebMVC/Dockerfile.nanowin index 4eaad3b22..739f27746 100644 --- a/src/Web/WebMVC/Dockerfile.nanowin +++ b/src/Web/WebMVC/Dockerfile.nanowin @@ -1,4 +1,4 @@ -FROM microsoft/dotnet:1.1-runtime-nanoserver +FROM microsoft/dotnet:2.0-runtime-nanoserver SHELL ["powershell"] ARG source WORKDIR /app diff --git a/src/Web/WebSPA/Dockerfile.nanowin b/src/Web/WebSPA/Dockerfile.nanowin index 700c23391..7e678c9ac 100644 --- a/src/Web/WebSPA/Dockerfile.nanowin +++ b/src/Web/WebSPA/Dockerfile.nanowin @@ -1,4 +1,4 @@ -FROM microsoft/dotnet:1.1-runtime-nanoserver +FROM microsoft/dotnet:2.0-runtime-nanoserver SHELL ["powershell"] ARG source WORKDIR /app diff --git a/src/Web/WebStatus/Dockerfile.nanowin b/src/Web/WebStatus/Dockerfile.nanowin index 4eaad3b22..9405cf26d 100644 --- a/src/Web/WebStatus/Dockerfile.nanowin +++ b/src/Web/WebStatus/Dockerfile.nanowin @@ -1,8 +1,8 @@ -FROM microsoft/dotnet:1.1-runtime-nanoserver +FROM microsoft/dotnet:2.0-runtime-nanoserver SHELL ["powershell"] ARG source WORKDIR /app RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord EXPOSE 80 COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "WebMVC.dll"] +ENTRYPOINT ["dotnet", "WebStatus.dll"] From c9ff332b84e6be3538688fa40311c73b9eef2e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ram=C3=B3n=20Tom=C3=A1s?= Date: Wed, 30 Aug 2017 08:59:39 +0200 Subject: [PATCH 49/86] Fix merging duplicated ConfigureAuth method --- src/Services/Basket/Basket.API/Startup.cs | 5 ----- src/Services/Location/Locations.API/Startup.cs | 5 ----- src/Services/Marketing/Marketing.API/Startup.cs | 7 +------ .../Services/Locations/LocationsTestsStartup.cs | 2 -- 4 files changed, 1 insertion(+), 18 deletions(-) diff --git a/src/Services/Basket/Basket.API/Startup.cs b/src/Services/Basket/Basket.API/Startup.cs index 9efa1f36a..6a432b290 100644 --- a/src/Services/Basket/Basket.API/Startup.cs +++ b/src/Services/Basket/Basket.API/Startup.cs @@ -237,10 +237,5 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API eventBus.Subscribe(); eventBus.Subscribe(); } - - protected virtual void ConfigureAuth(IApplicationBuilder app) - { - app.UseAuthentication(); - } } } diff --git a/src/Services/Location/Locations.API/Startup.cs b/src/Services/Location/Locations.API/Startup.cs index 189fea331..eb2077c8c 100644 --- a/src/Services/Location/Locations.API/Startup.cs +++ b/src/Services/Location/Locations.API/Startup.cs @@ -190,10 +190,5 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API services.AddSingleton(); } - - protected virtual void ConfigureAuth(IApplicationBuilder app) - { - app.UseAuthentication(); - } } } diff --git a/src/Services/Marketing/Marketing.API/Startup.cs b/src/Services/Marketing/Marketing.API/Startup.cs index c0fa3e5b4..89f8482f9 100644 --- a/src/Services/Marketing/Marketing.API/Startup.cs +++ b/src/Services/Marketing/Marketing.API/Startup.cs @@ -256,11 +256,6 @@ logger.LogTrace($"[{prefix}] Exception {exception.GetType().Name} with message ${exception.Message} detected on attempt {retry} of {retries}"); } ); - } - - protected virtual void ConfigureAuth(IApplicationBuilder app) - { - app.UseAuthentication(); - } + } } } diff --git a/test/Services/IntegrationTests/Services/Locations/LocationsTestsStartup.cs b/test/Services/IntegrationTests/Services/Locations/LocationsTestsStartup.cs index efcc9a3c0..bf19a1ca0 100644 --- a/test/Services/IntegrationTests/Services/Locations/LocationsTestsStartup.cs +++ b/test/Services/IntegrationTests/Services/Locations/LocationsTestsStartup.cs @@ -1,8 +1,6 @@ namespace IntegrationTests.Services.Locations { - using IntegrationTests.Middleware; using Microsoft.AspNetCore.Builder; - using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.eShopOnContainers.Services.Locations.API; using Microsoft.Extensions.Configuration; From 05aa265c602824ad2c2e973ec9d0681f65c86412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ram=C3=B3n=20Tom=C3=A1s?= Date: Wed, 30 Aug 2017 18:51:22 +0200 Subject: [PATCH 50/86] Updated aspnetcore.host to v2.0 in testing projects --- test/Services/IntegrationTests/IntegrationTests.csproj | 4 ++-- test/Services/UnitTest/UnitTest.csproj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Services/IntegrationTests/IntegrationTests.csproj b/test/Services/IntegrationTests/IntegrationTests.csproj index d787b10fc..d4de27425 100644 --- a/test/Services/IntegrationTests/IntegrationTests.csproj +++ b/test/Services/IntegrationTests/IntegrationTests.csproj @@ -45,10 +45,10 @@ - + - + diff --git a/test/Services/UnitTest/UnitTest.csproj b/test/Services/UnitTest/UnitTest.csproj index ec396c982..22a6fedcc 100644 --- a/test/Services/UnitTest/UnitTest.csproj +++ b/test/Services/UnitTest/UnitTest.csproj @@ -21,12 +21,12 @@ - + - + From 0d74b64c3374f590bbfc49bea771f4fa0420d729 Mon Sep 17 00:00:00 2001 From: Christian Arenas Date: Thu, 31 Aug 2017 15:56:04 +0200 Subject: [PATCH 51/86] Add globar variables in app.config and refactor Catalog.API & Marketing.API --- .../LoadTest/Basket.API/AddBasket.webtest | 39 ++++++++++-------- .../Catalog.API/GetCatalogBrands.webtest | 16 +++++--- .../Catalog.API/GetCatalogFiltered.webtest | 14 +++++-- .../Catalog.API/GetCatalogTypes.webtest | 16 +++++--- .../LoadTest/Catalog.API/GetItem.webtest | 14 +++++-- .../LoadTest/Catalog.API/GetItemPic.webtest | 14 +++++-- .../LoadTest/Catalog.API/GetItems.webtest | 16 +++++--- .../Catalog.API/GetItemsByName.webtest | 14 +++++-- test/Services/LoadTest/Local.testsettings | 13 ++++++ .../Marketing.API/GetAllCampaigns.webtest | 41 ++++++++++--------- .../Marketing.API/GetCampaign.webtest | 39 ++++++++++-------- .../Marketing.API/GetUserCampaigns.webtest | 41 ++++++++++--------- test/Services/LoadTest/app.config | 13 ++++++ 13 files changed, 184 insertions(+), 106 deletions(-) create mode 100644 test/Services/LoadTest/Local.testsettings diff --git a/test/Services/LoadTest/Basket.API/AddBasket.webtest b/test/Services/LoadTest/Basket.API/AddBasket.webtest index 50ce0ebfb..9ad6d5a6e 100644 --- a/test/Services/LoadTest/Basket.API/AddBasket.webtest +++ b/test/Services/LoadTest/Basket.API/AddBasket.webtest @@ -1,9 +1,9 @@ - + - + -
+
@@ -27,9 +27,9 @@ - + -
+
@@ -40,19 +40,19 @@ - + - - + + - + -
+
@@ -65,7 +65,7 @@ - +
@@ -73,14 +73,19 @@ ewAiAEIAdQB5AGUAcgBJAGQAIgA6ACIAYQBjADEAMAAwAGYAZgBjAC0AOABmADAANwAtADQAMQAzADAALQBhADMAZgA0AC0AMAA2AGYAOQBlADEAZQA4ADkANABhADQAIgB9AA== + + + + + + + + + + + - - - - - - diff --git a/test/Services/LoadTest/Catalog.API/GetCatalogBrands.webtest b/test/Services/LoadTest/Catalog.API/GetCatalogBrands.webtest index ba4224c13..8247a72a4 100644 --- a/test/Services/LoadTest/Catalog.API/GetCatalogBrands.webtest +++ b/test/Services/LoadTest/Catalog.API/GetCatalogBrands.webtest @@ -1,12 +1,16 @@ - + - + - - - - + + + + + + + + diff --git a/test/Services/LoadTest/Catalog.API/GetCatalogFiltered.webtest b/test/Services/LoadTest/Catalog.API/GetCatalogFiltered.webtest index e273211b4..a3d36923f 100644 --- a/test/Services/LoadTest/Catalog.API/GetCatalogFiltered.webtest +++ b/test/Services/LoadTest/Catalog.API/GetCatalogFiltered.webtest @@ -1,13 +1,19 @@ - + - + + + + + + + + + - - diff --git a/test/Services/LoadTest/Catalog.API/GetCatalogTypes.webtest b/test/Services/LoadTest/Catalog.API/GetCatalogTypes.webtest index 7c7bbadf2..854d5d78c 100644 --- a/test/Services/LoadTest/Catalog.API/GetCatalogTypes.webtest +++ b/test/Services/LoadTest/Catalog.API/GetCatalogTypes.webtest @@ -1,12 +1,16 @@ - + - + - - - - + + + + + + + + diff --git a/test/Services/LoadTest/Catalog.API/GetItem.webtest b/test/Services/LoadTest/Catalog.API/GetItem.webtest index 11ee2e39f..3807cabcf 100644 --- a/test/Services/LoadTest/Catalog.API/GetItem.webtest +++ b/test/Services/LoadTest/Catalog.API/GetItem.webtest @@ -1,11 +1,17 @@ - + - + + + + + + + + + - - diff --git a/test/Services/LoadTest/Catalog.API/GetItemPic.webtest b/test/Services/LoadTest/Catalog.API/GetItemPic.webtest index 3fe51a341..9bfd649bb 100644 --- a/test/Services/LoadTest/Catalog.API/GetItemPic.webtest +++ b/test/Services/LoadTest/Catalog.API/GetItemPic.webtest @@ -1,11 +1,17 @@ - + - + + + + + + + + + - - diff --git a/test/Services/LoadTest/Catalog.API/GetItems.webtest b/test/Services/LoadTest/Catalog.API/GetItems.webtest index f7d826d6e..8364086d2 100644 --- a/test/Services/LoadTest/Catalog.API/GetItems.webtest +++ b/test/Services/LoadTest/Catalog.API/GetItems.webtest @@ -1,12 +1,16 @@ - + - + - - - - + + + + + + + + diff --git a/test/Services/LoadTest/Catalog.API/GetItemsByName.webtest b/test/Services/LoadTest/Catalog.API/GetItemsByName.webtest index f829ba5ab..bc659d083 100644 --- a/test/Services/LoadTest/Catalog.API/GetItemsByName.webtest +++ b/test/Services/LoadTest/Catalog.API/GetItemsByName.webtest @@ -1,12 +1,18 @@ - + - + + + + + + + + + - - diff --git a/test/Services/LoadTest/Local.testsettings b/test/Services/LoadTest/Local.testsettings new file mode 100644 index 000000000..4e1e6ab7f --- /dev/null +++ b/test/Services/LoadTest/Local.testsettings @@ -0,0 +1,13 @@ + + + These are default test settings for a local test run. + + + + + + + + + + \ No newline at end of file diff --git a/test/Services/LoadTest/Marketing.API/GetAllCampaigns.webtest b/test/Services/LoadTest/Marketing.API/GetAllCampaigns.webtest index 462f44079..0f894fcc9 100644 --- a/test/Services/LoadTest/Marketing.API/GetAllCampaigns.webtest +++ b/test/Services/LoadTest/Marketing.API/GetAllCampaigns.webtest @@ -1,9 +1,9 @@  - + -
+
@@ -27,9 +27,9 @@ - + -
+
@@ -40,19 +40,19 @@ - + - - - + + + - + -
+
@@ -65,21 +65,24 @@ - +
- - - - - - - - + + + + + + + + + + + diff --git a/test/Services/LoadTest/Marketing.API/GetCampaign.webtest b/test/Services/LoadTest/Marketing.API/GetCampaign.webtest index 2726b89a6..62fd029db 100644 --- a/test/Services/LoadTest/Marketing.API/GetCampaign.webtest +++ b/test/Services/LoadTest/Marketing.API/GetCampaign.webtest @@ -1,9 +1,9 @@  - + -
+
@@ -27,9 +27,9 @@ - + -
+
@@ -40,19 +40,19 @@ - + - - - + + + - + -
+
@@ -65,20 +65,25 @@ - +
+ + + + + + + + + + + - - - - - - diff --git a/test/Services/LoadTest/Marketing.API/GetUserCampaigns.webtest b/test/Services/LoadTest/Marketing.API/GetUserCampaigns.webtest index 6978b6766..beb5981e7 100644 --- a/test/Services/LoadTest/Marketing.API/GetUserCampaigns.webtest +++ b/test/Services/LoadTest/Marketing.API/GetUserCampaigns.webtest @@ -1,9 +1,9 @@  - + -
+
@@ -27,9 +27,9 @@ - + -
+
@@ -40,19 +40,19 @@ - + - - - + + + - + -
+
@@ -65,21 +65,24 @@ - +
- - - - - - - - + + + + + + + + + + + diff --git a/test/Services/LoadTest/app.config b/test/Services/LoadTest/app.config index 99ddf3e08..0098f2f5e 100644 --- a/test/Services/LoadTest/app.config +++ b/test/Services/LoadTest/app.config @@ -1,3 +1,16 @@  + + + + + + + + + + + + + \ No newline at end of file From 4a6fc5299a1544446e09af2962a58ff4d8ae7e1a Mon Sep 17 00:00:00 2001 From: Unai Zorrilla Castro Date: Thu, 31 Aug 2017 16:23:51 +0200 Subject: [PATCH 52/86] Remove warning on usings in Marketing.API --- .../Events/UserLocationUpdatedIntegrationEvent.cs | 1 + .../Handlers/UserLocationUpdatedIntegrationEventHandler.cs | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Services/Marketing/Marketing.API/IntegrationEvents/Events/UserLocationUpdatedIntegrationEvent.cs b/src/Services/Marketing/Marketing.API/IntegrationEvents/Events/UserLocationUpdatedIntegrationEvent.cs index f894d903f..b73e7b659 100644 --- a/src/Services/Marketing/Marketing.API/IntegrationEvents/Events/UserLocationUpdatedIntegrationEvent.cs +++ b/src/Services/Marketing/Marketing.API/IntegrationEvents/Events/UserLocationUpdatedIntegrationEvent.cs @@ -7,6 +7,7 @@ public class UserLocationUpdatedIntegrationEvent : IntegrationEvent { public string UserId { get; set; } + public List LocationList { get; set; } public UserLocationUpdatedIntegrationEvent(string userId, List locationList) diff --git a/src/Services/Marketing/Marketing.API/IntegrationEvents/Handlers/UserLocationUpdatedIntegrationEventHandler.cs b/src/Services/Marketing/Marketing.API/IntegrationEvents/Handlers/UserLocationUpdatedIntegrationEventHandler.cs index 5393608a0..77574c0e5 100644 --- a/src/Services/Marketing/Marketing.API/IntegrationEvents/Handlers/UserLocationUpdatedIntegrationEventHandler.cs +++ b/src/Services/Marketing/Marketing.API/IntegrationEvents/Handlers/UserLocationUpdatedIntegrationEventHandler.cs @@ -4,7 +4,6 @@ using Marketing.API.Model; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; using Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.Repositories; - using Microsoft.eShopOnContainers.Services.Marketing.API.Model; using System; using System.Collections.Generic; using System.Threading.Tasks; From 146c302a5d7ab78b4d5330e6388beeea00a28fd9 Mon Sep 17 00:00:00 2001 From: Christian Arenas Date: Thu, 31 Aug 2017 16:28:31 +0200 Subject: [PATCH 53/86] Add Ordering refactor --- .../LoadTest/Ordering.API/CancelOrder.webtest | 45 ++++++++++--------- .../Ordering.API/GetAllOrders.webtest | 41 +++++++++-------- .../Ordering.API/GetCardTypes.webtest | 41 +++++++++-------- .../LoadTest/Ordering.API/GetOrder.webtest | 39 +++++++++------- .../LoadTest/Ordering.API/ShipOrder.webtest | 45 ++++++++++--------- test/Services/LoadTest/app.config | 2 + 6 files changed, 116 insertions(+), 97 deletions(-) diff --git a/test/Services/LoadTest/Ordering.API/CancelOrder.webtest b/test/Services/LoadTest/Ordering.API/CancelOrder.webtest index dc7d55244..ca87f175d 100644 --- a/test/Services/LoadTest/Ordering.API/CancelOrder.webtest +++ b/test/Services/LoadTest/Ordering.API/CancelOrder.webtest @@ -1,9 +1,9 @@  - + -
+
@@ -27,9 +27,9 @@ - + -
+
@@ -40,19 +40,19 @@ - + - - - + + + - + -
+
@@ -65,24 +65,27 @@ - +
-
+
ewAiAE8AcgBkAGUAcgBOAHUAbQBiAGUAcgAiADoAIAAxAH0A - - - - - - - - - + + + + + + + + + + + + diff --git a/test/Services/LoadTest/Ordering.API/GetAllOrders.webtest b/test/Services/LoadTest/Ordering.API/GetAllOrders.webtest index c9860e076..58c7016f3 100644 --- a/test/Services/LoadTest/Ordering.API/GetAllOrders.webtest +++ b/test/Services/LoadTest/Ordering.API/GetAllOrders.webtest @@ -1,9 +1,9 @@  - + -
+
@@ -27,9 +27,9 @@ - + -
+
@@ -40,19 +40,19 @@ - + - - - + + + - + -
+
@@ -65,21 +65,24 @@ - +
- - - - - - - - + + + + + + + + + + + diff --git a/test/Services/LoadTest/Ordering.API/GetCardTypes.webtest b/test/Services/LoadTest/Ordering.API/GetCardTypes.webtest index fb3ca3dc3..ac103ced3 100644 --- a/test/Services/LoadTest/Ordering.API/GetCardTypes.webtest +++ b/test/Services/LoadTest/Ordering.API/GetCardTypes.webtest @@ -1,9 +1,9 @@  - + -
+
@@ -27,9 +27,9 @@ - + -
+
@@ -40,19 +40,19 @@ - + - - - + + + - + -
+
@@ -65,21 +65,24 @@ - +
- - - - - - - - + + + + + + + + + + + diff --git a/test/Services/LoadTest/Ordering.API/GetOrder.webtest b/test/Services/LoadTest/Ordering.API/GetOrder.webtest index 73024671b..62c3d9b99 100644 --- a/test/Services/LoadTest/Ordering.API/GetOrder.webtest +++ b/test/Services/LoadTest/Ordering.API/GetOrder.webtest @@ -1,9 +1,9 @@  - + -
+
@@ -27,9 +27,9 @@ - + -
+
@@ -40,19 +40,19 @@ - + - - - + + + - + -
+
@@ -65,20 +65,25 @@ - +
+ + + + + + + + + + + - - - - - - diff --git a/test/Services/LoadTest/Ordering.API/ShipOrder.webtest b/test/Services/LoadTest/Ordering.API/ShipOrder.webtest index 85e6ed92d..6a424a4f5 100644 --- a/test/Services/LoadTest/Ordering.API/ShipOrder.webtest +++ b/test/Services/LoadTest/Ordering.API/ShipOrder.webtest @@ -1,9 +1,9 @@  - + -
+
@@ -27,9 +27,9 @@ - + -
+
@@ -40,19 +40,19 @@ - + - - - + + + - + -
+
@@ -65,24 +65,27 @@ - +
-
+
ewAiAE8AcgBkAGUAcgBOAHUAbQBiAGUAcgAiADoAIAAxAH0A - - - - - - - - - + + + + + + + + + + + + diff --git a/test/Services/LoadTest/app.config b/test/Services/LoadTest/app.config index 0098f2f5e..1a0e53942 100644 --- a/test/Services/LoadTest/app.config +++ b/test/Services/LoadTest/app.config @@ -8,8 +8,10 @@ + + From ecef3bed68835bb6ce99897a60754f16f2daa08a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ram=C3=B3n=20Tom=C3=A1s?= Date: Thu, 31 Aug 2017 17:06:03 +0200 Subject: [PATCH 54/86] Set same vs version for all the solutions --- eShopOnContainers-Android.sln | 2 +- eShopOnContainers-AzureFunctions.sln | 2 +- eShopOnContainers-MobileApps.sln | 2 +- eShopOnContainers-iOS.sln | 2 +- eShopOnContainers.sln | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/eShopOnContainers-Android.sln b/eShopOnContainers-Android.sln index f1f10b26f..b3324f540 100644 --- a/eShopOnContainers-Android.sln +++ b/eShopOnContainers-Android.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26430.6 +VisualStudioVersion = 15.0.26730.8 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{932D8224-11F6-4D07-B109-DA28AD288A63}" EndProject diff --git a/eShopOnContainers-AzureFunctions.sln b/eShopOnContainers-AzureFunctions.sln index 7e14fc19d..d129fc0fe 100644 --- a/eShopOnContainers-AzureFunctions.sln +++ b/eShopOnContainers-AzureFunctions.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26608.5 +VisualStudioVersion = 15.0.26730.8 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Infrastructure", "Infrastructure", "{5B1011EC-CEE5-47AA-B336-99381D573679}" EndProject diff --git a/eShopOnContainers-MobileApps.sln b/eShopOnContainers-MobileApps.sln index cda44c042..ecc3fdb6b 100755 --- a/eShopOnContainers-MobileApps.sln +++ b/eShopOnContainers-MobileApps.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26430.16 +VisualStudioVersion = 15.0.26730.8 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{932D8224-11F6-4D07-B109-DA28AD288A63}" EndProject diff --git a/eShopOnContainers-iOS.sln b/eShopOnContainers-iOS.sln index a6e889786..e220e7c4e 100644 --- a/eShopOnContainers-iOS.sln +++ b/eShopOnContainers-iOS.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26430.6 +VisualStudioVersion = 15.0.26730.8 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{932D8224-11F6-4D07-B109-DA28AD288A63}" EndProject diff --git a/eShopOnContainers.sln b/eShopOnContainers.sln index 414ff7993..ae44be741 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.26430.6 +VisualStudioVersion = 15.0.26730.8 MinimumVisualStudioVersion = 10.0.40219.1 Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FEA0C318-FFED-4D39-8781-265718CA43DD}" ProjectSection(ProjectDependencies) = postProject From 70e429b76013b106df0c2a0dc12a0b7206836454 Mon Sep 17 00:00:00 2001 From: Unai Zorrilla Castro Date: Thu, 31 Aug 2017 17:16:28 +0200 Subject: [PATCH 55/86] Added IEntityTypeConfiguration feature from EF Core 2 --- .../Catalog/Catalog.API/Catalog.API.csproj | 3 + .../Infrastructure/CatalogContext.cs | 68 +----- .../CatalogBrandEntityTypeConfiguration.cs | 25 +++ .../CatalogItemEntityTypeConfiguration.cs | 39 ++++ .../CatalogTypeEntityTypeConfiguration.cs | 25 +++ .../{settings.json => appsettings.json} | 0 .../CampaignEntityTypeConfiguration.cs | 46 ++++ .../RuleEntityTypeConfiguration.cs | 30 +++ ...UserLocationRuleEntityTypeConfiguration.cs | 17 ++ .../Infrastructure/MarketingContext.cs | 71 +------ .../BuyerEntityTYpeConfiguration.cs | 39 ++++ .../CardTypeEntityTypeConfiguration.cs | 27 +++ .../ClientRequestEntityTypeConfiguration.cs | 19 ++ .../OrderEntityTypeConfiguration.cs | 54 +++++ .../OrderItemEntityTypeConfiguration.cs | 44 ++++ .../OrderStatusEntityTypeConfiguration.cs | 27 +++ .../PaymentMethodEntityTypeConfiguration.cs | 49 +++++ .../OrderingContext.cs | 201 +----------------- 18 files changed, 462 insertions(+), 322 deletions(-) create mode 100644 src/Services/Catalog/Catalog.API/Infrastructure/EntityConfigurations/CatalogBrandEntityTypeConfiguration.cs create mode 100644 src/Services/Catalog/Catalog.API/Infrastructure/EntityConfigurations/CatalogItemEntityTypeConfiguration.cs create mode 100644 src/Services/Catalog/Catalog.API/Infrastructure/EntityConfigurations/CatalogTypeEntityTypeConfiguration.cs rename src/Services/Catalog/Catalog.API/{settings.json => appsettings.json} (100%) create mode 100644 src/Services/Marketing/Marketing.API/Infrastructure/EntityConfigurations/CampaignEntityTypeConfiguration.cs create mode 100644 src/Services/Marketing/Marketing.API/Infrastructure/EntityConfigurations/RuleEntityTypeConfiguration.cs create mode 100644 src/Services/Marketing/Marketing.API/Infrastructure/EntityConfigurations/UserLocationRuleEntityTypeConfiguration.cs create mode 100644 src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/BuyerEntityTYpeConfiguration.cs create mode 100644 src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/CardTypeEntityTypeConfiguration.cs create mode 100644 src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/ClientRequestEntityTypeConfiguration.cs create mode 100644 src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/OrderEntityTypeConfiguration.cs create mode 100644 src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/OrderItemEntityTypeConfiguration.cs create mode 100644 src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/OrderStatusEntityTypeConfiguration.cs create mode 100644 src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/PaymentMethodEntityTypeConfiguration.cs diff --git a/src/Services/Catalog/Catalog.API/Catalog.API.csproj b/src/Services/Catalog/Catalog.API/Catalog.API.csproj index 7f55b6432..de280179f 100644 --- a/src/Services/Catalog/Catalog.API/Catalog.API.csproj +++ b/src/Services/Catalog/Catalog.API/Catalog.API.csproj @@ -12,6 +12,9 @@ + + Always + PreserveNewest diff --git a/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs index f58541b62..b0dd2a082 100644 --- a/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs +++ b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs @@ -1,9 +1,8 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure { - using EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore; + using EntityConfigurations; using Model; - using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF; public class CatalogContext : DbContext { @@ -16,68 +15,9 @@ protected override void OnModelCreating(ModelBuilder builder) { - builder.Entity(ConfigureCatalogBrand); - builder.Entity(ConfigureCatalogType); - builder.Entity(ConfigureCatalogItem); + builder.ApplyConfiguration(new CatalogBrandEntityTypeConfiguration()); + builder.ApplyConfiguration(new CatalogTypeEntityTypeConfiguration()); + builder.ApplyConfiguration(new CatalogItemEntityTypeConfiguration()); } - - void ConfigureCatalogItem(EntityTypeBuilder builder) - { - builder.ToTable("Catalog"); - - builder.Property(ci => ci.Id) - .ForSqlServerUseSequenceHiLo("catalog_hilo") - .IsRequired(); - - builder.Property(ci => ci.Name) - .IsRequired(true) - .HasMaxLength(50); - - builder.Property(ci => ci.Price) - .IsRequired(true); - - builder.Property(ci => ci.PictureFileName) - .IsRequired(false); - - builder.Ignore(ci => ci.PictureUri); - - builder.HasOne(ci => ci.CatalogBrand) - .WithMany() - .HasForeignKey(ci => ci.CatalogBrandId); - - builder.HasOne(ci => ci.CatalogType) - .WithMany() - .HasForeignKey(ci => ci.CatalogTypeId); - } - - void ConfigureCatalogBrand(EntityTypeBuilder builder) - { - builder.ToTable("CatalogBrand"); - - builder.HasKey(ci => ci.Id); - - builder.Property(ci => ci.Id) - .ForSqlServerUseSequenceHiLo("catalog_brand_hilo") - .IsRequired(); - - builder.Property(cb => cb.Brand) - .IsRequired() - .HasMaxLength(100); - } - - void ConfigureCatalogType(EntityTypeBuilder builder) - { - builder.ToTable("CatalogType"); - - builder.HasKey(ci => ci.Id); - - builder.Property(ci => ci.Id) - .ForSqlServerUseSequenceHiLo("catalog_type_hilo") - .IsRequired(); - - builder.Property(cb => cb.Type) - .IsRequired() - .HasMaxLength(100); - } } } diff --git a/src/Services/Catalog/Catalog.API/Infrastructure/EntityConfigurations/CatalogBrandEntityTypeConfiguration.cs b/src/Services/Catalog/Catalog.API/Infrastructure/EntityConfigurations/CatalogBrandEntityTypeConfiguration.cs new file mode 100644 index 000000000..8312b023d --- /dev/null +++ b/src/Services/Catalog/Catalog.API/Infrastructure/EntityConfigurations/CatalogBrandEntityTypeConfiguration.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.eShopOnContainers.Services.Catalog.API.Model; + +namespace Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure.EntityConfigurations +{ + class CatalogBrandEntityTypeConfiguration + : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("CatalogBrand"); + + builder.HasKey(ci => ci.Id); + + builder.Property(ci => ci.Id) + .ForSqlServerUseSequenceHiLo("catalog_brand_hilo") + .IsRequired(); + + builder.Property(cb => cb.Brand) + .IsRequired() + .HasMaxLength(100); + } + } +} diff --git a/src/Services/Catalog/Catalog.API/Infrastructure/EntityConfigurations/CatalogItemEntityTypeConfiguration.cs b/src/Services/Catalog/Catalog.API/Infrastructure/EntityConfigurations/CatalogItemEntityTypeConfiguration.cs new file mode 100644 index 000000000..f7f093ce8 --- /dev/null +++ b/src/Services/Catalog/Catalog.API/Infrastructure/EntityConfigurations/CatalogItemEntityTypeConfiguration.cs @@ -0,0 +1,39 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.eShopOnContainers.Services.Catalog.API.Model; + +namespace Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure.EntityConfigurations +{ + class CatalogItemEntityTypeConfiguration + : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("Catalog"); + + builder.Property(ci => ci.Id) + .ForSqlServerUseSequenceHiLo("catalog_hilo") + .IsRequired(); + + builder.Property(ci => ci.Name) + .IsRequired(true) + .HasMaxLength(50); + + builder.Property(ci => ci.Price) + .IsRequired(true); + + builder.Property(ci => ci.PictureFileName) + .IsRequired(false); + + builder.Ignore(ci => ci.PictureUri); + + builder.HasOne(ci => ci.CatalogBrand) + .WithMany() + .HasForeignKey(ci => ci.CatalogBrandId); + + builder.HasOne(ci => ci.CatalogType) + .WithMany() + .HasForeignKey(ci => ci.CatalogTypeId); + } + } +} diff --git a/src/Services/Catalog/Catalog.API/Infrastructure/EntityConfigurations/CatalogTypeEntityTypeConfiguration.cs b/src/Services/Catalog/Catalog.API/Infrastructure/EntityConfigurations/CatalogTypeEntityTypeConfiguration.cs new file mode 100644 index 000000000..4c30bb3b6 --- /dev/null +++ b/src/Services/Catalog/Catalog.API/Infrastructure/EntityConfigurations/CatalogTypeEntityTypeConfiguration.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.eShopOnContainers.Services.Catalog.API.Model; + +namespace Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure.EntityConfigurations +{ + class CatalogTypeEntityTypeConfiguration + : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("CatalogType"); + + builder.HasKey(ci => ci.Id); + + builder.Property(ci => ci.Id) + .ForSqlServerUseSequenceHiLo("catalog_type_hilo") + .IsRequired(); + + builder.Property(cb => cb.Type) + .IsRequired() + .HasMaxLength(100); + } + } +} diff --git a/src/Services/Catalog/Catalog.API/settings.json b/src/Services/Catalog/Catalog.API/appsettings.json similarity index 100% rename from src/Services/Catalog/Catalog.API/settings.json rename to src/Services/Catalog/Catalog.API/appsettings.json diff --git a/src/Services/Marketing/Marketing.API/Infrastructure/EntityConfigurations/CampaignEntityTypeConfiguration.cs b/src/Services/Marketing/Marketing.API/Infrastructure/EntityConfigurations/CampaignEntityTypeConfiguration.cs new file mode 100644 index 000000000..833133dae --- /dev/null +++ b/src/Services/Marketing/Marketing.API/Infrastructure/EntityConfigurations/CampaignEntityTypeConfiguration.cs @@ -0,0 +1,46 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.eShopOnContainers.Services.Marketing.API.Model; + +namespace Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.EntityConfigurations +{ + class CampaignEntityTypeConfiguration + : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("Campaign"); + + builder.HasKey(m => m.Id); + + builder.Property(m => m.Id) + .ForSqlServerUseSequenceHiLo("campaign_hilo") + .IsRequired(); + + builder.Property(m => m.Name) + .HasColumnName("Name") + .IsRequired(); + + builder.Property(m => m.From) + .HasColumnName("From") + .IsRequired(); + + builder.Property(m => m.To) + .HasColumnName("To") + .IsRequired(); + + builder.Property(m => m.Description) + .HasColumnName("Description") + .IsRequired(); + + builder.Property(m => m.PictureUri) + .HasColumnName("PictureUri") + .IsRequired(); + + builder.HasMany(m => m.Rules) + .WithOne(r => r.Campaign) + .HasForeignKey(r => r.CampaignId) + .IsRequired(); + } + } +} diff --git a/src/Services/Marketing/Marketing.API/Infrastructure/EntityConfigurations/RuleEntityTypeConfiguration.cs b/src/Services/Marketing/Marketing.API/Infrastructure/EntityConfigurations/RuleEntityTypeConfiguration.cs new file mode 100644 index 000000000..49c015014 --- /dev/null +++ b/src/Services/Marketing/Marketing.API/Infrastructure/EntityConfigurations/RuleEntityTypeConfiguration.cs @@ -0,0 +1,30 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.eShopOnContainers.Services.Marketing.API.Model; + +namespace Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.EntityConfigurations +{ + class RuleEntityTypeConfiguration + : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("Rule"); + + builder.HasKey(r => r.Id); + + builder.Property(r => r.Id) + .ForSqlServerUseSequenceHiLo("rule_hilo") + .IsRequired(); + + builder.HasDiscriminator("RuleTypeId") + .HasValue(RuleType.UserProfileRule.Id) + .HasValue(RuleType.PurchaseHistoryRule.Id) + .HasValue(RuleType.UserLocationRule.Id); + + builder.Property(r => r.Description) + .HasColumnName("Description") + .IsRequired(); + } + } +} diff --git a/src/Services/Marketing/Marketing.API/Infrastructure/EntityConfigurations/UserLocationRuleEntityTypeConfiguration.cs b/src/Services/Marketing/Marketing.API/Infrastructure/EntityConfigurations/UserLocationRuleEntityTypeConfiguration.cs new file mode 100644 index 000000000..84840d3a5 --- /dev/null +++ b/src/Services/Marketing/Marketing.API/Infrastructure/EntityConfigurations/UserLocationRuleEntityTypeConfiguration.cs @@ -0,0 +1,17 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.eShopOnContainers.Services.Marketing.API.Model; + +namespace Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.EntityConfigurations +{ + class UserLocationRuleEntityTypeConfiguration + : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.Property(r => r.LocationId) + .HasColumnName("LocationId") + .IsRequired(); + } + } +} diff --git a/src/Services/Marketing/Marketing.API/Infrastructure/MarketingContext.cs b/src/Services/Marketing/Marketing.API/Infrastructure/MarketingContext.cs index f530fae37..c843f9b5b 100644 --- a/src/Services/Marketing/Marketing.API/Infrastructure/MarketingContext.cs +++ b/src/Services/Marketing/Marketing.API/Infrastructure/MarketingContext.cs @@ -1,7 +1,7 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure { + using EntityConfigurations; using Microsoft.EntityFrameworkCore; - using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.eShopOnContainers.Services.Marketing.API.Model; public class MarketingContext : DbContext @@ -16,72 +16,9 @@ protected override void OnModelCreating(ModelBuilder builder) { - builder.Entity(ConfigureCampaigns); - builder.Entity(ConfigureRules); - builder.Entity(ConfigureUserLocationRules); - } - - void ConfigureCampaigns(EntityTypeBuilder builder) - { - builder.ToTable("Campaign"); - - builder.HasKey(m => m.Id); - - builder.Property(m => m.Id) - .ForSqlServerUseSequenceHiLo("campaign_hilo") - .IsRequired(); - - builder.Property(m => m.Name) - .HasColumnName("Name") - .IsRequired(); - - builder.Property(m => m.From) - .HasColumnName("From") - .IsRequired(); - - builder.Property(m => m.To) - .HasColumnName("To") - .IsRequired(); - - builder.Property(m => m.Description) - .HasColumnName("Description") - .IsRequired(); - - builder.Property(m => m.PictureUri) - .HasColumnName("PictureUri") - .IsRequired(); - - builder.HasMany(m => m.Rules) - .WithOne(r => r.Campaign) - .HasForeignKey(r => r.CampaignId) - .IsRequired(); - } - - void ConfigureRules(EntityTypeBuilder builder) - { - builder.ToTable("Rule"); - - builder.HasKey(r => r.Id); - - builder.Property(r => r.Id) - .ForSqlServerUseSequenceHiLo("rule_hilo") - .IsRequired(); - - builder.HasDiscriminator("RuleTypeId") - .HasValue(RuleType.UserProfileRule.Id) - .HasValue(RuleType.PurchaseHistoryRule.Id) - .HasValue(RuleType.UserLocationRule.Id); - - builder.Property(r => r.Description) - .HasColumnName("Description") - .IsRequired(); - } - - void ConfigureUserLocationRules(EntityTypeBuilder builder) - { - builder.Property(r => r.LocationId) - .HasColumnName("LocationId") - .IsRequired(); + builder.ApplyConfiguration(new CampaignEntityTypeConfiguration()); + builder.ApplyConfiguration(new RuleEntityTypeConfiguration()); + builder.ApplyConfiguration(new UserLocationRuleEntityTypeConfiguration()); } } } \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/BuyerEntityTYpeConfiguration.cs b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/BuyerEntityTYpeConfiguration.cs new file mode 100644 index 000000000..177f68d91 --- /dev/null +++ b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/BuyerEntityTYpeConfiguration.cs @@ -0,0 +1,39 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate; +using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; + +namespace Ordering.Infrastructure.EntityConfigurations +{ + class BuyerEntityTypeConfiguration + : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder buyerConfiguration) + { + buyerConfiguration.ToTable("buyers", OrderingContext.DEFAULT_SCHEMA); + + buyerConfiguration.HasKey(b => b.Id); + + buyerConfiguration.Ignore(b => b.DomainEvents); + + buyerConfiguration.Property(b => b.Id) + .ForSqlServerUseSequenceHiLo("buyerseq", OrderingContext.DEFAULT_SCHEMA); + + buyerConfiguration.Property(b => b.IdentityGuid) + .HasMaxLength(200) + .IsRequired(); + + buyerConfiguration.HasIndex("IdentityGuid") + .IsUnique(true); + + buyerConfiguration.HasMany(b => b.PaymentMethods) + .WithOne() + .HasForeignKey("BuyerId") + .OnDelete(DeleteBehavior.Cascade); + + var navigation = buyerConfiguration.Metadata.FindNavigation(nameof(Buyer.PaymentMethods)); + + navigation.SetPropertyAccessMode(PropertyAccessMode.Field); + } + } +} diff --git a/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/CardTypeEntityTypeConfiguration.cs b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/CardTypeEntityTypeConfiguration.cs new file mode 100644 index 000000000..cdac780a1 --- /dev/null +++ b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/CardTypeEntityTypeConfiguration.cs @@ -0,0 +1,27 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate; +using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; + +namespace Ordering.Infrastructure.EntityConfigurations +{ + class CardTypeEntityTypeConfiguration + : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder cardTypesConfiguration) + { + cardTypesConfiguration.ToTable("cardtypes", OrderingContext.DEFAULT_SCHEMA); + + cardTypesConfiguration.HasKey(ct => ct.Id); + + cardTypesConfiguration.Property(ct => ct.Id) + .HasDefaultValue(1) + .ValueGeneratedNever() + .IsRequired(); + + cardTypesConfiguration.Property(ct => ct.Name) + .HasMaxLength(200) + .IsRequired(); + } + } +} diff --git a/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/ClientRequestEntityTypeConfiguration.cs b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/ClientRequestEntityTypeConfiguration.cs new file mode 100644 index 000000000..5a5f8547e --- /dev/null +++ b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/ClientRequestEntityTypeConfiguration.cs @@ -0,0 +1,19 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; +using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency; + +namespace Ordering.Infrastructure.EntityConfigurations +{ + class ClientRequestEntityTypeConfiguration + : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder requestConfiguration) + { + requestConfiguration.ToTable("requests", OrderingContext.DEFAULT_SCHEMA); + requestConfiguration.HasKey(cr => cr.Id); + requestConfiguration.Property(cr => cr.Name).IsRequired(); + requestConfiguration.Property(cr => cr.Time).IsRequired(); + } + } +} diff --git a/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/OrderEntityTypeConfiguration.cs b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/OrderEntityTypeConfiguration.cs new file mode 100644 index 000000000..19684d5e3 --- /dev/null +++ b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/OrderEntityTypeConfiguration.cs @@ -0,0 +1,54 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate; +using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; +using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; +using System; + +namespace Ordering.Infrastructure.EntityConfigurations +{ + class OrderEntityTypeConfiguration + : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder orderConfiguration) + { + orderConfiguration.ToTable("orders", OrderingContext.DEFAULT_SCHEMA); + + orderConfiguration.HasKey(o => o.Id); + + orderConfiguration.Ignore(b => b.DomainEvents); + + orderConfiguration.Property(o => o.Id) + .ForSqlServerUseSequenceHiLo("orderseq", OrderingContext.DEFAULT_SCHEMA); + + orderConfiguration.OwnsOne(o => o.Address); + + 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") + .IsRequired(false) + .OnDelete(DeleteBehavior.Restrict); + + orderConfiguration.HasOne() + .WithMany() + .IsRequired(false) + .HasForeignKey("BuyerId"); + + orderConfiguration.HasOne(o => o.OrderStatus) + .WithMany() + .HasForeignKey("OrderStatusId"); + } + } +} diff --git a/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/OrderItemEntityTypeConfiguration.cs b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/OrderItemEntityTypeConfiguration.cs new file mode 100644 index 000000000..ca16eddad --- /dev/null +++ b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/OrderItemEntityTypeConfiguration.cs @@ -0,0 +1,44 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; +using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; + +namespace Ordering.Infrastructure.EntityConfigurations +{ + class OrderItemEntityTypeConfiguration + : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder orderItemConfiguration) + { + orderItemConfiguration.ToTable("orderItems", OrderingContext.DEFAULT_SCHEMA); + + orderItemConfiguration.HasKey(o => o.Id); + + orderItemConfiguration.Ignore(b => b.DomainEvents); + + orderItemConfiguration.Property(o => o.Id) + .ForSqlServerUseSequenceHiLo("orderitemseq"); + + orderItemConfiguration.Property("OrderId") + .IsRequired(); + + orderItemConfiguration.Property("Discount") + .IsRequired(); + + orderItemConfiguration.Property("ProductId") + .IsRequired(); + + orderItemConfiguration.Property("ProductName") + .IsRequired(); + + orderItemConfiguration.Property("UnitPrice") + .IsRequired(); + + orderItemConfiguration.Property("Units") + .IsRequired(); + + orderItemConfiguration.Property("PictureUrl") + .IsRequired(false); + } + } +} diff --git a/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/OrderStatusEntityTypeConfiguration.cs b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/OrderStatusEntityTypeConfiguration.cs new file mode 100644 index 000000000..f968d9011 --- /dev/null +++ b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/OrderStatusEntityTypeConfiguration.cs @@ -0,0 +1,27 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; +using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; + +namespace Ordering.Infrastructure.EntityConfigurations +{ + class OrderStatusEntityTypeConfiguration + : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder orderStatusConfiguration) + { + orderStatusConfiguration.ToTable("orderstatus", OrderingContext.DEFAULT_SCHEMA); + + orderStatusConfiguration.HasKey(o => o.Id); + + orderStatusConfiguration.Property(o => o.Id) + .HasDefaultValue(1) + .ValueGeneratedNever() + .IsRequired(); + + orderStatusConfiguration.Property(o => o.Name) + .HasMaxLength(200) + .IsRequired(); + } + } +} diff --git a/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/PaymentMethodEntityTypeConfiguration.cs b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/PaymentMethodEntityTypeConfiguration.cs new file mode 100644 index 000000000..871c2057e --- /dev/null +++ b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/PaymentMethodEntityTypeConfiguration.cs @@ -0,0 +1,49 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate; +using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; +using System; + +namespace Ordering.Infrastructure.EntityConfigurations +{ + class PaymentMethodEntityTypeConfiguration + : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder paymentConfiguration) + { + paymentConfiguration.ToTable("paymentmethods", OrderingContext.DEFAULT_SCHEMA); + + paymentConfiguration.HasKey(b => b.Id); + + paymentConfiguration.Ignore(b => b.DomainEvents); + + paymentConfiguration.Property(b => b.Id) + .ForSqlServerUseSequenceHiLo("paymentseq", OrderingContext.DEFAULT_SCHEMA); + + paymentConfiguration.Property("BuyerId") + .IsRequired(); + + paymentConfiguration.Property("CardHolderName") + .HasMaxLength(200) + .IsRequired(); + + paymentConfiguration.Property("Alias") + .HasMaxLength(200) + .IsRequired(); + + paymentConfiguration.Property("CardNumber") + .HasMaxLength(25) + .IsRequired(); + + paymentConfiguration.Property("Expiration") + .IsRequired(); + + paymentConfiguration.Property("CardTypeId") + .IsRequired(); + + paymentConfiguration.HasOne(p => p.CardType) + .WithMany() + .HasForeignKey("CardTypeId"); + } + } +} diff --git a/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs b/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs index 85e2cb0f9..3fe60a2c2 100644 --- a/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs +++ b/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs @@ -1,12 +1,10 @@ using MediatR; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate; using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; using Microsoft.eShopOnContainers.Services.Ordering.Domain.Seedwork; -using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency; using Ordering.Infrastructure; +using Ordering.Infrastructure.EntityConfigurations; using System; using System.Threading; using System.Threading.Tasks; @@ -17,7 +15,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure : DbContext,IUnitOfWork { - const string DEFAULT_SCHEMA = "ordering"; + public const string DEFAULT_SCHEMA = "ordering"; public DbSet Orders { get; set; } @@ -40,6 +38,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure } private OrderingContext(DbContextOptions options) : base (options) { } + public OrderingContext(DbContextOptions options, IMediator mediator) : base(options) { _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator)); @@ -50,193 +49,13 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure protected override void OnModelCreating(ModelBuilder modelBuilder) { - - modelBuilder.Entity(ConfigureRequests); - modelBuilder.Entity(ConfigurePayment); - modelBuilder.Entity(ConfigureOrder); - modelBuilder.Entity(ConfigureOrderItems); - modelBuilder.Entity(ConfigureCardTypes); - modelBuilder.Entity(ConfigureOrderStatus); - modelBuilder.Entity(ConfigureBuyer); - } - - private void ConfigureRequests(EntityTypeBuilder requestConfiguration) - { - requestConfiguration.ToTable("requests", DEFAULT_SCHEMA); - requestConfiguration.HasKey(cr => cr.Id); - requestConfiguration.Property(cr => cr.Name).IsRequired(); - requestConfiguration.Property(cr => cr.Time).IsRequired(); - } - - - void ConfigureBuyer(EntityTypeBuilder buyerConfiguration) - { - buyerConfiguration.ToTable("buyers", DEFAULT_SCHEMA); - - buyerConfiguration.HasKey(b => b.Id); - - buyerConfiguration.Ignore(b => b.DomainEvents); - - buyerConfiguration.Property(b => b.Id) - .ForSqlServerUseSequenceHiLo("buyerseq", DEFAULT_SCHEMA); - - buyerConfiguration.Property(b=>b.IdentityGuid) - .HasMaxLength(200) - .IsRequired(); - - buyerConfiguration.HasIndex("IdentityGuid") - .IsUnique(true); - - buyerConfiguration.HasMany(b => b.PaymentMethods) - .WithOne() - .HasForeignKey("BuyerId") - .OnDelete(DeleteBehavior.Cascade); - - var navigation = buyerConfiguration.Metadata.FindNavigation(nameof(Buyer.PaymentMethods)); - - navigation.SetPropertyAccessMode(PropertyAccessMode.Field); - } - - void ConfigurePayment(EntityTypeBuilder paymentConfiguration) - { - paymentConfiguration.ToTable("paymentmethods", DEFAULT_SCHEMA); - - paymentConfiguration.HasKey(b => b.Id); - - paymentConfiguration.Ignore(b => b.DomainEvents); - - paymentConfiguration.Property(b => b.Id) - .ForSqlServerUseSequenceHiLo("paymentseq", DEFAULT_SCHEMA); - - paymentConfiguration.Property("BuyerId") - .IsRequired(); - - paymentConfiguration.Property("CardHolderName") - .HasMaxLength(200) - .IsRequired(); - - paymentConfiguration.Property("Alias") - .HasMaxLength(200) - .IsRequired(); - - paymentConfiguration.Property("CardNumber") - .HasMaxLength(25) - .IsRequired(); - - paymentConfiguration.Property("Expiration") - .IsRequired(); - - paymentConfiguration.Property("CardTypeId") - .IsRequired(); - - paymentConfiguration.HasOne(p => p.CardType) - .WithMany() - .HasForeignKey("CardTypeId"); - } - - void ConfigureOrder(EntityTypeBuilder orderConfiguration) - { - orderConfiguration.ToTable("orders", DEFAULT_SCHEMA); - - orderConfiguration.HasKey(o => o.Id); - - orderConfiguration.Ignore(b => b.DomainEvents); - - orderConfiguration.Property(o => o.Id) - .ForSqlServerUseSequenceHiLo("orderseq", DEFAULT_SCHEMA); - - orderConfiguration.OwnsOne(o => o.Address); - - 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") - .IsRequired(false) - .OnDelete(DeleteBehavior.Restrict); - - orderConfiguration.HasOne() - .WithMany() - .IsRequired(false) - .HasForeignKey("BuyerId"); - - orderConfiguration.HasOne(o => o.OrderStatus) - .WithMany() - .HasForeignKey("OrderStatusId"); - } - - void ConfigureOrderItems(EntityTypeBuilder orderItemConfiguration) - { - orderItemConfiguration.ToTable("orderItems", DEFAULT_SCHEMA); - - orderItemConfiguration.HasKey(o => o.Id); - - orderItemConfiguration.Ignore(b => b.DomainEvents); - - orderItemConfiguration.Property(o => o.Id) - .ForSqlServerUseSequenceHiLo("orderitemseq"); - - orderItemConfiguration.Property("OrderId") - .IsRequired(); - - orderItemConfiguration.Property("Discount") - .IsRequired(); - - orderItemConfiguration.Property("ProductId") - .IsRequired(); - - orderItemConfiguration.Property("ProductName") - .IsRequired(); - - orderItemConfiguration.Property("UnitPrice") - .IsRequired(); - - orderItemConfiguration.Property("Units") - .IsRequired(); - - orderItemConfiguration.Property("PictureUrl") - .IsRequired(false); - } - - void ConfigureOrderStatus(EntityTypeBuilder orderStatusConfiguration) - { - orderStatusConfiguration.ToTable("orderstatus", DEFAULT_SCHEMA); - - orderStatusConfiguration.HasKey(o => o.Id); - - orderStatusConfiguration.Property(o => o.Id) - .HasDefaultValue(1) - .ValueGeneratedNever() - .IsRequired(); - - orderStatusConfiguration.Property(o => o.Name) - .HasMaxLength(200) - .IsRequired(); - } - - void ConfigureCardTypes(EntityTypeBuilder cardTypesConfiguration) - { - cardTypesConfiguration.ToTable("cardtypes", DEFAULT_SCHEMA); - - cardTypesConfiguration.HasKey(ct => ct.Id); - - cardTypesConfiguration.Property(ct => ct.Id) - .HasDefaultValue(1) - .ValueGeneratedNever() - .IsRequired(); - - cardTypesConfiguration.Property(ct => ct.Name) - .HasMaxLength(200) - .IsRequired(); + modelBuilder.ApplyConfiguration(new ClientRequestEntityTypeConfiguration()); + modelBuilder.ApplyConfiguration(new PaymentMethodEntityTypeConfiguration()); + modelBuilder.ApplyConfiguration(new OrderEntityTypeConfiguration()); + modelBuilder.ApplyConfiguration(new OrderItemEntityTypeConfiguration()); + modelBuilder.ApplyConfiguration(new CardTypeEntityTypeConfiguration()); + modelBuilder.ApplyConfiguration(new OrderStatusEntityTypeConfiguration()); + modelBuilder.ApplyConfiguration(new BuyerEntityTypeConfiguration()); } public async Task SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken)) From 8dd071ba83bc36c54154de18d5d7d4a9257d92fd Mon Sep 17 00:00:00 2001 From: Christian Arenas Date: Fri, 1 Sep 2017 14:17:51 +0200 Subject: [PATCH 56/86] Refactor global variables --- .../LoadTest/Basket.API/AddBasket.webtest | 30 ++++----- .../LoadTest/Basket.API/Checkout.webtest | 46 +++++++------ .../LoadTest/Basket.API/DeleteBasket.webtest | 43 +++++++------ .../LoadTest/Basket.API/GetBasket.webtest | 43 +++++++------ .../CreateOrUpdateUserLocation.webtest | 42 ++++++------ .../Location.API/GetAllLocations.webtest | 42 ++++++------ .../LoadTest/Location.API/GetLocation.webtest | 40 +++++++----- .../Location.API/GetUserLocation.webtest | 43 +++++++------ .../Marketing.API/GetAllCampaigns.webtest | 13 ++-- .../Marketing.API/GetCampaign.webtest | 13 ++-- .../Marketing.API/GetUserCampaigns.webtest | 13 ++-- .../LoadTest/Ordering.API/CancelOrder.webtest | 13 ++-- .../Ordering.API/GetAllOrders.webtest | 13 ++-- .../Ordering.API/GetCardTypes.webtest | 13 ++-- .../LoadTest/Ordering.API/GetOrder.webtest | 13 ++-- .../LoadTest/Ordering.API/ShipOrder.webtest | 13 ++-- .../LoadTest/WebMVC/AddProducts.webtest | 16 +++-- .../WebMVC/AddProductsWithLogin.webtest | 45 +++++++------ .../LoadTest/WebMVC/CatalogFilter.webtest | 52 ++++++++------- .../LoadTest/WebMVC/CreateNewOrder.webtest | 64 ++++++++++--------- .../LoadTest/WebMVC/LoginAndLogout.webtest | 40 ++++++------ test/Services/LoadTest/app.config | 4 +- 22 files changed, 356 insertions(+), 298 deletions(-) diff --git a/test/Services/LoadTest/Basket.API/AddBasket.webtest b/test/Services/LoadTest/Basket.API/AddBasket.webtest index 9ad6d5a6e..fc4af448a 100644 --- a/test/Services/LoadTest/Basket.API/AddBasket.webtest +++ b/test/Services/LoadTest/Basket.API/AddBasket.webtest @@ -1,7 +1,7 @@ - + - +
@@ -27,9 +27,9 @@ - + -
+
@@ -40,10 +40,10 @@ - + - + @@ -52,7 +52,7 @@ -
+
@@ -70,23 +70,21 @@
- ewAiAEIAdQB5AGUAcgBJAGQAIgA6ACIAYQBjADEAMAAwAGYAZgBjAC0AOABmADAANwAtADQAMQAzADAALQBhADMAZgA0AC0AMAA2AGYAOQBlADEAZQA4ADkANABhADQAIgB9AA== + ewAiAEIAdQB5AGUAcgBJAGQAIgA6ACIAewB7AEwAbwBjAGEAbABUAGUAcwB0AFMAZQB0AHQAaQBuAGcAcwAuAFUAcwBlAHIALgBpAGQAfQB9ACIAfQA= - - - - - + + + + + + - - - diff --git a/test/Services/LoadTest/Basket.API/Checkout.webtest b/test/Services/LoadTest/Basket.API/Checkout.webtest index a12e46e6d..d9357ce04 100644 --- a/test/Services/LoadTest/Basket.API/Checkout.webtest +++ b/test/Services/LoadTest/Basket.API/Checkout.webtest @@ -1,9 +1,9 @@  - + -
+
@@ -27,9 +27,9 @@ - + -
+
@@ -40,19 +40,19 @@ - + - - - + + + - + -
+
@@ -65,24 +65,28 @@ - +
-
+
ewAiAEMAaQB0AHkAIgA6ACIAYwBpAHQAeQAiACwAIgBTAHQAcgBlAGUAdAAiADoAIgBzAHQAcgBlAGUAdAAiACwAIgBTAHQAYQB0AGUAIgA6ACIAcwB0AGEAdABlACIALAAiAEMAbwB1AG4AdAByAHkAIgA6ACIAYwBvAHUAdAByAHkAIgAsACIAWgBpAHAAQwBvAGQAZQAiADoAIgB6AGkAcABjAG8AZABlACIALAAiAEMAYQByAGQATgB1AG0AYgBlAHIAIgA6ACIAQwBhAHIAZABOAHUAbQBiAGUAcgAiACwAIgBDAGEAcgBkAEgAbwBsAGQAZQByAE4AYQBtAGUAIgA6ACIAQwBhAHIAZABIAG8AbABkAGUAcgBOAGEAbQBlACIALAAiAEMAYQByAGQARQB4AHAAaQByAGEAdABpAG8AbgAiADoAIgAyADAAMQA3AC0AMAA2AC0AMwAwAFQAMQAyADoAMgA1ADoAMwAxAC4AOAA3ADQANwAyADIANwBaACIALAAiAEMAYQByAGQAUwBlAGMAdQByAGkAdAB5AE4AdQBtAGIAZQByACIAOgAiADEAMgAzADQAIgAsACIAQwBhAHIAZABUAHkAcABlAEkAZAAiADoAMQAsACIAQgB1AHkAZQByACIAOgAiAEIAdQB5AGUAcgAiACwAIgBSAGUAcQB1AGUAcwB0AEkAZAAiADoAIgBlAGIAOAAwADAAMwA2ADQALQBiADQAZQAxAC0ANAA2AGUAYgAtADkAMgAzADUALQBlADgAYwA0ADcANAA3AGQAYQAyAGQANAAiAH0A - - - - - - - - - + + + + + + + + + + + + + diff --git a/test/Services/LoadTest/Basket.API/DeleteBasket.webtest b/test/Services/LoadTest/Basket.API/DeleteBasket.webtest index 38ffc4538..face3c799 100644 --- a/test/Services/LoadTest/Basket.API/DeleteBasket.webtest +++ b/test/Services/LoadTest/Basket.API/DeleteBasket.webtest @@ -1,9 +1,9 @@  - + -
+
@@ -27,9 +27,9 @@ - + -
+
@@ -40,19 +40,19 @@ - + - - - + + + - + -
+
@@ -65,22 +65,25 @@ - +
- - - - - - - - - + + + + + + + + + + + + diff --git a/test/Services/LoadTest/Basket.API/GetBasket.webtest b/test/Services/LoadTest/Basket.API/GetBasket.webtest index 881e94570..e7d6d08d7 100644 --- a/test/Services/LoadTest/Basket.API/GetBasket.webtest +++ b/test/Services/LoadTest/Basket.API/GetBasket.webtest @@ -1,9 +1,9 @@  - + -
+
@@ -27,9 +27,9 @@ - + -
+
@@ -40,19 +40,19 @@ - + - - - + + + - + -
+
@@ -65,22 +65,25 @@ - +
- - - - - - - - - + + + + + + + + + + + + diff --git a/test/Services/LoadTest/Location.API/CreateOrUpdateUserLocation.webtest b/test/Services/LoadTest/Location.API/CreateOrUpdateUserLocation.webtest index d95b56cf8..c5da33f35 100644 --- a/test/Services/LoadTest/Location.API/CreateOrUpdateUserLocation.webtest +++ b/test/Services/LoadTest/Location.API/CreateOrUpdateUserLocation.webtest @@ -1,9 +1,9 @@  - + -
+
@@ -27,9 +27,9 @@ - + -
+
@@ -40,19 +40,19 @@ - + - - - + + + - + -
+
@@ -65,7 +65,7 @@ - +
@@ -73,14 +73,18 @@ ewAiAEwAbwBuAGcAaQB0AHUAZABlACIAOgAtADEAMgAxAC4AMAA0ADAAMwA2ACwAIgBMAGEAdABpAHQAdQBkAGUAIgA6ADQAOAAuADAAOQAxADYAMwAxAH0A - - - - - - - - + + + + + + + + + + + + diff --git a/test/Services/LoadTest/Location.API/GetAllLocations.webtest b/test/Services/LoadTest/Location.API/GetAllLocations.webtest index 6900daf36..9c10c08c5 100644 --- a/test/Services/LoadTest/Location.API/GetAllLocations.webtest +++ b/test/Services/LoadTest/Location.API/GetAllLocations.webtest @@ -1,9 +1,9 @@  - + -
+
@@ -27,9 +27,9 @@ - + -
+
@@ -40,19 +40,19 @@ - + - - - + + + - + -
+
@@ -65,21 +65,25 @@ - +
- - - - - - - - + + + + + + + + + + + + diff --git a/test/Services/LoadTest/Location.API/GetLocation.webtest b/test/Services/LoadTest/Location.API/GetLocation.webtest index bcaa470d7..9f1019084 100644 --- a/test/Services/LoadTest/Location.API/GetLocation.webtest +++ b/test/Services/LoadTest/Location.API/GetLocation.webtest @@ -1,9 +1,9 @@  - + -
+
@@ -27,9 +27,9 @@ - + -
+
@@ -40,19 +40,19 @@ - + - - - + + + - + -
+
@@ -65,20 +65,26 @@ - +
+ + + + + + + + + + + + - - - - - - diff --git a/test/Services/LoadTest/Location.API/GetUserLocation.webtest b/test/Services/LoadTest/Location.API/GetUserLocation.webtest index 767580b71..7ab6c1dac 100644 --- a/test/Services/LoadTest/Location.API/GetUserLocation.webtest +++ b/test/Services/LoadTest/Location.API/GetUserLocation.webtest @@ -1,9 +1,9 @@  - + -
+
@@ -27,9 +27,9 @@ - + -
+
@@ -40,19 +40,19 @@ - + - - - + + + - + -
+
@@ -65,22 +65,25 @@ - +
- - - - - - - - - + + + + + + + + + + + + diff --git a/test/Services/LoadTest/Marketing.API/GetAllCampaigns.webtest b/test/Services/LoadTest/Marketing.API/GetAllCampaigns.webtest index 0f894fcc9..45fbbbd2f 100644 --- a/test/Services/LoadTest/Marketing.API/GetAllCampaigns.webtest +++ b/test/Services/LoadTest/Marketing.API/GetAllCampaigns.webtest @@ -1,7 +1,7 @@  - +
@@ -27,9 +27,9 @@ - + -
+
@@ -40,10 +40,10 @@ - + - + @@ -52,7 +52,7 @@ -
+
@@ -80,6 +80,7 @@ + diff --git a/test/Services/LoadTest/Marketing.API/GetCampaign.webtest b/test/Services/LoadTest/Marketing.API/GetCampaign.webtest index 62fd029db..c46c053b9 100644 --- a/test/Services/LoadTest/Marketing.API/GetCampaign.webtest +++ b/test/Services/LoadTest/Marketing.API/GetCampaign.webtest @@ -1,7 +1,7 @@  - +
@@ -27,9 +27,9 @@ - + -
+
@@ -40,10 +40,10 @@ - + - + @@ -52,7 +52,7 @@ -
+
@@ -80,6 +80,7 @@ + diff --git a/test/Services/LoadTest/Marketing.API/GetUserCampaigns.webtest b/test/Services/LoadTest/Marketing.API/GetUserCampaigns.webtest index beb5981e7..9d44c3aee 100644 --- a/test/Services/LoadTest/Marketing.API/GetUserCampaigns.webtest +++ b/test/Services/LoadTest/Marketing.API/GetUserCampaigns.webtest @@ -1,7 +1,7 @@  - +
@@ -27,9 +27,9 @@ - + -
+
@@ -40,10 +40,10 @@ - + - + @@ -52,7 +52,7 @@ -
+
@@ -80,6 +80,7 @@ + diff --git a/test/Services/LoadTest/Ordering.API/CancelOrder.webtest b/test/Services/LoadTest/Ordering.API/CancelOrder.webtest index ca87f175d..708b3b013 100644 --- a/test/Services/LoadTest/Ordering.API/CancelOrder.webtest +++ b/test/Services/LoadTest/Ordering.API/CancelOrder.webtest @@ -1,7 +1,7 @@  - +
@@ -27,9 +27,9 @@ - + -
+
@@ -40,10 +40,10 @@ - + - + @@ -52,7 +52,7 @@ -
+
@@ -83,6 +83,7 @@ + diff --git a/test/Services/LoadTest/Ordering.API/GetAllOrders.webtest b/test/Services/LoadTest/Ordering.API/GetAllOrders.webtest index 58c7016f3..765281042 100644 --- a/test/Services/LoadTest/Ordering.API/GetAllOrders.webtest +++ b/test/Services/LoadTest/Ordering.API/GetAllOrders.webtest @@ -1,7 +1,7 @@  - +
@@ -27,9 +27,9 @@ - + -
+
@@ -40,10 +40,10 @@ - + - + @@ -52,7 +52,7 @@ -
+
@@ -80,6 +80,7 @@ + diff --git a/test/Services/LoadTest/Ordering.API/GetCardTypes.webtest b/test/Services/LoadTest/Ordering.API/GetCardTypes.webtest index ac103ced3..28241f8a1 100644 --- a/test/Services/LoadTest/Ordering.API/GetCardTypes.webtest +++ b/test/Services/LoadTest/Ordering.API/GetCardTypes.webtest @@ -1,7 +1,7 @@  - +
@@ -27,9 +27,9 @@ - + -
+
@@ -40,10 +40,10 @@ - + - + @@ -52,7 +52,7 @@ -
+
@@ -80,6 +80,7 @@ + diff --git a/test/Services/LoadTest/Ordering.API/GetOrder.webtest b/test/Services/LoadTest/Ordering.API/GetOrder.webtest index 62c3d9b99..97a5556f6 100644 --- a/test/Services/LoadTest/Ordering.API/GetOrder.webtest +++ b/test/Services/LoadTest/Ordering.API/GetOrder.webtest @@ -1,7 +1,7 @@  - +
@@ -27,9 +27,9 @@ - + -
+
@@ -40,10 +40,10 @@ - + - + @@ -52,7 +52,7 @@ -
+
@@ -80,6 +80,7 @@ + diff --git a/test/Services/LoadTest/Ordering.API/ShipOrder.webtest b/test/Services/LoadTest/Ordering.API/ShipOrder.webtest index 6a424a4f5..c3104a744 100644 --- a/test/Services/LoadTest/Ordering.API/ShipOrder.webtest +++ b/test/Services/LoadTest/Ordering.API/ShipOrder.webtest @@ -1,7 +1,7 @@  - +
@@ -27,9 +27,9 @@ - + -
+
@@ -40,10 +40,10 @@ - + - + @@ -52,7 +52,7 @@ -
+
@@ -83,6 +83,7 @@ + diff --git a/test/Services/LoadTest/WebMVC/AddProducts.webtest b/test/Services/LoadTest/WebMVC/AddProducts.webtest index b92ac98c0..3305509ae 100644 --- a/test/Services/LoadTest/WebMVC/AddProducts.webtest +++ b/test/Services/LoadTest/WebMVC/AddProducts.webtest @@ -12,9 +12,9 @@ - + -
+
@@ -32,10 +32,16 @@ + + + + + + + + + - - - diff --git a/test/Services/LoadTest/WebMVC/AddProductsWithLogin.webtest b/test/Services/LoadTest/WebMVC/AddProductsWithLogin.webtest index 12df248d8..3b617826c 100644 --- a/test/Services/LoadTest/WebMVC/AddProductsWithLogin.webtest +++ b/test/Services/LoadTest/WebMVC/AddProductsWithLogin.webtest @@ -1,9 +1,10 @@ - +< +?xml version="1.0" encoding="utf-8"?> - + -
+
@@ -27,9 +28,9 @@ - + -
+
@@ -40,19 +41,19 @@ - + - - - + + + - + -
+
@@ -81,9 +82,9 @@ - + -
+
@@ -100,20 +101,26 @@ - + -
+
+ + + + + + + + + + - - - - diff --git a/test/Services/LoadTest/WebMVC/CatalogFilter.webtest b/test/Services/LoadTest/WebMVC/CatalogFilter.webtest index 5be4227b7..9f6583b50 100644 --- a/test/Services/LoadTest/WebMVC/CatalogFilter.webtest +++ b/test/Services/LoadTest/WebMVC/CatalogFilter.webtest @@ -1,9 +1,9 @@  - + -
+
@@ -27,9 +27,9 @@ - + -
+
@@ -40,19 +40,19 @@ - + - - - + + + - + -
+
@@ -70,9 +70,9 @@ - + -
+
@@ -104,9 +104,9 @@ - + -
+
@@ -138,9 +138,9 @@ - + -
+
@@ -151,21 +151,25 @@ - + -
+
- - - - - - + + + + + + + + + + diff --git a/test/Services/LoadTest/WebMVC/CreateNewOrder.webtest b/test/Services/LoadTest/WebMVC/CreateNewOrder.webtest index 7cf3b32d9..266fd63b4 100644 --- a/test/Services/LoadTest/WebMVC/CreateNewOrder.webtest +++ b/test/Services/LoadTest/WebMVC/CreateNewOrder.webtest @@ -1,9 +1,9 @@  - + -
+
@@ -27,9 +27,9 @@ - + -
+
@@ -40,19 +40,19 @@ - + - - - + + + - + -
+
@@ -70,9 +70,9 @@ - + -
+
@@ -87,9 +87,9 @@ - + -
+
@@ -118,9 +118,9 @@ - + -
+
@@ -210,9 +210,9 @@ - + -
+
@@ -234,31 +234,35 @@ - + -
+
- + -
+
- + -
+
- - - - - - + + + + + + + + + + diff --git a/test/Services/LoadTest/WebMVC/LoginAndLogout.webtest b/test/Services/LoadTest/WebMVC/LoginAndLogout.webtest index 09eb965c9..759b2e2fd 100644 --- a/test/Services/LoadTest/WebMVC/LoginAndLogout.webtest +++ b/test/Services/LoadTest/WebMVC/LoginAndLogout.webtest @@ -1,9 +1,9 @@  - + -
+
@@ -27,9 +27,9 @@ - + -
+
@@ -40,19 +40,19 @@ - + - - - + + + - + -
+
@@ -70,19 +70,23 @@ - + -
+
- - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/test/Services/LoadTest/app.config b/test/Services/LoadTest/app.config index 1a0e53942..5e1a9dbc8 100644 --- a/test/Services/LoadTest/app.config +++ b/test/Services/LoadTest/app.config @@ -8,11 +8,11 @@ - + - + \ No newline at end of file From cf7bbc804f52679c3584b89f6e7580dc82f860a9 Mon Sep 17 00:00:00 2001 From: Christian Arenas Date: Fri, 1 Sep 2017 15:10:20 +0200 Subject: [PATCH 57/86] Add logout at performance test --- .../LoadTest/Basket.API/AddBasket.webtest | 8 ++ .../LoadTest/Basket.API/Checkout.webtest | 8 ++ .../LoadTest/Basket.API/DeleteBasket.webtest | 8 ++ .../LoadTest/Basket.API/GetBasket.webtest | 8 ++ .../Login.webtest} | 10 +- .../LoadTest/Identity.API/Logout.webtest | 23 +++ test/Services/LoadTest/LoadTest.csproj | 11 +- .../CreateOrUpdateUserLocation.webtest | 8 ++ .../Location.API/GetAllLocations.webtest | 8 ++ .../LoadTest/Location.API/GetLocation.webtest | 8 ++ .../Location.API/GetUserLocation.webtest | 8 ++ .../Marketing.API/GetAllCampaigns.webtest | 8 ++ .../Marketing.API/GetCampaign.webtest | 8 ++ .../Marketing.API/GetUserCampaigns.webtest | 8 ++ .../LoadTest/Ordering.API/CancelOrder.webtest | 8 ++ .../Ordering.API/GetAllOrders.webtest | 8 ++ .../Ordering.API/GetCardTypes.webtest | 8 ++ .../LoadTest/Ordering.API/GetOrder.webtest | 8 ++ .../LoadTest/Ordering.API/ShipOrder.webtest | 8 ++ .../LoadTest/WebMVC/AddProducts.webtest | 72 ++++++++++ .../WebMVC/AddProductsWithLogin.webtest | 134 ------------------ 21 files changed, 231 insertions(+), 147 deletions(-) rename test/Services/LoadTest/{WebMVC/LoginAndLogout.webtest => Identity.API/Login.webtest} (90%) create mode 100644 test/Services/LoadTest/Identity.API/Logout.webtest delete mode 100644 test/Services/LoadTest/WebMVC/AddProductsWithLogin.webtest diff --git a/test/Services/LoadTest/Basket.API/AddBasket.webtest b/test/Services/LoadTest/Basket.API/AddBasket.webtest index fc4af448a..cb933b141 100644 --- a/test/Services/LoadTest/Basket.API/AddBasket.webtest +++ b/test/Services/LoadTest/Basket.API/AddBasket.webtest @@ -72,6 +72,14 @@ ewAiAEIAdQB5AGUAcgBJAGQAIgA6ACIAewB7AEwAbwBjAGEAbABUAGUAcwB0AFMAZQB0AHQAaQBuAGcAcwAuAFUAcwBlAHIALgBpAGQAfQB9ACIAfQA= + + +
+ + + + + diff --git a/test/Services/LoadTest/Basket.API/Checkout.webtest b/test/Services/LoadTest/Basket.API/Checkout.webtest index d9357ce04..168e6e422 100644 --- a/test/Services/LoadTest/Basket.API/Checkout.webtest +++ b/test/Services/LoadTest/Basket.API/Checkout.webtest @@ -73,6 +73,14 @@ ewAiAEMAaQB0AHkAIgA6ACIAYwBpAHQAeQAiACwAIgBTAHQAcgBlAGUAdAAiADoAIgBzAHQAcgBlAGUAdAAiACwAIgBTAHQAYQB0AGUAIgA6ACIAcwB0AGEAdABlACIALAAiAEMAbwB1AG4AdAByAHkAIgA6ACIAYwBvAHUAdAByAHkAIgAsACIAWgBpAHAAQwBvAGQAZQAiADoAIgB6AGkAcABjAG8AZABlACIALAAiAEMAYQByAGQATgB1AG0AYgBlAHIAIgA6ACIAQwBhAHIAZABOAHUAbQBiAGUAcgAiACwAIgBDAGEAcgBkAEgAbwBsAGQAZQByAE4AYQBtAGUAIgA6ACIAQwBhAHIAZABIAG8AbABkAGUAcgBOAGEAbQBlACIALAAiAEMAYQByAGQARQB4AHAAaQByAGEAdABpAG8AbgAiADoAIgAyADAAMQA3AC0AMAA2AC0AMwAwAFQAMQAyADoAMgA1ADoAMwAxAC4AOAA3ADQANwAyADIANwBaACIALAAiAEMAYQByAGQAUwBlAGMAdQByAGkAdAB5AE4AdQBtAGIAZQByACIAOgAiADEAMgAzADQAIgAsACIAQwBhAHIAZABUAHkAcABlAEkAZAAiADoAMQAsACIAQgB1AHkAZQByACIAOgAiAEIAdQB5AGUAcgAiACwAIgBSAGUAcQB1AGUAcwB0AEkAZAAiADoAIgBlAGIAOAAwADAAMwA2ADQALQBiADQAZQAxAC0ANAA2AGUAYgAtADkAMgAzADUALQBlADgAYwA0ADcANAA3AGQAYQAyAGQANAAiAH0A + + +
+ + + + + diff --git a/test/Services/LoadTest/Basket.API/DeleteBasket.webtest b/test/Services/LoadTest/Basket.API/DeleteBasket.webtest index face3c799..129f6c946 100644 --- a/test/Services/LoadTest/Basket.API/DeleteBasket.webtest +++ b/test/Services/LoadTest/Basket.API/DeleteBasket.webtest @@ -71,6 +71,14 @@
+ + +
+ + + + + diff --git a/test/Services/LoadTest/Basket.API/GetBasket.webtest b/test/Services/LoadTest/Basket.API/GetBasket.webtest index e7d6d08d7..061f0ecec 100644 --- a/test/Services/LoadTest/Basket.API/GetBasket.webtest +++ b/test/Services/LoadTest/Basket.API/GetBasket.webtest @@ -71,6 +71,14 @@
+ + +
+ + + + + diff --git a/test/Services/LoadTest/WebMVC/LoginAndLogout.webtest b/test/Services/LoadTest/Identity.API/Login.webtest similarity index 90% rename from test/Services/LoadTest/WebMVC/LoginAndLogout.webtest rename to test/Services/LoadTest/Identity.API/Login.webtest index 759b2e2fd..62c93eb66 100644 --- a/test/Services/LoadTest/WebMVC/LoginAndLogout.webtest +++ b/test/Services/LoadTest/Identity.API/Login.webtest @@ -1,5 +1,5 @@  - + @@ -70,14 +70,6 @@ - - -
- - - - - diff --git a/test/Services/LoadTest/Identity.API/Logout.webtest b/test/Services/LoadTest/Identity.API/Logout.webtest new file mode 100644 index 000000000..393952ab2 --- /dev/null +++ b/test/Services/LoadTest/Identity.API/Logout.webtest @@ -0,0 +1,23 @@ + + + + + +
+ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Services/LoadTest/LoadTest.csproj b/test/Services/LoadTest/LoadTest.csproj index 374492daa..3178554c1 100644 --- a/test/Services/LoadTest/LoadTest.csproj +++ b/test/Services/LoadTest/LoadTest.csproj @@ -88,6 +88,9 @@ PreserveNewest + + Always + Always @@ -127,18 +130,18 @@ Always - - Always - PreserveNewest - + PreserveNewest PreserveNewest + + Always + diff --git a/test/Services/LoadTest/Location.API/CreateOrUpdateUserLocation.webtest b/test/Services/LoadTest/Location.API/CreateOrUpdateUserLocation.webtest index c5da33f35..d5d1630ac 100644 --- a/test/Services/LoadTest/Location.API/CreateOrUpdateUserLocation.webtest +++ b/test/Services/LoadTest/Location.API/CreateOrUpdateUserLocation.webtest @@ -72,6 +72,14 @@ ewAiAEwAbwBuAGcAaQB0AHUAZABlACIAOgAtADEAMgAxAC4AMAA0ADAAMwA2ACwAIgBMAGEAdABpAHQAdQBkAGUAIgA6ADQAOAAuADAAOQAxADYAMwAxAH0A + + +
+ + + + + diff --git a/test/Services/LoadTest/Location.API/GetAllLocations.webtest b/test/Services/LoadTest/Location.API/GetAllLocations.webtest index 9c10c08c5..f0171aa26 100644 --- a/test/Services/LoadTest/Location.API/GetAllLocations.webtest +++ b/test/Services/LoadTest/Location.API/GetAllLocations.webtest @@ -71,6 +71,14 @@
+ + +
+ + + + + diff --git a/test/Services/LoadTest/Location.API/GetLocation.webtest b/test/Services/LoadTest/Location.API/GetLocation.webtest index 9f1019084..fb078c9a1 100644 --- a/test/Services/LoadTest/Location.API/GetLocation.webtest +++ b/test/Services/LoadTest/Location.API/GetLocation.webtest @@ -71,6 +71,14 @@
+ + +
+ + + + + diff --git a/test/Services/LoadTest/Location.API/GetUserLocation.webtest b/test/Services/LoadTest/Location.API/GetUserLocation.webtest index 7ab6c1dac..a60387329 100644 --- a/test/Services/LoadTest/Location.API/GetUserLocation.webtest +++ b/test/Services/LoadTest/Location.API/GetUserLocation.webtest @@ -71,6 +71,14 @@
+ + +
+ + + + + diff --git a/test/Services/LoadTest/Marketing.API/GetAllCampaigns.webtest b/test/Services/LoadTest/Marketing.API/GetAllCampaigns.webtest index 45fbbbd2f..cb5ac96b3 100644 --- a/test/Services/LoadTest/Marketing.API/GetAllCampaigns.webtest +++ b/test/Services/LoadTest/Marketing.API/GetAllCampaigns.webtest @@ -71,6 +71,14 @@
+ + +
+ + + + + diff --git a/test/Services/LoadTest/Marketing.API/GetCampaign.webtest b/test/Services/LoadTest/Marketing.API/GetCampaign.webtest index c46c053b9..d37f95364 100644 --- a/test/Services/LoadTest/Marketing.API/GetCampaign.webtest +++ b/test/Services/LoadTest/Marketing.API/GetCampaign.webtest @@ -71,6 +71,14 @@
+ + +
+ + + + + diff --git a/test/Services/LoadTest/Marketing.API/GetUserCampaigns.webtest b/test/Services/LoadTest/Marketing.API/GetUserCampaigns.webtest index 9d44c3aee..4b81e5de1 100644 --- a/test/Services/LoadTest/Marketing.API/GetUserCampaigns.webtest +++ b/test/Services/LoadTest/Marketing.API/GetUserCampaigns.webtest @@ -71,6 +71,14 @@
+ + +
+ + + + + diff --git a/test/Services/LoadTest/Ordering.API/CancelOrder.webtest b/test/Services/LoadTest/Ordering.API/CancelOrder.webtest index 708b3b013..efc3a69b0 100644 --- a/test/Services/LoadTest/Ordering.API/CancelOrder.webtest +++ b/test/Services/LoadTest/Ordering.API/CancelOrder.webtest @@ -73,6 +73,14 @@ ewAiAE8AcgBkAGUAcgBOAHUAbQBiAGUAcgAiADoAIAAxAH0A + + +
+ + + + + diff --git a/test/Services/LoadTest/Ordering.API/GetAllOrders.webtest b/test/Services/LoadTest/Ordering.API/GetAllOrders.webtest index 765281042..64a7c54e7 100644 --- a/test/Services/LoadTest/Ordering.API/GetAllOrders.webtest +++ b/test/Services/LoadTest/Ordering.API/GetAllOrders.webtest @@ -71,6 +71,14 @@
+ + +
+ + + + + diff --git a/test/Services/LoadTest/Ordering.API/GetCardTypes.webtest b/test/Services/LoadTest/Ordering.API/GetCardTypes.webtest index 28241f8a1..9548aef0c 100644 --- a/test/Services/LoadTest/Ordering.API/GetCardTypes.webtest +++ b/test/Services/LoadTest/Ordering.API/GetCardTypes.webtest @@ -71,6 +71,14 @@
+ + +
+ + + + + diff --git a/test/Services/LoadTest/Ordering.API/GetOrder.webtest b/test/Services/LoadTest/Ordering.API/GetOrder.webtest index 97a5556f6..5a94b203f 100644 --- a/test/Services/LoadTest/Ordering.API/GetOrder.webtest +++ b/test/Services/LoadTest/Ordering.API/GetOrder.webtest @@ -71,6 +71,14 @@
+ + +
+ + + + + diff --git a/test/Services/LoadTest/Ordering.API/ShipOrder.webtest b/test/Services/LoadTest/Ordering.API/ShipOrder.webtest index c3104a744..812371fc6 100644 --- a/test/Services/LoadTest/Ordering.API/ShipOrder.webtest +++ b/test/Services/LoadTest/Ordering.API/ShipOrder.webtest @@ -73,6 +73,14 @@ ewAiAE8AcgBkAGUAcgBOAHUAbQBiAGUAcgAiADoAIAAxAH0A + + +
+ + + + + diff --git a/test/Services/LoadTest/WebMVC/AddProducts.webtest b/test/Services/LoadTest/WebMVC/AddProducts.webtest index 3305509ae..b9217d6ff 100644 --- a/test/Services/LoadTest/WebMVC/AddProducts.webtest +++ b/test/Services/LoadTest/WebMVC/AddProducts.webtest @@ -1,6 +1,70 @@  + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + @@ -31,6 +95,14 @@ + + +
+ + + + + diff --git a/test/Services/LoadTest/WebMVC/AddProductsWithLogin.webtest b/test/Services/LoadTest/WebMVC/AddProductsWithLogin.webtest deleted file mode 100644 index 3b617826c..000000000 --- a/test/Services/LoadTest/WebMVC/AddProductsWithLogin.webtest +++ /dev/null @@ -1,134 +0,0 @@ -< -?xml version="1.0" encoding="utf-8"?> - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 7bf0fb8faa0a280591c496f3a5da55de61195ba4 Mon Sep 17 00:00:00 2001 From: Jorge Arteiro Date: Sat, 2 Sep 2017 15:44:38 +1000 Subject: [PATCH 58/86] Updated Docker image version to Sql Server RC2 --- k8s/sql-data.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/k8s/sql-data.yaml b/k8s/sql-data.yaml index 6edcd21bc..1e5f1371f 100644 --- a/k8s/sql-data.yaml +++ b/k8s/sql-data.yaml @@ -25,7 +25,7 @@ spec: spec: containers: - name: sql-data - image: microsoft/mssql-server-linux:ctp1-3 + image: microsoft/mssql-server-linux:rc2 env: - name: ACCEPT_EULA value: "Y" From 5b90e1efe405ee0b0931af5eef291431079bd89e Mon Sep 17 00:00:00 2001 From: Igor Sychev Date: Sat, 2 Sep 2017 14:14:33 +0300 Subject: [PATCH 59/86] Parallel dotnet build process. it's working 2m 24s instead of 3m 48s (sequential execution) theis only one problem... write-host not working inside the workflow --- cli-windows/build-bits.ps1 | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/cli-windows/build-bits.ps1 b/cli-windows/build-bits.ps1 index 272227b3d..4191515f6 100644 --- a/cli-windows/build-bits.ps1 +++ b/cli-windows/build-bits.ps1 @@ -8,6 +8,9 @@ if ([string]::IsNullOrEmpty($rootPath)) { } Write-Host "Root path used is $rootPath" -ForegroundColor Yellow +workflow BuildAndPublish { + param ([string] $rootPath + ) $projectPaths = @{Path="$rootPath\src\Web\WebMVC";Prj="WebMVC.csproj"}, @{Path="$rootPath\src\Web\WebSPA";Prj="WebSPA.csproj"}, @@ -21,19 +24,20 @@ $projectPaths = @{Path="$rootPath\src\Services\Payment\Payment.API";Prj="Payment.API.csproj"}, @{Path="$rootPath\src\Web\WebStatus";Prj="WebStatus.csproj"} -$projectPaths | foreach { - $projectPath = $_.Path - $projectFile = $_.Prj - $outPath = $_.Path + "\obj\Docker\publish" - $projectPathAndFile = "$projectPath\$projectFile" - Write-Host "Deleting old publish files in $outPath" -ForegroundColor Yellow - remove-item -path $outPath -Force -Recurse -ErrorAction SilentlyContinue - Write-Host "Publishing $projectPathAndFile to $outPath" -ForegroundColor Yellow - dotnet restore $projectPathAndFile - dotnet build $projectPathAndFile - dotnet publish $projectPathAndFile -o $outPath + foreach -parallel ($item in $projectPaths) { + $projectPath = $item.Path + $projectFile = $item.Prj + $outPath = $item.Path + "\obj\Docker\publish" + $projectPathAndFile = "$projectPath\$projectFile" + #Write-Host "Deleting old publish files in $outPath" -ForegroundColor Yellow + remove-item -path $outPath -Force -Recurse -ErrorAction SilentlyContinue + #Write-Host "Publishing $projectPathAndFile to $outPath" -ForegroundColor Yellow + dotnet build $projectPathAndFile + dotnet publish $projectPathAndFile -o $outPath + } } +BuildAndPublish $rootPath ######################################################################################## # Delete old eShop Docker images From c514c8c31d7285ae76d4fc4355c1836c8686be7b Mon Sep 17 00:00:00 2001 From: Igor Sychev Date: Sun, 3 Sep 2017 11:30:27 +0300 Subject: [PATCH 60/86] release publish configuration for win/mac, because for Linux it's already done --- cli-mac/build-bits.sh | 2 +- cli-windows/build-bits.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cli-mac/build-bits.sh b/cli-mac/build-bits.sh index 681c3605d..fdf61e359 100755 --- a/cli-mac/build-bits.sh +++ b/cli-mac/build-bits.sh @@ -25,7 +25,7 @@ do echo -e "\e[33m\tRestoring project" dotnet restore echo -e "\e[33m\tBuilding and publishing projects" - dotnet publish -o obj/Docker/publish + dotnet publish -o obj/Docker/publish -c Release popd done diff --git a/cli-windows/build-bits.ps1 b/cli-windows/build-bits.ps1 index 272227b3d..f74a00bfa 100644 --- a/cli-windows/build-bits.ps1 +++ b/cli-windows/build-bits.ps1 @@ -31,7 +31,7 @@ $projectPaths | foreach { Write-Host "Publishing $projectPathAndFile to $outPath" -ForegroundColor Yellow dotnet restore $projectPathAndFile dotnet build $projectPathAndFile - dotnet publish $projectPathAndFile -o $outPath + dotnet publish $projectPathAndFile -o $outPath -c Release } From 34a08fb7cbe887450e965e129c8726aa3c2cb523 Mon Sep 17 00:00:00 2001 From: Igor Sychev Date: Sun, 3 Sep 2017 11:50:43 +0300 Subject: [PATCH 61/86] k8 readme fix. --- k8s/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/k8s/readme.md b/k8s/readme.md index 680652e35..43534d32e 100644 --- a/k8s/readme.md +++ b/k8s/readme.md @@ -9,4 +9,4 @@ Refer to file [README.k8s.md](./README.k8s.md) for detailed information Refer to file [README.CICD.k8s.md](./README.CICD.k8s.md) for information about how to set a VSTS build for deploying on k8s -Refer to file [conf-files.md](./conf-files.md) for a brief descriptio of every YAML file in this folder \ No newline at end of file +Refer to file [conf-files.md](./conf-files.md) for a brief description of every YAML file in this folder \ No newline at end of file From c722d4907bcc1bee85f4507369f17e26111a7bfc Mon Sep 17 00:00:00 2001 From: jacano Date: Mon, 4 Sep 2017 12:42:31 +0200 Subject: [PATCH 62/86] project.json removed from core --- .../eShopOnContainers.Core/project.json | 24 ------------------- 1 file changed, 24 deletions(-) delete mode 100755 src/Mobile/eShopOnContainers/eShopOnContainers.Core/project.json diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/project.json b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/project.json deleted file mode 100755 index a832cc982..000000000 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/project.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "dependencies": { - "Acr.UserDialogs": "6.3.3", - "Autofac": "4.5.0", - "IdentityModel": "1.3.1", - "Microsoft.Bcl": "1.1.10", - "Microsoft.Bcl.Build": "1.0.21", - "Microsoft.Net.Http": "2.2.29", - "modernhttpclient": "2.4.2", - "Newtonsoft.Json": "9.0.1", - "PCLCrypto": "2.0.147", - "SlideOverKit": "2.1.4", - "Splat": "1.6.2", - "System.ComponentModel.Annotations": "4.3.0", - "Xam.Plugin.Geolocator": "3.0.4", - "Xam.Plugins.Settings": "2.6.0.12-beta", - "Xamarin.FFImageLoading": "2.2.9", - "Xamarin.FFImageLoading.Forms": "2.2.9", - "Xamarin.Forms": "2.3.4.231" - }, - "frameworks": { - ".NETPortable,Version=v4.5,Profile=Profile111": {} - } -} \ No newline at end of file From 6515a3b58fcfbccc7fad502ce18d49a5048943bc Mon Sep 17 00:00:00 2001 From: jacano Date: Mon, 4 Sep 2017 12:32:46 +0200 Subject: [PATCH 63/86] update sdk to 2.0.2 --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index bfd985e30..dfad1f9f9 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version":"2.0.0" + "version":"2.0.2" } } \ No newline at end of file From f01431407a64fc13706846630807c3930b8a8034 Mon Sep 17 00:00:00 2001 From: jacano Date: Mon, 4 Sep 2017 12:28:21 +0200 Subject: [PATCH 64/86] UWP in netstandard 2 --- ...ShopOnContainers.TestRunner.Windows.csproj | 20 ++++--- .../project.json | 18 ------- .../eShopOnContainers.Windows.csproj | 53 +++++++++++++++---- .../eShopOnContainers.Windows/project.json | 26 --------- 4 files changed, 58 insertions(+), 59 deletions(-) delete mode 100755 src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Windows/project.json delete mode 100644 src/Mobile/eShopOnContainers/eShopOnContainers.Windows/project.json diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Windows/eShopOnContainers.TestRunner.Windows.csproj b/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Windows/eShopOnContainers.TestRunner.Windows.csproj index 61229f89a..2e01e5b11 100755 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Windows/eShopOnContainers.TestRunner.Windows.csproj +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Windows/eShopOnContainers.TestRunner.Windows.csproj @@ -11,13 +11,14 @@ eShopOnContainers.TestRunner.Windows en-US UAP - 10.0.14393.0 - 10.0.10586.0 + 10.0.16267.0 + 10.0.16267.0 14 512 {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} true eShopOnContainers.TestRunner.Windows_TemporaryKey.pfx + win10-arm;win10-arm-aot;win10-x86;win10-x86-aot;win10-x64;win10-x64-aot true @@ -88,10 +89,6 @@ true true - - - - App.xaml @@ -130,6 +127,17 @@ eShopOnContainers.UnitTests + + + 6.0.0-preview1-25611-03 + + + 2.3.4.231 + + + 2.1.0 + + 14.0 diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Windows/project.json b/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Windows/project.json deleted file mode 100755 index f32fb6319..000000000 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Windows/project.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "dependencies": { - "Microsoft.NETCore.UniversalWindowsPlatform": "5.3.3", - "Xamarin.Forms": "2.3.4.231", - "xunit.runner.devices": "2.1.0" - }, - "frameworks": { - "uap10.0": {} - }, - "runtimes": { - "win10-arm": {}, - "win10-arm-aot": {}, - "win10-x86": {}, - "win10-x86-aot": {}, - "win10-x64": {}, - "win10-x64-aot": {} - } -} \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Windows/eShopOnContainers.Windows.csproj b/src/Mobile/eShopOnContainers/eShopOnContainers.Windows/eShopOnContainers.Windows.csproj index 342acf6b2..5f9a72577 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Windows/eShopOnContainers.Windows.csproj +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Windows/eShopOnContainers.Windows.csproj @@ -11,14 +11,16 @@ eShopOnContainers.Windows en-US UAP - 10.0.10586.0 - 10.0.10586.0 + 10.0.16267.0 + 10.0.16267.0 14 true + true 512 {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} Windows_TemporaryKey.pfx true + win10-arm;win10-arm-aot;win10-x86;win10-x86-aot;win10-x64;win10-x64-aot true @@ -100,7 +102,6 @@ Assets\Fonts\SourceSansPro-Regular.ttf - @@ -171,18 +172,52 @@ Designer - - - Windows Mobile Extensions for the UWP - - {67f9d3a8-f71e-4428-913f-c37ae82cdb24} eShopOnContainers.Core - + + + 6.3.3 + + + 2.10.0 + + + 6.0.0-preview1-25611-03 + + + 10.0.3 + + + 2.0.147 + + + 2.1.4 + + + 3.0.4 + + + 2.6.0.12-beta + + + 2.2.9 + + + 2.2.9 + + + 2.3.4.231 + + + + + Windows Mobile Extensions for the UWP + + 14.0 diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Windows/project.json b/src/Mobile/eShopOnContainers/eShopOnContainers.Windows/project.json deleted file mode 100644 index faafe1f18..000000000 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Windows/project.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "dependencies": { - "Acr.UserDialogs": "6.3.3", - "IdentityModel": "1.3.1", - "Microsoft.NETCore.UniversalWindowsPlatform": "5.3.3", - "Newtonsoft.Json": "9.0.1", - "PCLCrypto": "2.0.147", - "SlideOverKit": "2.1.4", - "Xam.Plugin.Geolocator": "3.0.4", - "Xam.Plugins.Settings": "2.6.0.12-beta", - "Xamarin.FFImageLoading": "2.2.9", - "Xamarin.FFImageLoading.Forms": "2.2.9", - "Xamarin.Forms": "2.3.4.231" - }, - "frameworks": { - "uap10.0": {} - }, - "runtimes": { - "win10-arm": {}, - "win10-arm-aot": {}, - "win10-x86": {}, - "win10-x86-aot": {}, - "win10-x64": {}, - "win10-x64-aot": {} - } -} \ No newline at end of file From d3aa16f27de1e2be6979fe4426d5fb01c4be10df Mon Sep 17 00:00:00 2001 From: jacano Date: Fri, 1 Sep 2017 19:27:20 +0200 Subject: [PATCH 65/86] UITest to package reference --- .../eShopOnContainers.UITests.csproj | 31 +++++-------------- 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.UITests/eShopOnContainers.UITests.csproj b/src/Mobile/eShopOnContainers/eShopOnContainers.UITests/eShopOnContainers.UITests.csproj index aa4f41fa2..faef9f61f 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.UITests/eShopOnContainers.UITests.csproj +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.UITests/eShopOnContainers.UITests.csproj @@ -28,32 +28,15 @@ false - - ..\..\..\..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll - False - - - ..\..\..\..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.interfaces.dll - False - - - ..\..\..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll - True - - - ..\..\..\..\packages\NUnitTestAdapter.2.0.0\lib\nunit.util.dll - False - - - ..\..\..\..\packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll - False - - - ..\..\..\..\packages\Xamarin.UITest.2.0.3\lib\Xamarin.UITest.dll - True - + + + + + + + From 208047c6ca73f3a074788c9cf951573de6a8d604 Mon Sep 17 00:00:00 2001 From: jacano Date: Fri, 1 Sep 2017 19:22:45 +0200 Subject: [PATCH 66/86] test runners updated --- .../eShopOnContainers.TestRunner.Droid.csproj | 226 +++--------------- .../eShopOnContainers.TestRunner.iOS.csproj | 148 ++---------- 2 files changed, 60 insertions(+), 314 deletions(-) diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Droid/eShopOnContainers.TestRunner.Droid.csproj b/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Droid/eShopOnContainers.TestRunner.Droid.csproj index 326158569..6cfb21aed 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Droid/eShopOnContainers.TestRunner.Droid.csproj +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Droid/eShopOnContainers.TestRunner.Droid.csproj @@ -45,174 +45,6 @@ 4 False - - - ..\..\..\..\packages\Xamarin.Forms.2.3.4.231\lib\MonoAndroid10\FormsViewGroup.dll - - - - - ..\..\..\..\packages\PCLCrypto.2.0.147\lib\MonoAndroid23\PCLCrypto.dll - - - ..\..\..\..\packages\PInvoke.BCrypt.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.BCrypt.dll - - - ..\..\..\..\packages\PInvoke.Kernel32.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.Kernel32.dll - - - ..\..\..\..\packages\PInvoke.NCrypt.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.NCrypt.dll - - - ..\..\..\..\packages\PInvoke.Windows.Core.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.Windows.Core.dll - - - ..\..\..\..\packages\Plugin.CurrentActivity.1.0.1\lib\MonoAndroid10\Plugin.CurrentActivity.dll - - - ..\..\..\..\packages\Xam.Plugin.Geolocator.3.0.4\lib\MonoAndroid10\Plugin.Geolocator.dll - - - ..\..\..\..\packages\Xam.Plugin.Geolocator.3.0.4\lib\MonoAndroid10\Plugin.Geolocator.Abstractions.dll - - - ..\..\..\..\packages\Plugin.Permissions.1.1.7\lib\MonoAndroid10\Plugin.Permissions.dll - - - ..\..\..\..\packages\Plugin.Permissions.1.1.7\lib\MonoAndroid10\Plugin.Permissions.Abstractions.dll - - - - - ..\..\..\..\packages\Microsoft.Net.Http.2.2.29\lib\monoandroid\System.Net.Http.Extensions.dll - - - ..\..\..\..\packages\Microsoft.Net.Http.2.2.29\lib\monoandroid\System.Net.Http.Primitives.dll - - - - - ..\..\..\..\packages\Validation.2.2.8\lib\dotnet\Validation.dll - - - ..\..\..\..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.Animated.Vector.Drawable.dll - True - - - ..\..\..\..\packages\Xamarin.Android.Support.Design.23.3.0\lib\MonoAndroid43\Xamarin.Android.Support.Design.dll - True - - - ..\..\..\..\packages\Xamarin.Android.Support.v4.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v4.dll - True - - - ..\..\..\..\packages\Xamarin.Android.Support.v7.AppCompat.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.AppCompat.dll - True - - - ..\..\..\..\packages\Xamarin.Android.Support.v7.CardView.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.CardView.dll - True - - - ..\..\..\..\packages\Xamarin.Android.Support.v7.MediaRouter.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.MediaRouter.dll - True - - - ..\..\..\..\packages\Xamarin.Android.Support.v7.RecyclerView.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.RecyclerView.dll - True - - - ..\..\..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.Vector.Drawable.dll - True - - - ..\..\..\..\packages\Xamarin.Forms.2.3.4.231\lib\MonoAndroid10\Xamarin.Forms.Core.dll - - - ..\..\..\..\packages\Xamarin.Forms.2.3.4.231\lib\MonoAndroid10\Xamarin.Forms.Platform.dll - - - ..\..\..\..\packages\Xamarin.Forms.2.3.4.231\lib\MonoAndroid10\Xamarin.Forms.Platform.Android.dll - - - ..\..\..\..\packages\Xamarin.Forms.2.3.4.231\lib\MonoAndroid10\Xamarin.Forms.Xaml.dll - - - ..\..\..\..\packages\xunit.abstractions.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.abstractions.dll - - - ..\..\..\..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll - - - ..\..\..\..\packages\xunit.extensibility.execution.2.1.0\lib\monoandroid\xunit.execution.dotnet.dll - - - ..\..\..\..\packages\xunit.runner.utility.2.1.0\lib\dotnet\xunit.runner.utility.dotnet.dll - - - ..\..\..\..\packages\xunit.runner.devices.2.1.0\lib\MonoAndroid\xunit.runner.devices.dll - - - ..\..\..\..\packages\Newtonsoft.Json.9.0.1\lib\portable-net45+wp80+win8+wpa81\Newtonsoft.Json.dll - - - - - ..\..\..\..\packages\Autofac.4.5.0\lib\netstandard1.1\Autofac.dll - - - ..\..\..\..\packages\Xam.Plugins.Settings.2.6.0.12-beta\lib\MonoAndroid10\Plugin.Settings.Abstractions.dll - - - ..\..\..\..\packages\Xam.Plugins.Settings.2.6.0.12-beta\lib\MonoAndroid10\Plugin.Settings.dll - - - ..\..\..\..\packages\xunit.assert.2.2.0\lib\netstandard1.1\xunit.assert.dll - - - ..\..\..\..\packages\SlideOverKit.2.1.4\lib\MonoAndroid10\SlideOverKit.dll - - - ..\..\..\..\packages\SlideOverKit.2.1.4\lib\MonoAndroid10\SlideOverKit.Droid.dll - - - ..\..\..\..\packages\Acr.Support.2.1.0\lib\MonoAndroid10\Acr.Support.Android.dll - - - ..\..\..\..\packages\AndHUD.1.2.0\lib\MonoAndroid\AndHUD.dll - - - ..\..\..\..\packages\Splat.1.6.2\lib\monoandroid\Splat.dll - - - ..\..\..\..\packages\Acr.UserDialogs.6.3.3\lib\MonoAndroid10\Acr.UserDialogs.dll - - - ..\..\..\..\packages\Acr.UserDialogs.6.3.3\lib\MonoAndroid10\Acr.UserDialogs.Interface.dll - - - ..\..\..\..\packages\IdentityModel.1.3.1\lib\portable-net45+wp80+win8+wpa81\IdentityModel.Portable.dll - - - ..\..\..\..\packages\Xamarin.FFImageLoading.2.2.9\lib\MonoAndroid10\FFImageLoading.dll - - - ..\..\..\..\packages\Xamarin.FFImageLoading.2.2.9\lib\MonoAndroid10\FFImageLoading.Platform.dll - - - ..\..\..\..\packages\Xamarin.FFImageLoading.Forms.2.2.9\lib\MonoAndroid10\FFImageLoading.Forms.dll - - - ..\..\..\..\packages\Xamarin.FFImageLoading.Forms.2.2.9\lib\MonoAndroid10\FFImageLoading.Forms.Droid.dll - - - ..\..\..\..\packages\modernhttpclient.2.4.2\lib\MonoAndroid\ModernHttpClient.dll - - - ..\..\..\..\packages\modernhttpclient.2.4.2\lib\MonoAndroid\OkHttp.dll - - @@ -221,9 +53,6 @@ - - Designer - @@ -241,6 +70,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2.2.0 + + {f7b6a162-bc4d-4924-b16a-713f9b0344e7} @@ -248,22 +114,4 @@ - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - - \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.iOS/eShopOnContainers.TestRunner.iOS.csproj b/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.iOS/eShopOnContainers.TestRunner.iOS.csproj index 78410457a..6ff33a496 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.iOS/eShopOnContainers.TestRunner.iOS.csproj +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.iOS/eShopOnContainers.TestRunner.iOS.csproj @@ -106,129 +106,36 @@ - - - ..\..\..\..\packages\PCLCrypto.2.0.147\lib\xamarinios10\PCLCrypto.dll - - - ..\..\..\..\packages\PInvoke.BCrypt.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.BCrypt.dll - - - ..\..\..\..\packages\PInvoke.Kernel32.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.Kernel32.dll - - - ..\..\..\..\packages\PInvoke.NCrypt.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.NCrypt.dll - - - ..\..\..\..\packages\PInvoke.Windows.Core.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.Windows.Core.dll - + + + - - ..\..\..\..\packages\Microsoft.Net.Http.2.2.29\lib\Xamarin.iOS10\System.Net.Http.Extensions.dll - - - ..\..\..\..\packages\Microsoft.Net.Http.2.2.29\lib\Xamarin.iOS10\System.Net.Http.Primitives.dll - - - - ..\..\..\..\packages\Validation.2.2.8\lib\dotnet\Validation.dll - - - ..\..\..\..\packages\Xamarin.Forms.2.3.4.231\lib\Xamarin.iOS10\Xamarin.Forms.Core.dll - - - ..\..\..\..\packages\Xamarin.Forms.2.3.4.231\lib\Xamarin.iOS10\Xamarin.Forms.Platform.dll - - - ..\..\..\..\packages\Xamarin.Forms.2.3.4.231\lib\Xamarin.iOS10\Xamarin.Forms.Platform.iOS.dll - - - ..\..\..\..\packages\Xamarin.Forms.2.3.4.231\lib\Xamarin.iOS10\Xamarin.Forms.Xaml.dll - - - ..\..\..\..\packages\xunit.abstractions.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.abstractions.dll - - - ..\..\..\..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll - - - ..\..\..\..\packages\xunit.extensibility.execution.2.1.0\lib\xamarinios\xunit.execution.dotnet.dll - - - ..\..\..\..\packages\xunit.runner.utility.2.1.0\lib\dotnet\xunit.runner.utility.dotnet.dll - - - ..\..\..\..\packages\xunit.runner.devices.2.1.0\lib\Xamarin.iOS\xunit.runner.devices.dll - - - - - ..\..\..\..\packages\xunit.assert.2.2.0\lib\netstandard1.1\xunit.assert.dll - - - ..\..\..\..\packages\Newtonsoft.Json.9.0.1\lib\portable-net45+wp80+win8+wpa81\Newtonsoft.Json.dll - - - ..\..\..\..\packages\Autofac.4.5.0\lib\netstandard1.1\Autofac.dll - - - ..\..\..\..\packages\Xam.Plugins.Settings.2.6.0.12-beta\lib\Xamarin.iOS10\Plugin.Settings.Abstractions.dll - - - ..\..\..\..\packages\Xam.Plugins.Settings.2.6.0.12-beta\lib\Xamarin.iOS10\Plugin.Settings.dll - - - ..\..\..\..\packages\SlideOverKit.2.1.4\lib\Xamarin.iOS10\SlideOverKit.dll - - - ..\..\..\..\packages\SlideOverKit.2.1.4\lib\Xamarin.iOS10\SlideOverKit.iOS.dll - - - ..\..\..\..\packages\Acr.Support.2.1.0\lib\Xamarin.iOS10\Acr.Support.iOS.dll - - - ..\..\..\..\packages\Splat.1.6.2\lib\Xamarin.iOS10\Splat.dll - - - ..\..\..\..\packages\Acr.UserDialogs.6.3.3\lib\Xamarin.iOS10\Acr.UserDialogs.dll - - - ..\..\..\..\packages\Acr.UserDialogs.6.3.3\lib\Xamarin.iOS10\Acr.UserDialogs.Interface.dll - - - ..\..\..\..\packages\IdentityModel.1.3.1\lib\portable-net45+wp80+win8+wpa81\IdentityModel.Portable.dll - - - ..\..\..\..\packages\WebP.Touch.1.0.3\lib\Xamarin.iOS10\WebP.Touch.dll - - - ..\..\..\..\packages\Xamarin.FFImageLoading.2.2.9\lib\Xamarin.iOS10\FFImageLoading.dll - - - ..\..\..\..\packages\Xamarin.FFImageLoading.2.2.9\lib\Xamarin.iOS10\FFImageLoading.Platform.dll - - - ..\..\..\..\packages\Xamarin.FFImageLoading.Forms.2.2.9\lib\Xamarin.iOS10\FFImageLoading.Forms.dll - - - ..\..\..\..\packages\Xamarin.FFImageLoading.Forms.2.2.9\lib\Xamarin.iOS10\FFImageLoading.Forms.Touch.dll - - - ..\..\..\..\packages\modernhttpclient.2.4.2\lib\Xamarin.iOS10\ModernHttpClient.dll - - - ..\..\..\..\packages\Xam.Plugin.Geolocator.3.0.4\lib\Xamarin.iOS10\Plugin.Geolocator.Abstractions.dll - - - ..\..\..\..\packages\Xam.Plugin.Geolocator.3.0.4\lib\Xamarin.iOS10\Plugin.Geolocator.dll - - + + + + + + + + + + + + + + + + + + + 2.2.0 + @@ -237,13 +144,4 @@ - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - \ No newline at end of file From 41d9afb84df3a9b3dbbeb8e0cec88deb67edf945 Mon Sep 17 00:00:00 2001 From: jacano Date: Fri, 1 Sep 2017 19:05:05 +0200 Subject: [PATCH 67/86] Core, Android and iOS project updated to netstandard 2.0 --- .../eShopOnContainers.Core.csproj | 350 ++---------------- .../eShopOnContainers.Core.csproj.bak | 322 ++++++++++++++++ .../eShopOnContainers.Droid.csproj | 201 ++-------- .../{packages.config => packages.config.bak} | 0 .../eShopOnContainers.UnitTests.csproj | 75 +--- .../eShopOnContainers.UnitTests.csproj.bak | 71 ++++ .../eShopOnContainers.iOS.csproj | 137 +------ .../{packages.config => packages.config.bak} | 0 8 files changed, 484 insertions(+), 672 deletions(-) create mode 100644 src/Mobile/eShopOnContainers/eShopOnContainers.Core/eShopOnContainers.Core.csproj.bak rename src/Mobile/eShopOnContainers/eShopOnContainers.Droid/{packages.config => packages.config.bak} (100%) create mode 100644 src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/eShopOnContainers.UnitTests.csproj.bak rename src/Mobile/eShopOnContainers/eShopOnContainers.iOS/{packages.config => packages.config.bak} (100%) diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/eShopOnContainers.Core.csproj b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/eShopOnContainers.Core.csproj index 9b2619bc9..90c478422 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/eShopOnContainers.Core.csproj +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/eShopOnContainers.Core.csproj @@ -1,322 +1,34 @@ - - - + + - 10.0 - Debug - AnyCPU - {67F9D3A8-F71E-4428-913F-C37AE82CDB24} - Library - Properties - eShopOnContainers.Core - eShopOnContainers.Core - v4.5 - 512 - {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - - - Profile111 - - - true + netstandard2.0 + portable-net45+win8+wpa81+wp8 full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 + false - - - - - - - App.xaml - - - - - AddBasketButton.xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BasketView.xaml - - - CampaignView.xaml - - - CatalogView.xaml - - - CampaignDetailsView.xaml - - - CheckoutView.xaml - - - CustomNavigationView.xaml - - - FiltersView.xaml - - - LoginView.xaml - - - MainView.xaml - - - OrderDetailView.xaml - - - ProfileView.xaml - - - SettingsView.xaml - - - BasketItemTemplate.xaml - - - OrderItemTemplate.xaml - - - OrderTemplate.xaml - - - CampaignTemplate.xaml - - - ProductTemplate.xaml - - - - - - - - - - - - - - - Designer - MSBuild:UpdateDesignTimeXaml - - - Designer - MSBuild:UpdateDesignTimeXaml - - - Designer - MSBuild:UpdateDesignTimeXaml - - - Designer - MSBuild:UpdateDesignTimeXaml - - - Designer - MSBuild:UpdateDesignTimeXaml - - - - - Designer - MSBuild:UpdateDesignTimeXaml - - - - - Designer - MSBuild:UpdateDesignTimeXaml - - - - - Designer - MSBuild:UpdateDesignTimeXaml - - - - - Designer - MSBuild:UpdateDesignTimeXaml - - - - - Designer - MSBuild:UpdateDesignTimeXaml - - - - - Designer - MSBuild:UpdateDesignTimeXaml - - - - - Designer - MSBuild:UpdateDesignTimeXaml - - - - - Designer - MSBuild:UpdateDesignTimeXaml - - - - - Designer - MSBuild:UpdateDesignTimeXaml - - - - - Designer - MSBuild:UpdateDesignTimeXaml - - - - - Designer - MSBuild:UpdateDesignTimeXaml - - - - - MSBuild:UpdateDesignTimeXaml - Designer - - - - - MSBuild:UpdateDesignTimeXaml - Designer - - - - - MSBuild:UpdateDesignTimeXaml - Designer - - - - - - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/eShopOnContainers.Core.csproj.bak b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/eShopOnContainers.Core.csproj.bak new file mode 100644 index 000000000..9b2619bc9 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/eShopOnContainers.Core.csproj.bak @@ -0,0 +1,322 @@ + + + + + 10.0 + Debug + AnyCPU + {67F9D3A8-F71E-4428-913F-C37AE82CDB24} + Library + Properties + eShopOnContainers.Core + eShopOnContainers.Core + v4.5 + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + Profile111 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + App.xaml + + + + + AddBasketButton.xaml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BasketView.xaml + + + CampaignView.xaml + + + CatalogView.xaml + + + CampaignDetailsView.xaml + + + CheckoutView.xaml + + + CustomNavigationView.xaml + + + FiltersView.xaml + + + LoginView.xaml + + + MainView.xaml + + + OrderDetailView.xaml + + + ProfileView.xaml + + + SettingsView.xaml + + + BasketItemTemplate.xaml + + + OrderItemTemplate.xaml + + + OrderTemplate.xaml + + + CampaignTemplate.xaml + + + ProductTemplate.xaml + + + + + + + + + + + + + + + Designer + MSBuild:UpdateDesignTimeXaml + + + Designer + MSBuild:UpdateDesignTimeXaml + + + Designer + MSBuild:UpdateDesignTimeXaml + + + Designer + MSBuild:UpdateDesignTimeXaml + + + Designer + MSBuild:UpdateDesignTimeXaml + + + + + Designer + MSBuild:UpdateDesignTimeXaml + + + + + Designer + MSBuild:UpdateDesignTimeXaml + + + + + Designer + MSBuild:UpdateDesignTimeXaml + + + + + Designer + MSBuild:UpdateDesignTimeXaml + + + + + Designer + MSBuild:UpdateDesignTimeXaml + + + + + Designer + MSBuild:UpdateDesignTimeXaml + + + + + Designer + MSBuild:UpdateDesignTimeXaml + + + + + Designer + MSBuild:UpdateDesignTimeXaml + + + + + Designer + MSBuild:UpdateDesignTimeXaml + + + + + Designer + MSBuild:UpdateDesignTimeXaml + + + + + Designer + MSBuild:UpdateDesignTimeXaml + + + + + MSBuild:UpdateDesignTimeXaml + Designer + + + + + MSBuild:UpdateDesignTimeXaml + Designer + + + + + MSBuild:UpdateDesignTimeXaml + Designer + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Droid/eShopOnContainers.Droid.csproj b/src/Mobile/eShopOnContainers/eShopOnContainers.Droid/eShopOnContainers.Droid.csproj index 41c864d97..a96ca94ac 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Droid/eShopOnContainers.Droid.csproj +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Droid/eShopOnContainers.Droid.csproj @@ -54,170 +54,9 @@ SdkOnly - - ..\..\..\..\packages\Acr.Support.2.1.0\lib\MonoAndroid10\Acr.Support.Android.dll - True - - - ..\..\..\..\packages\Acr.UserDialogs.6.3.3\lib\MonoAndroid10\Acr.UserDialogs.dll - True - - - ..\..\..\..\packages\Acr.UserDialogs.6.3.3\lib\MonoAndroid10\Acr.UserDialogs.Interface.dll - True - - - ..\..\..\..\packages\AndHUD.1.2.0\lib\MonoAndroid\AndHUD.dll - True - - - ..\..\..\..\packages\Xamarin.FFImageLoading.2.2.9\lib\MonoAndroid10\FFImageLoading.dll - - - ..\..\..\..\packages\Xamarin.FFImageLoading.Forms.2.2.9\lib\MonoAndroid10\FFImageLoading.Forms.dll - - - ..\..\..\..\packages\Xamarin.FFImageLoading.Forms.2.2.9\lib\MonoAndroid10\FFImageLoading.Forms.Droid.dll - - - ..\..\..\..\packages\Xamarin.FFImageLoading.2.2.9\lib\MonoAndroid10\FFImageLoading.Platform.dll - - - ..\..\..\..\packages\IdentityModel.1.3.1\lib\portable-net45+wp80+win8+wpa81\IdentityModel.Portable.dll - True - - - - ..\..\..\..\packages\modernhttpclient.2.4.2\lib\MonoAndroid\ModernHttpClient.dll - True - - - ..\..\..\..\packages\Newtonsoft.Json.9.0.1\lib\portable-net45+wp80+win8+wpa81\Newtonsoft.Json.dll - - - ..\..\..\..\packages\modernhttpclient.2.4.2\lib\MonoAndroid\OkHttp.dll - True - - - ..\..\..\..\packages\PCLCrypto.2.0.147\lib\MonoAndroid23\PCLCrypto.dll - - - ..\..\..\..\packages\PInvoke.BCrypt.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.BCrypt.dll - - - ..\..\..\..\packages\PInvoke.Kernel32.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.Kernel32.dll - - - ..\..\..\..\packages\PInvoke.NCrypt.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.NCrypt.dll - - - ..\..\..\..\packages\PInvoke.Windows.Core.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.Windows.Core.dll - - - ..\..\..\..\packages\Plugin.CurrentActivity.1.0.1\lib\MonoAndroid10\Plugin.CurrentActivity.dll - - - ..\..\..\..\packages\Xam.Plugin.Geolocator.3.0.4\lib\MonoAndroid10\Plugin.Geolocator.dll - - - ..\..\..\..\packages\Xam.Plugin.Geolocator.3.0.4\lib\MonoAndroid10\Plugin.Geolocator.Abstractions.dll - - - ..\..\..\..\packages\Plugin.Permissions.1.1.7\lib\MonoAndroid10\Plugin.Permissions.dll - - - ..\..\..\..\packages\Plugin.Permissions.1.1.7\lib\MonoAndroid10\Plugin.Permissions.Abstractions.dll - - - ..\..\..\..\packages\Xam.Plugins.Settings.2.6.0.12-beta\lib\MonoAndroid10\Plugin.Settings.dll - True - - - ..\..\..\..\packages\Xam.Plugins.Settings.2.6.0.12-beta\lib\MonoAndroid10\Plugin.Settings.Abstractions.dll - True - - - ..\..\..\..\packages\SlideOverKit.2.1.4\lib\MonoAndroid10\SlideOverKit.dll - True - - - ..\..\..\..\packages\SlideOverKit.2.1.4\lib\MonoAndroid10\SlideOverKit.Droid.dll - True - - - ..\..\..\..\packages\Splat.1.6.2\lib\monoandroid\Splat.dll - True - - - - - ..\..\..\..\packages\Microsoft.Net.Http.2.2.29\lib\monoandroid\System.Net.Http.Extensions.dll - True - - - ..\..\..\..\packages\Microsoft.Net.Http.2.2.29\lib\monoandroid\System.Net.Http.Primitives.dll - True - - - - - - ..\..\..\..\packages\Validation.2.2.8\lib\dotnet\Validation.dll - - - ..\..\..\..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.Animated.Vector.Drawable.dll - True - - - ..\..\..\..\packages\Xamarin.Android.Support.Design.23.3.0\lib\MonoAndroid43\Xamarin.Android.Support.Design.dll - True - - - ..\..\..\..\packages\Xamarin.Android.Support.v4.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v4.dll - True - - - ..\..\..\..\packages\Xamarin.Android.Support.v7.AppCompat.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.AppCompat.dll - True - - - ..\..\..\..\packages\Xamarin.Android.Support.v7.CardView.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.CardView.dll - True - - - ..\..\..\..\packages\Xamarin.Android.Support.v7.MediaRouter.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.MediaRouter.dll - True - - - ..\..\..\..\packages\Xamarin.Android.Support.v7.RecyclerView.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.RecyclerView.dll - True - - - ..\..\..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.Vector.Drawable.dll - True - - - ..\..\..\..\packages\Xamarin.Forms.2.3.4.231\lib\MonoAndroid10\FormsViewGroup.dll - - - ..\..\..\..\packages\Xamarin.Forms.2.3.4.231\lib\MonoAndroid10\Xamarin.Forms.Core.dll - - - ..\..\..\..\packages\Xamarin.Forms.2.3.4.231\lib\MonoAndroid10\Xamarin.Forms.Platform.Android.dll - - - ..\..\..\..\packages\Xamarin.Forms.2.3.4.231\lib\MonoAndroid10\Xamarin.Forms.Platform.dll - - - ..\..\..\..\packages\Xamarin.Forms.2.3.4.231\lib\MonoAndroid10\Xamarin.Forms.Xaml.dll - - - - ..\..\..\..\packages\Autofac.4.5.0\lib\netstandard1.1\Autofac.dll - @@ -246,7 +85,6 @@ Assets\SourceSansPro-Regular.ttf - @@ -393,15 +231,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Droid/packages.config b/src/Mobile/eShopOnContainers/eShopOnContainers.Droid/packages.config.bak similarity index 100% rename from src/Mobile/eShopOnContainers/eShopOnContainers.Droid/packages.config rename to src/Mobile/eShopOnContainers/eShopOnContainers.Droid/packages.config.bak diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/eShopOnContainers.UnitTests.csproj b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/eShopOnContainers.UnitTests.csproj index fd8c23eca..757dc43e5 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/eShopOnContainers.UnitTests.csproj +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/eShopOnContainers.UnitTests.csproj @@ -1,71 +1,20 @@ - - - + + - 10.0 - Debug - AnyCPU - {F7B6A162-BC4D-4924-B16A-713F9B0344E7} - Library - Properties - eShopOnContainers.UnitTests - eShopOnContainers.UnitTests - es-ES - 512 - {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - v4.5 - Profile111 - - - true + netstandard2.0 + portable-net45+win8+wpa81+wp8 full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 + false + - - - - - - - - - - - - - - - - - + + + + - - {67f9d3a8-f71e-4428-913f-c37ae82cdb24} - eShopOnContainers.Core - + - - - - + \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/eShopOnContainers.UnitTests.csproj.bak b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/eShopOnContainers.UnitTests.csproj.bak new file mode 100644 index 000000000..fd8c23eca --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/eShopOnContainers.UnitTests.csproj.bak @@ -0,0 +1,71 @@ + + + + + 10.0 + Debug + AnyCPU + {F7B6A162-BC4D-4924-B16A-713F9B0344E7} + Library + Properties + eShopOnContainers.UnitTests + eShopOnContainers.UnitTests + es-ES + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + v4.5 + Profile111 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + {67f9d3a8-f71e-4428-913f-c37ae82cdb24} + eShopOnContainers.Core + + + + + + + \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.iOS/eShopOnContainers.iOS.csproj b/src/Mobile/eShopOnContainers/eShopOnContainers.iOS/eShopOnContainers.iOS.csproj index 205112e74..5cc36912e 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.iOS/eShopOnContainers.iOS.csproj +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.iOS/eShopOnContainers.iOS.csproj @@ -122,7 +122,6 @@ - @@ -132,118 +131,9 @@ - - ..\..\..\..\packages\Acr.Support.2.1.0\lib\Xamarin.iOS10\Acr.Support.iOS.dll - True - - - ..\..\..\..\packages\Acr.UserDialogs.6.3.3\lib\Xamarin.iOS10\Acr.UserDialogs.dll - True - - - ..\..\..\..\packages\Acr.UserDialogs.6.3.3\lib\Xamarin.iOS10\Acr.UserDialogs.Interface.dll - True - - - ..\..\..\..\packages\Xamarin.FFImageLoading.2.2.9\lib\Xamarin.iOS10\FFImageLoading.dll - - - ..\..\..\..\packages\Xamarin.FFImageLoading.Forms.2.2.9\lib\Xamarin.iOS10\FFImageLoading.Forms.dll - - - ..\..\..\..\packages\Xamarin.FFImageLoading.Forms.2.2.9\lib\Xamarin.iOS10\FFImageLoading.Forms.Touch.dll - - - ..\..\..\..\packages\Xamarin.FFImageLoading.2.2.9\lib\Xamarin.iOS10\FFImageLoading.Platform.dll - - - ..\..\..\..\packages\IdentityModel.1.3.1\lib\portable-net45+wp80+win8+wpa81\IdentityModel.Portable.dll - True - - - ..\..\..\..\packages\modernhttpclient.2.4.2\lib\Xamarin.iOS10\ModernHttpClient.dll - True - - - ..\..\..\..\packages\Newtonsoft.Json.9.0.1\lib\portable-net45+wp80+win8+wpa81\Newtonsoft.Json.dll - True - - - ..\..\..\..\packages\PCLCrypto.2.0.147\lib\xamarinios10\PCLCrypto.dll - - - ..\..\..\..\packages\PInvoke.BCrypt.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.BCrypt.dll - - - ..\..\..\..\packages\PInvoke.Kernel32.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.Kernel32.dll - - - ..\..\..\..\packages\PInvoke.NCrypt.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.NCrypt.dll - - - ..\..\..\..\packages\PInvoke.Windows.Core.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.Windows.Core.dll - - - ..\..\..\..\packages\Xam.Plugins.Settings.2.6.0.12-beta\lib\Xamarin.iOS10\Plugin.Settings.dll - True - - - ..\..\..\..\packages\Xam.Plugins.Settings.2.6.0.12-beta\lib\Xamarin.iOS10\Plugin.Settings.Abstractions.dll - True - - - ..\..\..\..\packages\SlideOverKit.2.1.4\lib\Xamarin.iOS10\SlideOverKit.dll - True - - - ..\..\..\..\packages\SlideOverKit.2.1.4\lib\Xamarin.iOS10\SlideOverKit.iOS.dll - True - - - ..\..\..\..\packages\Splat.1.6.2\lib\Xamarin.iOS10\Splat.dll - True - - - ..\..\..\..\packages\Microsoft.Net.Http.2.2.29\lib\Xamarin.iOS10\System.Net.Http.Extensions.dll - True - - - ..\..\..\..\packages\Microsoft.Net.Http.2.2.29\lib\Xamarin.iOS10\System.Net.Http.Primitives.dll - True - - - - ..\..\..\..\packages\Validation.2.2.8\lib\dotnet\Validation.dll - - - ..\..\..\..\packages\WebP.Touch.1.0.3\lib\Xamarin.iOS10\WebP.Touch.dll - - - - - ..\..\..\..\packages\Autofac.4.5.0\lib\netstandard1.1\Autofac.dll - - - ..\..\..\..\packages\Xamarin.Forms.2.3.4.231\lib\Xamarin.iOS10\Xamarin.Forms.Core.dll - - - ..\..\..\..\packages\Xamarin.Forms.2.3.4.231\lib\Xamarin.iOS10\Xamarin.Forms.Platform.dll - - - ..\..\..\..\packages\Xamarin.Forms.2.3.4.231\lib\Xamarin.iOS10\Xamarin.Forms.Platform.iOS.dll - - - ..\..\..\..\packages\Xamarin.Forms.2.3.4.231\lib\Xamarin.iOS10\Xamarin.Forms.Xaml.dll - - - ..\..\..\..\packages\Xam.Plugin.Geolocator.3.0.4\lib\Xamarin.iOS10\Plugin.Geolocator.Abstractions.dll - - - ..\..\..\..\packages\Xam.Plugin.Geolocator.3.0.4\lib\Xamarin.iOS10\Plugin.Geolocator.dll - @@ -436,13 +326,24 @@ + + + + + + + + + + + + + + + + + + + - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.iOS/packages.config b/src/Mobile/eShopOnContainers/eShopOnContainers.iOS/packages.config.bak similarity index 100% rename from src/Mobile/eShopOnContainers/eShopOnContainers.iOS/packages.config rename to src/Mobile/eShopOnContainers/eShopOnContainers.iOS/packages.config.bak From 8198126dafb363124be4ff974afeef34e20efee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Tom=C3=A0s?= Date: Mon, 4 Sep 2017 19:07:53 +0200 Subject: [PATCH 68/86] Use dotnet multi-architecture images. Removing docker-compose.windows.override (not needed as is identical to docker-compose.override) --- cli-windows/start-windows-containers.ps1 | 13 +- docker-compose-windows.override.yml | 163 ---------------- docker-compose-windows.yml | 64 ++++--- .../Basket/Basket.API/Dockerfile.nanowin | 8 - .../Catalog/Catalog.API/Dockerfile.nanowin | 8 - .../Identity/Identity.API/Dockerfile.nanowin | 8 - .../Location/Locations.API/Dockerfile.nanowin | 8 - .../Marketing.API/Dockerfile.nanowin | 8 - .../Ordering/Ordering.API/Dockerfile.nanowin | 8 - .../Payment/Payment.API/Dockerfile.nanowin | 8 - src/Web/WebMVC/Dockerfile.nanowin | 8 - src/Web/WebSPA/Dockerfile.nanowin | 8 - src/Web/WebSPA/package-lock.json | 176 +++++++++--------- src/Web/WebStatus/Dockerfile.nanowin | 8 - 14 files changed, 132 insertions(+), 364 deletions(-) delete mode 100644 docker-compose-windows.override.yml delete mode 100644 src/Services/Basket/Basket.API/Dockerfile.nanowin delete mode 100644 src/Services/Catalog/Catalog.API/Dockerfile.nanowin delete mode 100644 src/Services/Identity/Identity.API/Dockerfile.nanowin delete mode 100644 src/Services/Location/Locations.API/Dockerfile.nanowin delete mode 100644 src/Services/Marketing/Marketing.API/Dockerfile.nanowin delete mode 100644 src/Services/Ordering/Ordering.API/Dockerfile.nanowin delete mode 100644 src/Services/Payment/Payment.API/Dockerfile.nanowin delete mode 100644 src/Web/WebMVC/Dockerfile.nanowin delete mode 100644 src/Web/WebSPA/Dockerfile.nanowin delete mode 100644 src/Web/WebStatus/Dockerfile.nanowin diff --git a/cli-windows/start-windows-containers.ps1 b/cli-windows/start-windows-containers.ps1 index 300c63568..56b7a34e9 100644 --- a/cli-windows/start-windows-containers.ps1 +++ b/cli-windows/start-windows-containers.ps1 @@ -1,9 +1,16 @@ -Param([string] $rootPath) +Param( + [parameter(Mandatory=$false)][string] $rootPath, + [parameter(Mandatory=$false)][bool]$buildBits=$true +) + $scriptPath = Split-Path $script:MyInvocation.MyCommand.Path if ([string]::IsNullOrEmpty($rootPath)) { $rootPath = "$scriptPath\.." } Write-Host "Root path used is $rootPath" -ForegroundColor Yellow -& .\build-bits.ps1 -rootPath $rootPath -docker-compose -f "$rootPath\docker-compose-windows.yml" -f "$rootPath\docker-compose-windows.override.yml" up + +if ($buildBits) { + & $scriptPath\build-bits.ps1 -rootPath $rootPath +} +docker-compose -f "$rootPath\docker-compose-windows.yml" -f "$rootPath\docker-compose.override.yml" up diff --git a/docker-compose-windows.override.yml b/docker-compose-windows.override.yml deleted file mode 100644 index 6c791b1a6..000000000 --- a/docker-compose-windows.override.yml +++ /dev/null @@ -1,163 +0,0 @@ -version: '2.1' - -# 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: - - 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. - - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 - - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - - AzureServiceBusEnabled=False - ports: - - "5103:80" - - 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} - - 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} - - AzureStorageAccountKey=${ESHOP_AZURE_STORAGE_CATALOG_KEY} - - UseCustomizationData=True - - AzureServiceBusEnabled=False - - AzureStorageEnabled=False - ports: - - "5101:80" - - 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 #localhost do not work for UWP login, so we have to use "external" IP always - - ConnectionStrings__DefaultConnection=${ESHOP_AZURE_IDENTITY_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word} - - MvcClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5100 #Local: You need to open your local dev-machine firewall at range 5100-5110. - - 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 - - UseCustomizationData=True - ports: - - "5105:80" - - 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. - - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 - - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - - UseCustomizationData=True - - AzureServiceBusEnabled=False - ports: - - "5102:80" - - webspa: - environment: - - ASPNETCORE_ENVIRONMENT=Development - - ASPNETCORE_URLS=http://0.0.0.0:80 - - CatalogUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5101 - - OrderingUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5102 - - IdentityUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105. - - BasketUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5103 - - MarketingUrl=http://${ESHOP_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 - - UseCustomizationData=True - ports: - - "5104:80" - - webmvc: - environment: - - ASPNETCORE_ENVIRONMENT=Development - - ASPNETCORE_URLS=http://0.0.0.0:80 - - CatalogUrl=http://catalog.api - - OrderingUrl=http://ordering.api - - BasketUrl=http://basket.api - - IdentityUrl=http://10.0.75.1:5105 - - MarketingUrl=http://marketing.api #Local: Use 10.0.75.1 in a "Docker for Windows" environment, if using "localhost" from browser. - - UseCustomizationData=True #Remote: Use ${ESHOP_EXTERNAL_DNS_NAME_OR_IP} if using external IP or DNS name from browser. - ports: - - "5100:80" - - sql.data: - environment: - - SA_PASSWORD=Pass@word - - ACCEPT_EULA=Y - ports: - - "5433:1433" - - nosql.data: - ports: - - "27017:27017" - - locations.api: - environment: - - ASPNETCORE_ENVIRONMENT=Development - - ASPNETCORE_URLS=http://0.0.0.0:80 - - ConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosql.data} - - Database=LocationsDb - - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. - - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 - - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - - AzureServiceBusEnabled=False - ports: - - "5109:80" - - 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} - - 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. - - IdentityUrlExternal=http://${ESHOP_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/} - - AzureStorageAccountName=${ESHOP_AZURE_STORAGE_MARKETING_NAME} - - AzureStorageAccountKey=${ESHOP_AZURE_STORAGE_MARKETING_KEY} - - AzureServiceBusEnabled=False - - AzureStorageEnabled=False - ports: - - "5110:80" - - webstatus: - environment: - - ASPNETCORE_ENVIRONMENT=Development - - 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 - - mvc=http://webmvc/hc - - spa=http://webspa/hc - ports: - - "5107:80" - - payment.api: - environment: - - ASPNETCORE_ENVIRONMENT=Development - - ASPNETCORE_URLS=http://0.0.0.0:80 - - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - - AzureServiceBusEnabled=False - ports: - - "5108:80" \ No newline at end of file diff --git a/docker-compose-windows.yml b/docker-compose-windows.yml index 190b823b6..1a71968ba 100644 --- a/docker-compose-windows.yml +++ b/docker-compose-windows.yml @@ -5,7 +5,7 @@ services: image: eshop/basket.api-win:${TAG:-latest} build: context: ./src/Services/Basket/Basket.API - dockerfile: Dockerfile.nanowin + dockerfile: Dockerfile depends_on: - basket.data - identity.api @@ -15,7 +15,7 @@ services: image: eshop/catalog.api-win:${TAG:-latest} build: context: ./src/Services/Catalog/Catalog.API - dockerfile: Dockerfile.nanowin + dockerfile: Dockerfile depends_on: - sql.data - rabbitmq @@ -24,7 +24,7 @@ services: image: eshop/identity.api-win:${TAG:-latest} build: context: ./src/Services/Identity/Identity.API - dockerfile: Dockerfile.nanowin + dockerfile: Dockerfile depends_on: - sql.data @@ -32,25 +32,39 @@ services: image: eshop/ordering.api-win:${TAG:-latest} build: context: ./src/Services/Ordering/Ordering.API - dockerfile: Dockerfile.nanowin + dockerfile: Dockerfile depends_on: - sql.data - rabbitmq + marketing.api: + image: eshop/marketing.api:${TAG:-latest} + build: + context: ./src/Services/Marketing/Marketing.API + dockerfile: Dockerfile + depends_on: + - sql.data + - nosql.data + - identity.api + - rabbitmq + webspa: image: eshop/webspa-win:${TAG:-latest} build: context: ./src/Web/WebSPA - dockerfile: Dockerfile.nanowin + dockerfile: Dockerfile depends_on: + - catalog.api + - ordering.api - identity.api - basket.api + - marketing.api webmvc: image: eshop/webmvc-win:${TAG:-latest} build: context: ./src/Web/WebMVC - dockerfile: Dockerfile.nanowin + dockerfile: Dockerfile depends_on: - catalog.api - ordering.api @@ -62,26 +76,23 @@ services: image: eshop/webstatus:${TAG:-latest} build: context: ./src/Web/WebStatus - dockerfile: Dockerfile.nanowin + dockerfile: Dockerfile - locations.api: - image: eshop/locations.api:${TAG:-latest} + payment.api: + image: eshop/payment.api:${TAG:-latest} build: - context: ./src/Services/Location/Locations.API - dockerfile: Dockerfile.nanowin + context: ./src/Services/Payment/Payment.API + dockerfile: Dockerfile depends_on: - - nosql.data - - rabbitmq + - rabbitmq - marketing.api: - image: eshop/marketing.api:${TAG:-latest} + locations.api: + image: eshop/locations.api:${TAG:-latest} build: - context: ./src/Services/Marketing/Marketing.API - dockerfile: Dockerfile.nanowin + context: ./src/Services/Location/Locations.API + dockerfile: Dockerfile depends_on: - - sql.data - nosql.data - - identity.api - rabbitmq sql.data: @@ -94,7 +105,7 @@ services: image: redis:nanoserver # build: # context: ./_docker/redis -# dockerfile: Dockerfile.nanowin +# dockerfile: Dockerfile ports: - "6379:6379" @@ -102,17 +113,10 @@ services: image: spring2/rabbitmq # build: # context: ./_docker/rabbitmq -# dockerfile: Dockerfile.nanowin +# dockerfile: Dockerfile ports: - - "5672:5672" - - payment.api: - image: eshop/payment.api:${TAG:-latest} - build: - context: ./src/Services/Payment/Payment.API - dockerfile: Dockerfile.nanowin - depends_on: - - rabbitmq + - "15672:15672" + - "5672:5672" networks: default: diff --git a/src/Services/Basket/Basket.API/Dockerfile.nanowin b/src/Services/Basket/Basket.API/Dockerfile.nanowin deleted file mode 100644 index deab637ef..000000000 --- a/src/Services/Basket/Basket.API/Dockerfile.nanowin +++ /dev/null @@ -1,8 +0,0 @@ -FROM microsoft/dotnet:2.0-runtime-nanoserver -SHELL ["powershell"] -ARG source -WORKDIR /app -RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord -EXPOSE 80 -COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "Basket.API.dll"] diff --git a/src/Services/Catalog/Catalog.API/Dockerfile.nanowin b/src/Services/Catalog/Catalog.API/Dockerfile.nanowin deleted file mode 100644 index 68eb9262d..000000000 --- a/src/Services/Catalog/Catalog.API/Dockerfile.nanowin +++ /dev/null @@ -1,8 +0,0 @@ -FROM microsoft/dotnet:2.0-runtime-nanoserver -SHELL ["powershell"] -ARG source -WORKDIR /app -RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord -EXPOSE 80 -COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "Catalog.API.dll"] diff --git a/src/Services/Identity/Identity.API/Dockerfile.nanowin b/src/Services/Identity/Identity.API/Dockerfile.nanowin deleted file mode 100644 index 9d24ccf1a..000000000 --- a/src/Services/Identity/Identity.API/Dockerfile.nanowin +++ /dev/null @@ -1,8 +0,0 @@ -FROM microsoft/dotnet:1.1-runtime-nanoserver -SHELL ["powershell"] -ARG source -WORKDIR /app -RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord -EXPOSE 80 -COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "Identity.API.dll"] diff --git a/src/Services/Location/Locations.API/Dockerfile.nanowin b/src/Services/Location/Locations.API/Dockerfile.nanowin deleted file mode 100644 index 59fe001da..000000000 --- a/src/Services/Location/Locations.API/Dockerfile.nanowin +++ /dev/null @@ -1,8 +0,0 @@ -FROM microsoft/dotnet:2.0-runtime-nanoserver -SHELL ["powershell"] -ARG source -WORKDIR /app -RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord -EXPOSE 80 -COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "Locations.API.dll"] diff --git a/src/Services/Marketing/Marketing.API/Dockerfile.nanowin b/src/Services/Marketing/Marketing.API/Dockerfile.nanowin deleted file mode 100644 index 33bcd0e82..000000000 --- a/src/Services/Marketing/Marketing.API/Dockerfile.nanowin +++ /dev/null @@ -1,8 +0,0 @@ -FROM microsoft/dotnet:2.0-runtime-nanoserver -SHELL ["powershell"] -ARG source -WORKDIR /app -RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord -EXPOSE 80 -COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "Marketing.API.dll"] diff --git a/src/Services/Ordering/Ordering.API/Dockerfile.nanowin b/src/Services/Ordering/Ordering.API/Dockerfile.nanowin deleted file mode 100644 index c5dd08a2e..000000000 --- a/src/Services/Ordering/Ordering.API/Dockerfile.nanowin +++ /dev/null @@ -1,8 +0,0 @@ -FROM microsoft/dotnet:2.0-runtime-nanoserver -SHELL ["powershell"] -ARG source -WORKDIR /app -RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord -EXPOSE 80 -COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "Ordering.API.dll"] diff --git a/src/Services/Payment/Payment.API/Dockerfile.nanowin b/src/Services/Payment/Payment.API/Dockerfile.nanowin deleted file mode 100644 index c04327048..000000000 --- a/src/Services/Payment/Payment.API/Dockerfile.nanowin +++ /dev/null @@ -1,8 +0,0 @@ -FROM microsoft/dotnet:2.0-runtime-nanoserver -SHELL ["powershell"] -ARG source -WORKDIR /app -RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord -EXPOSE 80 -COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "Payment.API.dll"] diff --git a/src/Web/WebMVC/Dockerfile.nanowin b/src/Web/WebMVC/Dockerfile.nanowin deleted file mode 100644 index 739f27746..000000000 --- a/src/Web/WebMVC/Dockerfile.nanowin +++ /dev/null @@ -1,8 +0,0 @@ -FROM microsoft/dotnet:2.0-runtime-nanoserver -SHELL ["powershell"] -ARG source -WORKDIR /app -RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord -EXPOSE 80 -COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "WebMVC.dll"] diff --git a/src/Web/WebSPA/Dockerfile.nanowin b/src/Web/WebSPA/Dockerfile.nanowin deleted file mode 100644 index 7e678c9ac..000000000 --- a/src/Web/WebSPA/Dockerfile.nanowin +++ /dev/null @@ -1,8 +0,0 @@ -FROM microsoft/dotnet:2.0-runtime-nanoserver -SHELL ["powershell"] -ARG source -WORKDIR /app -RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord -EXPOSE 80 -COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "WebSPA.dll"] diff --git a/src/Web/WebSPA/package-lock.json b/src/Web/WebSPA/package-lock.json index 92ad21584..bc4b391e9 100644 --- a/src/Web/WebSPA/package-lock.json +++ b/src/Web/WebSPA/package-lock.json @@ -7,7 +7,7 @@ "@angular-devkit/build-optimizer": { "version": "0.0.13", "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.0.13.tgz", - "integrity": "sha512-yEMkYU4YU8XlA5OauPhg22ZEWJ4X2VhiFKUwfeo4UWJ7lz4XWiuBJocrT5NHWqI1S0rOLpSixLXG9byvFMbavA==", + "integrity": "sha1-zzl692q+iZqpCdSnNRBmlMofCM8=", "dev": true, "requires": { "loader-utils": "1.1.0", @@ -26,7 +26,7 @@ "@angular/cli": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-1.3.0.tgz", - "integrity": "sha512-Sv6Gly7yNPZtNEsJJegtHxUTrkrvl0IsDRVcALrBQzdMvMXRWOEhn1jrdOY5HtU9eFQ27sdqrwijUVrTabZubw==", + "integrity": "sha1-FA/mmFCKjAI7S32gHAzAY89xEBg=", "dev": true, "requires": { "@angular-devkit/build-optimizer": "0.0.13", @@ -261,7 +261,7 @@ "@ngtools/webpack": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-1.6.0.tgz", - "integrity": "sha512-qlY3Fj5ZJULIeFVvnnmzrKJCJnBkZ3rDf6ApaSc3uAAlhWjmBenUCJKlDQFTYZ6SuixmGYN3WTR5kGy6P7jZrA==", + "integrity": "sha1-YmLxECg/y/76KtRbx5wshVw5Y7s=", "dev": true, "requires": { "loader-utils": "1.1.0", @@ -290,7 +290,7 @@ "@types/node": { "version": "6.0.85", "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.85.tgz", - "integrity": "sha512-6qLZpfQFO/g5Ns2e7RsW6brk0Q6Xzwiw7kVVU/XiQNOiJXSojhX76GP457PBYIsNMH2WfcGgcnZB4awFDHrwpA==", + "integrity": "sha1-7AK/5UphBE8r5E8Ts4nGoOjuBa4=", "dev": true }, "@types/protractor": { @@ -327,7 +327,7 @@ "acorn": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.1.tgz", - "integrity": "sha512-vOk6uEMctu0vQrvuSqFdJyqj1Q0S5VTDL79qtjo+DhRr+1mmaD+tluFSCZqhvi/JUhXSzoZN2BhtstaPEeE8cw==", + "integrity": "sha1-U/4WERH5EquZnuiHqQoLxSgi/XU=", "dev": true }, "acorn-dynamic-import": { @@ -415,7 +415,7 @@ "anymatch": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", - "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "integrity": "sha1-VT3Lj5HjyImEXf26NMd3IbkLnXo=", "dev": true, "requires": { "micromatch": "2.3.11", @@ -425,7 +425,7 @@ "aproba": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.1.2.tgz", - "integrity": "sha512-ZpYajIfO0j2cOFTO955KUMIKNmj6zhX8kVztMAxFsDaMwz+9Z9SV0uou2pC9HJqcfpffOsjnbrDMvkNy+9RXPw==", + "integrity": "sha1-RcZikJTeTpb2k+9+q3SuB5wkD8E=", "dev": true }, "are-we-there-yet": { @@ -465,7 +465,7 @@ "readable-stream": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", "dev": true, "requires": { "core-util-is": "1.0.2", @@ -486,7 +486,7 @@ "string_decoder": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", "dev": true, "requires": { "safe-buffer": "5.1.1" @@ -521,7 +521,7 @@ "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", "dev": true }, "array-find-index": { @@ -601,7 +601,7 @@ "async": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", - "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", + "integrity": "sha1-hDGQ/WtzV6C54clW7d3V7IRitU0=", "dev": true, "requires": { "lodash": "4.17.4" @@ -775,7 +775,7 @@ "babylon": { "version": "6.17.4", "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.17.4.tgz", - "integrity": "sha512-kChlV+0SXkjE0vUn9OZ7pBMWRFd8uq3mZe8x1K6jhuNcAFAtEnjchFAqB+dYEXKyd+JpT6eppRR78QAr5gTsUw==", + "integrity": "sha1-Pot0AriNIsNCPhN6FXeIOxX/hpo=", "dev": true }, "balanced-match": { @@ -787,7 +787,7 @@ "base64-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz", - "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==", + "integrity": "sha1-qRlH2h9KUW6jjltOwOw3c2deCIY=", "dev": true }, "batch": { @@ -846,7 +846,7 @@ "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "integrity": "sha1-LN4J617jQfSEdGuwMJsyU7GxRC8=", "dev": true }, "bonjour": { @@ -1134,7 +1134,7 @@ "chalk": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", - "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "integrity": "sha1-rFvs8U+iG5nGySynp9fP1bF+dD4=", "dev": true, "requires": { "ansi-styles": "3.2.0", @@ -1145,7 +1145,7 @@ "ansi-styles": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "integrity": "sha1-wVm41b4PnlpvNG2rlPFs4CIWG4g=", "dev": true, "requires": { "color-convert": "1.9.0" @@ -1160,7 +1160,7 @@ "supports-color": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.2.1.tgz", - "integrity": "sha512-qxzYsob3yv6U+xMzPrv170y8AwGP7i74g+pbixCfD6rgso8BscLT2qXIuz6TpOaiJZ3mFgT5O9lyT9nMU4LfaA==", + "integrity": "sha1-ZaS7JjHpDgJCDbpVVMN1pHVLuDY=", "dev": true, "requires": { "has-flag": "2.0.0" @@ -1187,7 +1187,7 @@ "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "integrity": "sha1-h2Dk7MJy9MNjUy+SbYdKriwTl94=", "dev": true, "requires": { "inherits": "2.0.3", @@ -1501,7 +1501,7 @@ "commander": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", - "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "integrity": "sha1-FXFS/R56bI2YpbcVzzdt+SgARWM=", "dev": true }, "common-tags": { @@ -1623,7 +1623,7 @@ "cosmiconfig": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz", - "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", + "integrity": "sha1-YXPOvVb6wELB9DkO33r2wHx8uJI=", "dev": true, "requires": { "is-directory": "0.3.1", @@ -1747,7 +1747,7 @@ "crypto-browserify": { "version": "3.11.1", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.11.1.tgz", - "integrity": "sha512-Na7ZlwCOqoaW5RwUK1WpXws2kv8mNhWdTlzob0UXulk6G9BDbyiJaGTYBIX61Ozn9l1EPPJpICZb4DaOpT9NlQ==", + "integrity": "sha1-lIlF78Z1ekANbl5a9HGU0QBkJ58=", "dev": true, "requires": { "browserify-cipher": "1.0.0", @@ -2031,7 +2031,7 @@ "diff": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.0.tgz", - "integrity": "sha512-w0XZubFWn0Adlsapj9EAWX0FqWdO4tz8kc3RiYdWLh4k/V8PTb6i0SMgXt0vRM3zyKnT8tKO7mUlieRQHIjMNg==", + "integrity": "sha1-BWaVFQ16qTI3yn43isOxaCt5Y7k=", "dev": true }, "diffie-hellman": { @@ -2551,7 +2551,7 @@ "qs": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.0.tgz", - "integrity": "sha512-fjVFjW9yhqMhVGwRExCXLhJKrLlkYSaxNWdyc9rmHlrVZbk35YHH312dFd7191uQeXkI3mKLZTIbSvIeFwFemg==", + "integrity": "sha1-jQSVTTZN7z78VbWgeT4eLIsebkk=", "dev": true } } @@ -2711,7 +2711,7 @@ "finalhandler": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.4.tgz", - "integrity": "sha512-16l/r8RgzlXKmFOhZpHBztvye+lAhC5SU7hXavnerC9UfZqZxxXl3BzL8MhffPT3kF61lj9Oav2LKEzh0ei7tg==", + "integrity": "sha1-GFdPLnxLmLiuOyMMIfIB8xvbP7c=", "dev": true, "requires": { "debug": "2.6.8", @@ -3185,7 +3185,7 @@ "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", "dev": true, "requires": { "fs.realpath": "1.0.0", @@ -3236,7 +3236,7 @@ "globals": { "version": "9.18.0", "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo=", "dev": true }, "globby": { @@ -3378,7 +3378,7 @@ "hash.js": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "integrity": "sha1-NA3tvmKQGHFRweodd3o0SJNd+EY=", "dev": true, "requires": { "inherits": "2.0.3", @@ -3451,7 +3451,7 @@ "hosted-git-info": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", - "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", + "integrity": "sha1-bWDjSzq7yDEwYsO3mO+NkBoHrzw=", "dev": true }, "hpack.js": { @@ -3475,7 +3475,7 @@ "readable-stream": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", "dev": true, "requires": { "core-util-is": "1.0.2", @@ -3490,7 +3490,7 @@ "string_decoder": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", "dev": true, "requires": { "safe-buffer": "5.1.1" @@ -3513,7 +3513,7 @@ "html-minifier": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.3.tgz", - "integrity": "sha512-iKRzQQDuTCsq0Ultbi/mfJJnR0D3AdZKTq966Gsp92xkmAPCV4Xi08qhJ0Dl3ZAWemSgJ7qZK+UsZc0gFqK6wg==", + "integrity": "sha1-SideOxoWY5q7ebTBEZH/DQ/PGrk=", "dev": true, "requires": { "camel-case": "3.0.0", @@ -3655,7 +3655,7 @@ "iconv-lite": { "version": "0.4.18", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz", - "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==", + "integrity": "sha1-I9hlaxaq5nQqwpcy6o8DNqR4nPI=", "dev": true }, "icss-replace-symbols": { @@ -3682,7 +3682,7 @@ "postcss": { "version": "6.0.8", "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.8.tgz", - "integrity": "sha512-G6WnRmdTt2jvJvY+aY+M0AO4YlbxE+slKPZb+jG2P2U9Tyxi3h1fYZ/DgiFU6DC6bv3XIEJoZt+f/kNh8BrWFw==", + "integrity": "sha1-iQZ6nOixH4qEy8URfvwwQZoIV7M=", "dev": true, "requires": { "chalk": "2.1.0", @@ -3693,7 +3693,7 @@ "supports-color": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.2.1.tgz", - "integrity": "sha512-qxzYsob3yv6U+xMzPrv170y8AwGP7i74g+pbixCfD6rgso8BscLT2qXIuz6TpOaiJZ3mFgT5O9lyT9nMU4LfaA==", + "integrity": "sha1-ZaS7JjHpDgJCDbpVVMN1pHVLuDY=", "dev": true, "requires": { "has-flag": "2.0.0" @@ -3808,7 +3808,7 @@ "inquirer": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.2.1.tgz", - "integrity": "sha512-QgW3eiPN8gpj/K5vVpHADJJgrrF0ho/dZGylikGX7iqAdRgC9FVKYKWFLx6hZDBFcOLEoSqINYrVPeFAeG/PdA==", + "integrity": "sha1-Bs6w9UD0XKVIwX1oQJWYeCZfoXU=", "dev": true, "requires": { "ansi-escapes": "2.0.0", @@ -4027,7 +4027,7 @@ "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", "dev": true, "requires": { "isobject": "3.0.1" @@ -4188,7 +4188,7 @@ "istanbul-lib-coverage": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz", - "integrity": "sha512-0+1vDkmzxqJIn5rcoEqapSB4DmPxE31EtI2dF2aCkV5esN9EWHxZ0dwgDClivMXJqE7zaYQxq30hj5L0nlTN5Q==", + "integrity": "sha1-c7+5mIhSmUFck9OKPprfeEp3qdo=", "dev": true }, "istanbul-lib-instrument": { @@ -4238,7 +4238,7 @@ "jschardet": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.5.1.tgz", - "integrity": "sha512-vE2hT1D0HLZCLLclfBSfkfTTedhVj0fubHpJBHKwwUWX0nSbhPAfk+SG9rTX95BYNmau8rGFfCeaT6T5OW1C2A==", + "integrity": "sha1-xRn2KfhrOlvtuliojTETCe7Al/k=", "dev": true }, "jsesc": { @@ -4250,7 +4250,7 @@ "json-loader": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", - "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==", + "integrity": "sha1-3KFKcCNf+C8KyaOr62DTN6NlGF0=", "dev": true }, "json-schema": { @@ -4539,7 +4539,7 @@ "lru-cache": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", - "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "integrity": "sha1-Yi4y6CSItJJ5EUpPns9F581rulU=", "dev": true, "requires": { "pseudomap": "1.0.2", @@ -4555,7 +4555,7 @@ "magic-string": { "version": "0.22.4", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.4.tgz", - "integrity": "sha512-kxBL06p6iO2qPBHsqGK2b3cRwiRGpnmSuVWNhwHcMX7qJOUr1HvricYP1LZOCdkQBUp0jiWg2d6WJwR3vYgByw==", + "integrity": "sha1-MQObTkA2Y5VhjB1s+Bk8U5F0df8=", "dev": true, "requires": { "vlq": "0.2.2" @@ -4616,7 +4616,7 @@ "readable-stream": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", "dev": true, "requires": { "core-util-is": "1.0.2", @@ -4631,7 +4631,7 @@ "string_decoder": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", "dev": true, "requires": { "safe-buffer": "5.1.1" @@ -4971,7 +4971,7 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", "dev": true, "requires": { "brace-expansion": "1.1.8" @@ -5819,7 +5819,7 @@ "readable-stream": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", "dev": true, "requires": { "core-util-is": "1.0.2", @@ -5834,7 +5834,7 @@ "string_decoder": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", "dev": true, "requires": { "safe-buffer": "5.1.1" @@ -6566,7 +6566,7 @@ "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=", "dev": true, "requires": { "hosted-git-info": "2.5.0", @@ -6619,7 +6619,7 @@ "npmlog": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "integrity": "sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=", "dev": true, "requires": { "are-we-there-yet": "1.1.4", @@ -6733,7 +6733,7 @@ "opn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.1.0.tgz", - "integrity": "sha512-iPNl7SyM8L30Rm1sjGdLLheyHVw5YXVfi3SKWJzBI7efxRwHojfRFjwE/OLM6qp9xJYMgab8WicTU1cPoY+Hpg==", + "integrity": "sha1-cs4jBqF9vqWP8QQYUzUrSo/HdRk=", "dev": true, "requires": { "is-wsl": "1.1.0" @@ -6944,7 +6944,7 @@ "pbkdf2": { "version": "3.0.13", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.13.tgz", - "integrity": "sha512-+dCHxDH+djNtjgWmvVC/my3SYBAKpKNqKSjLkp+GtWWYe4XPE+e/PSD2aCanlEZZnqPk2uekTKNC/ccbwd2X2Q==", + "integrity": "sha1-w30pVTHnhrHaPj6tyEBCasywriU=", "dev": true, "requires": { "create-hash": "1.1.3", @@ -7270,7 +7270,7 @@ "postcss": { "version": "6.0.8", "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.8.tgz", - "integrity": "sha512-G6WnRmdTt2jvJvY+aY+M0AO4YlbxE+slKPZb+jG2P2U9Tyxi3h1fYZ/DgiFU6DC6bv3XIEJoZt+f/kNh8BrWFw==", + "integrity": "sha1-iQZ6nOixH4qEy8URfvwwQZoIV7M=", "dev": true, "requires": { "chalk": "2.1.0", @@ -7281,7 +7281,7 @@ "supports-color": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.2.1.tgz", - "integrity": "sha512-qxzYsob3yv6U+xMzPrv170y8AwGP7i74g+pbixCfD6rgso8BscLT2qXIuz6TpOaiJZ3mFgT5O9lyT9nMU4LfaA==", + "integrity": "sha1-ZaS7JjHpDgJCDbpVVMN1pHVLuDY=", "dev": true, "requires": { "has-flag": "2.0.0" @@ -7308,7 +7308,7 @@ "postcss": { "version": "6.0.8", "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.8.tgz", - "integrity": "sha512-G6WnRmdTt2jvJvY+aY+M0AO4YlbxE+slKPZb+jG2P2U9Tyxi3h1fYZ/DgiFU6DC6bv3XIEJoZt+f/kNh8BrWFw==", + "integrity": "sha1-iQZ6nOixH4qEy8URfvwwQZoIV7M=", "dev": true, "requires": { "chalk": "2.1.0", @@ -7319,7 +7319,7 @@ "supports-color": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.2.1.tgz", - "integrity": "sha512-qxzYsob3yv6U+xMzPrv170y8AwGP7i74g+pbixCfD6rgso8BscLT2qXIuz6TpOaiJZ3mFgT5O9lyT9nMU4LfaA==", + "integrity": "sha1-ZaS7JjHpDgJCDbpVVMN1pHVLuDY=", "dev": true, "requires": { "has-flag": "2.0.0" @@ -7346,7 +7346,7 @@ "postcss": { "version": "6.0.8", "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.8.tgz", - "integrity": "sha512-G6WnRmdTt2jvJvY+aY+M0AO4YlbxE+slKPZb+jG2P2U9Tyxi3h1fYZ/DgiFU6DC6bv3XIEJoZt+f/kNh8BrWFw==", + "integrity": "sha1-iQZ6nOixH4qEy8URfvwwQZoIV7M=", "dev": true, "requires": { "chalk": "2.1.0", @@ -7357,7 +7357,7 @@ "supports-color": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.2.1.tgz", - "integrity": "sha512-qxzYsob3yv6U+xMzPrv170y8AwGP7i74g+pbixCfD6rgso8BscLT2qXIuz6TpOaiJZ3mFgT5O9lyT9nMU4LfaA==", + "integrity": "sha1-ZaS7JjHpDgJCDbpVVMN1pHVLuDY=", "dev": true, "requires": { "has-flag": "2.0.0" @@ -7384,7 +7384,7 @@ "postcss": { "version": "6.0.8", "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.8.tgz", - "integrity": "sha512-G6WnRmdTt2jvJvY+aY+M0AO4YlbxE+slKPZb+jG2P2U9Tyxi3h1fYZ/DgiFU6DC6bv3XIEJoZt+f/kNh8BrWFw==", + "integrity": "sha1-iQZ6nOixH4qEy8URfvwwQZoIV7M=", "dev": true, "requires": { "chalk": "2.1.0", @@ -7395,7 +7395,7 @@ "supports-color": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.2.1.tgz", - "integrity": "sha512-qxzYsob3yv6U+xMzPrv170y8AwGP7i74g+pbixCfD6rgso8BscLT2qXIuz6TpOaiJZ3mFgT5O9lyT9nMU4LfaA==", + "integrity": "sha1-ZaS7JjHpDgJCDbpVVMN1pHVLuDY=", "dev": true, "requires": { "has-flag": "2.0.0" @@ -7572,7 +7572,7 @@ "promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", "dev": true, "optional": true, "requires": { @@ -7664,7 +7664,7 @@ "randomatic": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", - "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", + "integrity": "sha1-x6vpzIuHwLqodrGf3oP9RkeX44w=", "dev": true, "requires": { "is-number": "3.0.0", @@ -7705,7 +7705,7 @@ "randombytes": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz", - "integrity": "sha512-8T7Zn1AhMsQ/HI1SjcCfT/t4ii3eAqco3yOcSzS4mozsOz69lHLsoMXmF9nZgnFanYscnSlUSgs8uZyKzpE6kg==", + "integrity": "sha1-3ACaJGuNCaF3tLegrne8Vw9LG3k=", "dev": true, "requires": { "safe-buffer": "5.1.1" @@ -7777,7 +7777,7 @@ "readable-stream": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", "dev": true, "requires": { "core-util-is": "1.0.2", @@ -7792,7 +7792,7 @@ "string_decoder": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", "dev": true, "requires": { "safe-buffer": "5.1.1" @@ -7990,7 +7990,7 @@ "resolve": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz", - "integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==", + "integrity": "sha1-p1vgHFPaJdk0qY69DkxKcxL5KoY=", "dev": true, "requires": { "path-parse": "1.0.5" @@ -8037,7 +8037,7 @@ "rsvp": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz", - "integrity": "sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==", + "integrity": "sha1-LpZJFZmpbN4bUV1WdKj3qRRSkmo=", "dev": true }, "run-async": { @@ -8081,7 +8081,7 @@ "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=", "dev": true }, "sass-graph": { @@ -9428,7 +9428,7 @@ "sass-loader": { "version": "6.0.6", "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-6.0.6.tgz", - "integrity": "sha512-c3/Zc+iW+qqDip6kXPYLEgsAu2lf4xz0EZDplB7EmSUMda12U1sGJPetH55B/j9eu0bTtKzKlNPWWyYC7wFNyQ==", + "integrity": "sha1-6dXmwfFV+qMqSybXqbcQfCJeQPk=", "dev": true, "requires": { "async": "2.5.0", @@ -9449,7 +9449,7 @@ "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=", "dev": true }, "schema-utils": { @@ -9525,7 +9525,7 @@ "semver": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", - "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", + "integrity": "sha1-4FnAnYVx8FQII3M0M1BdOi8AsY4=", "dev": true }, "send": { @@ -9852,7 +9852,7 @@ "readable-stream": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", "dev": true, "requires": { "core-util-is": "1.0.2", @@ -9867,7 +9867,7 @@ "string_decoder": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", "dev": true, "requires": { "safe-buffer": "5.1.1" @@ -9954,7 +9954,7 @@ "readable-stream": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", "dev": true, "optional": true, "requires": { @@ -9976,7 +9976,7 @@ "string_decoder": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", "dev": true, "optional": true, "requires": { @@ -10011,7 +10011,7 @@ "readable-stream": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", "dev": true, "requires": { "core-util-is": "1.0.2", @@ -10026,7 +10026,7 @@ "string_decoder": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", "dev": true, "requires": { "safe-buffer": "5.1.1" @@ -10037,7 +10037,7 @@ "stream-http": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz", - "integrity": "sha512-c0yTD2rbQzXtSsFSVhtpvY/vS6u066PcXOX9kBB3mSO76RiUQzL340uJkGBWnlBg4/HZzqiUXtaVA7wcRcJgEw==", + "integrity": "sha1-QKBQ7I3DtTsz2ZCUFcAsC/Gr+60=", "dev": true, "requires": { "builtin-status-codes": "3.0.0", @@ -10056,7 +10056,7 @@ "readable-stream": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", "dev": true, "requires": { "core-util-is": "1.0.2", @@ -10071,7 +10071,7 @@ "string_decoder": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", "dev": true, "requires": { "safe-buffer": "5.1.1" @@ -10094,7 +10094,7 @@ "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", "dev": true, "requires": { "is-fullwidth-code-point": "2.0.0", @@ -10310,7 +10310,7 @@ "timers-browserify": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.3.tgz", - "integrity": "sha512-+JAqyNgg+M8+gXIrq2EeUr4kZqRz47Ysco7X5QKRGScRE9HIHckyHD1asozSFGeqx2nmPCgA8T5tIGVO0ML7/w==", + "integrity": "sha1-Qf0L3JJqX+7cM6F6jh99SRkl9/w=", "dev": true, "requires": { "global": "4.3.2", @@ -11931,7 +11931,7 @@ "uglify-js": { "version": "3.0.27", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.0.27.tgz", - "integrity": "sha512-HD8CmxPXUI62v5tweiulMcP/apAtx1DXGcNZkhKQZyC+MTrTsoCBb8yPAwVrbvpgw3EpRU76bRe6axjIiCYcQg==", + "integrity": "sha1-qX24yLprnbpOL4jYaqlUj6YyADQ=", "dev": true, "requires": { "commander": "2.11.0", @@ -12154,7 +12154,7 @@ "uuid": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", + "integrity": "sha1-PdPT55Crwk17DToDT/q6vijrvAQ=", "dev": true, "optional": true }, @@ -12219,7 +12219,7 @@ "walk-sync": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.2.tgz", - "integrity": "sha512-FMB5VqpLqOCcqrzA9okZFc0wq0Qbmdm396qJxvQZhDpyu0W95G9JCmp74tx7iyYnyOcBtUuKJsgIKAqjozvmmQ==", + "integrity": "sha1-SCcoCvxC0OA1NnxKTjHurA0Tb3U=", "dev": true, "requires": { "ensure-posix-path": "1.0.2", @@ -12324,7 +12324,7 @@ "supports-color": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.2.1.tgz", - "integrity": "sha512-qxzYsob3yv6U+xMzPrv170y8AwGP7i74g+pbixCfD6rgso8BscLT2qXIuz6TpOaiJZ3mFgT5O9lyT9nMU4LfaA==", + "integrity": "sha1-ZaS7JjHpDgJCDbpVVMN1pHVLuDY=", "dev": true, "requires": { "has-flag": "2.0.0" @@ -12583,7 +12583,7 @@ "webpack-sources": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.0.1.tgz", - "integrity": "sha512-05tMxipUCwHqYaVS8xc7sYPTly8PzXayRCB4dTxLhWTqlKUiwH6ezmEe0OSreL1c30LAuA3Zqmc+uEBUGFJDjw==", + "integrity": "sha1-xzVkNqTRMSO+LiQmoF0drZy+Zc8=", "dev": true, "requires": { "source-list-map": "2.0.0", @@ -12593,7 +12593,7 @@ "source-list-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", - "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==", + "integrity": "sha1-qqR0A/eyRakvvJfqCPJQ1gh+0IU=", "dev": true } } @@ -12628,7 +12628,7 @@ "which": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "integrity": "sha1-/wS9/AEO5UfXgL7DjhrBwnd9JTo=", "dev": true, "requires": { "isexe": "2.0.0" @@ -12643,7 +12643,7 @@ "wide-align": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", - "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "integrity": "sha1-Vx4PGwYEY268DfwhsDObvjE0FxA=", "dev": true, "requires": { "string-width": "1.0.2" diff --git a/src/Web/WebStatus/Dockerfile.nanowin b/src/Web/WebStatus/Dockerfile.nanowin deleted file mode 100644 index 9405cf26d..000000000 --- a/src/Web/WebStatus/Dockerfile.nanowin +++ /dev/null @@ -1,8 +0,0 @@ -FROM microsoft/dotnet:2.0-runtime-nanoserver -SHELL ["powershell"] -ARG source -WORKDIR /app -RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord -EXPOSE 80 -COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "WebStatus.dll"] From dcc1ec620fe5919e9033f4d8e4e64e84d086af94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Tom=C3=A0s?= Date: Tue, 5 Sep 2017 08:43:24 +0200 Subject: [PATCH 69/86] Removed GracePeriodManager project as it is no longer used in netcore2 --- cli-windows/build-bits.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/cli-windows/build-bits.ps1 b/cli-windows/build-bits.ps1 index 4191515f6..a33f3bc8b 100644 --- a/cli-windows/build-bits.ps1 +++ b/cli-windows/build-bits.ps1 @@ -18,7 +18,6 @@ $projectPaths = @{Path="$rootPath\src\Services\Catalog\Catalog.API";Prj="Catalog.API.csproj"}, @{Path="$rootPath\src\Services\Ordering\Ordering.API";Prj="Ordering.API.csproj"}, @{Path="$rootPath\src\Services\Basket\Basket.API";Prj="Basket.API.csproj"}, - @{Path="$rootPath\src\Services\GracePeriod\GracePeriodManager";Prj="GracePeriodManager.csproj"}, @{Path="$rootPath\src\Services\Location\Locations.API";Prj="Locations.API.csproj"}, @{Path="$rootPath\src\Services\Marketing\Marketing.API";Prj="Marketing.API.csproj"}, @{Path="$rootPath\src\Services\Payment\Payment.API";Prj="Payment.API.csproj"}, From 6fd4f46058e85fc4d862b8a5d1e9447f844857b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Tom=C3=A0s?= Date: Tue, 5 Sep 2017 15:55:17 +0200 Subject: [PATCH 70/86] Fix for rabbitMQ under windows containers. Also some config tweaking on windows --- .env | 2 + cli-windows/start-windows-containers.ps1 | 18 ++++++- docker-compose-windows.yml | 14 ++--- docker-compose.override.windows.yml | 53 +++++++++++++++++++ docker-compose.override.yml | 14 ++++- src/Services/Basket/Basket.API/Startup.cs | 9 ++++ src/Services/Catalog/Catalog.API/Startup.cs | 13 ++++- .../Location/Locations.API/Startup.cs | 14 ++++- .../Marketing/Marketing.API/Startup.cs | 9 ++++ src/Services/Ordering/Ordering.API/Startup.cs | 11 ++++ src/Services/Payment/Payment.API/Startup.cs | 11 +++- 11 files changed, 152 insertions(+), 16 deletions(-) create mode 100644 docker-compose.override.windows.yml diff --git a/.env b/.env index f77f64682..797e5fc5c 100644 --- a/.env +++ b/.env @@ -21,3 +21,5 @@ ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP=10.121.122.92 #ESHOP_AZURE_STORAGE_CATALOG_KEY= #ESHOP_AZURE_STORAGE_MARKETING_NAME= #ESHOP_AZURE_STORAGE_MARKETING_KEY= +#ESHOP_SERVICE_BUS_USERNAME= +#ESHOP_SERVICE_BUS_PASSWORD= diff --git a/cli-windows/start-windows-containers.ps1 b/cli-windows/start-windows-containers.ps1 index 56b7a34e9..91d8eb7f7 100644 --- a/cli-windows/start-windows-containers.ps1 +++ b/cli-windows/start-windows-containers.ps1 @@ -1,5 +1,10 @@ +# rootPath: Root path of the repo (where docker-compose*.yml are). If not passed ../cli-windows/ is assumed +# buildBits: If the projects must be built before. Default value: $true +# customEventBusLoginPassword: If a custom RabbitMQ image is used that do not use the default user login/pwd. Default: $false (means assume use default spring2/rabbitmq image) + Param( [parameter(Mandatory=$false)][string] $rootPath, + [parameter(Mandatory=$false)][bool] $customEventBusLoginPassword=$false, [parameter(Mandatory=$false)][bool]$buildBits=$true ) @@ -13,4 +18,15 @@ Write-Host "Root path used is $rootPath" -ForegroundColor Yellow if ($buildBits) { & $scriptPath\build-bits.ps1 -rootPath $rootPath } -docker-compose -f "$rootPath\docker-compose-windows.yml" -f "$rootPath\docker-compose.override.yml" up + + +$env:ESHOP_EXTERNAL_DNS_NAME_OR_IP = "10.0.75.1" +$env:ESHOP_AZURE_STORAGE_CATALOG_URL ="http://10.0.75.1:5101/api/v1/catalog/items/[0]/pic/" +$env:ESHOP_AZURE_STORAGE_MARKETING_URL ="http://10.0.75.1:5110/api/v1/campaigns/[0]/pic/" + +if (-Not $customEventBusLoginPassword) { + docker-compose -f "$rootPath\docker-compose-windows.yml" -f "$rootPath\docker-compose.override.yml" -f "$rootPath\docker-compose.override.windows.yml" up +} +else { + docker-compose -f "$rootPath\docker-compose-windows.yml" -f "$rootPath\docker-compose.override.yml" up +} diff --git a/docker-compose-windows.yml b/docker-compose-windows.yml index 1a71968ba..294d5f7f5 100644 --- a/docker-compose-windows.yml +++ b/docker-compose-windows.yml @@ -38,7 +38,7 @@ services: - rabbitmq marketing.api: - image: eshop/marketing.api:${TAG:-latest} + image: eshop/marketing.api-win:${TAG:-latest} build: context: ./src/Services/Marketing/Marketing.API dockerfile: Dockerfile @@ -73,13 +73,13 @@ services: - marketing.api webstatus: - image: eshop/webstatus:${TAG:-latest} + image: eshop/webstatus-win:${TAG:-latest} build: context: ./src/Web/WebStatus dockerfile: Dockerfile payment.api: - image: eshop/payment.api:${TAG:-latest} + image: eshop/payment.api-win:${TAG:-latest} build: context: ./src/Services/Payment/Payment.API dockerfile: Dockerfile @@ -87,7 +87,7 @@ services: - rabbitmq locations.api: - image: eshop/locations.api:${TAG:-latest} + image: eshop/locations.api-win:${TAG:-latest} build: context: ./src/Services/Location/Locations.API dockerfile: Dockerfile @@ -103,17 +103,11 @@ services: basket.data: image: redis:nanoserver -# build: -# context: ./_docker/redis -# dockerfile: Dockerfile ports: - "6379:6379" rabbitmq: image: spring2/rabbitmq -# build: -# context: ./_docker/rabbitmq -# dockerfile: Dockerfile ports: - "15672:15672" - "5672:5672" diff --git a/docker-compose.override.windows.yml b/docker-compose.override.windows.yml new file mode 100644 index 000000000..130405d3b --- /dev/null +++ b/docker-compose.override.windows.yml @@ -0,0 +1,53 @@ +version: '2.1' + +# ONLY NEEDED WHEN RUNNING WINDOWS CONTAINERS +# +# This file sets the containers' environment variables: +# +# - EventBusUerName +# - EventBusPassword +# +# To the default username & password used in the spring2/rabbitmq image. +# +# If you are using any other rabbitmq image with any other username/pwd then you can: +# +# Set your shell environment variables: +# - ESHOP_SERVICE_BUS_USERNAME +# - ESHOP_SERVICE_BUS_PASSWORD +# +# With the appropiate values (note that you can use .env file also) AND DO NOT USE THIS FILE when launching windows container: +# +# docker-compose -f docker-compose-windows.yml -f docker-compose.override.yml up +# INSTEAD OF +# docker-compose -f docker-compose-windows.yml -f docker-compose.override.yml -f docker-compose.override.windows.yml up + +services: + basket.api: + environment: + - EventBusUserName=admin + - EventBusPassword=password + + catalog.api: + environment: + - EventBusUserName=admin + - EventBusPassword=password + + ordering.api: + environment: + - EventBusUserName=admin + - EventBusPassword=password + + marketing.api: + environment: + - EventBusUserName=admin + - EventBusPassword=password + + payment.api: + environment: + - EventBusUserName=admin + - EventBusPassword=password + + locations.api: + environment: + - EventBusUserName=admin + - EventBusPassword=password \ No newline at end of file diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 6870b617f..8757c8f83 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -16,6 +16,8 @@ services: - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. - 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 ports: - "5103:80" @@ -27,6 +29,8 @@ services: - ConnectionString=${ESHOP_AZURE_CATALOG_DB:-Server=sql.data;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} + - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} - AzureStorageAccountName=${ESHOP_AZURE_STORAGE_CATALOG_NAME} - AzureStorageAccountKey=${ESHOP_AZURE_STORAGE_CATALOG_KEY} - UseCustomizationData=True @@ -47,7 +51,7 @@ services: - 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 - - UseCustomizationData=True + - UseCustomizationData=True ports: - "5105:80" @@ -59,6 +63,8 @@ services: - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. - 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 - GracePeriodTime=1 @@ -74,6 +80,8 @@ services: - MongoConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosql.data} - 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. - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 - CampaignDetailFunctionUri=${ESHOP_AZUREFUNC_CAMPAIGN_DETAILS_URI} @@ -137,6 +145,8 @@ services: - 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 ports: - "5108:80" @@ -150,6 +160,8 @@ services: - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. - 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 ports: - "5109:80" diff --git a/src/Services/Basket/Basket.API/Startup.cs b/src/Services/Basket/Basket.API/Startup.cs index 6a432b290..1f62e44cb 100644 --- a/src/Services/Basket/Basket.API/Startup.cs +++ b/src/Services/Basket/Basket.API/Startup.cs @@ -103,6 +103,15 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API HostName = Configuration["EventBusConnection"] }; + if (!string.IsNullOrEmpty(Configuration["EventBusUserName"])) { + factory.UserName = Configuration["EventBusUserName"]; + } + + if (!string.IsNullOrEmpty(Configuration["EventBusPassword"])) + { + factory.Password = Configuration["EventBusPassword"]; + } + return new DefaultRabbitMQPersistentConnection(factory, logger); }); } diff --git a/src/Services/Catalog/Catalog.API/Startup.cs b/src/Services/Catalog/Catalog.API/Startup.cs index 64754c3ab..354d0643e 100644 --- a/src/Services/Catalog/Catalog.API/Startup.cs +++ b/src/Services/Catalog/Catalog.API/Startup.cs @@ -132,11 +132,22 @@ { var settings = sp.GetRequiredService>().Value; var logger = sp.GetRequiredService>(); + var factory = new ConnectionFactory() { - HostName = settings.EventBusConnection + HostName = Configuration["EventBusConnection"] }; + if (!string.IsNullOrEmpty(Configuration["EventBusUserName"])) + { + factory.UserName = Configuration["EventBusUserName"]; + } + + if (!string.IsNullOrEmpty(Configuration["EventBusPassword"])) + { + factory.Password = Configuration["EventBusPassword"]; + } + return new DefaultRabbitMQPersistentConnection(factory, logger); }); } diff --git a/src/Services/Location/Locations.API/Startup.cs b/src/Services/Location/Locations.API/Startup.cs index eb2077c8c..4b92afa02 100644 --- a/src/Services/Location/Locations.API/Startup.cs +++ b/src/Services/Location/Locations.API/Startup.cs @@ -62,12 +62,22 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API services.AddSingleton(sp => { var logger = sp.GetRequiredService>(); - - var factory = new ConnectionFactory + + var factory = new ConnectionFactory() { HostName = Configuration["EventBusConnection"] }; + if (!string.IsNullOrEmpty(Configuration["EventBusUserName"])) + { + factory.UserName = Configuration["EventBusUserName"]; + } + + if (!string.IsNullOrEmpty(Configuration["EventBusPassword"])) + { + factory.Password = Configuration["EventBusPassword"]; + } + return new DefaultRabbitMQPersistentConnection(factory, logger); }); } diff --git a/src/Services/Marketing/Marketing.API/Startup.cs b/src/Services/Marketing/Marketing.API/Startup.cs index 89f8482f9..37d6911c1 100644 --- a/src/Services/Marketing/Marketing.API/Startup.cs +++ b/src/Services/Marketing/Marketing.API/Startup.cs @@ -106,6 +106,15 @@ HostName = Configuration["EventBusConnection"] }; + if (!string.IsNullOrEmpty(Configuration["EventBusUserName"])) + { + factory.UserName = Configuration["EventBusUserName"]; + } + + if (!string.IsNullOrEmpty(Configuration["EventBusPassword"])) + { + factory.Password = Configuration["EventBusPassword"]; + } return new DefaultRabbitMQPersistentConnection(factory, logger); }); } diff --git a/src/Services/Ordering/Ordering.API/Startup.cs b/src/Services/Ordering/Ordering.API/Startup.cs index 7f22540fa..2d2f94423 100644 --- a/src/Services/Ordering/Ordering.API/Startup.cs +++ b/src/Services/Ordering/Ordering.API/Startup.cs @@ -148,11 +148,22 @@ { var logger = sp.GetRequiredService>(); + var factory = new ConnectionFactory() { HostName = Configuration["EventBusConnection"] }; + if (!string.IsNullOrEmpty(Configuration["EventBusUserName"])) + { + factory.UserName = Configuration["EventBusUserName"]; + } + + if (!string.IsNullOrEmpty(Configuration["EventBusPassword"])) + { + factory.Password = Configuration["EventBusPassword"]; + } + return new DefaultRabbitMQPersistentConnection(factory, logger); }); } diff --git a/src/Services/Payment/Payment.API/Startup.cs b/src/Services/Payment/Payment.API/Startup.cs index 5e87c4e19..c4ab2c322 100644 --- a/src/Services/Payment/Payment.API/Startup.cs +++ b/src/Services/Payment/Payment.API/Startup.cs @@ -51,12 +51,21 @@ namespace Payment.API services.AddSingleton(sp => { var logger = sp.GetRequiredService>(); - var factory = new ConnectionFactory() { HostName = Configuration["EventBusConnection"] }; + if (!string.IsNullOrEmpty(Configuration["EventBusUserName"])) + { + factory.UserName = Configuration["EventBusUserName"]; + } + + if (!string.IsNullOrEmpty(Configuration["EventBusPassword"])) + { + factory.Password = Configuration["EventBusPassword"]; + } + return new DefaultRabbitMQPersistentConnection(factory, logger); }); } From 210c42b7de035eff825b51c3a524d6a99d2d2d99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Tom=C3=A0s?= Date: Tue, 5 Sep 2017 16:18:01 +0200 Subject: [PATCH 71/86] doc updated to reflect netcore2 moving --- README.md | 9 +++++++-- branch-guide.md | 3 +-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9271da0b7..c06c0c874 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,13 @@ Sample .NET Core reference application, powered by Microsoft, based on a simplified microservices architecture and Docker containers.

**Note for Pull Requests**: We accept pull request from the community. When doing it, please do it onto the DEV branch which is the consolidated work-in-progress branch. Do not request it onto Master, if possible. -## Moving to .NET Core 2.0 "wave" -NOTE: During August/September 2017 we'll be moving the solution to .NET Core "wave". Not just compilation but also new recommended code in EF Core 2.0, ASP.NET Core 2.0, and other new related versions. +## Moved to .NET Core 2.0 "wave" +We have moved to .NET Core 2.0! + +* Branch `dev` is in .NET Core 2.0. +* Branch `master` is *still* in .NET Core 1.1 (but it will be updated soon) + +To access the .NET Core 1.1 version you can use the `netcore1.1` tag ([https://github.com/dotnet-architecture/eShopOnContainers/tree/netcore1.1](https://github.com/dotnet-architecture/eShopOnContainers/tree/netcore1.1)) >**PLEASE** Read our [branch guide](./branch-guide.md) to know about our branching policy diff --git a/branch-guide.md b/branch-guide.md index 67b2d0eaf..386e74ee5 100644 --- a/branch-guide.md +++ b/branch-guide.md @@ -2,9 +2,8 @@ Following are the most important branches: -- `dev`: Contains the latest code **and it is the branch actively developed**. Note that **all PRs must be against `dev` branch to be considered**. +- `dev`: Contains the latest code **and it is the branch actively developed**. Note that **all PRs must be against `dev` branch to be considered**. This branch is developed using .NET Core 2.0 - `master`: Synced time to time from dev. It contains "stable" code, although not the latest one. We plan to do periodic merges from `dev` to `master`, but we are not doing it right now. -- `netcore2`: Contains NETCore 2.0 (preview2) based code. All APIs and webs are migrated to netcore2 except `Identity.API` which still uses netcore1.1 (because of Identity Server). Dockerfiles are updated also. Use this branch to test the NETCore 2.0 code. You can also submit PR to this branch if they are related to netcore2. Any other branch is considered temporary and could be deleted at any time. Do not do any PR to them! From 30644de2a116305a6b002eb4265660b17f127da8 Mon Sep 17 00:00:00 2001 From: Igor Sychev Date: Tue, 5 Sep 2017 19:03:22 +0300 Subject: [PATCH 72/86] NoBuild missed some images --- docker-compose.nobuild.yml | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/docker-compose.nobuild.yml b/docker-compose.nobuild.yml index 0905f9799..186ab8639 100644 --- a/docker-compose.nobuild.yml +++ b/docker-compose.nobuild.yml @@ -23,12 +23,24 @@ services: 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 @@ -37,20 +49,35 @@ services: - 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 - + + nosql.data: + image: mongo + basket.data: image: redis ports: - "6379:6379" rabbitmq: - image: rabbitmq + image: rabbitmq:3-management ports: - "5672:5672" - webstatus: - image: eshop/webstatus - \ No newline at end of file From cc9f589c0a45203b2fb3ead8b64ef876a55dc033 Mon Sep 17 00:00:00 2001 From: Cesar De la Torre Date: Tue, 5 Sep 2017 10:40:20 -0700 Subject: [PATCH 73/86] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c06c0c874..47ed0059d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# eShopOnContainers - Microservices Architecture and Containers based Reference Application (**BETA state** - Visual Studio 2017 and CLI environments compatible) + # eShopOnContainers - Microservices Architecture and Containers based Reference Application (Visual Studio 2017 and CLI environments compatible) Sample .NET Core reference application, powered by Microsoft, based on a simplified microservices architecture and Docker containers.

**Note for Pull Requests**: We accept pull request from the community. When doing it, please do it onto the DEV branch which is the consolidated work-in-progress branch. Do not request it onto Master, if possible. @@ -13,7 +13,7 @@ To access the .NET Core 1.1 version you can use the `netcore1.1` tag ([https://g >**PLEASE** Read our [branch guide](./branch-guide.md) to know about our branching policy > ### DISCLAIMER -> **IMPORTANT:** The current state of this sample application is **BETA**, consider it version a 0.1 foundational version, therefore, many areas could be improved and change significantly while refactoring current code and implementing new features. **Feedback with improvements and pull requests from the community will be highly appreciated and accepted.** +> **IMPORTANT:** The current state of this sample application is **BETA** for the .NET Core 2.0 version, and v1.0 for the .NET Core 1.1.2 version tagged ([https://github.com/dotnet-architecture/eShopOnContainers/tree/netcore1.1](https://github.com/dotnet-architecture/eShopOnContainers/tree/netcore1.1)) > > This reference application proposes a simplified microservice oriented architecture implementation to introduce technologies like .NET Core with Docker containers through a comprehensive application. The chosen domain is an eShop/eCommerce but simply because it is a well-know domain by most people/developers. However, this sample application should not be considered as an "eCommerce reference model", at all. The implemented business domain might not be ideal from an eCommerce business point of view. It is neither trying to solve all the problems in a large, scalable and mission-critical distributed system. It is just a bootstrap for developers to easily get started in the world of Docker containers and microservices with .NET Core. From 38ad91ac0114afd3d805e5417d3faa552435c5d9 Mon Sep 17 00:00:00 2001 From: Cesar De la Torre Date: Tue, 5 Sep 2017 10:44:22 -0700 Subject: [PATCH 74/86] Update README.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 47ed0059d..e88368522 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,8 @@ To access the .NET Core 1.1 version you can use the `netcore1.1` tag ([https://g > > This reference application proposes a simplified microservice oriented architecture implementation to introduce technologies like .NET Core with Docker containers through a comprehensive application. The chosen domain is an eShop/eCommerce but simply because it is a well-know domain by most people/developers. However, this sample application should not be considered as an "eCommerce reference model", at all. The implemented business domain might not be ideal from an eCommerce business point of view. It is neither trying to solve all the problems in a large, scalable and mission-critical distributed system. It is just a bootstrap for developers to easily get started in the world of Docker containers and microservices with .NET Core. ->

For example, the next step (still not covered in eShopOnContainers) after understanding Docker containers and microservices development with .NET Core, is to select a microservice cluster/orchestrator like Docker Swarm, Kubernetes or DC/OS (in Azure Container Service) or Azure Service Fabric which in most of the cases will require additional partial changes to your application's configuration (although the present architecture should work on most orchestrators with small changes). -> Additional steps would be to move your databases to HA cloud services, or to implement your EventBus with Azure Service Bus or any other production ready Service Bus in the market. ->

In the future we might fork this project and make multiple versions targeting specific microservice cluster/orchestrators plus using additional cloud infrastructure.

+>

The next step after understanding Docker containers and microservices development with .NET Core, is to select a microservice cluster/orchestrator like Azure Service Fabric or Kubernetes, DC/OS or Docker Swarm (in Azure Container Service). Kubernetes and Service Fabric are being tested with eShopOnContainer. +> Additional steps already tested in eShopOnContainers are about moving your databases to HA cloud services (like Azure SQL DB), to implement your EventBus with Azure Service Bus or any other production ready Service Bus in the market. > > Read the planned Roadmap and Milestones for future releases of eShopOnContainers within the Wiki for further info about possible new implementations and provide feedback at the ISSUES section if you'd like to see any specific scenario implemented or improved. Also, feel free to discuss on any current issue. From 7be5cb933d3dd9580c6c19ed93598e4e05c399a4 Mon Sep 17 00:00:00 2001 From: Unai Zorrilla Castro Date: Tue, 5 Sep 2017 20:24:58 +0200 Subject: [PATCH 75/86] Update BundlerMinimifier.Core version to netcoreapp2 --- src/Web/WebMVC/WebMVC.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Web/WebMVC/WebMVC.csproj b/src/Web/WebMVC/WebMVC.csproj index 5e73cdfda..3bb66a650 100644 --- a/src/Web/WebMVC/WebMVC.csproj +++ b/src/Web/WebMVC/WebMVC.csproj @@ -45,7 +45,7 @@ - + From 903b26d529dd34f0a84fcdacc3a0cad01493b63b Mon Sep 17 00:00:00 2001 From: Cesar De la Torre Date: Tue, 5 Sep 2017 15:35:28 -0700 Subject: [PATCH 76/86] Setting to use SQL Server Developer Edition so there's no issue about any time bomb because of licensing or trial period. --- docker-compose.override.yml | 1 + docker-compose.prod.yml | 1 + docker-compose.yml | 2 +- k8s/sql-data.yaml | 4 +++- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 8757c8f83..f918eee3c 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -170,6 +170,7 @@ services: environment: - SA_PASSWORD=Pass@word - ACCEPT_EULA=Y + - MSSQL_PID=Developer ports: - "5433:1433" diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index f768b5872..83198c760 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -124,6 +124,7 @@ services: environment: - SA_PASSWORD=Pass@word - ACCEPT_EULA=Y + - MSSQL_PID=Developer ports: - "5433:1433" diff --git a/docker-compose.yml b/docker-compose.yml index cf26bcf5f..23acd8af7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -97,7 +97,7 @@ services: - rabbitmq sql.data: - image: microsoft/mssql-server-linux + image: microsoft/mssql-server-linux:latest nosql.data: image: mongo diff --git a/k8s/sql-data.yaml b/k8s/sql-data.yaml index 1e5f1371f..4b607ac98 100644 --- a/k8s/sql-data.yaml +++ b/k8s/sql-data.yaml @@ -25,9 +25,11 @@ spec: spec: containers: - name: sql-data - image: microsoft/mssql-server-linux:rc2 + image: microsoft/mssql-server-linux:latest env: - name: ACCEPT_EULA value: "Y" + - name: MSSQL_PID + value: Developer - name: SA_PASSWORD value: Pass@word From 442671a722e4c0ab195475262fcef9e5843dc1bc Mon Sep 17 00:00:00 2001 From: Igor Sychev Date: Wed, 6 Sep 2017 09:59:56 +0300 Subject: [PATCH 77/86] dropped GracePeriodManager from k8 --- k8s/conf_cloud.yml | 4 ---- k8s/conf_local.yml | 3 --- k8s/deployments.yaml | 47 -------------------------------------------- k8s/services.yaml | 14 ------------- 4 files changed, 68 deletions(-) diff --git a/k8s/conf_cloud.yml b/k8s/conf_cloud.yml index ac8fd56fc..ccf99f0e2 100644 --- a/k8s/conf_cloud.yml +++ b/k8s/conf_cloud.yml @@ -27,10 +27,6 @@ data: OrderingSqlDb: Ordering SQL SERVER CONNECTION STRING (Server=xxxx;Intial Catalog=yyy;....) # Payment.API entries PaymentBus: CONNECTION_STRING (NAME OF RABBITMQ CONTAINER OR Endpoint=sb://XXXX in case of using Azure) -# GracePeriodManager entries - GracePeriodTime: "5" # Grace period duration (time when you can cancel order) in minutes - GracePeriodCheckUpdateTime: "60000" # Interval time to check new Order status (in milliseconds) - GracePeriodManagerBus: CONNECTION_STRING (NAME OF RABBITMQ CONTAINER OR Endpoint=sb://XXXX in case of using Azure) # Global entries UseAzureServiceBus: "TRUE" IF USE AZURE SB ("FALSE" FOR USING RABBITMQ) keystore: REDIS CONNECTION STRING FOR KEYSTORE \ No newline at end of file diff --git a/k8s/conf_local.yml b/k8s/conf_local.yml index 1ac16bb28..26afa09a2 100644 --- a/k8s/conf_local.yml +++ b/k8s/conf_local.yml @@ -21,8 +21,5 @@ data: OrderingBus: rabbitmq OrderingSqlDb: Server=sql-data;Initial Catalog=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word; PaymentBus: rabbitmq - GracePeriodTime: "1" - GracePeriodCheckUpdateTime: "60000" - GracePeriodManagerBus: rabbitmq UseAzureServiceBus: "False" keystore: keystore-data diff --git a/k8s/deployments.yaml b/k8s/deployments.yaml index 9006c3642..59e37de90 100644 --- a/k8s/deployments.yaml +++ b/k8s/deployments.yaml @@ -198,53 +198,6 @@ spec: --- apiVersion: extensions/v1beta1 kind: Deployment -metadata: - name: graceperiodmanager -spec: - paused: true - template: - metadata: - labels: - app: eshop - component: graceperiodmanager - spec: - containers: - - name: graceperiodmanager - image: eshop/graceperiodmanager - imagePullPolicy: Always - env: - - name: ConnectionString - valueFrom: - configMapKeyRef: - name: externalcfg - key: OrderingSqlDb - - name: EventBusConnection - valueFrom: - configMapKeyRef: - name: externalcfg - key: GracePeriodManagerBus - - name: GracePeriodTime - valueFrom: - configMapKeyRef: - name: externalcfg - key: GracePeriodTime - - name: CheckUpdateTime - valueFrom: - configMapKeyRef: - name: externalcfg - key: GracePeriodCheckUpdateTime - - name: AzureServiceBusEnabled - valueFrom: - configMapKeyRef: - name: externalcfg - key: UseAzureServiceBus - ports: - - containerPort: 80 - imagePullSecrets: - - name: registry-key ---- -apiVersion: extensions/v1beta1 -kind: Deployment metadata: name: locations spec: diff --git a/k8s/services.yaml b/k8s/services.yaml index d88604e88..02b73448a 100644 --- a/k8s/services.yaml +++ b/k8s/services.yaml @@ -56,20 +56,6 @@ spec: --- apiVersion: v1 kind: Service -metadata: - labels: - app: eshop - component: graceperiodmanager - name: graceperiodmanager -spec: - ports: - - port: 80 - selector: - app: eshop - component: graceperiodmanager ---- -apiVersion: v1 -kind: Service metadata: labels: app: eshop From 6c5bdda2f58edbebe08de586fa2fb6ab9ca4094c Mon Sep 17 00:00:00 2001 From: Unai Zorrilla Castro Date: Wed, 6 Sep 2017 18:43:38 +0200 Subject: [PATCH 78/86] Improve build-bits-linux.sh (removed dotnet restore (doing with publish now) and set quiet on verbosity in order to reduce issues with System.Console.dll on build container). Remove unnecesary namespace on Identity.Api startup.cs --- cli-linux/build-bits-linux.sh | 4 +--- src/Services/Identity/Identity.API/Startup.cs | 7 +++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/cli-linux/build-bits-linux.sh b/cli-linux/build-bits-linux.sh index 8715dd0cf..ac68031e0 100755 --- a/cli-linux/build-bits-linux.sh +++ b/cli-linux/build-bits-linux.sh @@ -30,10 +30,8 @@ do echo -e "\e[33m\tRemoving old publish output" pushd $path/$project rm -rf obj/Docker/publish - echo -e "\e[33m\tRestoring project $project" - dotnet restore --verbosity minimal echo -e "\e[33m\tBuilding and publishing $project" - dotnet publish -c Release -o obj/Docker/publish --verbosity minimal + dotnet publish -c Release -o obj/Docker/publish --verbosity quiet popd done diff --git a/src/Services/Identity/Identity.API/Startup.cs b/src/Services/Identity/Identity.API/Startup.cs index a07cd69c2..edd02d0a1 100644 --- a/src/Services/Identity/Identity.API/Startup.cs +++ b/src/Services/Identity/Identity.API/Startup.cs @@ -1,4 +1,6 @@ -using Identity.API.Certificate; +using Autofac; +using Autofac.Extensions.DependencyInjection; +using Identity.API.Certificate; using Identity.API.Configuration; using Identity.API.Data; using Identity.API.Models; @@ -16,9 +18,6 @@ using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.HealthChecks; -using Identity.API.Certificate; -using Autofac.Extensions.DependencyInjection; -using Autofac; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; From 2a64cd57ded0d839b6afecd0288affcb28ad6786 Mon Sep 17 00:00:00 2001 From: Igor Sychev Date: Sat, 2 Sep 2017 09:17:01 +0300 Subject: [PATCH 79/86] dotnet restore not needed in cli 2.0 "Starting with .NET Core 2.0 SDK, dotnet restore runs implicitily when you run dotnet build." (C) https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-build?tabs=netcore2x --- cli-mac/build-bits.sh | 2 -- cli-windows/build-bits-simple.ps1 | 2 -- 2 files changed, 4 deletions(-) diff --git a/cli-mac/build-bits.sh b/cli-mac/build-bits.sh index fdf61e359..8548ec72b 100755 --- a/cli-mac/build-bits.sh +++ b/cli-mac/build-bits.sh @@ -22,8 +22,6 @@ do echo -e "\e[33m\tRemoving old publish output" pushd $(pwd)/$project rm -rf obj/Docker/publish - echo -e "\e[33m\tRestoring project" - dotnet restore echo -e "\e[33m\tBuilding and publishing projects" dotnet publish -o obj/Docker/publish -c Release popd diff --git a/cli-windows/build-bits-simple.ps1 b/cli-windows/build-bits-simple.ps1 index 461384cc2..008f4f599 100644 --- a/cli-windows/build-bits-simple.ps1 +++ b/cli-windows/build-bits-simple.ps1 @@ -13,7 +13,5 @@ Write-Host "Root path used is $rootPath" -ForegroundColor Yellow $SolutionFilePath = [IO.Path]::Combine($rootPath, "eShopOnContainers-ServicesAndWebApps.sln") -dotnet restore $SolutionFilePath - dotnet publish $SolutionFilePath -c Release -o .\obj\Docker\publish From fda16ba61761d587f6892037d968594424e8afa2 Mon Sep 17 00:00:00 2001 From: Igor Sychev Date: Wed, 6 Sep 2017 14:46:22 +0300 Subject: [PATCH 80/86] dotnet restore not needed in cli 2.0 "Starting with .NET Core 2.0 SDK, dotnet restore runs implicitily when you run dotnet build." (C) https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-build?tabs=netcore2x --- cli-windows/build-bits.ps1 | 1 - k8s/deploy.ps1 | 1 - 2 files changed, 2 deletions(-) diff --git a/cli-windows/build-bits.ps1 b/cli-windows/build-bits.ps1 index 38cdfddcd..3b3d8da3f 100644 --- a/cli-windows/build-bits.ps1 +++ b/cli-windows/build-bits.ps1 @@ -31,7 +31,6 @@ $projectPaths = #Write-Host "Deleting old publish files in $outPath" -ForegroundColor Yellow remove-item -path $outPath -Force -Recurse -ErrorAction SilentlyContinue #Write-Host "Publishing $projectPathAndFile to $outPath" -ForegroundColor Yellow - dotnet build $projectPathAndFile dotnet publish $projectPathAndFile -o $outPath -c Release } } diff --git a/k8s/deploy.ps1 b/k8s/deploy.ps1 index be9424b4f..6b6318aca 100644 --- a/k8s/deploy.ps1 +++ b/k8s/deploy.ps1 @@ -54,7 +54,6 @@ Write-Host "Docker image Tag: $imageTag" -ForegroundColor Yellow # building and publishing docker images if needed if($buildBits) { Write-Host "Building and publishing eShopOnContainers..." -ForegroundColor Yellow - dotnet restore ../eShopOnContainers-ServicesAndWebApps.sln dotnet publish -c Release -o obj/Docker/publish ../eShopOnContainers-ServicesAndWebApps.sln } if ($buildImages) { From b8652c734b1207c91b5778f6729c463ce24da101 Mon Sep 17 00:00:00 2001 From: Igor Sychev Date: Wed, 6 Sep 2017 18:00:55 +0300 Subject: [PATCH 81/86] sync k8 images with local windows/linux images for consistency --- k8s/basket-data.yaml | 2 +- k8s/keystore-data.yaml | 2 +- k8s/rabbitmq.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/k8s/basket-data.yaml b/k8s/basket-data.yaml index b4f84f188..b48e73fed 100644 --- a/k8s/basket-data.yaml +++ b/k8s/basket-data.yaml @@ -25,5 +25,5 @@ spec: spec: containers: - name: basket-data - image: redis:3.2-alpine + image: redis diff --git a/k8s/keystore-data.yaml b/k8s/keystore-data.yaml index 3340cce35..0e2dfa9b9 100644 --- a/k8s/keystore-data.yaml +++ b/k8s/keystore-data.yaml @@ -25,5 +25,5 @@ spec: spec: containers: - name: keystore-data - image: redis:3.2-alpine + image: redis diff --git a/k8s/rabbitmq.yaml b/k8s/rabbitmq.yaml index a0d87549c..d2a7de906 100644 --- a/k8s/rabbitmq.yaml +++ b/k8s/rabbitmq.yaml @@ -25,6 +25,6 @@ spec: spec: containers: - name: rabbitmq - image: rabbitmq:3.6.9-alpine + image: rabbitmq:3-management ports: - containerPort: 5672 From 7321d5e5fcb8643f13d3deb48a80247fdf6f095c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Tom=C3=A0s?= Date: Thu, 7 Sep 2017 19:18:53 +0200 Subject: [PATCH 82/86] Base path fix and k8s config updated --- k8s/deployments.yaml | 36 +++++++++---------- k8s/gen-k8s-env.ps1 | 10 +++--- src/Services/Basket/Basket.API/Startup.cs | 6 ++++ src/Services/Catalog/Catalog.API/Startup.cs | 7 ++++ src/Services/Identity/Identity.API/Startup.cs | 7 ++++ .../Location/Locations.API/Startup.cs | 6 ++++ .../Marketing/Marketing.API/Startup.cs | 6 ++++ src/Services/Ordering/Ordering.API/Startup.cs | 7 ++++ src/Services/Payment/Payment.API/Startup.cs | 6 ++++ src/Web/WebMVC/Startup.cs | 7 ++++ src/Web/WebSPA/Startup.cs | 7 ++++ src/Web/WebStatus/Startup.cs | 6 ++++ 12 files changed, 89 insertions(+), 22 deletions(-) diff --git a/k8s/deployments.yaml b/k8s/deployments.yaml index 59e37de90..e542e8924 100644 --- a/k8s/deployments.yaml +++ b/k8s/deployments.yaml @@ -15,8 +15,8 @@ spec: image: eshop/basket.api imagePullPolicy: Always env: - - name: ASPNETCORE_URLS - value: http://0.0.0.0:80/basket-api + - name: PATH_BASE + value: /basket-api - name: ConnectionString valueFrom: configMapKeyRef: @@ -59,8 +59,8 @@ spec: image: eshop/catalog.api imagePullPolicy: Always env: - - name: ASPNETCORE_URLS - value: http://0.0.0.0:80/catalog-api + - name: PATH_BASE + value: /catalog-api - name: ConnectionString valueFrom: configMapKeyRef: @@ -103,8 +103,8 @@ spec: image: eshop/identity.api imagePullPolicy: Always env: - - name: ASPNETCORE_URLS - value: http://0.0.0.0:80/identity + - name: PATH_BASE + value: /identity - name: ConnectionStrings__DefaultConnection valueFrom: configMapKeyRef: @@ -169,8 +169,8 @@ spec: image: eshop/ordering.api imagePullPolicy: Always env: - - name: ASPNETCORE_URLS - value: http://0.0.0.0:80/ordering-api + - name: PATH_BASE + value: /ordering-api - name: ConnectionString valueFrom: configMapKeyRef: @@ -213,8 +213,8 @@ spec: image: eshop/locations.api imagePullPolicy: Always env: - - name: ASPNETCORE_URLS - value: http://0.0.0.0:80/locations-api + - name: PATH_BASE + value: /locations-api - name: ConnectionString valueFrom: configMapKeyRef: @@ -267,8 +267,8 @@ spec: image: eshop/marketing.api imagePullPolicy: Always env: - - name: ASPNETCORE_URLS - value: http://0.0.0.0:80/marketing-api + - name: PATH_BASE + value: /marketing-api - name: ConnectionString valueFrom: configMapKeyRef: @@ -331,8 +331,8 @@ spec: image: eshop/payment.api imagePullPolicy: Always env: - - name: ASPNETCORE_URLS - value: http://0.0.0.0:80/payment-api + - name: PATH_BASE + value: /payment-api - name: AzureServiceBusEnabled valueFrom: configMapKeyRef: @@ -365,8 +365,8 @@ spec: image: eshop/webmvc imagePullPolicy: Always env: - - name: ASPNETCORE_URLS - value: http://0.0.0.0:80/webmvc + - name: PATH_BASE + value: /webmvc - name: DPConnectionString valueFrom: configMapKeyRef: @@ -426,8 +426,8 @@ spec: image: eshop/webstatus imagePullPolicy: Always env: - - name: ASPNETCORE_URLS - value: http://0.0.0.0:80/webstatus + - name: PATH_BASE + value: /webstatus - name: BasketUrl valueFrom: configMapKeyRef: diff --git a/k8s/gen-k8s-env.ps1 b/k8s/gen-k8s-env.ps1 index c3b82469c..5276262f5 100644 --- a/k8s/gen-k8s-env.ps1 +++ b/k8s/gen-k8s-env.ps1 @@ -1,7 +1,7 @@ Param( [parameter(Mandatory=$true)][string]$resourceGroupName, [parameter(Mandatory=$true)][string]$location, - [parameter(Mandatory=$true)][string]$registryName, + [parameter(Mandatory=$false)][string]$registryName, [parameter(Mandatory=$true)][string]$orchestratorName, [parameter(Mandatory=$true)][string]$dnsName, [parameter(Mandatory=$true)][string]$createAcr=$true @@ -11,7 +11,7 @@ Write-Host "Creating resource group..." -ForegroundColor Yellow az group create --name=$resourceGroupName --location=$location -if ($createAcr) { +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 @@ -24,5 +24,7 @@ az acs create --orchestrator-type=kubernetes --resource-group $resourceGroupName # Retrieve kubernetes cluster configuration and save it under ~/.kube/config az acs kubernetes get-credentials --resource-group=$resourceGroupName --name=$orchestratorName -# Show ACR credentials -az acr credential show -n $registryName \ No newline at end of file +if ($createAcr -eq $true) { + # Show ACR credentials + az acr credential show -n $registryName +} \ No newline at end of file diff --git a/src/Services/Basket/Basket.API/Startup.cs b/src/Services/Basket/Basket.API/Startup.cs index 1f62e44cb..df079e4e6 100644 --- a/src/Services/Basket/Basket.API/Startup.cs +++ b/src/Services/Basket/Basket.API/Startup.cs @@ -169,6 +169,12 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { + + var pathBase = Configuration["PATH_BASE"]; + if (!string.IsNullOrEmpty(pathBase)) + { + app.UsePathBase(pathBase); + } app.UseStaticFiles(); app.UseCors("CorsPolicy"); diff --git a/src/Services/Catalog/Catalog.API/Startup.cs b/src/Services/Catalog/Catalog.API/Startup.cs index 354d0643e..21b9ae1c8 100644 --- a/src/Services/Catalog/Catalog.API/Startup.cs +++ b/src/Services/Catalog/Catalog.API/Startup.cs @@ -167,6 +167,13 @@ loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); + var pathBase = Configuration["PATH_BASE"]; + if (!string.IsNullOrEmpty(pathBase)) + { + loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'"); + app.UsePathBase(pathBase); + } + app.UseCors("CorsPolicy"); app.UseMvcWithDefaultRoute(); diff --git a/src/Services/Identity/Identity.API/Startup.cs b/src/Services/Identity/Identity.API/Startup.cs index edd02d0a1..c4ee28f25 100644 --- a/src/Services/Identity/Identity.API/Startup.cs +++ b/src/Services/Identity/Identity.API/Startup.cs @@ -125,6 +125,13 @@ namespace eShopOnContainers.Identity app.UseExceptionHandler("/Home/Error"); } + var pathBase = Configuration["PATH_BASE"]; + if (!string.IsNullOrEmpty(pathBase)) + { + loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'"); + app.UsePathBase(pathBase); + } + app.UseStaticFiles(); diff --git a/src/Services/Location/Locations.API/Startup.cs b/src/Services/Location/Locations.API/Startup.cs index 4b92afa02..b2147cbd1 100644 --- a/src/Services/Location/Locations.API/Startup.cs +++ b/src/Services/Location/Locations.API/Startup.cs @@ -141,6 +141,12 @@ 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) { + var pathBase = Configuration["PATH_BASE"]; + if (!string.IsNullOrEmpty(pathBase)) + { + app.UsePathBase(pathBase); + } + app.UseCors("CorsPolicy"); ConfigureAuth(app); diff --git a/src/Services/Marketing/Marketing.API/Startup.cs b/src/Services/Marketing/Marketing.API/Startup.cs index 37d6911c1..bac62095f 100644 --- a/src/Services/Marketing/Marketing.API/Startup.cs +++ b/src/Services/Marketing/Marketing.API/Startup.cs @@ -173,6 +173,12 @@ // 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) { + var pathBase = Configuration["PATH_BASE"]; + if (!string.IsNullOrEmpty(pathBase)) + { + app.UsePathBase(pathBase); + } + app.UseCors("CorsPolicy"); ConfigureAuth(app); diff --git a/src/Services/Ordering/Ordering.API/Startup.cs b/src/Services/Ordering/Ordering.API/Startup.cs index 2d2f94423..1bf2fd22c 100644 --- a/src/Services/Ordering/Ordering.API/Startup.cs +++ b/src/Services/Ordering/Ordering.API/Startup.cs @@ -189,6 +189,13 @@ loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); + var pathBase = Configuration["PATH_BASE"]; + if (!string.IsNullOrEmpty(pathBase)) + { + loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'"); + app.UsePathBase(pathBase); + } + app.UseCors("CorsPolicy"); ConfigureAuth(app); diff --git a/src/Services/Payment/Payment.API/Startup.cs b/src/Services/Payment/Payment.API/Startup.cs index c4ab2c322..e4378dcef 100644 --- a/src/Services/Payment/Payment.API/Startup.cs +++ b/src/Services/Payment/Payment.API/Startup.cs @@ -92,6 +92,12 @@ 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) { + var pathBase = Configuration["PATH_BASE"]; + if (!string.IsNullOrEmpty(pathBase)) + { + app.UsePathBase(pathBase); + } + app.UseMvcWithDefaultRoute(); app.UseSwagger() diff --git a/src/Web/WebMVC/Startup.cs b/src/Web/WebMVC/Startup.cs index 8b10c1ecc..58fae38f9 100644 --- a/src/Web/WebMVC/Startup.cs +++ b/src/Web/WebMVC/Startup.cs @@ -123,6 +123,13 @@ namespace Microsoft.eShopOnContainers.WebMVC app.UseExceptionHandler("/Error"); } + var pathBase = Configuration["PATH_BASE"]; + if (!string.IsNullOrEmpty(pathBase)) + { + loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'"); + app.UsePathBase(pathBase); + } + app.UseSession(); app.UseStaticFiles(); diff --git a/src/Web/WebSPA/Startup.cs b/src/Web/WebSPA/Startup.cs index 1659af537..15c27da42 100644 --- a/src/Web/WebSPA/Startup.cs +++ b/src/Web/WebSPA/Startup.cs @@ -95,6 +95,13 @@ namespace eShopConContainers.WebSPA //Seed Data WebContextSeed.Seed(app, env, loggerFactory); + var pathBase = Configuration["PATH_BASE"]; + if (!string.IsNullOrEmpty(pathBase)) + { + loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'"); + app.UsePathBase(pathBase); + } + app.Use(async (context, next) => { await next(); diff --git a/src/Web/WebStatus/Startup.cs b/src/Web/WebStatus/Startup.cs index eb559acd9..167a01baa 100644 --- a/src/Web/WebStatus/Startup.cs +++ b/src/Web/WebStatus/Startup.cs @@ -60,6 +60,12 @@ namespace WebStatus app.UseExceptionHandler("/Home/Error"); } + var pathBase = Configuration["PATH_BASE"]; + if (!string.IsNullOrEmpty(pathBase)) + { + app.UsePathBase(pathBase); + } + app.UseStaticFiles(); app.UseMvc(routes => From aed97fdc99cba51210438c46efa4cf3271f0a6fd Mon Sep 17 00:00:00 2001 From: Unai Zorrilla Castro Date: Mon, 11 Sep 2017 12:43:45 +0200 Subject: [PATCH 83/86] Migrated Identity.API to Identity Server 4 on dotnetcore2 --- .../Controllers/AccountController.cs | 43 +++++++++++-------- .../Identity.API/Data/ApplicationDbContext.cs | 6 +-- .../Identity/Identity.API/Identity.API.csproj | 41 ++++-------------- .../Identity.API/Models/ApplicationUser.cs | 6 +-- src/Services/Identity/Identity.API/Startup.cs | 21 +++++---- 5 files changed, 48 insertions(+), 69 deletions(-) diff --git a/src/Services/Identity/Identity.API/Controllers/AccountController.cs b/src/Services/Identity/Identity.API/Controllers/AccountController.cs index 02b50129f..51e582ed7 100644 --- a/src/Services/Identity/Identity.API/Controllers/AccountController.cs +++ b/src/Services/Identity/Identity.API/Controllers/AccountController.cs @@ -2,26 +2,23 @@ // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. +using Identity.API.Models; +using Identity.API.Models.AccountViewModels; +using Identity.API.Services; using IdentityModel; -using IdentityServer4.Quickstart.UI.Models; +using IdentityServer4.Models; using IdentityServer4.Services; -using Microsoft.AspNetCore.Http.Authentication; +using IdentityServer4.Stores; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; using System; -using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Text.Encodings.Web; using System.Threading.Tasks; -using IdentityServer4.Models; -using IdentityServer4.Stores; -using Identity.API.Services; -using Identity.API.Models; -using Microsoft.Extensions.Logging; -using Microsoft.AspNetCore.Authorization; -using Identity.API.Models.AccountViewModels; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Authentication; namespace IdentityServer4.Quickstart.UI.Controllers { @@ -36,7 +33,7 @@ namespace IdentityServer4.Quickstart.UI.Controllers private readonly ILoginService _loginService; private readonly IIdentityServerInteractionService _interaction; private readonly IClientStore _clientStore; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly UserManager _userManager; public AccountController( @@ -45,13 +42,13 @@ namespace IdentityServer4.Quickstart.UI.Controllers ILoginService loginService, IIdentityServerInteractionService interaction, IClientStore clientStore, - ILoggerFactory loggerFactory, + ILogger logger, UserManager userManager) { _loginService = loginService; _interaction = interaction; _clientStore = clientStore; - _logger = loggerFactory.CreateLogger(); + _logger = logger; _userManager = userManager; } @@ -69,6 +66,7 @@ namespace IdentityServer4.Quickstart.UI.Controllers } var vm = await BuildLoginViewModelAsync(returnUrl, context); + ViewData["ReturnUrl"] = returnUrl; return View(vm); @@ -97,6 +95,7 @@ namespace IdentityServer4.Quickstart.UI.Controllers }; await _loginService.SignIn(user); + // make sure the returnUrl is still valid, and if yes - redirect back to authorize endpoint if (_interaction.IsValidReturnUrl(model.ReturnUrl)) { @@ -111,7 +110,9 @@ namespace IdentityServer4.Quickstart.UI.Controllers // something went wrong, show form with error var vm = await BuildLoginViewModelAsync(model); + ViewData["ReturnUrl"] = model.ReturnUrl; + return View(vm); } @@ -180,6 +181,7 @@ namespace IdentityServer4.Quickstart.UI.Controllers public async Task Logout(LogoutViewModel model) { var idp = User?.FindFirst(JwtClaimTypes.IdentityProvider)?.Value; + if (idp != null && idp != IdentityServerConstants.LocalIdentityProvider) { if (model.LogoutId == null) @@ -191,10 +193,15 @@ namespace IdentityServer4.Quickstart.UI.Controllers } string url = "/Account/Logout?logoutId=" + model.LogoutId; + try { + // hack: try/catch to handle social providers that throw - await HttpContext.Authentication.SignOutAsync(idp, new AuthenticationProperties { RedirectUri = url }); + await HttpContext.SignOutAsync(idp, new AuthenticationProperties + { + RedirectUri = url + }); } catch (Exception ex) { @@ -203,7 +210,7 @@ namespace IdentityServer4.Quickstart.UI.Controllers } // delete authentication cookie - await HttpContext.Authentication.SignOutAsync(); + await HttpContext.SignOutAsync(); // set this so UI rendering sees an anonymous user HttpContext.User = new ClaimsPrincipal(new ClaimsIdentity()); @@ -217,7 +224,7 @@ namespace IdentityServer4.Quickstart.UI.Controllers public async Task DeviceLogOut(string redirectUrl) { // delete authentication cookie - await HttpContext.Authentication.SignOutAsync(); + await HttpContext.SignOutAsync(); // set this so UI rendering sees an anonymous user HttpContext.User = new ClaimsPrincipal(new ClaimsIdentity()); diff --git a/src/Services/Identity/Identity.API/Data/ApplicationDbContext.cs b/src/Services/Identity/Identity.API/Data/ApplicationDbContext.cs index ddbe7bbfd..bbbe04962 100644 --- a/src/Services/Identity/Identity.API/Data/ApplicationDbContext.cs +++ b/src/Services/Identity/Identity.API/Data/ApplicationDbContext.cs @@ -1,10 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using Identity.API.Models; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; -using Identity.API.Models; namespace Identity.API.Data { diff --git a/src/Services/Identity/Identity.API/Identity.API.csproj b/src/Services/Identity/Identity.API/Identity.API.csproj index 7c221e858..ae6aab44b 100644 --- a/src/Services/Identity/Identity.API/Identity.API.csproj +++ b/src/Services/Identity/Identity.API/Identity.API.csproj @@ -1,8 +1,8 @@  - netcoreapp1.1 - 1.1.2 + netcoreapp2.0 + 2.0.0 aspnet-eShopOnContainers.Identity-90487118-103c-4ff0-b9da-e5e26f7ab0c5 $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; ..\..\..\..\docker-compose.dcproj @@ -16,32 +16,9 @@ - - - - - - - - - - - - All - - - All - - - - - - - - - - - + + + @@ -51,10 +28,10 @@ - - - - + + + + diff --git a/src/Services/Identity/Identity.API/Models/ApplicationUser.cs b/src/Services/Identity/Identity.API/Models/ApplicationUser.cs index b520c333b..1c1f7bda1 100644 --- a/src/Services/Identity/Identity.API/Models/ApplicationUser.cs +++ b/src/Services/Identity/Identity.API/Models/ApplicationUser.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.AspNetCore.Identity; using System.ComponentModel.DataAnnotations; namespace Identity.API.Models diff --git a/src/Services/Identity/Identity.API/Startup.cs b/src/Services/Identity/Identity.API/Startup.cs index c4ee28f25..f579071e7 100644 --- a/src/Services/Identity/Identity.API/Startup.cs +++ b/src/Services/Identity/Identity.API/Startup.cs @@ -11,7 +11,6 @@ using IdentityServer4.Services; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.eShopOnContainers.BuildingBlocks; using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; @@ -95,16 +94,21 @@ namespace eShopOnContainers.Identity services.AddIdentityServer(x => x.IssuerUri = "null") .AddSigningCredential(Certificate.Get()) .AddAspNetIdentity() - .AddConfigurationStore(builder => - builder.UseSqlServer(connectionString, options => - options.MigrationsAssembly(migrationsAssembly))) - .AddOperationalStore(builder => - builder.UseSqlServer(connectionString, options => - options.MigrationsAssembly(migrationsAssembly))) + .AddConfigurationStore(options => + { + options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString, opts => + opts.MigrationsAssembly(migrationsAssembly)); + }) + .AddOperationalStore(options => + { + options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString, opts => + opts.MigrationsAssembly(migrationsAssembly)); + }) .Services.AddTransient(); var container = new ContainerBuilder(); container.Populate(services); + return new AutofacServiceProvider(container.Build()); } @@ -118,7 +122,6 @@ namespace eShopOnContainers.Identity { app.UseDeveloperExceptionPage(); app.UseDatabaseErrorPage(); - app.UseBrowserLink(); } else { @@ -142,7 +145,7 @@ namespace eShopOnContainers.Identity await next(); }); - app.UseIdentity(); + app.UseAuthentication(); // Adds IdentityServer app.UseIdentityServer(); From 4f8ca3eebb84db579454810bbf953be54883bfe5 Mon Sep 17 00:00:00 2001 From: Unai Zorrilla Castro Date: Tue, 12 Sep 2017 13:44:52 +0200 Subject: [PATCH 84/86] Fix migrations for new identity server, fix new program template for dotnetcore2 --- .../20161020101725_extendProfile.Designer.cs | 246 ----------------- .../20161020101725_extendProfile.cs | 33 --- .../20170604151240_Init-persisted-grant.cs | 40 --- .../20170912114036_Initial.Designer.cs} | 241 ++++++++-------- .../20170912114036_Initial.cs} | 150 +++++----- .../ApplicationDbContextModelSnapshot.cs | 242 ++++++++-------- ....cs => 20170912114152_Initial.Designer.cs} | 63 ++++- ...iguration.cs => 20170912114152_Initial.cs} | 258 ++++++++++-------- .../ConfigurationDbContextModelSnapshot.cs | 59 +++- .../20170912114120_Initial.Designer.cs} | 16 +- .../20170912114120_Initial.cs | 40 +++ .../PersistedGrantDbContextModelSnapshot.cs | 12 +- src/Services/Identity/Identity.API/Program.cs | 19 +- src/Services/Identity/Identity.API/Startup.cs | 23 +- 14 files changed, 674 insertions(+), 768 deletions(-) delete mode 100644 src/Services/Identity/Identity.API/Data/Migrations/20161020101725_extendProfile.Designer.cs delete mode 100644 src/Services/Identity/Identity.API/Data/Migrations/20161020101725_extendProfile.cs delete mode 100644 src/Services/Identity/Identity.API/Migrations/20170604151240_Init-persisted-grant.cs rename src/Services/Identity/Identity.API/{Data/Migrations/20161019122215_Init_Scheme.Designer.cs => Migrations/20170912114036_Initial.Designer.cs} (54%) rename src/Services/Identity/Identity.API/{Data/Migrations/20161019122215_Init_Scheme.cs => Migrations/20170912114036_Initial.cs} (53%) rename src/Services/Identity/Identity.API/{Data => }/Migrations/ApplicationDbContextModelSnapshot.cs (55%) rename src/Services/Identity/Identity.API/Migrations/ConfigurationDb/{20170604151338_Init-configuration.Designer.cs => 20170912114152_Initial.Designer.cs} (90%) rename src/Services/Identity/Identity.API/Migrations/ConfigurationDb/{20170604151338_Init-configuration.cs => 20170912114152_Initial.cs} (62%) rename src/Services/Identity/Identity.API/Migrations/{20170604151240_Init-persisted-grant.Designer.cs => PersistedGrantDb/20170912114120_Initial.Designer.cs} (81%) create mode 100644 src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20170912114120_Initial.cs rename src/Services/Identity/Identity.API/Migrations/{ => PersistedGrantDb}/PersistedGrantDbContextModelSnapshot.cs (85%) diff --git a/src/Services/Identity/Identity.API/Data/Migrations/20161020101725_extendProfile.Designer.cs b/src/Services/Identity/Identity.API/Data/Migrations/20161020101725_extendProfile.Designer.cs deleted file mode 100644 index 2d118647d..000000000 --- a/src/Services/Identity/Identity.API/Data/Migrations/20161020101725_extendProfile.Designer.cs +++ /dev/null @@ -1,246 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Identity.API.Data; - -namespace WebMVC.Migrations -{ - [DbContext(typeof(ApplicationDbContext))] - [Migration("20161020101725_extendProfile")] - partial class extendProfile - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { - modelBuilder - .HasAnnotation("ProductVersion", "1.0.0-rtm-21431") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", b => - { - b.Property("Id"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken(); - - b.Property("Name") - .HasAnnotation("MaxLength", 256); - - b.Property("NormalizedName") - .HasAnnotation("MaxLength", 256); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .HasName("RoleNameIndex"); - - b.ToTable("AspNetRoles"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("ClaimType"); - - b.Property("ClaimValue"); - - b.Property("RoleId") - .IsRequired(); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("ClaimType"); - - b.Property("ClaimValue"); - - b.Property("UserId") - .IsRequired(); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b => - { - b.Property("LoginProvider"); - - b.Property("ProviderKey"); - - b.Property("ProviderDisplayName"); - - b.Property("UserId") - .IsRequired(); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b => - { - b.Property("UserId"); - - b.Property("RoleId"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserRoles"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken", b => - { - b.Property("UserId"); - - b.Property("LoginProvider"); - - b.Property("Name"); - - b.Property("Value"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens"); - }); - - modelBuilder.Entity("Microsoft.eShopOnContainers.WebMVC.ViewModels.ApplicationUser", b => - { - b.Property("Id"); - - b.Property("AccessFailedCount"); - - b.Property("CardHolderName"); - - b.Property("CardNumber"); - - b.Property("CardType"); - - b.Property("City"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken(); - - b.Property("Country"); - - b.Property("CountryCode"); - - b.Property("Email") - .HasAnnotation("MaxLength", 256); - - b.Property("EmailConfirmed"); - - b.Property("Expiration"); - - b.Property("LastName"); - - b.Property("Latitude"); - - b.Property("LockoutEnabled"); - - b.Property("LockoutEnd"); - - b.Property("Longitude"); - - b.Property("Name"); - - b.Property("NormalizedEmail") - .HasAnnotation("MaxLength", 256); - - b.Property("NormalizedUserName") - .HasAnnotation("MaxLength", 256); - - b.Property("PasswordHash"); - - b.Property("PhoneNumber"); - - b.Property("PhoneNumberConfirmed"); - - b.Property("SecurityNumber"); - - b.Property("SecurityStamp"); - - b.Property("State"); - - b.Property("StateCode"); - - b.Property("Street"); - - b.Property("TwoFactorEnabled"); - - b.Property("UserName") - .HasAnnotation("MaxLength", 256); - - b.Property("ZipCode"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasName("UserNameIndex"); - - b.ToTable("AspNetUsers"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole") - .WithMany("Claims") - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b => - { - b.HasOne("Microsoft.eShopOnContainers.WebMVC.ViewModels.ApplicationUser") - .WithMany("Claims") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b => - { - b.HasOne("Microsoft.eShopOnContainers.WebMVC.ViewModels.ApplicationUser") - .WithMany("Logins") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole") - .WithMany("Users") - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Microsoft.eShopOnContainers.WebMVC.ViewModels.ApplicationUser") - .WithMany("Roles") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - }); - } - } -} diff --git a/src/Services/Identity/Identity.API/Data/Migrations/20161020101725_extendProfile.cs b/src/Services/Identity/Identity.API/Data/Migrations/20161020101725_extendProfile.cs deleted file mode 100644 index 46dfceb9a..000000000 --- a/src/Services/Identity/Identity.API/Data/Migrations/20161020101725_extendProfile.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace WebMVC.Migrations -{ - public partial class extendProfile : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "LastName", - table: "AspNetUsers", - nullable: true); - - migrationBuilder.AddColumn( - name: "Name", - table: "AspNetUsers", - nullable: true); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "LastName", - table: "AspNetUsers"); - - migrationBuilder.DropColumn( - name: "Name", - table: "AspNetUsers"); - } - } -} diff --git a/src/Services/Identity/Identity.API/Migrations/20170604151240_Init-persisted-grant.cs b/src/Services/Identity/Identity.API/Migrations/20170604151240_Init-persisted-grant.cs deleted file mode 100644 index 51c896f5f..000000000 --- a/src/Services/Identity/Identity.API/Migrations/20170604151240_Init-persisted-grant.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Identity.API.Migrations -{ - public partial class Initpersistedgrant : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "PersistedGrants", - columns: table => new - { - Key = table.Column(maxLength: 200, nullable: false), - ClientId = table.Column(maxLength: 200, nullable: false), - CreationTime = table.Column(nullable: false), - Data = table.Column(maxLength: 50000, nullable: false), - Expiration = table.Column(nullable: true), - SubjectId = table.Column(maxLength: 200, nullable: true), - Type = table.Column(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/Data/Migrations/20161019122215_Init_Scheme.Designer.cs b/src/Services/Identity/Identity.API/Migrations/20170912114036_Initial.Designer.cs similarity index 54% rename from src/Services/Identity/Identity.API/Data/Migrations/20161019122215_Init_Scheme.Designer.cs rename to src/Services/Identity/Identity.API/Migrations/20170912114036_Initial.Designer.cs index 07e821f4c..59f056335 100644 --- a/src/Services/Identity/Identity.API/Data/Migrations/20161019122215_Init_Scheme.Designer.cs +++ b/src/Services/Identity/Identity.API/Migrations/20170912114036_Initial.Designer.cs @@ -1,44 +1,137 @@ -using System; +// +using Identity.API.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -using Identity.API.Data; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Internal; +using System; -namespace WebMVC.Migrations +namespace Identity.API.Migrations { [DbContext(typeof(ApplicationDbContext))] - [Migration("20161019122215_Init_Scheme")] - partial class Init_Scheme + [Migration("20170912114036_Initial")] + partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) { +#pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "1.0.0-rtm-21431") + .HasAnnotation("ProductVersion", "2.0.0-rtm-26452") .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", b => + 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"); + b.Property("Id") + .ValueGeneratedOnAdd(); b.Property("ConcurrencyStamp") .IsConcurrencyToken(); b.Property("Name") - .HasAnnotation("MaxLength", 256); + .HasMaxLength(256); b.Property("NormalizedName") - .HasAnnotation("MaxLength", 256); + .HasMaxLength(256); b.HasKey("Id"); b.HasIndex("NormalizedName") - .HasName("RoleNameIndex"); + .IsUnique() + .HasName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); b.ToTable("AspNetRoles"); }); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b => + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => { b.Property("Id") .ValueGeneratedOnAdd(); @@ -57,7 +150,7 @@ namespace WebMVC.Migrations b.ToTable("AspNetRoleClaims"); }); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b => + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { b.Property("Id") .ValueGeneratedOnAdd(); @@ -76,7 +169,7 @@ namespace WebMVC.Migrations b.ToTable("AspNetUserClaims"); }); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b => + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { b.Property("LoginProvider"); @@ -94,7 +187,7 @@ namespace WebMVC.Migrations b.ToTable("AspNetUserLogins"); }); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b => + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => { b.Property("UserId"); @@ -104,12 +197,10 @@ namespace WebMVC.Migrations b.HasIndex("RoleId"); - b.HasIndex("UserId"); - b.ToTable("AspNetUserRoles"); }); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken", b => + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { b.Property("UserId"); @@ -124,119 +215,51 @@ namespace WebMVC.Migrations b.ToTable("AspNetUserTokens"); }); - modelBuilder.Entity("Microsoft.eShopOnContainers.WebMVC.ViewModels.ApplicationUser", b => - { - b.Property("Id"); - - b.Property("AccessFailedCount"); - - b.Property("CardHolderName"); - - b.Property("CardNumber"); - - b.Property("CardType"); - - b.Property("City"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken(); - - b.Property("Country"); - - b.Property("CountryCode"); - - b.Property("Email") - .HasAnnotation("MaxLength", 256); - - b.Property("EmailConfirmed"); - - b.Property("Expiration"); - - b.Property("Latitude"); - - b.Property("LockoutEnabled"); - - b.Property("LockoutEnd"); - - b.Property("Longitude"); - - b.Property("NormalizedEmail") - .HasAnnotation("MaxLength", 256); - - b.Property("NormalizedUserName") - .HasAnnotation("MaxLength", 256); - - b.Property("PasswordHash"); - - b.Property("PhoneNumber"); - - b.Property("PhoneNumberConfirmed"); - - b.Property("SecurityNumber"); - - b.Property("SecurityStamp"); - - b.Property("State"); - - b.Property("StateCode"); - - b.Property("Street"); - - b.Property("TwoFactorEnabled"); - - b.Property("UserName") - .HasAnnotation("MaxLength", 256); - - b.Property("ZipCode"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasName("UserNameIndex"); - - b.ToTable("AspNetUsers"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b => + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => { - b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole") - .WithMany("Claims") + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade); }); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b => + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("Microsoft.eShopOnContainers.WebMVC.ViewModels.ApplicationUser") - .WithMany("Claims") + b.HasOne("Identity.API.Models.ApplicationUser") + .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade); }); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b => + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("Microsoft.eShopOnContainers.WebMVC.ViewModels.ApplicationUser") - .WithMany("Logins") + b.HasOne("Identity.API.Models.ApplicationUser") + .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade); }); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b => + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => { - b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole") - .WithMany("Users") + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade); - b.HasOne("Microsoft.eShopOnContainers.WebMVC.ViewModels.ApplicationUser") - .WithMany("Roles") + b.HasOne("Identity.API.Models.ApplicationUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Identity.API.Models.ApplicationUser") + .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade); }); +#pragma warning restore 612, 618 } } } diff --git a/src/Services/Identity/Identity.API/Data/Migrations/20161019122215_Init_Scheme.cs b/src/Services/Identity/Identity.API/Migrations/20170912114036_Initial.cs similarity index 53% rename from src/Services/Identity/Identity.API/Data/Migrations/20161019122215_Init_Scheme.cs rename to src/Services/Identity/Identity.API/Migrations/20170912114036_Initial.cs index 278c3f422..cf771dac8 100644 --- a/src/Services/Identity/Identity.API/Data/Migrations/20161019122215_Init_Scheme.cs +++ b/src/Services/Identity/Identity.API/Migrations/20170912114036_Initial.cs @@ -1,11 +1,11 @@ -using System; -using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Metadata; +using System; +using System.Collections.Generic; -namespace WebMVC.Migrations +namespace Identity.API.Migrations { - public partial class Init_Scheme : Migration + public partial class Initial : Migration { protected override void Up(MigrationBuilder migrationBuilder) { @@ -13,59 +13,47 @@ namespace WebMVC.Migrations name: "AspNetRoles", columns: table => new { - Id = table.Column(nullable: false), - ConcurrencyStamp = table.Column(nullable: true), - Name = table.Column(maxLength: 256, nullable: true), - NormalizedName = table.Column(maxLength: 256, nullable: true) + 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) }, constraints: table => { table.PrimaryKey("PK_AspNetRoles", x => x.Id); }); - migrationBuilder.CreateTable( - name: "AspNetUserTokens", - columns: table => new - { - UserId = table.Column(nullable: false), - LoginProvider = table.Column(nullable: false), - Name = table.Column(nullable: false), - Value = table.Column(nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); - }); - migrationBuilder.CreateTable( name: "AspNetUsers", columns: table => new { - Id = table.Column(nullable: false), - AccessFailedCount = table.Column(nullable: false), - CardHolderName = table.Column(nullable: true), - CardNumber = table.Column(nullable: true), - CardType = table.Column(nullable: false), - City = table.Column(nullable: true), - ConcurrencyStamp = table.Column(nullable: true), - Country = table.Column(nullable: true), - Email = table.Column(maxLength: 256, nullable: true), - EmailConfirmed = table.Column(nullable: false), - Expiration = table.Column(nullable: true), - LockoutEnabled = table.Column(nullable: false), - LockoutEnd = table.Column(nullable: true), - NormalizedEmail = table.Column(maxLength: 256, nullable: true), - NormalizedUserName = table.Column(maxLength: 256, nullable: true), - PasswordHash = table.Column(nullable: true), - PhoneNumber = table.Column(nullable: true), - PhoneNumberConfirmed = table.Column(nullable: false), - SecurityNumber = table.Column(nullable: true), - SecurityStamp = table.Column(nullable: true), - State = table.Column(nullable: true), - Street = table.Column(nullable: true), - TwoFactorEnabled = table.Column(nullable: false), - UserName = table.Column(maxLength: 256, nullable: true), - ZipCode = table.Column(nullable: true) + 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) }, constraints: table => { @@ -76,11 +64,11 @@ namespace WebMVC.Migrations name: "AspNetRoleClaims", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClaimType = table.Column(nullable: true), - ClaimValue = table.Column(nullable: true), - RoleId = table.Column(nullable: false) + ClaimType = table.Column(type: "nvarchar(max)", nullable: true), + ClaimValue = table.Column(type: "nvarchar(max)", nullable: true), + RoleId = table.Column(type: "nvarchar(450)", nullable: false) }, constraints: table => { @@ -97,11 +85,11 @@ namespace WebMVC.Migrations name: "AspNetUserClaims", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClaimType = table.Column(nullable: true), - ClaimValue = table.Column(nullable: true), - UserId = table.Column(nullable: false) + ClaimType = table.Column(type: "nvarchar(max)", nullable: true), + ClaimValue = table.Column(type: "nvarchar(max)", nullable: true), + UserId = table.Column(type: "nvarchar(450)", nullable: false) }, constraints: table => { @@ -118,10 +106,10 @@ namespace WebMVC.Migrations name: "AspNetUserLogins", columns: table => new { - LoginProvider = table.Column(nullable: false), - ProviderKey = table.Column(nullable: false), - ProviderDisplayName = table.Column(nullable: true), - UserId = table.Column(nullable: false) + 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) }, constraints: table => { @@ -138,8 +126,8 @@ namespace WebMVC.Migrations name: "AspNetUserRoles", columns: table => new { - UserId = table.Column(nullable: false), - RoleId = table.Column(nullable: false) + UserId = table.Column(type: "nvarchar(450)", nullable: false), + RoleId = table.Column(type: "nvarchar(450)", nullable: false) }, constraints: table => { @@ -158,16 +146,38 @@ namespace WebMVC.Migrations onDelete: ReferentialAction.Cascade); }); - migrationBuilder.CreateIndex( - name: "RoleNameIndex", - table: "AspNetRoles", - column: "NormalizedName"); + migrationBuilder.CreateTable( + 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) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); + table.ForeignKey( + name: "FK_AspNetUserTokens_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); migrationBuilder.CreateIndex( name: "IX_AspNetRoleClaims_RoleId", table: "AspNetRoleClaims", column: "RoleId"); + migrationBuilder.CreateIndex( + name: "RoleNameIndex", + table: "AspNetRoles", + column: "NormalizedName", + unique: true, + filter: "[NormalizedName] IS NOT NULL"); + migrationBuilder.CreateIndex( name: "IX_AspNetUserClaims_UserId", table: "AspNetUserClaims", @@ -183,11 +193,6 @@ namespace WebMVC.Migrations table: "AspNetUserRoles", column: "RoleId"); - migrationBuilder.CreateIndex( - name: "IX_AspNetUserRoles_UserId", - table: "AspNetUserRoles", - column: "UserId"); - migrationBuilder.CreateIndex( name: "EmailIndex", table: "AspNetUsers", @@ -197,7 +202,8 @@ namespace WebMVC.Migrations name: "UserNameIndex", table: "AspNetUsers", column: "NormalizedUserName", - unique: true); + unique: true, + filter: "[NormalizedUserName] IS NOT NULL"); } protected override void Down(MigrationBuilder migrationBuilder) diff --git a/src/Services/Identity/Identity.API/Data/Migrations/ApplicationDbContextModelSnapshot.cs b/src/Services/Identity/Identity.API/Migrations/ApplicationDbContextModelSnapshot.cs similarity index 55% rename from src/Services/Identity/Identity.API/Data/Migrations/ApplicationDbContextModelSnapshot.cs rename to src/Services/Identity/Identity.API/Migrations/ApplicationDbContextModelSnapshot.cs index 1f14e2321..ff7e60e21 100644 --- a/src/Services/Identity/Identity.API/Data/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/src/Services/Identity/Identity.API/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1,42 +1,136 @@ -using System; +// +using Identity.API.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; -using Identity.API.Data; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Internal; +using System; -namespace WebMVC.Migrations +namespace Identity.API.Migrations { [DbContext(typeof(ApplicationDbContext))] partial class ApplicationDbContextModelSnapshot : ModelSnapshot { protected override void BuildModel(ModelBuilder modelBuilder) { +#pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "1.0.0-rtm-21431") + .HasAnnotation("ProductVersion", "2.0.0-rtm-26452") .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", b => + modelBuilder.Entity("Identity.API.Models.ApplicationUser", b => { - b.Property("Id"); + 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") - .HasAnnotation("MaxLength", 256); + .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("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Name") + .HasMaxLength(256); b.Property("NormalizedName") - .HasAnnotation("MaxLength", 256); + .HasMaxLength(256); b.HasKey("Id"); b.HasIndex("NormalizedName") - .HasName("RoleNameIndex"); + .IsUnique() + .HasName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); b.ToTable("AspNetRoles"); }); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b => + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => { b.Property("Id") .ValueGeneratedOnAdd(); @@ -55,7 +149,7 @@ namespace WebMVC.Migrations b.ToTable("AspNetRoleClaims"); }); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b => + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { b.Property("Id") .ValueGeneratedOnAdd(); @@ -74,7 +168,7 @@ namespace WebMVC.Migrations b.ToTable("AspNetUserClaims"); }); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b => + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { b.Property("LoginProvider"); @@ -92,7 +186,7 @@ namespace WebMVC.Migrations b.ToTable("AspNetUserLogins"); }); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b => + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => { b.Property("UserId"); @@ -102,12 +196,10 @@ namespace WebMVC.Migrations b.HasIndex("RoleId"); - b.HasIndex("UserId"); - b.ToTable("AspNetUserRoles"); }); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken", b => + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { b.Property("UserId"); @@ -122,123 +214,51 @@ namespace WebMVC.Migrations b.ToTable("AspNetUserTokens"); }); - modelBuilder.Entity("Microsoft.eShopOnContainers.WebMVC.ViewModels.ApplicationUser", b => + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => { - b.Property("Id"); - - b.Property("AccessFailedCount"); - - b.Property("CardHolderName"); - - b.Property("CardNumber"); - - b.Property("CardType"); - - b.Property("City"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken(); - - b.Property("Country"); - - b.Property("CountryCode"); - - b.Property("Email") - .HasAnnotation("MaxLength", 256); - - b.Property("EmailConfirmed"); - - b.Property("Expiration"); - - b.Property("LastName"); - - b.Property("Latitude"); - - b.Property("LockoutEnabled"); - - b.Property("LockoutEnd"); - - b.Property("Longitude"); - - b.Property("Name"); - - b.Property("NormalizedEmail") - .HasAnnotation("MaxLength", 256); - - b.Property("NormalizedUserName") - .HasAnnotation("MaxLength", 256); - - b.Property("PasswordHash"); - - b.Property("PhoneNumber"); - - b.Property("PhoneNumberConfirmed"); - - b.Property("SecurityNumber"); - - b.Property("SecurityStamp"); - - b.Property("State"); - - b.Property("StateCode"); - - b.Property("Street"); - - b.Property("TwoFactorEnabled"); - - b.Property("UserName") - .HasAnnotation("MaxLength", 256); - - b.Property("ZipCode"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasName("UserNameIndex"); - - b.ToTable("AspNetUsers"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole") - .WithMany("Claims") + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade); }); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b => + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("Microsoft.eShopOnContainers.WebMVC.ViewModels.ApplicationUser") - .WithMany("Claims") + b.HasOne("Identity.API.Models.ApplicationUser") + .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade); }); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b => + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("Microsoft.eShopOnContainers.WebMVC.ViewModels.ApplicationUser") - .WithMany("Logins") + b.HasOne("Identity.API.Models.ApplicationUser") + .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade); }); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b => + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => { - b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole") - .WithMany("Users") + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade); - b.HasOne("Microsoft.eShopOnContainers.WebMVC.ViewModels.ApplicationUser") - .WithMany("Roles") + b.HasOne("Identity.API.Models.ApplicationUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Identity.API.Models.ApplicationUser") + .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade); }); +#pragma warning restore 612, 618 } } } diff --git a/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20170604151338_Init-configuration.Designer.cs b/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20170912114152_Initial.Designer.cs similarity index 90% rename from src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20170604151338_Init-configuration.Designer.cs rename to src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20170912114152_Initial.Designer.cs index 9e6eb2500..a718c0943 100644 --- a/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20170604151338_Init-configuration.Designer.cs +++ b/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20170912114152_Initial.Designer.cs @@ -1,20 +1,24 @@ -using System; +// +using IdentityServer4.EntityFramework.DbContexts; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -using IdentityServer4.EntityFramework.DbContexts; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Internal; +using System; namespace Identity.API.Migrations.ConfigurationDb { [DbContext(typeof(ConfigurationDbContext))] - [Migration("20170604151338_Init-configuration")] - partial class Initconfiguration + [Migration("20170912114152_Initial")] + partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) { +#pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "1.1.2") + .HasAnnotation("ProductVersion", "2.0.0-rtm-26452") .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResource", b => @@ -165,6 +169,10 @@ namespace Identity.API.Migrations.ConfigurationDb b.Property("AuthorizationCodeLifetime"); + b.Property("BackChannelLogoutSessionRequired"); + + b.Property("BackChannelLogoutUri"); + b.Property("ClientId") .IsRequired() .HasMaxLength(200); @@ -175,19 +183,26 @@ namespace Identity.API.Migrations.ConfigurationDb b.Property("ClientUri") .HasMaxLength(2000); + b.Property("ConsentLifetime"); + + b.Property("Description") + .HasMaxLength(1000); + b.Property("EnableLocalLogin"); b.Property("Enabled"); + b.Property("FrontChannelLogoutSessionRequired"); + + b.Property("FrontChannelLogoutUri"); + b.Property("IdentityTokenLifetime"); b.Property("IncludeJwtId"); b.Property("LogoUri"); - b.Property("LogoutSessionRequired"); - - b.Property("LogoutUri"); + b.Property("NormalizedClientId"); b.Property("PrefixClientClaims"); @@ -316,6 +331,29 @@ namespace Identity.API.Migrations.ConfigurationDb b.ToTable("ClientPostLogoutRedirectUris"); }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClientId") + .IsRequired(); + + b.Property("Key") + .IsRequired() + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientProperties"); + }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b => { b.Property("Id") @@ -503,6 +541,14 @@ namespace Identity.API.Migrations.ConfigurationDb .OnDelete(DeleteBehavior.Cascade); }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("Properties") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b => { b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") @@ -534,6 +580,7 @@ namespace Identity.API.Migrations.ConfigurationDb .HasForeignKey("IdentityResourceId") .OnDelete(DeleteBehavior.Cascade); }); +#pragma warning restore 612, 618 } } } diff --git a/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20170604151338_Init-configuration.cs b/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20170912114152_Initial.cs similarity index 62% rename from src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20170604151338_Init-configuration.cs rename to src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20170912114152_Initial.cs index 8cf20e865..257a6adde 100644 --- a/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20170604151338_Init-configuration.cs +++ b/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20170912114152_Initial.cs @@ -1,11 +1,11 @@ -using System; -using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Metadata; +using System; +using System.Collections.Generic; namespace Identity.API.Migrations.ConfigurationDb { - public partial class Initconfiguration : Migration + public partial class Initial : Migration { protected override void Up(MigrationBuilder migrationBuilder) { @@ -13,12 +13,12 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ApiResources", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - Description = table.Column(maxLength: 1000, nullable: true), - DisplayName = table.Column(maxLength: 200, nullable: true), - Enabled = table.Column(nullable: false), - Name = table.Column(maxLength: 200, nullable: false) + 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) }, constraints: table => { @@ -29,37 +29,42 @@ namespace Identity.API.Migrations.ConfigurationDb name: "Clients", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - AbsoluteRefreshTokenLifetime = table.Column(nullable: false), - AccessTokenLifetime = table.Column(nullable: false), - AccessTokenType = table.Column(nullable: false), - AllowAccessTokensViaBrowser = table.Column(nullable: false), - AllowOfflineAccess = table.Column(nullable: false), - AllowPlainTextPkce = table.Column(nullable: false), - AllowRememberConsent = table.Column(nullable: false), - AlwaysIncludeUserClaimsInIdToken = table.Column(nullable: false), - AlwaysSendClientClaims = table.Column(nullable: false), - AuthorizationCodeLifetime = table.Column(nullable: false), - ClientId = table.Column(maxLength: 200, nullable: false), - ClientName = table.Column(maxLength: 200, nullable: true), - ClientUri = table.Column(maxLength: 2000, nullable: true), - EnableLocalLogin = table.Column(nullable: false), - Enabled = table.Column(nullable: false), - IdentityTokenLifetime = table.Column(nullable: false), - IncludeJwtId = table.Column(nullable: false), - LogoUri = table.Column(nullable: true), - LogoutSessionRequired = table.Column(nullable: false), - LogoutUri = table.Column(nullable: true), - PrefixClientClaims = table.Column(nullable: false), - ProtocolType = table.Column(maxLength: 200, nullable: false), - RefreshTokenExpiration = table.Column(nullable: false), - RefreshTokenUsage = table.Column(nullable: false), - RequireClientSecret = table.Column(nullable: false), - RequireConsent = table.Column(nullable: false), - RequirePkce = table.Column(nullable: false), - SlidingRefreshTokenLifetime = table.Column(nullable: false), - UpdateAccessTokenClaimsOnRefresh = table.Column(nullable: false) + 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(max)", 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(max)", nullable: true), + IdentityTokenLifetime = table.Column(type: "int", nullable: false), + IncludeJwtId = table.Column(type: "bit", nullable: false), + LogoUri = table.Column(type: "nvarchar(max)", nullable: true), + NormalizedClientId = table.Column(type: "nvarchar(max)", nullable: true), + PrefixClientClaims = table.Column(type: "bit", nullable: false), + 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) }, constraints: table => { @@ -70,15 +75,15 @@ namespace Identity.API.Migrations.ConfigurationDb name: "IdentityResources", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - Description = table.Column(maxLength: 1000, nullable: true), - DisplayName = table.Column(maxLength: 200, nullable: true), - Emphasize = table.Column(nullable: false), - Enabled = table.Column(nullable: false), - Name = table.Column(maxLength: 200, nullable: false), - Required = table.Column(nullable: false), - ShowInDiscoveryDocument = table.Column(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), + 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) }, constraints: table => { @@ -89,10 +94,10 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ApiClaims", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ApiResourceId = table.Column(nullable: false), - Type = table.Column(maxLength: 200, nullable: false) + ApiResourceId = table.Column(type: "int", nullable: false), + Type = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false) }, constraints: table => { @@ -109,15 +114,15 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ApiScopes", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ApiResourceId = table.Column(nullable: false), - Description = table.Column(maxLength: 1000, nullable: true), - DisplayName = table.Column(maxLength: 200, nullable: true), - Emphasize = table.Column(nullable: false), - Name = table.Column(maxLength: 200, nullable: false), - Required = table.Column(nullable: false), - ShowInDiscoveryDocument = table.Column(nullable: false) + 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) }, constraints: table => { @@ -134,13 +139,13 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ApiSecrets", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ApiResourceId = table.Column(nullable: false), - Description = table.Column(maxLength: 1000, nullable: true), - Expiration = table.Column(nullable: true), - Type = table.Column(maxLength: 250, nullable: true), - Value = table.Column(maxLength: 2000, nullable: true) + 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) }, constraints: table => { @@ -157,11 +162,11 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ClientClaims", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClientId = table.Column(nullable: false), - Type = table.Column(maxLength: 250, nullable: false), - Value = table.Column(maxLength: 250, nullable: false) + 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) }, constraints: table => { @@ -178,10 +183,10 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ClientCorsOrigins", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClientId = table.Column(nullable: false), - Origin = table.Column(maxLength: 150, nullable: false) + ClientId = table.Column(type: "int", nullable: false), + Origin = table.Column(type: "nvarchar(150)", maxLength: 150, nullable: false) }, constraints: table => { @@ -198,10 +203,10 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ClientGrantTypes", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClientId = table.Column(nullable: false), - GrantType = table.Column(maxLength: 250, nullable: false) + ClientId = table.Column(type: "int", nullable: false), + GrantType = table.Column(type: "nvarchar(250)", maxLength: 250, nullable: false) }, constraints: table => { @@ -218,10 +223,10 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ClientIdPRestrictions", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClientId = table.Column(nullable: false), - Provider = table.Column(maxLength: 200, nullable: false) + ClientId = table.Column(type: "int", nullable: false), + Provider = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false) }, constraints: table => { @@ -238,10 +243,10 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ClientPostLogoutRedirectUris", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClientId = table.Column(nullable: false), - PostLogoutRedirectUri = table.Column(maxLength: 2000, nullable: false) + ClientId = table.Column(type: "int", nullable: false), + PostLogoutRedirectUri = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: false) }, constraints: table => { @@ -254,14 +259,35 @@ namespace Identity.API.Migrations.ConfigurationDb onDelete: ReferentialAction.Cascade); }); + migrationBuilder.CreateTable( + name: "ClientProperties", + columns: table => new + { + Id = table.Column(type: "int", 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) + }, + constraints: table => + { + table.PrimaryKey("PK_ClientProperties", x => x.Id); + table.ForeignKey( + name: "FK_ClientProperties_Clients_ClientId", + column: x => x.ClientId, + principalTable: "Clients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + migrationBuilder.CreateTable( name: "ClientRedirectUris", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClientId = table.Column(nullable: false), - RedirectUri = table.Column(maxLength: 2000, nullable: false) + ClientId = table.Column(type: "int", nullable: false), + RedirectUri = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: false) }, constraints: table => { @@ -278,10 +304,10 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ClientScopes", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClientId = table.Column(nullable: false), - Scope = table.Column(maxLength: 200, nullable: false) + ClientId = table.Column(type: "int", nullable: false), + Scope = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false) }, constraints: table => { @@ -298,13 +324,13 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ClientSecrets", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ClientId = table.Column(nullable: false), - Description = table.Column(maxLength: 2000, nullable: true), - Expiration = table.Column(nullable: true), - Type = table.Column(maxLength: 250, nullable: true), - Value = table.Column(maxLength: 2000, nullable: false) + 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) }, constraints: table => { @@ -321,10 +347,10 @@ namespace Identity.API.Migrations.ConfigurationDb name: "IdentityClaims", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - IdentityResourceId = table.Column(nullable: false), - Type = table.Column(maxLength: 200, nullable: false) + IdentityResourceId = table.Column(type: "int", nullable: false), + Type = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false) }, constraints: table => { @@ -341,10 +367,10 @@ namespace Identity.API.Migrations.ConfigurationDb name: "ApiScopeClaims", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - ApiScopeId = table.Column(nullable: false), - Type = table.Column(maxLength: 200, nullable: false) + ApiScopeId = table.Column(type: "int", nullable: false), + Type = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false) }, constraints: table => { @@ -357,6 +383,11 @@ namespace Identity.API.Migrations.ConfigurationDb onDelete: ReferentialAction.Cascade); }); + migrationBuilder.CreateIndex( + name: "IX_ApiClaims_ApiResourceId", + table: "ApiClaims", + column: "ApiResourceId"); + migrationBuilder.CreateIndex( name: "IX_ApiResources_Name", table: "ApiResources", @@ -364,9 +395,9 @@ namespace Identity.API.Migrations.ConfigurationDb unique: true); migrationBuilder.CreateIndex( - name: "IX_ApiClaims_ApiResourceId", - table: "ApiClaims", - column: "ApiResourceId"); + name: "IX_ApiScopeClaims_ApiScopeId", + table: "ApiScopeClaims", + column: "ApiScopeId"); migrationBuilder.CreateIndex( name: "IX_ApiScopes_ApiResourceId", @@ -379,22 +410,11 @@ namespace Identity.API.Migrations.ConfigurationDb column: "Name", unique: true); - migrationBuilder.CreateIndex( - name: "IX_ApiScopeClaims_ApiScopeId", - table: "ApiScopeClaims", - column: "ApiScopeId"); - migrationBuilder.CreateIndex( name: "IX_ApiSecrets_ApiResourceId", table: "ApiSecrets", column: "ApiResourceId"); - migrationBuilder.CreateIndex( - name: "IX_Clients_ClientId", - table: "Clients", - column: "ClientId", - unique: true); - migrationBuilder.CreateIndex( name: "IX_ClientClaims_ClientId", table: "ClientClaims", @@ -420,11 +440,22 @@ namespace Identity.API.Migrations.ConfigurationDb table: "ClientPostLogoutRedirectUris", column: "ClientId"); + migrationBuilder.CreateIndex( + name: "IX_ClientProperties_ClientId", + table: "ClientProperties", + column: "ClientId"); + migrationBuilder.CreateIndex( name: "IX_ClientRedirectUris_ClientId", table: "ClientRedirectUris", column: "ClientId"); + migrationBuilder.CreateIndex( + name: "IX_Clients_ClientId", + table: "Clients", + column: "ClientId", + unique: true); + migrationBuilder.CreateIndex( name: "IX_ClientScopes_ClientId", table: "ClientScopes", @@ -473,6 +504,9 @@ namespace Identity.API.Migrations.ConfigurationDb migrationBuilder.DropTable( name: "ClientPostLogoutRedirectUris"); + migrationBuilder.DropTable( + name: "ClientProperties"); + migrationBuilder.DropTable( name: "ClientRedirectUris"); diff --git a/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/ConfigurationDbContextModelSnapshot.cs b/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/ConfigurationDbContextModelSnapshot.cs index 7c725f5ae..560c5ea89 100644 --- a/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/ConfigurationDbContextModelSnapshot.cs +++ b/src/Services/Identity/Identity.API/Migrations/ConfigurationDb/ConfigurationDbContextModelSnapshot.cs @@ -1,9 +1,12 @@ -using System; +// +using IdentityServer4.EntityFramework.DbContexts; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -using IdentityServer4.EntityFramework.DbContexts; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Internal; +using System; namespace Identity.API.Migrations.ConfigurationDb { @@ -12,8 +15,9 @@ namespace Identity.API.Migrations.ConfigurationDb { protected override void BuildModel(ModelBuilder modelBuilder) { +#pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "1.1.2") + .HasAnnotation("ProductVersion", "2.0.0-rtm-26452") .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResource", b => @@ -164,6 +168,10 @@ namespace Identity.API.Migrations.ConfigurationDb b.Property("AuthorizationCodeLifetime"); + b.Property("BackChannelLogoutSessionRequired"); + + b.Property("BackChannelLogoutUri"); + b.Property("ClientId") .IsRequired() .HasMaxLength(200); @@ -174,19 +182,26 @@ namespace Identity.API.Migrations.ConfigurationDb b.Property("ClientUri") .HasMaxLength(2000); + b.Property("ConsentLifetime"); + + b.Property("Description") + .HasMaxLength(1000); + b.Property("EnableLocalLogin"); b.Property("Enabled"); + b.Property("FrontChannelLogoutSessionRequired"); + + b.Property("FrontChannelLogoutUri"); + b.Property("IdentityTokenLifetime"); b.Property("IncludeJwtId"); b.Property("LogoUri"); - b.Property("LogoutSessionRequired"); - - b.Property("LogoutUri"); + b.Property("NormalizedClientId"); b.Property("PrefixClientClaims"); @@ -315,6 +330,29 @@ namespace Identity.API.Migrations.ConfigurationDb b.ToTable("ClientPostLogoutRedirectUris"); }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClientId") + .IsRequired(); + + b.Property("Key") + .IsRequired() + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientProperties"); + }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b => { b.Property("Id") @@ -502,6 +540,14 @@ namespace Identity.API.Migrations.ConfigurationDb .OnDelete(DeleteBehavior.Cascade); }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("Properties") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b => { b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") @@ -533,6 +579,7 @@ namespace Identity.API.Migrations.ConfigurationDb .HasForeignKey("IdentityResourceId") .OnDelete(DeleteBehavior.Cascade); }); +#pragma warning restore 612, 618 } } } diff --git a/src/Services/Identity/Identity.API/Migrations/20170604151240_Init-persisted-grant.Designer.cs b/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20170912114120_Initial.Designer.cs similarity index 81% rename from src/Services/Identity/Identity.API/Migrations/20170604151240_Init-persisted-grant.Designer.cs rename to src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20170912114120_Initial.Designer.cs index a2b93219b..72f0df362 100644 --- a/src/Services/Identity/Identity.API/Migrations/20170604151240_Init-persisted-grant.Designer.cs +++ b/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20170912114120_Initial.Designer.cs @@ -1,20 +1,23 @@ -using System; +// +using IdentityServer4.EntityFramework.DbContexts; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -using IdentityServer4.EntityFramework.DbContexts; +using Microsoft.EntityFrameworkCore.Storage.Internal; +using System; -namespace Identity.API.Migrations +namespace Identity.API.Migrations.PersistedGrantDb { [DbContext(typeof(PersistedGrantDbContext))] - [Migration("20170604151240_Init-persisted-grant")] - partial class Initpersistedgrant + [Migration("20170912114120_Initial")] + partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) { +#pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "1.1.2") + .HasAnnotation("ProductVersion", "2.0.0-rtm-26452") .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => @@ -47,6 +50,7 @@ namespace Identity.API.Migrations b.ToTable("PersistedGrants"); }); +#pragma warning restore 612, 618 } } } diff --git a/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20170912114120_Initial.cs b/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20170912114120_Initial.cs new file mode 100644 index 000000000..44bd9fed1 --- /dev/null +++ b/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20170912114120_Initial.cs @@ -0,0 +1,40 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using System; +using System.Collections.Generic; + +namespace Identity.API.Migrations.PersistedGrantDb +{ + public partial class Initial : 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/PersistedGrantDbContextModelSnapshot.cs b/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/PersistedGrantDbContextModelSnapshot.cs similarity index 85% rename from src/Services/Identity/Identity.API/Migrations/PersistedGrantDbContextModelSnapshot.cs rename to src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/PersistedGrantDbContextModelSnapshot.cs index ffe6bc35a..7989f0586 100644 --- a/src/Services/Identity/Identity.API/Migrations/PersistedGrantDbContextModelSnapshot.cs +++ b/src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/PersistedGrantDbContextModelSnapshot.cs @@ -1,19 +1,22 @@ -using System; +// +using IdentityServer4.EntityFramework.DbContexts; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -using IdentityServer4.EntityFramework.DbContexts; +using Microsoft.EntityFrameworkCore.Storage.Internal; +using System; -namespace Identity.API.Migrations +namespace Identity.API.Migrations.PersistedGrantDb { [DbContext(typeof(PersistedGrantDbContext))] partial class PersistedGrantDbContextModelSnapshot : ModelSnapshot { protected override void BuildModel(ModelBuilder modelBuilder) { +#pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "1.1.2") + .HasAnnotation("ProductVersion", "2.0.0-rtm-26452") .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => @@ -46,6 +49,7 @@ namespace Identity.API.Migrations b.ToTable("PersistedGrants"); }); +#pragma warning restore 612, 618 } } } diff --git a/src/Services/Identity/Identity.API/Program.cs b/src/Services/Identity/Identity.API/Program.cs index 2f731c045..3a65c32ab 100644 --- a/src/Services/Identity/Identity.API/Program.cs +++ b/src/Services/Identity/Identity.API/Program.cs @@ -1,4 +1,6 @@ -using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Logging; using System.IO; namespace eShopOnContainers.Identity @@ -7,15 +9,22 @@ namespace eShopOnContainers.Identity { public static void Main(string[] args) { - var host = new WebHostBuilder() + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) .UseKestrel() .UseHealthChecks("/hc") .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartup() + .ConfigureLogging((hostingContext, builder) => + { + builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); + builder.AddConsole(); + builder.AddDebug(); + }) .Build(); - - host.Run(); - } } } diff --git a/src/Services/Identity/Identity.API/Startup.cs b/src/Services/Identity/Identity.API/Startup.cs index f579071e7..dfdece593 100644 --- a/src/Services/Identity/Identity.API/Startup.cs +++ b/src/Services/Identity/Identity.API/Startup.cs @@ -28,24 +28,12 @@ namespace eShopOnContainers.Identity { public class Startup { - public Startup(IHostingEnvironment env) + public Startup(IConfiguration configuration) { - var builder = new ConfigurationBuilder() - .SetBasePath(env.ContentRootPath) - .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) - .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); - - if (env.IsDevelopment()) - { - // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709 - builder.AddUserSecrets(); - } - - builder.AddEnvironmentVariables(); - Configuration = builder.Build(); + Configuration = configuration; } - public IConfigurationRoot Configuration { get; } + 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) @@ -179,7 +167,10 @@ namespace eShopOnContainers.Identity using (var serviceScope = app.ApplicationServices.GetService().CreateScope()) { - serviceScope.ServiceProvider.GetRequiredService().Database.Migrate(); + serviceScope.ServiceProvider.GetRequiredService() + .Database + .Migrate(); + var context = serviceScope.ServiceProvider.GetRequiredService(); context.Database.Migrate(); From 4e12176801b38c9bab75efdff073dbe28da2392a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ram=C3=B3n=20Tom=C3=A1s?= Date: Tue, 12 Sep 2017 15:39:06 +0200 Subject: [PATCH 85/86] Update identity.api base image to aspnetcore2.0 Rename Identity.api namespace --- .../Identity/Identity.API/Data/ApplicationContextSeed.cs | 3 +-- src/Services/Identity/Identity.API/Dockerfile | 2 +- src/Services/Identity/Identity.API/Program.cs | 2 ++ src/Services/Identity/Identity.API/Startup.cs | 3 ++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Services/Identity/Identity.API/Data/ApplicationContextSeed.cs b/src/Services/Identity/Identity.API/Data/ApplicationContextSeed.cs index 0f81bcf66..d0099cc21 100644 --- a/src/Services/Identity/Identity.API/Data/ApplicationContextSeed.cs +++ b/src/Services/Identity/Identity.API/Data/ApplicationContextSeed.cs @@ -5,8 +5,8 @@ using Extensions.Logging; using global::eShopOnContainers.Identity; using global::Identity.API.Data; + using global::Identity.API.Extensions; using global::Identity.API.Models; - using Identity.API.Extensions; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; @@ -16,7 +16,6 @@ using System.IO; using System.IO.Compression; using System.Linq; - using System.Security.Cryptography; using System.Text.RegularExpressions; using System.Threading.Tasks; diff --git a/src/Services/Identity/Identity.API/Dockerfile b/src/Services/Identity/Identity.API/Dockerfile index bd01695f3..029b5893e 100644 --- a/src/Services/Identity/Identity.API/Dockerfile +++ b/src/Services/Identity/Identity.API/Dockerfile @@ -1,4 +1,4 @@ -FROM microsoft/aspnetcore:1.1.2 +FROM microsoft/aspnetcore:2.0.0 ARG source WORKDIR /app EXPOSE 80 diff --git a/src/Services/Identity/Identity.API/Program.cs b/src/Services/Identity/Identity.API/Program.cs index 3a65c32ab..9802c36f1 100644 --- a/src/Services/Identity/Identity.API/Program.cs +++ b/src/Services/Identity/Identity.API/Program.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; +using Microsoft.eShopOnContainers.Services.Identity; using Microsoft.Extensions.Logging; using System.IO; @@ -28,3 +29,4 @@ namespace eShopOnContainers.Identity .Build(); } } + diff --git a/src/Services/Identity/Identity.API/Startup.cs b/src/Services/Identity/Identity.API/Startup.cs index dfdece593..572e0399f 100644 --- a/src/Services/Identity/Identity.API/Startup.cs +++ b/src/Services/Identity/Identity.API/Startup.cs @@ -1,5 +1,6 @@ using Autofac; using Autofac.Extensions.DependencyInjection; +using eShopOnContainers.Identity; using Identity.API.Certificate; using Identity.API.Configuration; using Identity.API.Data; @@ -24,7 +25,7 @@ using System.Linq; using System.Reflection; using System.Threading.Tasks; -namespace eShopOnContainers.Identity +namespace Microsoft.eShopOnContainers.Services.Identity { public class Startup { From 7a0331e39f96aa6f2abbfdb429962b1d8c63162f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ram=C3=B3n=20Tom=C3=A1s?= Date: Wed, 13 Sep 2017 13:27:03 +0200 Subject: [PATCH 86/86] Added images for SF as windows containers deployment docu --- img/sf/cloud-config-idsrv.PNG | Bin 0 -> 46951 bytes img/sf/cloud-config-mvc.PNG | Bin 0 -> 31888 bytes img/sf/cloud-config-spa.PNG | Bin 0 -> 44447 bytes img/sf/cloud-config.PNG | Bin 0 -> 54034 bytes img/sf/explorer-apps-status.PNG | Bin 0 -> 45966 bytes img/sf/explorer-deployment-status.PNG | Bin 0 -> 103354 bytes img/sf/publish-button.PNG | Bin 0 -> 12815 bytes img/sf/publish-window.PNG | Bin 0 -> 16348 bytes img/sf/sf-directory.PNG | Bin 0 -> 8628 bytes 9 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 img/sf/cloud-config-idsrv.PNG create mode 100644 img/sf/cloud-config-mvc.PNG create mode 100644 img/sf/cloud-config-spa.PNG create mode 100644 img/sf/cloud-config.PNG create mode 100644 img/sf/explorer-apps-status.PNG create mode 100644 img/sf/explorer-deployment-status.PNG create mode 100644 img/sf/publish-button.PNG create mode 100644 img/sf/publish-window.PNG create mode 100644 img/sf/sf-directory.PNG diff --git a/img/sf/cloud-config-idsrv.PNG b/img/sf/cloud-config-idsrv.PNG new file mode 100644 index 0000000000000000000000000000000000000000..86fbe663790f1fccfb50aa8e6ebdad57cb37c918 GIT binary patch literal 46951 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 literal 0 HcmV?d00001 diff --git a/img/sf/cloud-config-spa.PNG b/img/sf/cloud-config-spa.PNG new file mode 100644 index 0000000000000000000000000000000000000000..17809ea2da0cca7314af29c9561d6d13d25e7f36 GIT binary patch literal 44447 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 bk+!m7qIRkyK{bC5{iYb`86VEm`T5#k2VhP! literal 0 HcmV?d00001 diff --git a/img/sf/cloud-config.PNG b/img/sf/cloud-config.PNG new file mode 100644 index 0000000000000000000000000000000000000000..420b95e1c2e79448cc731d66890b63a9c96b682d GIT binary patch literal 54034 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

?x1eW<#ySL6mQfyq;HYNei(YIsI4 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

Ld%O9t3Z}@yzd;B*7=K!w<`O2`_o*LS0D+| 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

0l6pKdL_ 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 f06p05GG6q+{NDDct0on#j91suGB{gÓ@uh)Ol literal 0 HcmV?d00001 diff --git a/img/sf/explorer-deployment-status.PNG b/img/sf/explorer-deployment-status.PNG new file mode 100644 index 0000000000000000000000000000000000000000..2697a6374e46cf9333e2f88e71a08c5025f49b7a GIT binary patch literal 103354 zcmeEtcT`hZ`>qvK1gs$4j)jhb5D24;Vgp10DMCP+2mvWcXaUhdW<)>*sY0X)(n2o@ z5ELQwP!k{t5duU=L0SR{Np75PzM1d$yLa7x?z(H;Kkiv8>*VZn&OUqZ_ucRFywBO^ zk2@A-l6&O$Y}v9!^2YUF?{3*5#@MoDd+9DQQArN|^+(ZeYtUV@D_hF@73W0{>kwxKU%KX$4V=cW_AK*? z#AUqe(yjKK(>HbhGW`7EwWGuCw;iru$k}dnbZb(qj4!}&(_BC5Sx!uvSPekFLH_N& z3&%Vw%yl-c6db-(Efo%f4@^8kN({AL$hkj31Uo1*YpekG{~-O|FBpa0XBIC`u9X== zEV6jW#c;Y$fF*xCoKTM9kQ@<{kObbGKIUih|Ju~{ZUg-L{}z|6`^UEaeI)UFt6#R! z+Q>cDRICbAg*S%%`_$6|(PX1_kdPkLNJhiZ>FIK2Id{$++7ol-zwN$XanY9+tXc|3 z`uh82OfCM~>A&u=j%oE%?zF!4Ki~iJg7$Mepes*X6aIVMf8IP~y^AroHCpL^dh*Y+ z1)uhf^=;n<_+Qq0^Pb$<3P8kq1#c9@x4}7>$O`8C1s%NDsCDrm{-w?Ua+HuSXuy{{ z(Ypv7QcxmDwhm1%N9Xdz=H51yXYrx zqvk(m_JZf0{RRo=u(GNLSi=ZG4SM?J`R)&Dr|9kqyXiBvHfBj0(PYqOJ1Chc#QXD8 z!hd`gH{LL;(IoygSpRL8P^M$;lKKJ?h97^B^xCid3Sjs2OxkZd0;BkZD5vryr0Mm- zdA_*Zp|KnLR3R-ZS&P9S{=)sZ0-HA;RTg!j(|@SGETF2#sx%BJ!FcXVkF$HG#7Qw& zC0YW2b%oP9^>DmZXWkFTwlC7SCxsT*cu!mc4fwo0kcy!&fj^?jti`z097gyzGK;*Z zVN`*%lkWy{ez8lvao>!GU+|;Ut9f7qlT5+WVjS-&F$)?pR<*b_&ws@(A8rt0(C>^r zK{a@>bmkUtGM?t4*3Md?EDE0To`TN6Lyi)=&qxyJA>F^b8K}a$F_v>|qgC}Kj%Ot6 z)sP{O+7yZ9HxD#-);bCe45UwOD$3anA@Ux-pQC%_2<;1bS`%wbti$MF2zl*nbCkv{ zIcBp@vQO7y_3K5i|8UlMYeR9UgdBcn(Ef?8fZx)=2T1nBT^lDH>UNicGir81my2$B zgSHtsT>+pv^{SW;jFf|>zPxFaj+{f^o{W5tt_WXl_*EjB9C+5FB8BvQrDs&qG}MWF zsL%gO3NlF{b3VSUp_~nee46Ox$jx^6`PdJ%`n|_qV7-3$gu;zI2t{y=_oaBy75dF1 z)DzIJ^iqO|h3$^hi(okb59O_b2yn(wOMM!Kgy9d9ht_Dn2l!PXn$bP?^rcNC3gRc$ z-f(=<0^*PcXUC5ui&u?xKQf`o&N<}%<0{<|$rjP%hr8&{0%D=d>5#w&V8ku`R9(hQ zW$Im!VYNn0UYzfV9(P1QYK(-L`$v+NE?p+-ScQV+u?olayOZmstT~RH8#}qD#B0avtmQ*w#+96r3qCkB*N8u&~_c4LFKPh%5^kwO-bmy(CQQ zdL?DtjkTQnQoJwW`q&|SK~56o8dISR(L`2)O>JjYZ0h@-K*o(u?N1qOxdC$LS)O)H z^}k0rIB{cp-ouT2R^DOux}HBS?BGrABlEn;JD>w<3zb7~oqGS`LOfzRtwd@jdTx8W zU~u^k;(FqZi2>qQxHQ(Dl}^;j)}@4Vbcru8Laxj@~VGfvw8wY^R0 zMfBIm(LPtDPDzsfA$watLd5Vep^&o%#`0H%@9Y)lZznjQLjkjOT}Nitm>PAv>2KlI zd^S7u4aDYX0T!U>6ZxFDU^X!)4qYtILVi!{33@}Yhg237>Qyk|KL}QhMkDtX+km^p zmS;DX<_&{g?)V}T>s-b?3zLV{T17iy(U&1?mhp9&hyzhI!<4x3+5RaA7lW!V;&Ese@u)BV~O@39NVRKe8|S&7j= zl_f~d%SD9L+tcLjf~!rq5A+kj(`WIacX+X{D@aF)0_erb6N>(aejiP^_0E@4T(T7K z{eaT&8Jf1SXJ}dZS*KOb+vGNBqi-CA3#?Fu(Z>Gz`;b%Afsnl6hV%@-Ov)qJC!;T4()U&&v8xZeAm-BqY8X$StWXD;F=fEtTQ=N^{JIykJ8#`Z zj7LVa>1)o%yYNxpV;>U`arua_+bfx!Ht-gwi@?D&`Y#1~tem|IrgsZ9+xuu0@&0Cn zH*9pIE{RiE6a?CMblYiqsjSw%6v=&uB)A<;G{;r0o?_m+ca~e+F{0wH14Nb8_)(y? zW+7P|n>CY0=UK=ovWdT3OVLy63F$3}G}fy<4*8YecT>IM7PgRO(Pip>4#a=j+SI+S%H{)I1st+Xv4*yC>_eB9H{TzLR zRFACC%(Y0*Q$!7xS8bMxw6WM#5j&#Rum$gc>PQLWub?)|eCm)=>S(A8Juc#$I+SKNx%kSHBbhMI? z)rKma>@x2DI&-dj4M?K@<#9fKYX?)>oxhit;^x6bPH-+?*Xh4{gX2?HcyAyNt9l-9 zXGWCct?R`tJ#M}>J#^uP6?~9jGl<=Md1rA?W zu{Y z{0g_dXCt=y8FM>Py`@oUVL<;C6+Xh&QErFW4u?7AgFOr8H&d=MbzfALaz1@J0*_y) zpLm%%+CfUpWMM|H*%WJaV~XOB)+A3ooi+g-az_-O2=fSeXYi{<* zT+VOj%;9Q1AACMPy0?Z+eG!zw9`;wIIBsW;GVQSnOg9EHu@T~1b)ZaTAho#jQa5fl zB>NS-MEen{t~h8vCupEHIW>%upLNG;(vyn2U=wUS7a}RYc$t3oAGT3-=4PSU!xsY< zp8e|eW)B|+G8V%ryiMAqJw5Z)^7Y=2trm6f;PP?OZ{78*a+|ynlnh{`q*nlvvH3+e#b8#Nwy2G1zk}qz)oOj zRw#e)h)k{?zbeFc8Y(`bdu6~)+&;{Rv0|g_IKKERb93HsSf|05VqxXQTl1*DM=ZoI zYWZzXs4s|I;hw1@fZK_3Oi8#h9lXQaWbIOi$BzaA=N&xQgjxCNorXR~j2!XKaI@-T z=HNyZ8@_Uv>>}CT5?vOD)NjmrTz3lVN*?h&@*JO8RF&AWKa=$OA`$m;L{1a$=BZfH zV(-hox2OqHfWPd&(PD1Yf!h21c~rWxBfqH-E4Szd1~sMB<)T)O^RV!8LJk(I90l=p zJJJ(|$apzOD7AKTccLy;O)P!)8BeW=kBB03s*w1~LV`UhJFMaX23O0(xaEg`JdvQ zh@skq`=<<5%iy16qe$&+rkmEI2OiBp&F9F1JB6d3lNN1b8+R%Cig_jpVP;HD`JEA+ zps4@IHq>6~XjL4HJ6ogRWv6;FB8mDIS6q$vnOb3>d`oI~LR~vZ_c7ejhc}$v(+95B zz45@mYO4A*$2R=UFDG{F$=h)bxObOC*`3e3wDZ^Ny211u)9*bqOxMu;I^WqtKshG% zbGpXW%p`l^%RS3KJatN{7j7M1-+M-IiOLT~m#w|pH)fB`NQ_lRx~mvFn>wEW=h#m6 zeI}UwwDgIdZupQ}LI=2YNpBSgtmD?rL+2t-yf^!#%1p9YixJ+fh*(KmSd&6MW zr+Ot9=jObymf4fh?{7b{zN&ny#L~Qd!Zxv5d#n@6;uaAGIg1a`8qCNw9p+nl?VF z#q(-n+{MY~_i* zSA<0Fo!ff@ARZC()Azsend!BDQi~*tsHT4Cf@sYd5 za>p;DRK^JlE7<9MpLaP%dr_g>uQA zbM+-aEcT8>u){(Z#|AsqCU@A{o_ddwNBlukmA~g?hH3#Sqpl0{T2&uM)!;k9 zn(S2!4#H7NNAw+6GUJ!}sE^?j378E#Jf#J>c&jY&r+0jZEX9K;ek1<&$b~-=07%ux zj`)(ynzhWLuF8|`sQGg}3q*RP0#=@^)}MHpFogvevp%kTN-$Ue1uKiK9UCX4hA;~9 z^{c4xx6A^;!z^D}8};@kjRo)mwTFNe5re)X9aZ?kk8kS>>J#aD9Y*#ti6C3|-rSb? zrR&(!2KYzst(SVLeQM^@k`6>6X<%#3%zk^EHUWId&3d#j5de~1`@D$Qp*g2rxYp6m zu_910CdG9_L5KYjiI>6f@yJ1cG9sT+1#kB6TBpBVTa13hn_1sH^3_d)cFIA;$+AOG zMmu%B)-Znr8Ov^QUn|CmB_Bw1>N#=in5tnY#S}oMvAL+}wI(=wskamwsreocJOJ5I0+S^fN7A|^A zF!Dtb!DbB7@d`TlW7Z-2(<1#~9{24nr3Pu@iELO>Nhwj-@ILx>vNQE<>~`<0t7o5W z-DqkIRH%)Xj_!sJKRqUyAN=%fYM9oWRiw=A8SorrguX&lxNKHqZad_rLHxnH-$Ttg z|3x11Ab#!oAjG3bH803DJ~4Sl(G2U%Sb56I1KOVL5~L5fi=+kZL`Wz7#CfiKr$cbzHRpmQ*}IVlT7+r>PBOvT}Lea#KgQkEe)2M8ZcCbLz56Z!G-Y z;k59{Nuguxki>K*z4(Z}a9QESINLca$>wIHX@xgD@*wcKzo*{fdEU6bH3V)j-d~@` zWBF&#LAY)qF0dMZUi?%|Rs$sz?oC^*ocVHkjk%)G#ErJI<>{2Cf*a&gjR0R@UaV+o?7w)8S3U`o8x~ zQrL)?s?IUbRzV-F;7qMRj?nqEWu!dboj9lcI|dQlh4TmlAEJFKHEK+;MlW$Pob`+P zDl9ko^90GY$#?H2s%G9hW_|c4b?$CT&DjQc^8$+33vw<0g8Ej8RX*=EVed{pCk1!BaEY6{VxSFd+*4Uk4+6!I*KXz8$ZZb8@wwK!+p2;k#-z) z!<+10uvf#aMWf^H3)a1`m8i-T?X{rt{_*z_(tVspxe@1}PHNA?O@l8uz5hVNJBIIa zwgdKG0l1bSBo2)9+1SZ;26TB%#Qbviiq6LU!m3i7?-z~etV5wA1rfk3Bd*SlnB`hE zpQyca$ItA5#ue=wYmaGV*_}O5akY9^SW3Ih*hSo>+?sa*AX(}eDB`W0dbG4o$~707 zm*!PjZ=&|aR0Dul(7wH+iJ|4UFs*)80>%HLD(orvsR6b9wKU z`9l6}K&a8_zjfSw`~IumEA{soyI*!d|2}BlcD!Qy-$yb70f~{zR^opbxVS39Nbv|* z>zE=;@$b?X4`Vc1i+bbs{$0{nI1gWweaVIDE3z)ub60~$GWAv0MLYy!iJv%DwH|Bp#MPnx$zC@|_l!E{6Ns828Poyrj8VCoK9>4-;1VI*B z^*`SX{JGf~{?+?6PDYea^RcVbQFHA42Os>~KEEiO z5B6U9TA#(6vw}6&YFrE$V}{P7{Rk)8>9L8ZHVQ8x{QK70zPDOTWp3;u3M-@yF9jN8 zw}IkQAxo9MCLE=Ds#^!Dpuee;YcRzVNOQVYEH8+-jtFvmC;@g$a{yAgrZPmcWj!~1 z$uXUQG2@VFczI%fIvv{3rl|y#=I2)Wk?Mdn(yjK&YwQMT2ckllIMmJ1c|JB&4MdtM z*RETPZT+|RX`K_b_(XITFPpexcfeV$KipG~XuA`7FpADf3!BVJ^{rorj~dfjn5-MA zCOXsvWjSC4dLxbk5yvbk!GgK38zXP%YF14}2u*}uvjm-R*1Uc*Nj!)k{DE0gzC<$# zTV5+e3Sg00zIk2~^M+v?2D@FQP_g9zCw0)2EeM4#!xQ^zQ$bYLdRrzr6pso>YW1TS zvr!3uH5)sK^SeNZSBX~o%RnyHw%>=YZ9~hp&=Vr53frI6)5ugxwx~rp+t8 zX=rZd@xGb0%t=M^99f=0nWuW2I#F-7X!K?zZDH}fHpPW&y0RD&zc*?V7^HFx;i^jP ztgEuzwf@_PH*b~cbTk5wA{XF z7xe>)nP+zrG`rl}Dk!DIrHbPE&o6QOyl`!W)WiC$o{qV2KOAjA_poW^*|TPxp3){$ zKSF){7OT#NlJsyUwJ?!~W_??o5>%`7#ranBM1BXQ9?PtwZXP6;2-bvHl35ZMD%{*t zE%k{wQ5YA_HiZ4Kv`wQQ*96g7>x|2=nh3_U6^Dd)K(#Fbv&LZ~OzyiCk~rd0hW|>F zQA$7z@7q01lrhX6TngpDr>=6=kv#<4Bf%*2oF%)V%`8rD_Dxn4riZLp7NxN;{24c? z9fF_u(5eBzbNmvC#@w&sd10n5FfN4CNRzrxY+m1_vYz|nu?~s^9DIPe!HYn*B|6_z zzYpo|?Wn~xw;A8}r76Mt$%N&x-pkSC1(V(mRRBJuZe|Y*dvDy1-xVrY8^GRe>FP^?Tj&4a{VzNgP3Sq^+aO_W($qT`1t0kP6bP#@JVRXFrvj(O_mH#;oCTa4)0;a9{1 zHX_ZWqxzgy&|#Q1){<-sEjx4Kz8aCniDDr?l3!NzsVD{#k`YQA{Yd`Qd;@=2MeqVp zWD@T0tINn{Gh;qf?^zsTF7)?w@Y@4zsZXM_j3cXA-&$zo`PnK=08FvF|7x9os^Ef- zX4U7DY1Lo!LRSlFo3GZ@F1*GyRM#y&T*K2McGWG-vbm&CR(5kNIhz7<+!?Hi=`dd1 zx%=+&fZ6pk)wEB~2Xz+fISsNL^1+z!Ndr#fb2AmqZ4DRpI!uY8UIoA?G}f_%TQ}Y3 z6Q^Z{R|ytZX&%pVW(8%V-E@ewY6Uvj`}sDsNdzhOnhkn7gIW;V z2_53ZilQBHg=q7%ZkkXHj9kjmIi$d{3r2W6Nbsa8A@YWi;hjnmR@+dI)8XJ?Kx|8t zC9{ir>08sbKdtDp6f(TnUQm%4VI+!0QlO(gM3Sh4&_f9N8ir`^A~(KO4p z8AF}S=M1kMiVUG{XC>;Fm#TBblt5<}tIN$6%sFc>sinxMRd zioEcfOTdwuX^}7Fff|sZb)>RH1zoI;CZ>(Kffw1WZcAXY*+W6M25j|*RDE3tlVX$r zWKH_i9E^Rm?D?=y>-HDqEm%X__UFT>hB7fL^0)$(q5=hIl;NczYQ?xfr!g9O*Ust{ z+5W^(aIlfcWaDF?Y`=d2>C^V}lAkSvHXN+dl`11UpFKqigBjMn2j_<6LTHtx&PZIUQHjz z&_hTIS-@+5-s3cp9PKo`S6gYORvgMv6#N7~JFleH`EQ{1#CXyrz7y<6x>lSGQ_CWN^`qtaU{xk& zy*b5ge^inZj`LP7ux%$4zi!O=m2dU_isy{|F<-B_t9oOxk;~$}ADH^MP3bwd%s9T- zbfK0w?AOH052jeWD@KmR$4#tDRFV&LUoduFnIoH#Kl9eSW}R42 zMf_(gMKN;qeb1N}2xPgRS&s_F4&?l{l~wR#S4a0}vl***9c*V3W==n`Hy*vY zx6bJIxB5xXSuGAnWC*Z6uLM+EVyStZTyLy>M^7wLEMQzl-BBb5>$H(jre2qU}YJu75c$u*-ls#wQ z>9~jO)0xzbU;5dTrU#zPf{+c1KCH$lZZ=?ZlR)Y)88~J$8L8Z9|MDBI-Z-JPJmmKG z?OlPN^1SO@=9V#ngz%*&h6;XZt^M*ChU%*bTbGRuNTqQimMGoc)G3yP`w%`iooaSD zGvYLvBV38{^z(lM9>!HB8KNV^ob}sje>4Y=FdNSsp|pglQr<_cyZU*M4MExE^xoxj z&sC_9Lt-~F#mT1XiO*L3PcIwzcp?^}ZSvdpq7Qq4gH<9{1309~g&^L817jBjKFO&) zdBC>10ImCfr1qT9&ul|_X0?^3VhF|>hn`?DG+7+@W2@S6>uk9jJ96>%H^S&keF{yg<%qJY!I`vA zH8|fmuaPckN=OG;%k|D6KAw$=cG!+S>_Wpb3E}QeAxdJzt7B5PaJARo}*rfr3#mtT2#+* zuJ`d$s8CCvv5$-X-GqSMyc)5r7ve8l=UV|CYr%^$$^0Ht-w9Q6tS4G8<;n26@!Q%v$bGiI6kz%R=`VH|hR&{{lbPQmmg_ z%8}hQSAL&uD|W}fcUGAS)ATd0JmKeEgiY>lcf$} zEf!j@i$mubMwy2%ZHzxQPkggEW(8X(QUdiI={n~H=X|Pn)#USKF%e_FQSENR@6Ku} z%yHd{%ymFLt-x3KaXcbwT@v;qT=<=JCe@fZ8U7vJf-rY;ixMCrCY{(TZojy|NC+=1 ze)&khb8nn)$nv9}Ldt4jkds2_j*kqVG6j|0y~SFdOm-WvrpqhiqQarE4XxYCA_+1P zoo5Nx`lKmU@e?|gvLgJ0G8ZXSXQQSzC%-ZUk=D#R%ufd&-rY20_Rz4Jzq08iU~Vv< zBurC_Pxkotb$m_Z>s?>TOj`~*peKUJ^IPW)hWyxbAC>hD7b-gq9-}mDuMcoyc-;XP zknst$J6toDf1zN-*OSNWm~URkPdN};HIn)rd`hb|_Ox@wpmHngt7-;8b)*L(^a|dC z+T?#Wh%ovX$?&+%y-(KnZ6S;^Fa3+To~Qu$O^cWVb5ZWtop6^_+;Ltupn>BrVvayd z^eAGJSf#A{q`PkX5?=|n+5>{53jJy$+TpRHjA}C>;~l#RO+#9fBVUkV zWs>7j?-1i%XtF5@yQ6Hd@us5mSVj1^A^_>wdiV3s7@yszXRUH=#^&3;$c|i+`=Y0x zip3DfM#l7Pz=NG{zbKm+uofHhVx>fHBO6TEFh4?$e}hjhIM&_Sy$!uKD)jrF9*ErF z2)`_z;5pFE0#@*`q;O4RCv^bXshaO1u=jEu@6ks&MG12O4Sac6SR;8)J-35L3PSK* zmQbR!f%F(gkre?LP6d)k$taI&`!J`6Ji9G>rHbtwY^J*S#Aoz&^ROoW1M%XN9jZ9sy8>GgND8+3Hl;*=;rM`voXZ14;@~QetxN9); z9vDDaTQz_{!0#nERCT?=eV0NnWNn5>i0(eQJH1nuj7{FB z;e5@dUh!u(a=xPHL5n|L#3;CF?OUU>($*belod*V*{Byv$#`>AR5V5}-zf1n<2A2; zsVBpw7j1}&!6Keh9==pi(FY?3MXl8bJkir;veL5SiNcOoXe!Y7Ud6GBq;F4zu$Npf zvJ_qWyPBxTs%$P&R9oAE_{I%YFkdV_pl`z+=guF;Rof z>ksD~mnnIy9|t*&KGsjCo4N8Z%4FUsl=7CT9JmM%I=n+tijfd>o;5)w)homF33$2B z_?~J##3e=ommO%vnY`E68Mfg7!+J@h@;ne#YdmOUc=_jYc1Uj8gtMt>}_?F?fDOX#uq_o^UNT==#6s?GF26X=)PD z?}Ucg@RV3<5&he!dPwOojB~-+vFzb}du7KC_sp#0?GX1J|!uej(anq2TdbTK}2}?;9Ep>JK@5YuNJaYISHHGz;q^FQ@ z(MKahC@1`klwGc^jj!;eZp}OTw;0)L{FiFh=AG$EIIPRi()e4p{Ex>i7xj=$Fu5{c z_;cyP&&_ibVchR(x9XGNYk9hVOL#K+|E?>km1%0Sv7MD32V&J4Pv6DIFx^$Y82;6b zEfqC(|9ADq|EI*ye;RX56%kRjeanY9YNE-%r3fug(Re@YFV#Qr*XaCW^8X9|-y9FO z-HZhE(n?RtMdh}Ng|C|x{aCG1Lo2U%r4$W%{EoluH-H=42JqRa^i#x|f2h>D1Y3Eo zZOFFsKiPxx_Ur5D^IP!@C;;@3Ja==aF8bw}eC$2!HBMBNum#z_NB8+ruNHoS6gEms zW@}QCm4r9K5HajF*#8qb^FNe&~F z`3(d70}0Lne*lD73#e)u52wEk?TLh@k`8rvR-@Oz$cuIMF6Pl$K*3e0vnBeG+c>RV z>7!o&8Uv(D8Kb(gP9P~29c2b5$etCAyBK&9n$qVf3}5Cj)~FYjHcAU{mT7d9A#IMy z>eB3M7*Bo4&^=$R+3W6>If72!hStS5sB>6Q9_D~bYGzh|8Jh{^P$CkVL7KD%b7FRI zY!$sqP1A!$qsNjGIF3Zk_v%sFNo(qK0))-2$we)(P<9Kf0rcME1zPG0Bw>}K3uY{Hj?_Fchg9k1|N%}Z@C&yiXxmt?J} z$`jS|Q{+VLqEA-zJHc17{IJ7j?@NKp8)!1hoibP! z#98cloHf1(CDnG7g+EtwoW(z=?IJgV>xnI$+t3$P!iM@H_%~pjcG1X)M0ct3tR-=% z4~cB)X>u^TiCCsh_?d^cRz7bn7r%lihzrs;Ig;m=xOQy_v4=4kT7drczM4G#In;+_ zxLbRZy5)IHq}tJFrzAoP6aVnRIR)pa+(zaz@4XC}0qx~WLnS6bUmG<^{^bfCcOy^E zWmqZ(vf_wl(lQ#8EUB*BtrTYuq@{XvtKVpN6|nnNnJTfZ!A7AD&9Cn7W1*wea5$~k1F!3V{mRrleB6>lnd!R;rv6UrOzw&!fxCu$yw|cKa zt{S_Q^-A3j2DR@6!eN56k;{{)Ht`hRqLUj^<=GCiTNl@}Wd8+)72nk|T3I9aEFtxz zz&K*9Pbwg6wMZ4zQ+3b6pq=EEquw!~ddNrVT-+>4y`3I;gxbxbn*s^ zQBo}TK!UUJXa_XqAPAFVq_5zN8FKo;*19GkS1vF5{Gzu?nlUNN7kLO0O>`iPYRimm z*!xwFr|s45VZLxO+w5)F?MBwx#Sr@!azDN5WwitPbJ-gyPE!dI1$C)LhX)pfbG#B( zW_(0T8BU)*-3yl;dbk_@EYlCw#b5O27pQ_9iAU>?^k+Tb2ze@=B#DC|Z(DwVZNu)>{=D$ak>bA)-5Wb0YN{KOygXp45+W%nzFmV7hkp^Me+~L?<@%@OQs+3Fjv?hmVX& zwn$lCT2rf^dr2pszBno1h7G3=s$Id53&ukSX`qBz6okdNXPp(+E9oH=d+}-G6rh6wCEZyp}YqUw=(`G7;rps!4FT~}He1Vcpd7X{S&jpjr)Iz4r{FOe~kTx!Yb zX>v^>3Rd?QW~TQ|j0^ub$7tl;2(@*qi=xuv$^sn`eR>-a%W^?6L4K1gcH~v%z4poD za`jOJGHc;N=i33C?vp2p`!)>HW#Uf)K$##jk;FcC_mYZ}kj zQGA*A;wi z+P|UJaE+EW7-I>HVEvOlL=S3}dHHbea_MzGfLK0UKgonfeL8|oWuwd5!zhAkM<1RI zzCj7})@Sv_Cd6@lVoJUbvKYl_^?T>IlFbu=)=63f1zO(~rQuS#m(kx~$jipH$U+dA z+`Gy=Ll}o9^^VC9=0(6Ae^+U#&uxL9LZ6=FuAKYHFgwZi$VBEt~scJTIY* z+(?0YmhTCo14J#keING`kIf9CWJc!kCZqMa$TF}@7V)$bTeTsxsn1S7R)$OJs@-Jr zl!MI#i^Dx1G(?{aWwt}f(r)hw`ZD75_)K~+KD$~D>Q zydsr1p~I(Gqw~Orw`t!tOS8@AfiV-8UL6^$jd!ZypT!Kwe*s4luGODb?76fJeVNdF z9my}Jrmn5YM%pbB%0pj}PuKJ4{e2Ox^=M%oMP_yS+7gCgs)&QB;x_@J50N}us)os-Z+6VY^5AUZlaOUN)d|HyGx&p5ENuU}a-6(XKHQn#aQ{Q3ZOC^9G= zQav8hjv&luF8E&)bsf_wqv`rl<5PeXqNcLA3} zBf{)uH{32r8|RkCJ$XM~yI;u*T3*)~@Np|5#0TG^_;JTAC(rf6R2^PHgJ3hGB=JUM z*5o2oB|RW~vH3HIP@>^*FQ#jV#wZ?}4DM@!dqLZa)+D2y2tL7M0+zSC zu)`A$y0_yQR5WA3U3IW=4nB!v(Ew?$E73q1`FJ6T8{uJ&KS_(7yo_kP$4w7>wLg~S zL3v}jZhynpsX)9iF3MT1yM`zOu2y$Eph<)trIb&6%#4wO*Jzk#!%tHjlTpu1>(;xSqHZG*%9=r?9_`;VuU3uNyuAVep(p9Iz+>@rZpXB1^P5%u z+b*ys0Izu88Q)-^Zmp?bITN=`A60fag%75)+|#Z8|M$Ka@!J_8SdNwV_u5 zTbS55cyPs9e^>=%dFQb+s4k~vP~5C)3*JfQ3#ydj6S+APaeDlZ^W+V>DaIdizZ_Uu zOvh4eV{{fp*Fq=H!7^5vBQ~rE{>IaXovkbzS$TNx`whI7+j(ba`5uFYi$qv8dVXky zTzs#jvi!=ui})LvPTSE*lXqf@b)fg15B1Z#{ALqD-!#zE&mM>Go|>%Hrp(Q@uM0o) zDmK;03$S=LlP8rw7*sfl0Km7mxN9A&qC7rdZrhWeJ)SNHn+bC4g`aGFohh&s)JfHxRLls_ z1w{;zyM+g675($VR z&D&n|1peAxK5UwJ!O3L9OJ14#8$UEcVDvrc-fy;6TlBtOH1rh$#G(Ea_x^l<;FYg$ zbx;+@bSY4H=59KlFhGOYqsQMdq2KA9D(DEI1FilD{ba?;+6B1(&v4#)pw=ZiD*~8m zv`_{1bh;^8vp*ArDK&(DNEQnQ4h-lvOtgvv){=zo3>l{!$>`4%P<(g&>T|25F zy);yryw6`d<}zGuq%n!^tPGL!#KW1jCUk)}Cm9ep-L3N>3F(nux`M0*d#J3SQt9FQ zV~eP$mdX%OF2v>rcc_-$9uaJH2$scu=DtVu_ zw@M;4w{x8$~Kmtozni zEet6lqI>bm%xU0Lt?g(TU_{*W3m}{X7!mHd^TL5M2Cy03`z0O@#uaGZyuE(r=%CDW zu&%4PKNh+4`QApS>2qmrm39f|vT{HpQ7NNOs#x83IcKaie3{>2cgQcFm!Wu^*Fnu@n>HB^px-CZD>co#&-VrD!R`_qk&&7Oa*NA6_Ql5 z;f{^BMe?H$gll&GWA%Jsz|n$jfZc#=q7`6QVt{9j(X0k)!pe&b4^_89>}O2>HSg1s zh9!iJ(yzHi@RiDJ>u69V<#}M_%iQg!;geqokMU!@)|+yEp=UBv(?5aj0eQw2K{+DY zjHYC)lXc!Fxma}H64DJ+Ms{yFyeyR;kuEQ*GnkWWw4+2>%F4Z`Pd!l1kC1VL-pyD~Lwr;@@(+}8}AAOkV`l$AoM z^7T5tCCSzMD3J8L_jQ(bV<<0b$KGTCc zNh*x-XFO)vgN@#hXMp)tUGliB^Rxy!_&HjTl}Y;eqcOr+M>pteYdMPL5AhENS6Tj; zsDJl)*4#rY^%dm|V))UKvlY6}E`SoX9nam(R64nKB=PDiJRQn{hJ)VPhlOSCzhSrf zCCM+huKfFO-+W+!`lAEqd^19!KJdD%9ZKLFEBTBrsw8nj!aV}hLIj^n?W!!&>Q6T5 z9*T-gZ(@U00*MOG38y!_(4*VXzONQv)!iGSUMQW|2lVmlVDj@$Zh05*M?yV|W%H<4Rd?)Pl(Yjep;ujKra2Y97bFgI^H&*$N@Ea& zhiq(sPRfC~--KLn?h{>Niy}Qj&skCMeZXuXYY^kkqC9)|)M{HEZ*JRGA5d<%8teub@;8jkOa(0yI|H^PJ18%@0Sl-v_+Xm682P zN?o@B4u2_XEy;lB+sSb+i0Qv`qWpoH%BwGc_` zRpc#-A=_kaLB9m6QKxgIAOP|FdYfK6c!DtHEgN&^w)hKmi?A}s`*kIxuo84_#BHx3 z+WzeTp2N*Fh_pPWaW`YrE1!%eGdDLQ>xH*;{n$HqTjq~!M_<@cq`e(o*LvDMYDo(A zC|~RBJKQy0uR$kO-G0Mlshlp6lELqL;RB`cm)!Jyj#(bxeWhG*8<>ZzbGpfnd)9iH zdS0}KVejq|PZEps9gMoZu-{bKt9n{@XSHx1XR%5h%E^x=x6()6myJE?%g0_4!OTrz ztOTP!fbK_Js57Y|GRgH6rSz_A73*wsY-`kuEFerwx58)smLcA!D(Fn&2c`)?<|mDk zN!=;INKiJG-x)j&Qw9tQ^(E;;SkLYjZ@5*1^@+<@cPYIbIDQ_kve!_B^%_f%j%owN1Sh5j z=8VwjYs@Z&9{*~U$xllto{%wj;f$o3Oq(EBCoDJJee6^-wxRKI(80Y(?|SvD=8Ml_ z_P}datLa0nl`_e%*vM7i?nvxwaip!*4#)jNlOWm>}$RmqO*|XWPZ03%bl_ z9j)b4s70BvQLH6GWg8&>Pt`>Xsu^C3p82@%_*X<*-Lm=A3c=x7T=JgF#b!G@ipSl| z5yFBmuTry|l+36nv`0@E_h4;gtk-8%n(ct6b+ghx0wuuTUVVKQR^z$W2>nClzUw1G ztHsVDg7C}Dl?;Q8nRhJND?g6(9qN5Gub7-DGinjhOuREvW}^9Itd;du|F@%~VKZJ= zjBSJOF@x4dLKW`0+;`%rCw{f2L8!P`0nSU50gyLlN;COi*j%b&4C3mc*aLTQj3ihG z@l?bw`}->7bShSmX6gLHD~QV+2L44lkm{YM^CI0#N#&2m$HZgQH)*jXsq<-ST_+T& z)HUjGjxl(8rCOjnkc)#WurG<e z*LzYBffkggghuC<`m$Emz==`D)mzM^_uKpZ!KJYoO1pkq?iMyT*eaCYZ4JZLH4pCx_=Mj*Lr(sd&9}Cca+mUY4_ykyq5|Yf>0$H z(*py==#m&iSgqN^;tC5v2?n2&#nA0Op)D?2ACR`7ty*E4C6XUOv8}8b0;>L?%ON@mAyoXRl#b+BIsBz#`BKbahV;1gNj`_vO%*{YtXN8p?g6Zwnx6!5My7+arT12&cn=`jpvDiaYuqM}T z2`tz%+i_^@>M^<|=$o^Rgob6Ya;-x@>ClSY*p1GSO@jx5>ZZ3J+6h7Kh3L!bapZ4M z!pbS*8gDdy~3JWySC9NDn%3<(gbvg zpwdOUfP$zUx*U z_xtz3KKicz+VgN`X3nRMa*unAC;Ab;EADhVJZD&|-F};yBpG`NW{l@I&rbZ<(QT_Z z4yp2$VY5eHsdr0Y>zxSD80G?I`I)h6z=2G*SW<>GHYdY;rX?j>9%W2c_W4d!gE^m%EQP1$%1X&FKgts42Z<3c0Y z9?4b1w9APGYSRHn6rPI*zAN_8ur(HP-)gFCb(*ELAX9ZH|rUZMfp{32dnKCA zwk}+*nyYOeY5C4&w>Ufld(Tq+*=Mn-*Vb+4UHkbPU4t&V3#}p$$oC^9@E%i zrLuR@6^heSygOf_?5bs(+>4#I$W@*rgZAYSZ|*q8VBi)gaul9`cEEp@mvw#GMUe))X&Fs(uOYzU* zKB}fE)-2H1RXSdjPYb*ToC3I=8CnbQVmnC6`||U{O6QN^o@@l>DDUj^>Dg6F_wV%P zFxl!9hkJ+bf`M6g-iom(dND1dycbM(jT~L+;R2^!*rd!U5yFI=9P|fZy#fX|^oEg6 zckgj5=HO0wC1D9Nx&PveOXtc*&2#v)QvwW8^SW%wlL>Oh`-3U1Dmkmk?_e>rr)t4z zEd3Samo+Zlmj=)7^SR{1k@vkIXT-eQAqtFs7-Nd{BYb#odS|Vqv^yo9lD4W+t!Lq2A@x6+B^~q#J!Uqk#yn$zu{8 zbqmGQYR*E|vd==+1A9T%8;xC&jBxi4aMb7y_&CIj=?xIb(jM7-8@T*TdlKcV`AIr; z-a`2pfDP?@^h(UIO~ca)Pr(PL*@#~UPmDF?M?u_tmC?k`+RLQ19rMcVlk)XH5bVk} z_>E-#0+Qg!c81Ce-t|H}{fqY`YP9E?!4we5nKl$~+>MIaQZ6Wp^Xm*>XmM@5xsDln z*x|^&q&)K($!`<9?4L|s_8h%P z6xT)b$`<@cpR#;nglyEQU4$;KWSH59dnQ6}Dvt>Y-e6;E0cWc6TXhy6A7oYh0!}2{ z(_^#1n0)dS!q%lL$$laWsg&mxZ(9AwCav7(Q}vk~e`w+P!EUeIHWztM_#~sQr@ck( zd$R@&rO_p`Dzvt&IY|sNQ&=5)d7u2GOVt88b)-n$!HbkbA|x1ND8X)S$?i?>>}#YA zA1um*x60FK5D#pzBC(D(L0cPsQc|KU)fwQD;{!Z{(Uh^7A2F#cr%q`vii)Efq7i&88(T2n>#oAv&yI8>l8R-e zyyDnD$q$*j+JD{P9+&85N_3?|Gkwb1y{w`gq$X_`%av%{{n3U0`5v>#wC4b@N(aHR>9EcCGDxTFu}M%@`2 zuqxXNhuy01+u7tm#S_fmdd`J=KNMubgF0ryxe(bHlmc@4M;VoMHdhV zm~R=P_3#Y*oQyYZ^ao7y(e@gH;t~*|q4wx>S7^2=Fq3Rd3u1waESb7^G8(AN;k7A( z$!_jOIs2WOI1Tv2dutN6MHDFV-WQC8tOyS=3z3qs?k(RQ);$w34poiY|Aql0Y>3C7 zlDeVHn6>|QW3^TgOokd=WleZ}^~A262d!3q4M~d|QUgkiQG?JJA-X14e;c+;Yp|_Q zz?m3c0erfTjJ}pg6TxhJi7|esv`~QoY|)nw)_?w^q;Ac={k2YgqHP&O(tN#{vsKR8 z9bgG07OHdM(q_yX>Y3g^V5xy%u-%YkMB`!2FI=XC(WKbww7K%>Sm-adR7a)yQ5-Wh zsCXBo+JzH%l>+*A0mz_*q{?np)4ZNs*V4HMkdt#G*@@qFqpZy^5Ak ze$mM+i(^EQrp1LzoDup$Q<2`v5mp0F6r9OOFJo7MA9DpDd9apaK*nq$5N+FCF}qg} z8}QB7Qvd&rpThy_={DMn;ek}|0U>W0spPhP3^@BY#cov!)!1cn7?f=BYuSN7$W>t4 z8YRR2llz&-2T&;FB1AqmLI7IOgSw7t!XgAO2pDop>zM72FUx|)b`rO<^Atww6a&vi z`CvqC)7Tr}M(bZpH1DQRM-p8!YE?E>OiD-_<5ks!UZW%w_XvGI@x{eW!gh;~=CC-# zTd!N0lwRbI0~doEhLl{uo4Ki`a~D3z*ebcYo6;|tt|gfgOyAHvU2E(wnopC`Jxt+} zqdNGlT#Z0G`p?cFM}SJ1jrW$+a;y7v6hCgqRTd*{7%+*!pCk3!XrdW-i-Y)YZe&=M z3Xl+_iaY`!X>23kC^4Ix+r8iKRP6IPw$b^?d=M5&GYNyv;XZ6z$QdwT0ywAC%I!0} z_10_EMY|a=kyRh?gNJaC_U475hF4CkV-W|*Prr+^>^s+Z_7?~8Dlf47M0|w1Jvhv$ zKI>~1^(|(e6zK)D1q_36>NJK-3X|}Bfgx%8EPRmc8{6?9;Q>)(`!My@2N%j(3*hj9 zE@ZxD`zr=kwKh=Y%NpUCh?3BHROvwQ+pCyzNa)(@4ECgb;D>pQT_tB<{Y(M5DhtdX zGI{$Gbz!;6Vqw&;#c`m_5TLcxe)m{k6Yla=c^>A|YG;|m_<-Uq-#`yOQs8O1zL3KO z9cLlm2Mrym2gtMBb_=}D3LWMJc0(~|k@4Q@frqT{-$Trjlz%Ok-ETbJj#DIwVrwex z(;gNo4yE~jkzVM{xO>ff3U`ovX-sOI+x`nX;>qRE@(}#-s|KbEos^e?|mJVmylOWZVY2Z6)Oa=+0Aaegf5@*x$&vP^A@j?*dABQ*M&)WYRT zm!9tNdcabyR|T;rm{=w-TGn6Q=c}(o0f8-f9KTPgHO+ZjKbE;~X~;HH7{G(?eVXEP zFLvl_u_k9CupVL^DVD_-kOhohm2O=oGOrQll6|pXf2Bl&r<9TL!Q}iE0>X&Yl4I?+ zhOYFn1jxOXlH98+eMSwy+Pk(#|H3}sPDCT?*n?aykC3Cavp20}7F4t>r>nGSV6sZT zU)a~;l?~A|EAq`^}$NJuRh zay1M;B3dw>ztZjNY+D2Pj8tzbHa*PF-_HkTOw?c4;(vnw%pl|Je`CK-NnrWmu`(Z3 zA{56#qZ~Ij%iQkqeWxOF(0c|ZU2zB$18XwdS|d+uEX#XmXH6D7n4NNn?#Aio$AlZA!aM}^}Nz6 z#c)e|xXdrQtb}-oS#dJE;XcOzL9=3}S^@Iyq*=Fa*3oa@JF27y8;fULD;gl>ax$H+ zscQ#85i4h1tNYE?gET2fwqWSCpF%gL(>e zjfDQr#Q<5(o8P8g=k1pL=8)=a;w91uuE323t$EAaf!X$sEXt)dWnMiWTD zT4?FEjxLn^#otD5>?$lk(L(&oTR49{-S|xw1w4+F`=zI6n_1E%6r7`f31ATzKp6&s z+Cu?gE0SHo%4?AG*Jq5jb{m`ayIu5u;|-`0_~$@@8a>p2M2eXX76J`9{OexuBw$X1 zdVmrp6syW#Lk4O;^urny_98Vq{TeJ#A`f8FT(vit8H^nGn@umWt3m;ucux^q!J%I- zG=lsb#7t9u1D;>^kR!WQ9u&$|tCS06e%-UI*`04MyKuP^Pp1NRRO2ivd2R^l9T@TOD=wb8kUQ11NBc)U^T~=l{?68NJJ}NN!#CQ+bhE;|A<0vjN_L zAmoVgj}8#hNHQ*?WSLhS;wrw|iX+3=5AD12z-eASSZD1?CuSHH5#q38B>dMdX_O=C zb5ULC@bm~Jm7q9Sd>h5pm0!8&mRjDx{+DdAcR}67><4K61@Qg%EM1X$m_@0=3ri;}}ypR=|XD7uhAtbF7 zf|Nt@2s0lE8R9oqv@D+De~>RM;!M1bRud60EzPS$CCI$sDU)c zI1_4?OY8^u$Mk{pyT*39I+*<%mEtU$2e&l^8+H!Hryj5(%A@^vyDE}*1`v^ zLH+Gwi>$qh{5tt5fn$~Q&97HdxQr^Yc2GUr+8JbEJR~5VoVb`4c=`kGVPFa5MD>WU z^hBTTdX>qc#3yx#ysVJQ_fg}wVYz}d)!%x?zY{EDk9()mza7I!xfw`}Y;e)LA}Ev} z3Qsr)cxu*nmlZv@Znb&v-qCQ#fh`vA6=kNW9x-GiA5a=DqopabeO0x@t@>%xF_;p? z#hb=et0lARlo?;@_w~>qv&vbz^5aB~*7N~Wips)SU~nH8d4;4IDt|6Je=#hIq2jN% zE4D4#%6WD;b#H+^mPSbtP}_GXp?}6XjTUOUb40dDW?TGWGym9K&ZM2A_2#H&JZvA8 z+v@f4z{ocC3N{Ge%zVIvdK0JlX|eT~!GK!9k<|eP3{tletZzsO^cjUcaLv=CaWKM$ z>UY+cEBG@zznf^pW^b8Z6-DeQe+u(~#^ut672<(xV@uYP_P{V1z4)7vA|hDNci9g9i=A1-`X z?oBcLBg(Qc-x&k_(uklqw$7665b-fH09=}Lga_^BI3wSx)2l@dcXmY1B(dOaYG5a9 zxgNfop9?YLoBG(GM>?X5J!gSsz^uXUw@0#&w}?l0YLV~}-C1kO`aa!Vak}#4A4&Qp zZL2hGYtKAAk1gcYR;k&R^B86MrazEvIwY&+2V|iJTR)Kx)Pf}?5>ud`61I0v!T81C z(_Nuuhlc8@i){mo0|u5Hbe$qqk&VH4z?Qanu0B7F_s6h5FiG6T}^ANeorEYbW z3-|?OS-OiO{3(_HH>iz>@=k3`t(J;I5t|K$OV&TNvP(u%dVHkgZK}jzXWiIlpcWc@ zi6@-O7n$u-1WZRqE`4lgzDpc4E?zMxDs<^E(Tl#O;7oYH1tZh@T!V&qtDs4nx-AO8 z+;9A*pCZOWpEKY)yi5HLHwrk+9s7EP^IJ=8hnDsU(o|N%amXbeWwZP>MJF=-+gQo7 zJXUVQCg7Nj;CS(o$$HmmS%Uj}IGz6^n#x3m5qKNSD$}U-#0_t2%t@?LpDW$}YxCuS z*6{cuP18zI$qTw+^CGkldGz;xH|9+mM+F{6il8sFX9cXQ|HQ~h^*@y1~iZ26Rc z1Fwj#!`dgyOKloxfP3H;N( zg6q0UKN)GC|5^heGPsqDRjctdJnQb-tY_Qt7H!N|MOCXz4XEbiBbJ+8ZQ23Ku$cUaE3nz(lFY%-bEl z@=Ye)x`Ywbq4GniS#vsaN=ZudGCs7$>Fqmz(Qj#wE|c-o?}CQ{@{b4-8(7WD=7m!C zV$Og1%ph22!G3kp`=!;rq6Ur4FQv9`0@VDnRnfynANHi@G}l(7J9HdaQ*l%|r3o&K zms~E1f@Y0>t}0l=PYFhqjC-lh&?2p<^5&esmU`&l|^u~HQB{@u82xLUw0QK;f;h zoj^;7@q>)Qa@s})Y&^w@_05t9Eh!?T&7HJzvMQql+X@TvccGHbBQ;|s;bw*F_`%lv zE9nB{zG=Xlzij$Jid^iqt}Hul$KmLZ>*_$`@t!?|Pyd$sX4ew`VRSS*uvmK>dsPv3 zUxD@Mqs#{?-yEQt?!kT3?kmf&iE->2m`zQV4h6i z?MR^Z|A{Du*8z{Snv*Yo%^xJiT`bmJEZKV|^l-J)o;d$2{&YrH`$)IHSOx^%UR)ml zIwgiR&)`4EMSSi}4$zvT3^23?1Wx+3mkL?)zuWJ#R1>u(iz;dvtUi385-@RV)pu@n z>|~n3vbxanSlw+q2mZBALy(cnPi19w{Tf2ZDoRZBO!Q&L17Q*rAMUrA&ogTD#VHx< z>fiMbC;=UY#)12+pKLnR-P8|Bmp+-`q?nc7(j&6az>hJxFnqbi1Y3Ydpunt6y`JVT zLZ-zCuIVN0fP@Jb*z;M3_vBnHRhd22}F}s^1OrguHmuoMmFk5$hZ|R%S^R-V=2_+ehO!zr)c>RpKBXKchs!_}dQ*Vy&^$ZNpIZ}*MQGhw) zJqn*nu0stwRsdB}aSkZtYKR7J+TUcIU*>V?qfHT$jbzns0`(It9g#n*_=uyCXB~Uq zsGbxK`!c2%d8FlV)Wb@oUEYwv{C3eCiYR3giV~P`hOtHAi@>?9g*kI@@Ttqzg#|ma zlDAMroeKw_Ly!4b^ezo}za?Grbla8KB6*p1S7uLl9S&bU{VCZv;mb9|;kZId<>}%R zRi^l2N#ya1{Z2{?v{L=n;<-Gq^E^i)3Hs0{IB_tWBr*IX7E`Z$h-}hb!`?(4PqJ+* zHNq!a7nA^zXo=`^M{rM$s$tx+`m3$DA$e_`pYE)7c3&e=v^!{>@-;(-3CIj$u?Vf@ z^+l(MkoxzWi#)_z9aV(HZpim@_0RGUnM(&Qg1jt$*zK%pFquRZZ0~7x*jlcNb9=^s z|I9$Os~~M?0b8&hLiXO4B74mopO~LpN1UdyO5Y{9Zk3z!JMW~w9==V>ppTT8Z_az; z^iSz-rN^!7i)#|2wqWW?MceBXp-jWLRq5}ozNZzPwqe}h)U^^Ct0KJi%ch$;!t}y? zbI=1}r@-CCAhbtI>A^~IprH9ebIOrMT;?67^q}+o$H)_;ft_Q^{U}{EOl?Vkv8g2o z^uVjf!w&M0aa@>6J$*;(Mx@yis+V6WR3s=O&0_S(^I3P{>}$yY@wfiU>7u#3bt1wS zSI>!G#+75|Gpv&06?TeF!4*c0&D`-C67A7|#*9E+-;3#>fgu4tgW5!RY2D~)+3(9d zc55-Z7ibYL>ucm3>gu0x5%Po~s{^k6fC6I}=ksID5Dtw)#Isnbl5kZCb8 zY>!v&N5$X^QJut_1@~gi6d>1rKL(BQP+RfX!+)3K%NKF{hLIbl!v#%$-b_`^2->(0SA7^YHD=T?UHYAny&A9bq_}9Z%b$>YeEze(UjhF#BlfdpYie@4w@}*ob zOy%9Jqtf`wXe5O2*vgElvGACxByZV%kI-^b095L}tMmMHwiIE?Bf_jX1~^w@&()hh zQ3F~*ojC9!P!uSHaO|6k%3|sob+;s|rH;sGBV+<8*7u$BlL<0M#jvFtR=}4j?*P@a zOj3EOx8G&RnaYZ}EE2zs+3%AnKDXi##M6n`ba^%VMM4bJlkf*j@a7QNpn={^NWa^J z)*A2F%kMRL<^kVp?fewKC2JwZBEaMTJlDx{WR7lHs`6`loNdtQN$gN$29%L!02?snZZCRcM?4amV z;6cz=&g;Mo{ldUzAa^VcN4&n%A6B!pth!WxXM{761qu(6wmMnhdX`{H2_lAv4VK|h z1M&6b+o8huoJ!QNhz6^gwe1%BwcLs(W^Wf_u0$8?Tr=JFox6y1W}e?E^CTh+P2!{~AR%uvn)u@cj@-C{-o<$E!6z7E@L!@b5} zD;{d3+mybsFP%)DjnPGjb!G3-n%o-*lNxVFXZ zrA5Nz;!5+D7~pavnMBGOA(g3q8+{ASq$2OnG&YQ`%9Sw#Q&KInto%5D0(u>9L)VA! zgzyGW{zNTzXUu+Eli=q+A8{S!GSS#|knSOSc>E2|(aA&60hSzu4?t5uQ_)M93YwYx zcAYG})t0J2rST3e*2W-`fdXr79n~K20bOA5L2l8eHX#HaK+9iQv}-8Mm9O}Z4DNPu zcdZx$MyK4J4S>c&@t!Gd)u222J2z~aUa z*ZZAu7~%tvViuHtrsAL#As1EAQGDFrQq~_YBRfCQFn|vDDu~bXuuL^cssUdr$UH9< z4>3hIm}d-B6pa{SdDelDK2UQQfC#fNtAc7dCqIR^Y8t>lwDYf00a$^bN@)~paEvQT z;sNpQd|JPj`bEcRAryTlx6mSEzn^+-t-XaQ+ey10Mhwg%dbbA` zGJV*>4tbD#J@j3T__vD-_SOaPfAVH z_Tf7FWTZ}BqgY^(S~cK`G+ohEt$CQ@k_zPHZDO&S!Aad^QK2dzIhj9zT9I#!IwvyC z)*2S9(jGG?DjhFAiOWVb-p@3x0A~VB_1g}z8Mf0&M@II@-T3pb%fHY^EhC}cMlrpP zoG9f`NEnw-OgV*n$xjQ^3RKDd7Y+*;moZID(aP< zW@!hm@Eva~ZTh#Iw=)L9H&=nmtoIHM+MF~$Kg(L@Rd+(=Y)QbW9P!Fl$lk`@KTu-N z=mP+DQ}fdX-CgCt^)E=DbKqTW`W&QY@?@1W7N{ROb5|E&)a1VMc>13T+#(15!GB`z z?()?<#p}KLw}(PH7Z%zQ76=*gT|ZLxQj@=yUk9Yr?j@r0+n=nI)^OGf@5JFB2s=Y? z{R6wCA)vss!H*KsiRn+?aZMj~k;3w}qj=pQc1|_)&<|k9u)OT{>q^K1tI}GPHadk2 zkFVk)fj~c`^e^-w;!OFJz~gdNh4%Wh8Q;s73emUOK4(DDS{U#bndL~UTCE+20@q!U zCt`3M;?Y7c<4MT*t_CAkVzVi$8)?;RfqtIwN2tc)n(q0n#Wi4aG#Sahq!HN&ml5+l znO~Te8{F@6$#7DxC0vY>G~yk5$wSBCiBb1Xio6i*BAh3xm{AuAGn;?0S$e0mukEoc z-L*}AL1A9!GBkw{XqQyuq~|~?Behnspo_+Th>L#n)egtACH@guM(NJAT^zAPnwh!R zSmom(Phq2H#3#<}E3eP6u=Bk-1r>ZYbYnN$;%xtP=+hK()%GxMRVv62r;PIC!LjeT zcgaV&kwo)FNEW!@`~TWXbqsU1(P8W`g62E=?XzU+${^69sh|v1jgt5~tEJNBo@n^eMkN9|Om}G*CZ^t*PYj}2B%56xzDW=(559^AS1rt@H4ajb0XOa ze@@B_TkbbD4*Jd8%Z#kRbRh-2nDKLav`>hgXzw6C>3e+*P|ua|#4Mp4!Ict<%ro-( zqKE%zZV%$fhZmW_^tw6)v4ZZ-{^aWo^yveY36Uq9w6ex4TJhMFQ>lEeN;)RPiEy*Q zv+$BU*h@-2<%|0Ve2y2qFJOzb{A!wlo0f9STB|as&45VNc6GmVF^#!40+SK6x?$lV zYJl}E?V7Vjjqqh$o30t9Z)_}EmlU^wA@?jYzM!Zyxfd_69|IbSAO+^YNg!)~c?tlYE|j=fY0U65P@V-m@#uqRjLfpY7YHR@mN*ki&h)-)PX3 zt>Otk%1p}&?qC$p+(CLNXzLf{Uvp7K~Z$V;-*|1iucs=SsfA%46VUXO7-*}EuT=tot_7r=1%(x&L6-8r1s1%#+eNFYRZ?NTTpwn8 ziZ2u%FGG->2QI+1Y~VWA;lUH|iW%EB{@XijhzZ0=pl6nMr5>@urIZg{Ty@Tbb9B|m zLh`2ZhG(wT&##75r>(A&u4PzpFbcTy_?zX!R(w|`)_v9V7)S-((`g5|d`3@MB%;ppbK zFvw*qZd&#;RY`QJZMMgyOrN>cbyI9st$+R6^w3NLQN<;LKhS&O05rl(XE<3oZr}l4 zrdXI8`<58W1?52NG7O&z0$*q=)zQ)}K*d|{`D1VHDs29c3mJwSO>)e$>9l2j=?L$# zBC_Y_3%SYOPqz@P`cCkXHh#7xe%?wItsj$I#ANyA`KS>hH2o@U{g5oVkC>Kq^-O%k z`D+yxMy?S;e>M1La4?HKUt`nCw=RVXVWGw4h(5iL=GUm@Bj9_K0hWtzMe8gA`0~BM z)_86ppW-9z-fF2gPdSb9EY`wYSIrXZ@xZ*dVX(1Xc&?z5!!gbjPT&50)OYBlP}$kW%Y(PJNL%1grS2IDS~V7@_u*x~(4vj#(U#SgT*y1NOn7 zSlUW+uo&t#6R3SR4E$^3T66w5HqahxJoak0#76a#CliPtybeNJjL%BT&R;SS%2AKl+=CZD-W-xJ}?FK?4Dln_v?%hN^8k%^Q&5z7lrXi9iU1- zFk%2c&{6G}B42)f5~{ph`H&VX#>)`lzTf8{uivqJ5hV}sfZeMYZX9*Hw|8kX1rVK6 zr+$0q3E*H}KJN<|y1wfZ@C%^|RFlLug_Ick`CXg^6dDcCZ7sttYTojDo9$f>R8FS> z3q4qV7b5xPWpXA2iT%jy@|ho=1TtagcA3%2i(SLJ#?0<@l3_2#{~7$X2!Aq*<-0#v z67n|~{%6jEsm!v3q`2lh*D7c#^$!3?U5gE;Dz?^fdqcw*K0tnMDCU*mMx%218-%fr}F0J13{9s zGu%uC^!AVTBwn)=dfFqlX+cElu(F_AcyZLV`^=<5*i4)l%c4jJl0ib?59{9+NHH3K zv7{V8P^bb!7aCy%>iU0?o7Bb{c(XlC{>iy0SzP<=<&iWi_9l7ki}xsNFZp zxz=gF_=7L7`x?tvzrCbc&KJu5A>1~meA?zlI@{87F!x?X>Y`%5$FJrm3;*UFjj@-{ z6iO8PnRVp}+f8^glY<(Q=Ceq@h^fIfZX@opu+crBp77lrTPGQF+YTR|;%@s%5YZ{} z=n6mi&~Y4l$%=8%m1D<$zQ1wgAD)z}R#qACadc2&Hmw5#*gQ9>#(q>6C0^VUPi!lK z@QckK?Ea7E;;NOV0pbAUSCba{+ucMe>6?4X4kZG>W^1*R)rDlLE7g;QGR=#CVDOJC znc+XZA;tV;q5^q*|8T!3Eq|vB{6-QBu>QM)lmD>E>Lh>7$*zwo>smjT?&@jxGB+ydH6 zSUT#Qw*0JlA+teY!oY~cqI_O{S>MylC7nTn`6YUvoNf^2G0%#J7wt|dM41-&Y5r-d z;k<7@j{dRP;_O|n%f(^Y$?#pN@vqL90q0J=tSevm$WcFVY8X0!4BQG|tO*UI52iti z#BXu-i3+?V9?8)IN~Kf4zPdH!IJ`7(Q)|saNq@!x7xiH51yEryZ&pIF*?yb#nwg~Z>>67W?frDjJVcL?0L#!9@KbT zHSw=njnMRqVQuT;p-C>AW`Ko#!e(+${AdZw>t%&biFbppv3!*ZIO7>xeH6~ z{hOxy9e;+B2T)dZqc;(nX?%SqN>fYyoBWJMs+B_$gOfXD$}H>su)Fwc&_XY0z4+bI zSTlr1UA>7)^bQ-m=qG0_z}n7<#7 zDkpC*E0fjS{N-C}=Ttlk%zKeVto5H?=Z+Hd*~-8HBJTVophCrJVQF5)0eDQN@d#YS zr}AEfV{~P)VHH0Z&l#3IU3;FP+YC*-Vj&#-a2H<$_IPsg%eH#i9D8n{W@4zo*o z`6U5^sp^)p6}bdyHa3pICvvAWLQk@n83EDe423WWAEOfm;nHfID5phN{i<|PL&rnI z&*Mt!l^^5h`EXD2>6Pw1(WS+-+}6`WC>f0Stu+lCRHM}p`>eRV<9+2`ho5`maxEBQ zvg2!+42s=F%y+NGZ`Ukkb>Bz`9=f+hmf>vz4o(D4HY#u@YMrRvpe%Ki(Cl%>@9&O6 zxQn06NcCSYYH)XWix^nfu1Z+7cqCId>RQrV{LSy%Y2n2JbKp3V$~7W3Bh36-FSe1N z_{`P*K92oAq0U2RQuwOw4M$R|4f@xve%?jRMw27fzIyGPZ~t!L3^lennZ7S5ze5ZC z#6{6xV5*}(Op%Jxkd5ycjOPl1rNN8VGu-2=^zna-pYuR*PYv#tjjsYP&JukpjrIDD zb)3kSXdw>7QUePR-k8K}tPqEZr~?BsZ&zmy z^7P$#-dM;&$j7c(i{k;-`;D}UyB$p{dn`AG`>g)1T^$|K2&s9-rB8bne=xf7u#w5n zP3_2etWX{CzJJWbIeCx|HyiM#M?9d`PM>_|$j>PSq0bkB~B{)QpyB)t<3xSXTc_zYx8tn?J0SNM7mQFR|tA3e81;T(HVS}StH;YY0t z;J?lPxQed3F3;|T964n#x)0R&V~>D;-upND`Rm^QGD7qJ96^Jmn{Aak%6fi1TD5d4 z5C|m#=R^L%t6o{S?YrnH1@XBX=7S%pNClR(F==WD9B-_Prr6^5O#cYktlVsY41=Yx zqR~&@x$GOL{^V={aF4@=4_i-_n5p!fg^G*Dl4=zH%K+Rj>Es|gCK$yk_yQ(Ny9v-! zVStn=6mB}`X=dMBQav+%%DGYU`W?K=gU0a^r=RjrpQ@_zAj#zfhjg^RWtIYf86n59{a|zO~rfFd7H`5qF8LC zC2#1t25^mQ(5r+Xf0W&)M#vqItW!faWD}i|{8Fd5dtscXNo{2$!q^3<7C?;?RbcBR za?DaVEY$ELHZ@{&WiGFx*p+~Ew*PLH6RroqSLfcRu<@xrX^OdWrA;&M>|w!WsQxEC zLz+&S+X(?W`D_$JQTNn;H}*0V2*N8V8H zy>d1lln#sP(&uqhEP(fp)N|&(Ba<(i_qD;=I4jnxwgaM0Y{o`CQkxvf)M$u4yzVFIiztd&t&qyJ*7K&_ZAgvh|nogLIZ8M|)o+HO?;E+An z4)nB2<;Nn_Aa=qEA?9-@PB=7{>@3W5L5-ik{==SY+;=`^-WWwx&)XPt7x(YYwMlh= z9(yfdr3Dj-A3CYQ-z(F6>8#(;fS@@q+`VYM6SbUY5VvSf^QI{0m?t9TEdoO*7_4`^ zv_;~@s!>xwUF`*z=Kdjp8`^Upq1Ul9!RtT;}zF@&=ZJ%l8hRd1I>| z92ddhsN~NK<_S?1?EqR8&RbR}iR{aUb=1ENdCJ}e6baD2rlGHjQTWb0*S?iJus3_v z=;^mjn|{-Xd-LNQk)DH>3c68KFw@QU<&7Yq^4eCi;(nbr>XUAb-bfQg?P<*kXx``7 zr9F6i%B{y~4`c_E56+fD3)Sh|#SO1vye-~yl${6RG^cS%mH%?;PBz`LO1q_cDswMl z#tycG=98E>qsn*S#8`Xiu>&6|GU3PN&2Dy8ffIW8g^_($+M+CW<4vNqi?iMf^R)}lyct2kuCMjoz}&qgr2JJ!%2mQXHE4ipGQd0 z{Ors4u8%ofiRfd?SI!x~|Keix?QT=kIxGLbxHDAyi5gX+Ja{K9d}|L6Zt;j9yLwEP zxp`#@pZ(nkri?e9sn2(Ou2_tjtW5?-U*9ykj_28?ka&vE&U(t*eW4^J`>= zEw!w2t_M4Q%a&HNjHFua*IBvxD6s`}{&=`3=s?-%t-rgxeFSF(6S;0VjqfiXVl_kU zx%20b9h$&lV9YN$?7H`i+x}~;c7t>O*WO6A=YYEmcb@Y50KU>{&IXD~q1^c8WP@fR z8zG}+vkOp2OQ+b=9!P4cj}&BC#+h)>TZB(fVoVS?tO)<1KiYHGf0=4RF?4lmX(yB1 zT!4xSzYVtsveR^Kz6e%=bpI7-hcO@LW z{Y0%iB*g6UD7BQ8^_XebUEo}(BRC2h((vaj4{L%)hp8~e*LRvA2T{d$ zco;;L8X{=YuIoy#4%TVSc=q`n5>p-I`5U8o&A%5Dj)JA8rl)!Lty{R1AOx&*MFl?3 zT?`Gm($O9oyhRF-JF`d4JcEtB7wt83Y`+49HaDhzZ7~UIwlE%Ao`N%eeoO0TvsJ0mLY z-z)k|5gj;9Eyj3#D;HHgFi3m3)lx48mZf^Xwv5zO50=huPH-a1*)W}X9Aw7E3A8*@ zl2fB826aT}_&`ROLVd|(ee)?j%?2q)CIjvsY%N=Wh4-k*df#@b>MNU$y=Ps@V=K`I zo=QHQyE~1=a@;OWJLPGRzw^Pnzoevs4z`X%B#Gb1Xunt7=Z&AokuI*StG$xv!UyrgLFpbK^uGUNM#wKJ+&EToU!Ax8b)0~(?Y1)K-E+ew+sVDkGHZcXan_=U>#ap6tc(0DK9e4jXRwsvzViQf4|A=vJ(E6$f%ZuKJ?iVi_z$5;Ag z>{ijjww9wU=c6AM)Nas;RYI z8?_*af+$#!&a!|?5s?mwirA6T6 zvrbyh)9kYeKF2|i;2l(F)%Xu-%_TN3Y}#n`(&o?u_MDl*@?U_StKyhCR|v_|eqBsT zR^AX_CikjI3W}0Dx$WhD)26gsAXcmhW6kx4Clm(XuGaZPY2~`2v0~b5lTNp$lta7? z?299dV~qN@D;L%r7d87;?qL%mG*-fX_b!^s&hOPV?0Fk;QCs59-dSKI`rk~-k@f^6 zWsq$8XP69rPy37i^t0P*NwA03n?jeR{{Mp!Lr}+T+4Q^3Hk@&rQrQgHW6}WtV+4;+ zRxxMFS4JE}eUmW-_;rs>vv}Q_Le}z$*3A|SYD|6x2d>RB*^D$NymMjYBs=3p5IgqN zk^*{r;fl1isVU-yJ70=ta$toCYj_pPU(BcLs#JOGdDW}s>=l3QTI`EO%NaMiQT=Kc z&sl~EBiSv-1vNM2Hg#!WU2MScj15zJW&Fansvrq^b(66T_K0b%Y8~F`6P=s8Hacco zQM0XYzUZPh8xPBOLtJ&=7-<<3-3h8xch5JqG~Q5n(l*-ZMv@Tq4otgGU!qlGT$eBO z`aTryMr$BzI~hI|di=Q2OI8&uw+K{KB_Pye}Db}RYGe#YoPWU^;@ zqakQ;p;bJF+xDl1vN?!&ke;6x+dA%ti1 zf}?jE(zQ`P{!F~=toN+=kJ|UaJtnx3=gCrKnPo!5kBUT{u@MIkwO`YIb*OTQd3;Wv zVjc@$@)i&cd{`{3tUzfsVvqEH+1)$FVa8010?oF(sUV1#w6~NEpofCnH{p|(ez-c` zTAiA};(Jw(T`@gXy5>+Pdf~*5)U>t3P{ zxVk;8APTYhYKc9@}m657mVZ?GB=;LU)tKo5xBV0{4@rs%Ue4R!H>Q>Ok&-b|NE1sm7x@CpHD?)3o ze4}@`f4a7ELW>{OPoR|NkGTgo56jB0G{}JG0>@h1)yE-oP5nzGKi?-7PI9UgIWcSWArJgBgy40wg zv?hM4h%o%1j5Hjvv`1#uPX|S;^}-EoF4!bnVrGZqUMY$gwTxZ~)};(~KW3P@YOH?n z)fH&LHtecQpetg0GMcshXM7*@QA~46af1virAqy*Dszjpo&;HNsN&{oy5frG5**Gm z^^FN8Pi@m6ewE$d7kgT~!6p5;yr%pg${q86B}~XO$`oh*O3NRI67^pzm0S|}d?99E z98MS5nt@iQ8gFrm^t&Dw_qY_TP;^H9l@VA#zHX?@74#mN?|^*L0pHndAG`PrX#EDR zr*=^dZW)Ed*=z>~0-13NPg1B!0*k!>l88laEA(rbhYb6U>J24?yyCh3$tqnWD9_+L z=exe6fAFmOyokMj{br%4`0mWArLS1j4rb$r^3#}nU%bKeO={DCrV?1 zbVMt{s894#g%h{i+qDz*BH#^~<8_wNT6H2lIUxg2W?$0=Nlw0&plsUv_d-2IuS3Dm z2Xh7?kVkEx^EhoI8wiTY{bx$r zEus940KO-Hmc;Js`no~pMA*&Z;c1Xe%uO!w`{#omSsb^Dx=`W_z-9}tzQa&QX*%V1 z`nTo-G?gEM>g77n?Ol$OiT~2zB!6FRS4% zR$_h!KV~}^?#9iUXj@E2O zy^6iGtCw4w;tl-9-Thzx+2?Rc^6}~JtIB!NsCvjF&q3t0i5cKjB~-3`Ytg5I$H5}2 zo1mGg6ZZy{Dr<*|tC`t0P9ojmiWHU7t{4gWc^odCbgowB-heUIT{2_*v+K0YCu&}P zs$o8|tYF^Zp~ItBcH0y|M2uoIb>A*ap$h6r#SEa$M!7OShonBgz0Hi-{#(L^YJ?`d zsNPZs?)2XVE2@e>EBfPko00fm@4r4&XO|1OISrtdRLG7?h_>VNmyJ8iV(X1!Y+ZV; zg8Z0oN8REu%Z4M06KnAR{?`Xnm!VAgrW(T3N}ZyV;L+g|Q<6ws6LVuVYOzQ1t0WiN zu|#oo!Zvg3emY@4rf2nt{8HNn1p5ejOe88PH4~}0AJfPKoiCyn9vy2vqtjHN{!3j* z0P4bSxJ2)2xPX~ZwDJl5fu^T_9K5J~;+7FUd#|ZpV|Wl;Xm3vpa@lS#sV5m%P=S#HqLeK3BdNYC4E}x=99Ji)L$uCW_p^oE}vkl(R-r zMeV|jt?!XI0;@GX9%FKKU!^1aqbFBqZOjR-<~chwGb@L1`%HCS`RB&EMpg>h4P8s^ zx%4bFS&k1>t}Ei6!~t!c`vQTvTk7u@UI8G|GQhnKQ!_H!-L6mA9Adq0Srq{)LB#)J z22wbU;j>oV?esdz!&F0HV?r7`A~bv;Kl12h{OlEHji17behdi9`dvv^`LhGk5K#_x z%F%lf%AQ9JfzdnT!s3X7VP_52u7^LoQEh$TvZ_wxPzyt6hA}=%7dpUy%isZz$t0}P zCTl)8V6AFU`Rgc<^UZvuU!fb6#zD!8tk!@aydi}x?;LB-lRck=7Rwf^&qm{K3v50< zG$b%I7=yK3O_y^j)C-#iK#laQ5hVnC$YxzQ^ADO;DHrNR>R zqr;u3znah%B0d96VUKG}k?efDf9B%WbQx!Le$XEkQ>y%vKaGDB9(feO#e~(2AJlwa z)PzXgEIf2(a`SBN<;6=zj4qO6LHQHH@wAVh@2av#A@TOFw|gcYU8zsI?_P-|Uw0>t z=b&A5a*Uus^nlk>G{Ke+$}zNBZW~gzQkiEGh=A`5dY#V-3+sc?U^$4XBAY}Vw$F{0) zfYGw}SCY76U-@C}!Pj4Y00b1bW^9lH%V90i^^Fi;eNgjcslFWvR8zi_g3`b%oswS# z^lfZXaM)!{J*qb_`LfYJqD*_EJ1SiiakOo=e3ra~0m{>SB2f#}OZzcSV>1C%aU0Lq z6C3=nzeg|tw$;sJ!=2@Wt1NGn!HYiaZ)I#uq5iZ?F&Y^|;I+g+GPOA0-YR>-@zYjHodY#! z%=M!ECcwk<(r{>e7F6F}ErV+=Um0D@1=MRH4-gLxRpUYEe%-Ki)$%!6KXeQ+tpokD zcHdBT-6~=&_Nh%`dd5L3_ON?X=l5z0k-xleRJ2kl|1IHa-7(Oi;$3GgzE6!f`}DLG zknWB@{d+ha5Gk6I7?*upLoq3#K~E%*e>d;l^!sgg0Xu%X@Bg8FNy1ldXQ*syno__@J5=F-<*h_@g%6G?S_U!riv-u8y0`%w? zXz=>d{S&bg6tN6zt& z>gseVD*-9(*RaU1Kt{agZ-^IQGO4q=6<+}3kH;#qzs7)-9;l`wzdAPRc6oFHL{Wb) zL2hcM*z=TSa2Nh6p(g{Uw zoTegHg4!6#wm*XltN#eixR&GZT1i+pcT^;=1Qzh7%pYy#xFCM*w2jpq-JIvejjbW| zaDNk{aK%1sSy~XJcui?Ba{mX5gOpD&e-B$~`w+lKMLH<{P{<{$$JJ}tx#VCYKxFHQ z<$&-B*Rz7?gNnLS4@AAE%kX`UUq3=Y(BzS#tAbEoQi*5&m(NGP9v7XI}q;k+t&q85|X9Ts|m%&9X0< z;V*Xd-sxx0pJqz>TOD;5T>KQq(^{`;!ij$be??!$MZ9GbDAQX!1PnEOrF?pG=1hA# z{4Dv!;t)_lmG_4aCN3~LbzB9NR~~~kuMG+)pJT)ZkW0T@H$7Oj{vf}fLp{T2PTSof z%3(aB068*o%liIQ^@v%w_5f;&pCPB;3bTzcoE-)VC@OK404^gMimvzR=*Kl#aC`tY zdyT)fDQ~W=w)_N|BZi`7Bg23b(vqG$RIEOC2&?NBMVGTl4z^tAs{hlY4(xlsv@@p2 zQ^~@!D$uSBge#QU(~`*A;#+x3nXBn9fK5hN0(hTaaWyBLMm&I~vpRHyQxnO|Z#)OF z%|UV9g+K%@e&G*1S{PTiAGeH~q6 z%C=S3p;LV&XP;l$CaGWhv@cBA>frU;WL2`nqWL}HOdhtWk~0AJWVS$TZa0Ykw9s&6 z48*Zt#1EohS>Plgtm!OBhusoI4CQ3o=ye12DBBwS0B%5F&o5svH5Nn#yonR=vD_h% zQzCrHp6B1U6zkExqoSfQ^XC5QYo*Pkx89EjGjW1#pm*(k8>(Z8ej1zGwm`7c8_-XS zbHH2@Xe#vtD0-Z=tT?2!LxUfkCf(*)S~pl?jd^)*(}+9Q73g}h-TTW+^aibE^zGL* z$fv2RO`Cc7X>FP{KcJPry4#-i0=-us|AhoNa1u3Y28|ux;ThFDBQGTvc3B*e%FeDj z_98U;*&$&k5=^q6x95xaU0x^K0$&(76C@%2f`}@>@XIGfouFim+iz4yKIyn=gQz&m zRn~1?w_-6S`uNOB@gK{_vx0T3O}#ppJGu2+IO{rc-bHI*(ksiC+qYK4Y08*xA#Q=5HiVl{eN!KIP6#9F4wGWShI9No3fHvhH72{tsbajsEvYlxVZ3m= zH)tdVa@>BB@V!WRE^fQZRM8pvBTBaR=jgBw?uLriB&7LJkc zy^gzo?PTYhNL2pW_H#a$nrhtSmjKcXr_i6xf`5ziT?R1t%fWs^ZTLc{5GVKB%jvuv zmsMTvH1P^wOtgM>$Zm1(&A!{BwqKTCnq7+}!wpJ~EkmpBzcafQpHO9x?Qbg14OE0~sAA+4&1(&$RpOg6swe0t7qXi?bkm+S?w_L1&7#l74vK-40or zYs@mn9M+FX;5jv%m*g%zk(z5y9GNf|`oWoZW?)3TMEiy^=PJ1Xv^#1JT(@ppp^n}< zM7n8cC6;khySnFzA($Y01k_h@ljFdB$D_GD8TBB}htFgtUM*%07Ln!IMDHV`j(&U~ zL=WXX3Bcw&J6`8{wLSo1n48_!Pk%TYE7=;YPL;RDs6+^OcoBM(HVPvv6jd2Wu?i$pjUIMX{dfUH-Hn^Iw< zsi)SPY=^#?SJ(7K)DmR+C(^cu(N}HTM;DI|pJ2RL1oUitzA3Xv3T{mG zT|b2S^Xnn%t9}3!`N>zxO5eIDzY&_T#7DVSc<5W-QcGSVkYI6`WhNJE)0^cO1*rx z4_kcX>g3Z5k?&X8Bt8MnTW6fC!;a{V(xgbQXtnE_H-`wN04ei4A_<&@Sy07AJ};$*M-^3J716jb#K}cp%2y zU2P0z^;i(+16fy93IF;9$gyV9bxG=CvAlkfh~+oMP0EV?a!H8r;?31UdY?Ld ze0YXL3W4$-+(qOEuFJf@EYN>cns%~-EhbAoNmT;2%<hW`+8cTuwVruG#vb3#$vn6F~ zWz4GYg-2p#`$*?NqRY7JT})8Ed=Yh?-YOFFwISflHmjWKm+{_WJ9RZrn{f8z{EcdT z(RKa;8^IXNRd~?OKKrq6S@I9zR|is5it@4vpohN3tpZc13wAfAoXkcIZ^aE?6|v~) zdzw1Ko^b&ej~;8z{dQCDbXJF+%MHZEj{nCX_K6mjGUuKSWG6gz4u=eIHJ9U`9igrm6cCU!rRuP6- z-1}ml9TGg_ZGGIM`KHoa1$&9Y4I(lhJ6V?b?COTI96jC5g4#-Mo##~R1s^k}(qC$F z`0^ea@}hae@ZO2Th0e%5Y#u{GiUoY@D#r@lwe)*i(X@OyhM~K{>r3L^Zl7nU>k^t#U()6l!ldvdxERQZKi?31k$y&oe#C(qOY#nkX;Z_R>7{AmS~boF6~3N5b^CMfgpF5-jP-p*}3Oa9?9L;g3FkN@G<~7G0k$(Y!8dPWS;k zsvC+_cxj@_n-m52(_PAT)3w|r8qg=kfLHTxYm5F0G?H9;yeihoW^hhN#bw?HASjf4 zR%C%Hf?+;a%`}(f$)Lx1DuiWMvqD!8fwJw+ftH9PDyt3_*s3b3EgQ7mzR(U07KaxU z(YFp0oK2};$w`PJOIDXdAK;XREv_M1Cbhy1$2iAVCy|KraL>*_i|ygLtR2~$Qy>xd zQ`(zri*lhH2FAdnq$pB|b>= z=;zPhDvL%oh+_8&obTscdMZDuybr@n`LwjW50lg95S+8*&NWjxJ5~qHQlj zp`vN9^f7`6MvuRDkIib)Ll9!UIrQDOL0v6+QLa#;b?*#irk&3gcDkJ~rbmFrdYLF~ zZUAslK*SNPaxFhn#`=S%c_!8$}BSa}rHZ=`vI_9$X* zaZe{B`7%rG!2wrMS-aV?MU}aFeUU}^wbh<^;zZH7eX{DDA(HtgmS?Zn9`!qHzAX#e z;CrZ5f#}v5Vaq{t<-%wL#VGNefT)0!NjP^J*IE!HoN>MlSw#GDv-KucXK>frv}7?cod7zoH+dcWGSmvedmY=bl5G!M>L)zh`9jvDVOL%cV=4Aj6o}_~D)(H>T^Yr1trReq{ z>(rj>N$SpbZe%^JAa=ZCP>vF+vyw$0qn7tq5vR zKi(oDYe)LZuAn*ppFGgqJ60ei3sa;a!1W9h)MOHpxn z{VhfSE?B`gc7`4HijMM{<0*;>(j7R*F#z}w7SXawPC1GiRoO?H`Vt%#rEHA5`N$J; zfU+mOCJqm{gBF#9LIGJVk|qR2s8M&gnM=M8WuBfnsdL=1^XB!`gZIG?mkYS+FK;N?o*T5FWZ7Wgm!-pWR7r11wa7TplY876M^V%~|fX;_4gV`9VgY`xXjG zM~x5A)`&4H9B9QLr25d~S>nJ7F;%y2kV@K4oFIOICv~dq+2ed{SU5s64AvNa?A-J) z_YmcJD362BmfQ(jAN;w3%i?#BPfLQva%ZM-Kjr3~5ivq!7YR6hBQiY*0yR7(Y;oY8 z+D9v!{Sz^%VLFi z#al+xSBS&I9??dspAptxN3jR4gpZkh57G~TP>=gT=b0L6JA$PJ zJS+{#4r;+em275m2}AlYAGmgw$&KF;MCFkH_$CC{ZAgLTmNw6`rvZS;5w6q(X0zFS z?f!(8y^!9bb+mdOTI>QyeQp=A>$oZQ)=&qh4XD90Re(@9+LqPCX`cj0k1TJ`^}x%DHx=--QsK6?xdPn4tZ$n? zOyiFlw@<p9I&FP;DF(?NC}u&T%6y@H^w-($LqC2oA- zlR^JgV8aRl>sjO@ez?3XM-(s^TF=Tkf7*Uu<=-Nj zUvwG5bSLJa^#|M)OQz%x0q}Ou5ATWy597iwVwLbebn{sdK zAV~)i8IGd(vNm0r1ogGmz@Jho%|TFQ`Pg!{m;3|L5jNWkHQIfOS3KgB}{I!5e zxia^NvJUHOad{gv*fL+`m!-?*Hc{!&>_i*>oLvf=(Y4f<&;is`3u`}OC);l8yw#-O zUwN&Y=sLL|!@b|1=mcr5YRWKF(r2h1(oLSRT)I}cSV}TTvtWAz@Ck;ADBZ4ww%l+U z;B|g~p16fd<7d|4@>um(@69VP-z?_tU}PoL5^5k;IDTf7+Qw?nO9cKsJk(o{Nf+7U z0RUnuo1V4mwf=rySIqmW;sImDcWhnJfJdVDgC~g6smpAw2NXfJ1fHU#3aRPz-P2+- zDHs60|K>mjge4*(p;Dg++VBi?+1O4W8l>P4_+Ho0(ZH|IEhfa=M|w7?gaW2)7lkc_ z?RxI{4~W}~hz&bWD+gqw_skqZ)9uu7lBk$B%gvQ3EC8@M;LK5-sov{E>Yk^XXG)ql zAEXJGue0I40}fG87dN)cqZQO};rK5Hx?$~Qum|@Z58Bb;36s`XNBfaY+&+=J0KZSv z2Pt)ph>eTCT<@n-yPmkiE`I)hIPB58AyEqV|G>Zg_um452LBJ-eCHtM2J#nH##8T~ z(aCZ2Kk>ri^-IQlRJ-@}PAfykG4y$X1K43I9NHXoX6Ll-=YLWa^7GKXC>6yJL5qdaS*_hAG|q*r2U zRO96$TjZ@i5hY4yk)Fb2hnZQmq1m~%6Eztzcw~UJX zG^6#2r@@~bSy5g`gd66U2_jC(JorzFj=gg(p{I<)2P%nfo6Gx=rBZ~I`Y2r_#R*I< z)_o#j^u3>5vP%EG&85MXvLzO4jP#xVLVHZhG)>@1Yu_LYmFIAYN-W7OjV<$On1ND5 zOdw=`GUX^lRt^T~W^>Lal*7n#1dEse=@A-kc^T$dYzQx`w6UT2XTwLto7Zx+l>R;B zY+2qWR3KQvqX>rKnr|jMNB`buJANtOWk0{-G18eA|NNA*uGz~~@_tjI+}1ZdY){6s zLdoe|AK_8jqRq1_jSWR?=M}Abi|N<2Dz(a&xw?|*Srzyp6amTsLKla7`5?A&w+v#^ zPB-a{=4>vv46aPUW{ASwsU!_@h;;F?C}h)Zl!UFKSK`{=W$1TOrnZ^G7A@904(-zG zYY*@Nul;4e)mW(cBoT0Hp75H*F$`*U(KFFgJ)k#g`s}E`K8@4oagCv!PUuEKHuD^JGd&!PuT zsGe;Ld3xjzpPq@vP#um_y}rVq=8L5vEduYjA`bCAzF<;(&s$gdOOg{gyy9fJ;k{j6^z_f%2Ipgp?l+F zDAl(E-E?8@2`j(1Dsznnl%z!Omo*&s`#Q&l3r2J>% z^UEvMVlUpj`IBqO;*Rx@7M`-!Z~e7e|LC2>o?Bruj4Ny!j8gx#&vyq_N@QP&C$<)c z24I2(x-MxS;hOSQwA+3o!3F;abyd?aCn^uT98&nGPkum`C^ojqhw5)mWs}ZLR%wrD z(`|~P{cA0-BwUDkb`iuzlzsU!jDmZtfy>@BPj2oVxQ`@4kUZvq?YrGrQIrbV2ucSK z0e~(f%zs*-63J|}q0xo92| z_R@LRo4+@FVC1>MFeInzW!cYir&xbsdC`usp?*pGw6=*4u}Il1lT&?J*(|+>D)cAU6cN zXXUr?71vLPXp@U!F8kF+ZcEGW?dQK%V>1vN#QR}T3z_rWS*c|zNM)tgaOOCJ?|IXD za6la~o}?_59GsQqcH8*Y#w9t4HVXZlC+z<6kC0Ti{vL-F^TxkKQ5&p zxLR_XL6GB>p~{Ltb$$QkrZ=BB@4Z(YR*l)IT2cR$Vo|gr`k2+>OrUz(g8Ln6pma_MG9$^|0SaEe$WZ#RHjp}n8!Qo{oZxC2Vsppi1-=r)cvx7&>EhM8~IeGpsq zqR=@|kL!E7pzq4?x*3(ydKB24d4O|V`TXuhgV@WCTn+br46-|e#4fqK830);q3WJL zR7m`EJqZq>LIg|{V4a_n4q=~Nc9|v-ad~ORq9mHf8|wX*YG%dqd>apSgYpJPV*36< z2YC9dVdaGe1A|C%6TMi#=lXO;lbiG85};l$E%vc%0F+fnpHteIf)5^HSS9m&z6zVi zE7o4P{?d{Rat*9hytxo>76Dq4)Hcp$yL?gSiY?U84_{QntPp=gu%~BEb=z3pW(-Q# zzm6U#=9;h?&XE8=6b%*4XXl^D0A!=#%v@ohv+ zsYv&7_vBG~TD`O94-w(`Jm-?p0HGMmU9T=2q&j>BfET%W_uz>z!_@5ty?wp@eXV93c-%^|H2g3*stg~l^o2V&6f9f=)e@XsCbbQu^etPvYll|K6> z=`hH}fYa*U?!CcT3gM5>3-#?CytWyIyjQ;0==ksfZ7l0i2t)#@9iQ~$6To#U(XSI& znY(Nl0wKhos+0lvKEK=3wJYTlfYWyLJY87Y=6q@KN;C`@zBy_y1t9x@Iw%}Z?wUUz~?(_ai3p;?AZ${ ztCQ7Cn8S+~yVC7yCwq?le1wJx;1S+#KMXE&p}~SB!s&zW2#x*T4WYXl?PaJaXR+<+ z&=2cIV{gCf4EN-5fAiYD_^vOgCfSnbgF)$BOe>{-@2Jsyd|Z{1{=p%dzHmNnt{5il zl7z;(K(vWTo4(8HTi0@#$%X&OO!uE`E-X83z-d2PJa_RFrgL5Y<;-PiQKS8pyf>rT zO(I={xK%IbN*A}gjp}ne zUY&8on?3L~-6X!K5-n7)iJTJ0tv%*1|J_$LDd1YR9M|T6D;vc(g&9al543*9|DCor zUy2e)9@L_ChH@|Y7)Ziv)EjEwZVv2mlV{&nKRjyH;>*QHTKBl|wF%`Mn58=_BshL5 zYn5i_I_y$Z4!B}fNgLI!zEUoXe@x|`?>m2#s3{_~F{?x(sG|LP$YB>+`k(lt&Ecvo zI-?#X$W5L{>`r}P)z__zhnle*0RJW}dSX%${up`C!YoI?U|D(;uuMT7nRan+=#f)xILzY0r<$BsXjhOCY2axd z)7ag)9R;^~7M<7~1Or-}F-voMZ(9rie3Nsau{m1UuJ zg^2WKFPq~B(#37HvE=@#p!(ez95#vBc}5t1Lb#C{mq^9aK0iJ;X839 zU&A>90y(prm$xY%Zd9ZDCQ2th%><0}G$$ZQpEi48a(nNdAnGhq-PjrLNfAT*rnQ!=A7sNZabr3a|TI8Aj_ z&a|xGGY(%!ZdOjq7W%7QAYtu&Kkk}7)PdlMW)SY6nG_cUzO>2zaHi15a-u3Q?r>4v;J4 z{W<|;kGX_r*MVcFC3s**c`JzI9Eq7>F}tO9blozmtS-fQ3{@)wOH*^GTpo@l9a6EZ z9E=IW7t7eO@@N!SgDLf)JQsO*e%A#X2YQ{ujpntKa$KtYGgMV~8(Na9-1VI|SLA}k zAi#?95zhF4uX>y^y2%Fj+jsMK$KDQKqL*mZ-oN*zpux?(UDZWA7CU{&ONRvPL-{zh zoisA9eJga1CRWrzjYGN0Az|nI}*w z{Wi*W_)=jUH;|ZI!6klz9+l#TU-fhCBzxL^hGj `3Sf?!kF#rmibw(>`M#eT;5W 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μp+|?7mXQMskQlis>T@CtE0qp zraCpjH?i$B$*iH4!B1Lq!k|;d+*6~U`PP){DB|QaNnSG*6K;1~>x;^EQ^7tER&kjl zjzi=&sea@3$Zc#=p+ykuHf-#4RD>=+q-$1Y%04Mx6nbF23vr z`wq(c`eIiu6NW_hgXNvvg|o#?m{|-DeM)>0?u$Ja=$>A;;%7!Aw4@y?=$JvdJ zjFsY@9lZt034a=H``A)hx$mvxn~EkceP(b^kItE!i%@>F&ue4P5PX!j@*^W7bxz)= zL7~sL35J;`s9Q96^Sf2V7Zwb&oB~-gsXa?k=R1%rP9$38h1U>SboTs_PxXvz)2jmA zdXcJhNt`s^!?`|<@HynF5Jpba+^uUWDeP2@wVf(5iuOdW9@g6{&e!R>O4v3gDKltND$C}k^G=Sb5!!{*LB)eD9#PQ z^aLEz27MQ4VQml__T^yeKUP{G#UKp?GdtxO_~nD4u*aVBHrLnl*ZrHM2lX<~8E|r{ zN&Oa)Lt7x0TAJoBVbK^@(Qb%23Fxu%B8LO*gi%$!@NupsDSW2(;4eY{<|plNEtxFZwv@Y zJ^=*gy_8TF`0dV6kV;a3_~Acp&A zh5hft1HfMYgi7WXdUXNi;>PvDLFuda+VnrQaQ{x&^gl#iFD7Gd+ÐRHUhFQ;v>a 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 Mikb=-IrG5(1=4{Qo&W#< literal 0 HcmV?d00001 diff --git a/img/sf/publish-window.PNG b/img/sf/publish-window.PNG new file mode 100644 index 0000000000000000000000000000000000000000..4c27b8e2911782ff733384955bd8fe6d62056b99 GIT binary patch literal 16348 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 L1I>c#*3bSQ_V;YW literal 0 HcmV?d00001