diff --git a/.dockerignore b/.dockerignore
index be95b4e4c..f4850f3c7 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -28,5 +28,7 @@ cli-linux
**/node_modules/
**/bower_components/
**/wwwroot/lib/
+!**/wwwroot/lib/signalr/*
+!**/wwwroot/lib/toastr/*
global.json
src/Web/WebSPA/wwwroot/
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index a8d5986bc..1a11f9674 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,6 +27,8 @@ bld/
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
**/wwwroot/lib/
+!/wwwroot/lib/signalr
+!/wwwroot/lib/toastr
# MSTest test Results
[Tt]est[Rr]esult*/
diff --git a/README.md b/README.md
index 3b3aa9077..4637f13ce 100644
--- a/README.md
+++ b/README.md
@@ -2,10 +2,7 @@
Sample .NET Core reference application, powered by Microsoft, based on a simplified microservices architecture and Docker containers.
## IMPORTANT NOTES!
-**Since April 5 2018, Visual Studio 2017 15.7 Preview 2.0 or later is needed to run the solution from the *[DEV branch](https://github.com/dotnet-architecture/eShopOnContainers/tree/dev)* (current evolving code) which now includes API Gateways features**. Due to the configuration used in `docker-compose.yml` file, VS 15.7 (currently in Preview 2) is needed to run the solution at [DEV branch](https://github.com/dotnet-architecture/eShopOnContainers/tree/dev) or you can also run eShopOnContainers with Docker CLI with **"docker-compose up"** or deploying to **Kubernetes/AKS**.
-Trying to run the solution from [DEV branch](https://github.com/dotnet-architecture/eShopOnContainers/tree/dev) in VS 15.6 (current RTM of Visual Studio 2017) will generate errors (complaining about invalid values in docker-compose file).
-
-If you want/need to run eShopOnContainers in **Visual Studio 2017 15.6 RTM** or previous, you'll need to use the code at the **[MASTER branch](https://github.com/dotnet-architecture/eShopOnContainers/tree/master)** which is the previous stable version of eShopOnContainers.
+**The current supported Visual Studio version for eShopOnContainers is Visual Studio 2017 15.7** ([GA/RTM since May 8th 2018](https://docs.microsoft.com/en-us/visualstudio/releasenotes/vs2017-relnotes)) or later version.
**Note for Pull Requests (PRs)**: 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 branch, if possible.
@@ -28,8 +25,9 @@ For a list on the new .NET Core 2.0 related implemented features, see this [blog
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 after running the solution in the local dev PC and understanding Docker containers and microservices development with .NET Core, is to select a microservice cluster/orchestrator like Kubernetes in Azure (AKS) or Azure Service Fabric, both environments tested and supported by this solution.
> Additional steps would be to move your databases to HA cloud services (like Azure SQL Database), or switch your EventBus to use Azure Service Bus (instead of bare-bone RabbitMQ) or any other production ready Service Bus in the market.
->
->
+
+![image](https://user-images.githubusercontent.com/1712635/40397331-059a7ec6-5de7-11e8-8542-a597eca16fef.png)
+
> 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.
### Architecture overview
diff --git a/build/acr-build/queue-all.ps1 b/build/acr-build/queue-all.ps1
new file mode 100644
index 000000000..aacffea95
--- /dev/null
+++ b/build/acr-build/queue-all.ps1
@@ -0,0 +1,37 @@
+Param(
+ [parameter(Mandatory=$false)][string]$acrName,
+ [parameter(Mandatory=$false)][string]$gitUser,
+ [parameter(Mandatory=$false)][string]$repoName="eShopOnContainers",
+ [parameter(Mandatory=$false)][string]$gitBranch="dev",
+ [parameter(Mandatory=$true)][string]$patToken
+)
+
+$gitContext = "https://github.com/$gitUser/$repoName"
+
+$services = @(
+ @{ Name="eshopbasket"; Image="eshop/basket.api"; File="src/Services/Basket/Basket.API/Dockerfile" },
+ @{ Name="eshopcatalog"; Image="eshop/catalog.api"; File="src/Services/Catalog/Catalog.API/Dockerfile" },
+ @{ Name="eshopidentity"; Image="eshop/identity.api"; File="src/Services/Identity/Identity.API/Dockerfile" },
+ @{ Name="eshopordering"; Image="eshop/ordering.api"; File="src/Services/Ordering/Ordering.API/Dockerfile" },
+ @{ Name="eshoporderingbg"; Image="eshop/ordering.backgroundtasks"; File="src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile" },
+ @{ Name="eshopmarketing"; Image="eshop/marketing.api"; File="src/Services/Marketing/Marketing.API/Dockerfile" },
+ @{ Name="eshopwebspa"; Image="eshop/webspa"; File="src/Web/WebSPA/Dockerfile" },
+ @{ Name="eshopwebmvc"; Image="eshop/webmvc"; File="src/Web/WebMVC/Dockerfile" },
+ @{ Name="eshopwebstatus"; Image="eshop/webstatus"; File="src/Web/WebStatus/Dockerfile" },
+ @{ Name="eshoppayment"; Image="eshop/payment.api"; File="src/Services/Payment/Payment.API/Dockerfile" },
+ @{ Name="eshoplocations"; Image="eshop/locations.api"; File="src/Services/Location/Locations.API/Dockerfile" },
+ @{ Name="eshopocelotapigw"; Image="eshop/ocelotapigw"; File="src/ApiGateways/ApiGw-Base/Dockerfile" },
+ @{ Name="eshopmobileshoppingagg"; Image="eshop/mobileshoppingagg"; File="src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile" },
+ @{ Name="eshopwebshoppingagg"; Image="eshop/webshoppingagg"; File="src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile" },
+ @{ Name="eshoporderingsignalrhub"; Image="eshop/ordering.signalrhub"; File="src/Services/Ordering/Ordering.SignalrHub/Dockerfile" }
+)
+
+$services |% {
+ $bname = $_.Name
+ $bimg = $_.Image
+ $bfile = $_.File
+ Write-Host "Setting ACR build $bname ($bimg)"
+ az acr build-task create --registry $acrName --name $bname --image ${bimg}:$gitBranch --context $gitContext --branch $gitBranch --git-access-token $patToken --file $bfile
+}
+
+# Basket.API
diff --git a/docker-compose-windows.yml b/docker-compose-windows.yml
index cec7323d1..cdcd6f56b 100644
--- a/docker-compose-windows.yml
+++ b/docker-compose-windows.yml
@@ -46,6 +46,16 @@ services:
- sql.data
- rabbitmq
+ ordering.signalrhub:
+ image: eshop/ordering.signalrhub:${TAG:-latest}
+ build:
+ context: .
+ dockerfile: src/Services/Ordering/Ordering.SignalrHub/Dockerfile
+ depends_on:
+ - sql.data
+ - identity.api
+ - rabbitmq
+
marketing.api:
image: eshop/marketing.api-win:${TAG:-latest}
build:
diff --git a/docker-compose.ci.build.yml b/docker-compose.ci.build.yml
deleted file mode 100644
index 747e8e583..000000000
--- a/docker-compose.ci.build.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-version: '3.4'
-
-services:
- ci-build:
- image: microsoft/aspnetcore-build:2.0.2 #Depending on the bug below, you can also try this other SDK image: microsoft/aspnetcore-build:1.0-2.0-2017-10 or microsoft/aspnetcore-build:1.0-2.0
- volumes:
- - .:/src
- - ./cli-linux:/cli-linux
- working_dir: /src
-
-
-# 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 publish ./eShopOnContainers-ServicesAndWebApps.sln -c Release -o ./obj/Docker/publish"
-
-# 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"
-
\ No newline at end of file
diff --git a/docker-compose.dcproj b/docker-compose.dcproj
index 5f12f7d62..b9522f28f 100644
--- a/docker-compose.dcproj
+++ b/docker-compose.dcproj
@@ -10,7 +10,6 @@
-
docker-compose.yml
diff --git a/docker-compose.override.windows.yml b/docker-compose.override.windows.yml
index 76ccda8b0..0d31493e6 100644
--- a/docker-compose.override.windows.yml
+++ b/docker-compose.override.windows.yml
@@ -54,5 +54,10 @@ services:
locations.api:
environment:
+ - EventBusUserName=admin
+ - EventBusPassword=password
+
+ ordering.signalrhub:
+ environment:
- EventBusUserName=admin
- EventBusPassword=password
\ No newline at end of file
diff --git a/docker-compose.override.yml b/docker-compose.override.yml
index 093612225..d523b328a 100644
--- a/docker-compose.override.yml
+++ b/docker-compose.override.yml
@@ -88,6 +88,25 @@ services:
- "5102:80" # Important: In a production environment your should remove the external port (5102) kept here for microservice debugging purposes.
# The API Gateway redirects and access through the internal port (80).
+
+ ordering.backgroundtasks:
+ environment:
+ - ASPNETCORE_ENVIRONMENT=Development
+ - ASPNETCORE_URLS=http://0.0.0.0:80
+ - ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word}
+ - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
+ - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME}
+ - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD}
+ - UseCustomizationData=True
+ - AzureServiceBusEnabled=False
+ - CheckUpdateTime=30000
+ - GracePeriodTime=1
+ - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY}
+ - OrchestratorType=${ORCHESTRATOR_TYPE}
+ - UseLoadTest=${USE_LOADTEST:-False}
+ ports:
+ - "5111:80"
+
marketing.api:
environment:
- ASPNETCORE_ENVIRONMENT=Development
@@ -119,7 +138,7 @@ services:
- ASPNETCORE_URLS=http://0.0.0.0:80
- 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.
- PurchaseUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5202
- - MarketingUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5203
+ - MarketingUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5203
- CatalogUrlHC=http://catalog.api/hc
- OrderingUrlHC=http://ordering.api/hc
- IdentityUrlHC=http://identity.api/hc #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser.
@@ -129,6 +148,7 @@ services:
- UseCustomizationData=True
- ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY}
- OrchestratorType=${ORCHESTRATOR_TYPE}
+ - SignalrHubUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5202
ports:
- "5104:80"
@@ -145,6 +165,7 @@ services:
- BasketUrlHC=http://basket.api/hc
- MarketingUrlHC=http://marketing.api/hc
- PaymentUrlHC=http://payment.api/hc
+ - SignalrHubUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5202
- UseCustomizationData=True
- ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY}
- OrchestratorType=${ORCHESTRATOR_TYPE}
@@ -158,6 +179,7 @@ services:
- ASPNETCORE_URLS=http://0.0.0.0:80
- CatalogUrl=http://catalog.api/hc
- OrderingUrl=http://ordering.api/hc
+ - OrderingBackgroundTasksUrl=http://ordering.backgroundtasks/hc
- BasketUrl=http://basket.api/hc
- IdentityUrl=http://identity.api/hc
- LocationsUrl=http://locations.api/hc
@@ -202,6 +224,7 @@ services:
ports:
- "5109:80" # Important: In a production environment your should remove the external port (5109) kept here for microservice debugging purposes.
# The API Gateway redirects and access through the internal port (80).
+
sql.data:
environment:
@@ -279,4 +302,18 @@ services:
- urls__identity=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110.
ports:
- "5121:80" # Important: In a production environment your should remove the external port (5121) kept here for microservice debugging purposes.
- # The API Gateway redirects and access through the internal port (80).
\ No newline at end of file
+ # The API Gateway redirects and access through the internal port (80).
+ ordering.signalrhub:
+ environment:
+ - ASPNETCORE_ENVIRONMENT=Development
+ - ASPNETCORE_URLS=http://0.0.0.0:80
+ - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
+ - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME}
+ - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD}
+ - AzureServiceBusEnabled=False
+ - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY}
+ - OrchestratorType=${ORCHESTRATOR_TYPE}
+ - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110.
+ ports:
+ - "5112:80"
+
diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml
index 2b6893ba0..06dcbde6f 100644
--- a/docker-compose.prod.yml
+++ b/docker-compose.prod.yml
@@ -92,6 +92,25 @@ services:
ports:
- "80" # The API Gateway redirects and access through the internal port (80).
+
+ ordering.backgroundtasks:
+ environment:
+ - ASPNETCORE_ENVIRONMENT=Development
+ - ASPNETCORE_URLS=http://0.0.0.0:80
+ - ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word}
+ - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
+ - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME}
+ - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD}
+ - UseCustomizationData=True
+ - AzureServiceBusEnabled=False
+ - CheckUpdateTime=30000
+ - GracePeriodTime=1
+ - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY}
+ - OrchestratorType=${ORCHESTRATOR_TYPE}
+ - UseLoadTest=${USE_LOADTEST:-False}
+ ports:
+ - "5111:80"
+
marketing.api:
environment:
- ASPNETCORE_ENVIRONMENT=Development
@@ -161,6 +180,7 @@ services:
- ASPNETCORE_URLS=http://0.0.0.0:80
- CatalogUrl=http://catalog.api/hc
- OrderingUrl=http://ordering.api/hc
+ - OrderingBackgroundTasksUrl=http://ordering.backgroundtasks/hc
- BasketUrl=http://basket.api/hc
- IdentityUrl=http://identity.api/hc
- LocationsUrl=http://locations.api/hc
diff --git a/docker-compose.yml b/docker-compose.yml
index 122123644..414d9a1ef 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -38,6 +38,15 @@ services:
- sql.data
- rabbitmq
+ ordering.backgroundtasks:
+ image: eshop/ordering.backgroundtasks:${TAG:-latest}
+ build:
+ context: .
+ dockerfile: src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile
+ depends_on:
+ - sql.data
+ - rabbitmq
+
marketing.api:
image: eshop/marketing.api:${TAG:-latest}
build:
@@ -144,3 +153,9 @@ services:
context: .
dockerfile: src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile
+ ordering.signalrhub:
+ image: eshop/ordering.signalrhub:${TAG:-latest}
+ build:
+ context: .
+ dockerfile: src/Services/Ordering/Ordering.SignalrHub/Dockerfile
+
diff --git a/eShopOnContainers-ServicesAndWebApps.sln b/eShopOnContainers-ServicesAndWebApps.sln
index 93bfbf7b6..f127af6d9 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.27130.2024
+VisualStudioVersion = 15.0.27130.2027
MinimumVisualStudioVersion = 10.0.40219.1
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FEA0C318-FFED-4D39-8781-265718CA43DD}"
EndProject
@@ -98,7 +98,39 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebHost", "WebHost", "{1815
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebHost.Customization", "src\BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj", "{15F4B3AA-89B6-4A0D-9051-414305974781}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.BackgroundTasks", "src\Services\Ordering\Ordering.BackgroundTasks\Ordering.BackgroundTasks.csproj", "{2FF56999-0266-48B2-ACC1-FEBC482A5105}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ApiGateways", "ApiGateways", "{77849D35-37D4-4802-81DC-9477B2775A40}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ApiGw-Base", "ApiGw-Base", "{EC91ADE9-3D66-4AB2-9FB4-2B585E1F3531}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mobile.Bff.Marketing", "Mobile.Bff.Marketing", "{DB813A36-11BA-41FE-B258-CA9A7152247B}"
+ ProjectSection(SolutionItems) = preProject
+ src\ApiGateways\Mobile.Bff.Marketing\apigw\configuration.json = src\ApiGateways\Mobile.Bff.Marketing\apigw\configuration.json
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mobile.Bff.Shopping", "Mobile.Bff.Shopping", "{0189E4FB-6E2B-4F2E-9B1D-5473D23FC6DB}"
+ ProjectSection(SolutionItems) = preProject
+ src\ApiGateways\Mobile.Bff.Shopping\apigw\configuration.json = src\ApiGateways\Mobile.Bff.Shopping\apigw\configuration.json
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web.Bff.Marketing", "Web.Bff.Marketing", "{F8F0921C-EE5D-4AED-A4D6-5BF5FAE02CB5}"
+ ProjectSection(SolutionItems) = preProject
+ src\ApiGateways\Web.Bff.Marketing\apigw\configuration.json = src\ApiGateways\Web.Bff.Marketing\apigw\configuration.json
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web.Bff.Shopping", "Web.Bff.Shopping", "{28C0F5C8-4849-4035-80AB-45639424E73F}"
+ ProjectSection(SolutionItems) = preProject
+ src\ApiGateways\Web.Bff.Shopping\apigw\configuration.json = src\ApiGateways\Web.Bff.Shopping\apigw\configuration.json
+ EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OcelotApiGw", "src\ApiGateways\ApiGw-Base\OcelotApiGw.csproj", "{3F79558C-485D-49E1-BD3E-E12538D3D308}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mobile.Shopping.HttpAggregator", "src\ApiGateways\Mobile.Bff.Shopping\aggregator\Mobile.Shopping.HttpAggregator.csproj", "{BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Web.Shopping.HttpAggregator", "src\ApiGateways\Web.Bff.Shopping\aggregator\Web.Shopping.HttpAggregator.csproj", "{AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.BackgroundTasks", "src\Services\Ordering\Ordering.BackgroundTasks\Ordering.BackgroundTasks.csproj", "{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ordering.SignalrHub", "src\Services\Ordering\Ordering.SignalrHub\Ordering.SignalrHub.csproj", "{E1D2B260-4E7F-4A88-BC13-9910F7C44623}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -1314,54 +1346,246 @@ Global
{15F4B3AA-89B6-4A0D-9051-414305974781}.Release|x64.Build.0 = Release|Any CPU
{15F4B3AA-89B6-4A0D-9051-414305974781}.Release|x86.ActiveCfg = Release|Any CPU
{15F4B3AA-89B6-4A0D-9051-414305974781}.Release|x86.Build.0 = Release|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|Any CPU.Build.0 = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|ARM.ActiveCfg = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|ARM.Build.0 = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|iPhone.Build.0 = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|x64.ActiveCfg = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|x64.Build.0 = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|x86.ActiveCfg = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|x86.Build.0 = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|ARM.Build.0 = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|iPhone.Build.0 = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|x64.ActiveCfg = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|x64.Build.0 = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|x86.ActiveCfg = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|x86.Build.0 = Debug|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|Any CPU.Build.0 = Release|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|ARM.ActiveCfg = Release|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|ARM.Build.0 = Release|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|iPhone.ActiveCfg = Release|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|iPhone.Build.0 = Release|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|x64.ActiveCfg = Release|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|x64.Build.0 = Release|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|x86.ActiveCfg = Release|Any CPU
- {2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|x86.Build.0 = Release|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|ARM.ActiveCfg = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|ARM.Build.0 = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|x64.ActiveCfg = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|x64.Build.0 = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|x86.ActiveCfg = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.AppStore|x86.Build.0 = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|ARM.Build.0 = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|x64.Build.0 = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Debug|x86.Build.0 = Debug|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|ARM.ActiveCfg = Release|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|ARM.Build.0 = Release|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|iPhone.Build.0 = Release|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|x64.ActiveCfg = Release|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|x64.Build.0 = Release|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|x86.ActiveCfg = Release|Any CPU
+ {3F79558C-485D-49E1-BD3E-E12538D3D308}.Release|x86.Build.0 = Release|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.AppStore|ARM.ActiveCfg = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.AppStore|ARM.Build.0 = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.AppStore|x64.ActiveCfg = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.AppStore|x64.Build.0 = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.AppStore|x86.ActiveCfg = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.AppStore|x86.Build.0 = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Debug|ARM.Build.0 = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Debug|x64.Build.0 = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Debug|x86.Build.0 = Debug|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Release|ARM.ActiveCfg = Release|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Release|ARM.Build.0 = Release|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Release|iPhone.Build.0 = Release|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Release|x64.ActiveCfg = Release|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Release|x64.Build.0 = Release|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Release|x86.ActiveCfg = Release|Any CPU
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0}.Release|x86.Build.0 = Release|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.AppStore|ARM.ActiveCfg = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.AppStore|ARM.Build.0 = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.AppStore|x64.ActiveCfg = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.AppStore|x64.Build.0 = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.AppStore|x86.ActiveCfg = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.AppStore|x86.Build.0 = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Debug|ARM.Build.0 = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Debug|x64.Build.0 = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Debug|x86.Build.0 = Debug|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|ARM.ActiveCfg = Release|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|ARM.Build.0 = Release|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|iPhone.Build.0 = Release|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|x64.ActiveCfg = Release|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|x64.Build.0 = Release|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|x86.ActiveCfg = Release|Any CPU
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|x86.Build.0 = Release|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|ARM.ActiveCfg = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|ARM.Build.0 = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|x64.ActiveCfg = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|x64.Build.0 = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|x86.ActiveCfg = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|x86.Build.0 = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|ARM.Build.0 = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|x64.Build.0 = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|x86.Build.0 = Debug|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|ARM.ActiveCfg = Release|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|ARM.Build.0 = Release|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|iPhone.Build.0 = Release|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|x64.ActiveCfg = Release|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|x64.Build.0 = Release|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|x86.ActiveCfg = Release|Any CPU
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|x86.Build.0 = Release|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.AppStore|ARM.ActiveCfg = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.AppStore|ARM.Build.0 = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.AppStore|x64.ActiveCfg = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.AppStore|x64.Build.0 = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.AppStore|x86.ActiveCfg = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.AppStore|x86.Build.0 = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Debug|ARM.Build.0 = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Debug|x64.Build.0 = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Debug|x86.Build.0 = Debug|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Release|ARM.ActiveCfg = Release|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Release|ARM.Build.0 = Release|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Release|iPhone.Build.0 = Release|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Release|x64.ActiveCfg = Release|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Release|x64.Build.0 = Release|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Release|x86.ActiveCfg = Release|Any CPU
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1408,7 +1632,17 @@ Global
{969E793C-C413-490E-9C9D-B2B46DA5AF32} = {EF0337F2-ED00-4643-89FD-EE10863F1870}
{1815B651-941C-466B-AE33-D1D7EEB8F77F} = {DB0EFB20-B024-4E5E-A75C-52143C131D25}
{15F4B3AA-89B6-4A0D-9051-414305974781} = {1815B651-941C-466B-AE33-D1D7EEB8F77F}
- {2FF56999-0266-48B2-ACC1-FEBC482A5105} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B}
+ {77849D35-37D4-4802-81DC-9477B2775A40} = {932D8224-11F6-4D07-B109-DA28AD288A63}
+ {EC91ADE9-3D66-4AB2-9FB4-2B585E1F3531} = {77849D35-37D4-4802-81DC-9477B2775A40}
+ {DB813A36-11BA-41FE-B258-CA9A7152247B} = {77849D35-37D4-4802-81DC-9477B2775A40}
+ {0189E4FB-6E2B-4F2E-9B1D-5473D23FC6DB} = {77849D35-37D4-4802-81DC-9477B2775A40}
+ {F8F0921C-EE5D-4AED-A4D6-5BF5FAE02CB5} = {77849D35-37D4-4802-81DC-9477B2775A40}
+ {28C0F5C8-4849-4035-80AB-45639424E73F} = {77849D35-37D4-4802-81DC-9477B2775A40}
+ {3F79558C-485D-49E1-BD3E-E12538D3D308} = {EC91ADE9-3D66-4AB2-9FB4-2B585E1F3531}
+ {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0} = {0189E4FB-6E2B-4F2E-9B1D-5473D23FC6DB}
+ {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1} = {28C0F5C8-4849-4035-80AB-45639424E73F}
+ {7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B}
+ {E1D2B260-4E7F-4A88-BC13-9910F7C44623} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {25728519-5F0F-4973-8A64-0A81EB4EA8D9}
diff --git a/global.json b/global.json
index 2ab18dceb..00b3f36f2 100644
--- a/global.json
+++ b/global.json
@@ -1,5 +1,5 @@
{
- "sdk": {
- "version":"2.1.2"
- }
+ "sdk": {
+ "version": "2.1.4"
+ }
}
\ No newline at end of file
diff --git a/k8s/README.k8s.md b/k8s/README.k8s.md
index 77acdf236..62841aba1 100644
--- a/k8s/README.k8s.md
+++ b/k8s/README.k8s.md
@@ -4,16 +4,23 @@ The k8s directory contains Kubernetes configuration for the eShopOnContainers ap
## Prerequisites
* A Kubernetes cluster. Follow Azure Container Service's [walkthrough](https://docs.microsoft.com/en-us/azure/container-service/container-service-kubernetes-walkthrough) to create one.
* A private Docker registry. Follow Azure Container Registry's [guide](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-get-started-portal) to create one.
-* Optionally, previous steps can be skipped if you run gen-k8s-env.ps1 (or gen-k8s-env-aks.ps1 if you would like to use AKS instead of ACS) script to automatically create the azure environment needed for kubernetes deployment. Azure cli 2.0 must be previously installed [installation guide](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli). For example:
+* Optionally, previous steps can be skipped if you run the **gen-k8s-env-aks.ps1** script to create an AKS cluster environment or gen-k8s-env.ps1 script to create an ACS for Kuberentes cluster environment including the creation of additional Azure environment needed like an Azure Resource Manager and ACR registry.
+
+Azure cli 2.0 must be previously installed [installation guide](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli). For example:
**Important**: Note the parameter "-createAcr true". If you are creating the K8s cluster but you want to re-use and existing ACR, say "-createAcr false".
+
+For AKS:
+
>```
->./gen-k8s-env -resourceGroupName k8sGroup -location westeurope -registryName k8sregistry -createAcr true -orchestratorName k8s-cluster -dnsName k8s-dns
+>./gen-k8s-env-aks -resourceGroupName YoureShopAksResgroup -location centralus -serviceName YoureShopAksCluster -dnsNamePrefix youreshopaks -registryName YoureShopAcrRegistry -createAcr true -nodeCount 3 -nodeVMSize Standard_D2_v2
>```
-or using AKS instead of ACS
+
+For ACS:
+
>```
->./gen-k8s-env-aks -resourceGroupName k8sGroup -location westeurope -registryName k8sregistry -dnsName k8s-dns -serviceName k8s-cluster -createAcr true -nodeCount 3 -nodeVMSize Standard_D2_v2
+>./gen-k8s-env -resourceGroupName k8sGroup -location westeurope -registryName k8sregistry -createAcr true -orchestratorName k8s-cluster -dnsName k8s-dns
>```
* A Docker development environment with `docker` and `docker-compose`.
diff --git a/k8s/build-push-images.ps1 b/k8s/build-push-images.ps1
new file mode 100644
index 000000000..e2c8e06b6
--- /dev/null
+++ b/k8s/build-push-images.ps1
@@ -0,0 +1,72 @@
+Param(
+ [parameter(Mandatory=$false)][string]$registry,
+ [parameter(Mandatory=$false)][string]$dockerUser,
+ [parameter(Mandatory=$false)][string]$dockerPassword,
+ [parameter(Mandatory=$false)][string]$imageTag,
+ [parameter(Mandatory=$false)][bool]$buildImages=$true,
+ [parameter(Mandatory=$false)][bool]$pushImages=$true,
+ [parameter(Mandatory=$false)][string]$dockerOrg="eshop"
+)
+
+# Initialization
+
+$useDockerHub = [string]::IsNullOrEmpty($registry)
+
+# Check required commands (only if not in CI environment)
+
+$requiredCommands = ("docker", "docker-compose")
+foreach ($command in $requiredCommands) {
+ if ((Get-Command $command -ErrorAction SilentlyContinue) -eq $null) {
+ Write-Host "$command must be on path" -ForegroundColor Red
+ exit
+ }
+}
+
+# Get tag to use from current branch if no tag is passed
+if ([string]::IsNullOrEmpty($imageTag)) {
+ $imageTag = $(git rev-parse --abbrev-ref HEAD)
+}
+Write-Host "Docker image Tag: $imageTag" -ForegroundColor Yellow
+
+# Build docker images if needed
+if ($buildImages) {
+ Write-Host "Building Docker images tagged with '$imageTag'" -ForegroundColor Yellow
+ $env:TAG=$imageTag
+ docker-compose -p .. -f ../docker-compose.yml build
+}
+
+# Login to Docker registry
+if (-not [string]::IsNullOrEmpty($dockerUser)) {
+ $registryFDQN = if (-not $useDockerHub) {$registry} else {"index.docker.io/v1/"}
+
+ Write-Host "Logging in to $registryFDQN as user $dockerUser" -ForegroundColor Yellow
+ if ($useDockerHub) {
+ docker login -u $dockerUser -p $dockerPassword
+ }
+ else {
+ docker login -u $dockerUser -p $dockerPassword $registryFDQN
+ }
+
+ if (-not $LastExitCode -eq 0) {
+ Write-Host "Login failed" -ForegroundColor Red
+ exit
+ }
+
+}
+
+# Push images to Docker registry
+if ($pushImages) {
+ Write-Host "Pushing images to $registry/$dockerOrg..." -ForegroundColor Yellow
+ $services = ("basket.api", "catalog.api", "identity.api", "ordering.api", "ordering.backgroundtasks", "marketing.api","payment.api","locations.api", "webmvc", "webspa", "webstatus", "ocelotapigw", "mobileshoppingagg", "webshoppingagg", "ordering.signalrhub")
+
+ foreach ($service in $services) {
+ $imageFqdn = if ($useDockerHub) {"$dockerOrg/${service}"} else {"$registry/$dockerOrg/${service}"}
+ docker tag eshop/${service}:$imageTag ${imageFqdn}:$imageTag
+ docker push ${imageFqdn}:$imageTag
+ }
+}
+
+
+
+
+
diff --git a/k8s/conf_cloud.yml b/k8s/conf_cloud.yaml
similarity index 100%
rename from k8s/conf_cloud.yml
rename to k8s/conf_cloud.yaml
diff --git a/k8s/conf_local.yml b/k8s/conf_local.yaml
similarity index 100%
rename from k8s/conf_local.yml
rename to k8s/conf_local.yaml
diff --git a/k8s/deploy.ps1 b/k8s/deploy.ps1
index 27c5d3fde..f0905096a 100644
--- a/k8s/deploy.ps1
+++ b/k8s/deploy.ps1
@@ -8,6 +8,7 @@ Param(
[parameter(Mandatory=$false)][string]$imageTag,
[parameter(Mandatory=$false)][bool]$deployCI=$false,
[parameter(Mandatory=$false)][bool]$buildImages=$true,
+ [parameter(Mandatory=$false)][bool]$pushImages=$true,
[parameter(Mandatory=$false)][bool]$deployInfrastructure=$true,
[parameter(Mandatory=$false)][string]$dockerOrg="eshop"
)
@@ -63,9 +64,11 @@ if ($buildImages) {
Write-Host "Building Docker images tagged with '$imageTag'" -ForegroundColor Yellow
$env:TAG=$imageTag
docker-compose -p .. -f ../docker-compose.yml build
+}
+if ($pushImages) {
Write-Host "Pushing images to $registry/$dockerOrg..." -ForegroundColor Yellow
- $services = ("basket.api", "catalog.api", "identity.api", "ordering.api", "marketing.api","payment.api","locations.api", "webmvc", "webspa", "webstatus", "ocelotapigw", "mobileshoppingagg", "webshoppingagg")
+ $services = ("basket.api", "catalog.api", "identity.api", "ordering.api", "ordering.backgroundtasks", "marketing.api","payment.api","locations.api", "webmvc", "webspa", "webstatus", "ocelotapigw", "mobileshoppingagg", "webshoppingagg", "ordering.signalrhub")
foreach ($service in $services) {
$imageFqdn = if ($useDockerHub) {"$dockerOrg/${service}"} else {"$registry/$dockerOrg/${service}"}
@@ -91,7 +94,10 @@ if (-not [string]::IsNullOrEmpty($dockerUser)) {
exit
}
- # create registry key secret
+ # Try to delete the Docker registry key secret
+ ExecKube -cmd 'delete secret docker-registry registry-key'
+
+ # Create the Docker registry key secret
ExecKube -cmd 'create secret docker-registry registry-key `
--docker-server=$registryFDQN `
--docker-username=$dockerUser `
@@ -161,12 +167,14 @@ ExecKube -cmd 'set image deployments/basket basket=${registryPath}${dockerOrg}/b
ExecKube -cmd 'set image deployments/catalog catalog=${registryPath}${dockerOrg}/catalog.api:$imageTag'
ExecKube -cmd 'set image deployments/identity identity=${registryPath}${dockerOrg}/identity.api:$imageTag'
ExecKube -cmd 'set image deployments/ordering ordering=${registryPath}${dockerOrg}/ordering.api:$imageTag'
+ExecKube -cmd 'set image deployments/ordering-backgroundtasks ordering-backgroundtasks=${registryPath}${dockerOrg}/ordering.backgroundtasks:$imageTag'
ExecKube -cmd 'set image deployments/marketing marketing=${registryPath}${dockerOrg}/marketing.api:$imageTag'
ExecKube -cmd 'set image deployments/locations locations=${registryPath}${dockerOrg}/locations.api:$imageTag'
ExecKube -cmd 'set image deployments/payment payment=${registryPath}${dockerOrg}/payment.api:$imageTag'
ExecKube -cmd 'set image deployments/webmvc webmvc=${registryPath}${dockerOrg}/webmvc:$imageTag'
ExecKube -cmd 'set image deployments/webstatus webstatus=${registryPath}${dockerOrg}/webstatus:$imageTag'
ExecKube -cmd 'set image deployments/webspa webspa=${registryPath}${dockerOrg}/webspa:$imageTag'
+ExecKube -cmd 'set image deployments/ordering-signalrhub ordering-signalrhub=${registryPath}${dockerOrg}/ordering.signalrhub:$imageTag'
ExecKube -cmd 'set image deployments/mobileshoppingagg mobileshoppingagg=${registryPath}${dockerOrg}/mobileshoppingagg:$imageTag'
ExecKube -cmd 'set image deployments/webshoppingagg webshoppingagg=${registryPath}${dockerOrg}/webshoppingagg:$imageTag'
@@ -181,6 +189,7 @@ ExecKube -cmd 'rollout resume deployments/basket'
ExecKube -cmd 'rollout resume deployments/catalog'
ExecKube -cmd 'rollout resume deployments/identity'
ExecKube -cmd 'rollout resume deployments/ordering'
+ExecKube -cmd 'rollout resume deployments/ordering-backgroundtasks'
ExecKube -cmd 'rollout resume deployments/marketing'
ExecKube -cmd 'rollout resume deployments/locations'
ExecKube -cmd 'rollout resume deployments/payment'
@@ -193,6 +202,7 @@ ExecKube -cmd 'rollout resume deployments/apigwmm'
ExecKube -cmd 'rollout resume deployments/apigwms'
ExecKube -cmd 'rollout resume deployments/apigwwm'
ExecKube -cmd 'rollout resume deployments/apigwws'
+ExecKube -cmd 'rollout resume deployments/ordering-signalrhub'
Write-Host "WebSPA is exposed at http://$externalDns, WebMVC at http://$externalDns/webmvc, WebStatus at http://$externalDns/webstatus" -ForegroundColor Yellow
diff --git a/k8s/deployments.yaml b/k8s/deployments.yaml
index 034842f8c..f362c319c 100644
--- a/k8s/deployments.yaml
+++ b/k8s/deployments.yaml
@@ -21,50 +21,37 @@ spec:
valueFrom:
configMapKeyRef:
name: externalcfg
- key: BasketRedisConStr
+ key: basket__ConnectionString
- name: EventBusConnection
valueFrom:
configMapKeyRef:
name: externalcfg
- key: BasketBus
+ key: all__EventBusConnection
- name: AzureServiceBusEnabled
valueFrom:
configMapKeyRef:
name: externalcfg
- key: UseAzureServiceBus
+ key: all__UseAzureServiceBus
- name: ApplicationInsights__InstrumentationKey
valueFrom:
configMapKeyRef:
name: externalcfg
- key: Instrumentation_Key
+ key: all__InstrumentationKey
- name: IdentityUrl
valueFrom:
configMapKeyRef:
name: urls
- key: IdentityUrl
+ key: identity_e
- name: UseLoadTest
valueFrom:
configMapKeyRef:
name: externalcfg
- key: EnableLoadTest
+ key: all__EnableLoadTest
- name: OrchestratorType
value: 'K8S'
ports:
- containerPort: 80
- readinessProbe:
- httpGet:
- path: /hc
- port: 80
- scheme: HTTP
- initialDelaySeconds: 60
- periodSeconds: 60
- livenessProbe:
- httpGet:
- path: /liveness
- port: 80
- scheme: HTTP
- initialDelaySeconds: 120
- periodSeconds: 60
+
imagePullSecrets:
- name: registry-key
---
@@ -91,7 +78,7 @@ spec:
valueFrom:
configMapKeyRef:
name: externalcfg
- key: CatalogSqlDb
+ key: catalog__ConnectionString
- name: PicBaseUrl
valueFrom:
configMapKeyRef:
@@ -101,35 +88,22 @@ spec:
valueFrom:
configMapKeyRef:
name: externalcfg
- key: CatalogAzureStorageEnabled
+ key: catalog__AzureStorageEnabled
- name: EventBusConnection
valueFrom:
configMapKeyRef:
name: externalcfg
- key: CatalogBus
+ key: all__EventBusConnection
- name: ApplicationInsights__InstrumentationKey
valueFrom:
configMapKeyRef:
name: externalcfg
- key: Instrumentation_Key
+ key: all__InstrumentationKey
- name: OrchestratorType
value: 'K8S'
ports:
- containerPort: 80
- readinessProbe:
- httpGet:
- path: /hc
- port: 80
- scheme: HTTP
- initialDelaySeconds: 60
- periodSeconds: 60
- livenessProbe:
- httpGet:
- path: /liveness
- port: 80
- scheme: HTTP
- initialDelaySeconds: 120
- periodSeconds: 60
+
imagePullSecrets:
- name: registry-key
---
@@ -156,7 +130,7 @@ spec:
valueFrom:
configMapKeyRef:
name: externalcfg
- key: IdentitySqlDb
+ key: identity__ConnectionString
- name: DPConnectionString
valueFrom:
configMapKeyRef:
@@ -168,55 +142,57 @@ spec:
valueFrom:
configMapKeyRef:
name: urls
- key: MvcClientExternalUrl
+ key: mvc_e
- name: SpaClient
valueFrom:
configMapKeyRef:
name: urls
- key: SpaClientExternalUrl
+ key: spa_e
- name: LocationApiClient
valueFrom:
configMapKeyRef:
name: urls
- key: LocationApiClient
+ key: locations_e
- name: MarketingApiClient
valueFrom:
configMapKeyRef:
name: urls
- key: MarketingApiClient
+ key: marketing_e
- name: BasketApiClient
valueFrom:
configMapKeyRef:
name: urls
- key: BasketApiClient
+ key: basket_e
- name: OrderingApiClient
valueFrom:
configMapKeyRef:
name: urls
- key: OrderingApiClient
+ key: ordering_e
+ - name: MobileShoppingAggClient
+ valueFrom:
+ configMapKeyRef:
+ name: urls
+ key: mobileshoppingagg_e
+ - name: WebShoppingAggClient
+ valueFrom:
+ configMapKeyRef:
+ name: urls
+ key: webshoppingagg_e
+ - name: XamarinCallback
+ valueFrom:
+ configMapKeyRef:
+ name: urls
+ key: xamarin_callback_e
- name: ApplicationInsights__InstrumentationKey
valueFrom:
configMapKeyRef:
name: externalcfg
- key: Instrumentation_Key
+ key: all__InstrumentationKey
- name: OrchestratorType
value: 'K8S'
ports:
- containerPort: 80
- readinessProbe:
- httpGet:
- path: /hc
- port: 80
- scheme: HTTP
- initialDelaySeconds: 60
- periodSeconds: 60
- livenessProbe:
- httpGet:
- path: /liveness
- port: 80
- scheme: HTTP
- initialDelaySeconds: 120
- periodSeconds: 60
+
imagePullSecrets:
- name: registry-key
---
@@ -243,125 +219,157 @@ spec:
valueFrom:
configMapKeyRef:
name: externalcfg
- key: OrderingSqlDb
+ key: ordering__ConnectionString
- name: EventBusConnection
valueFrom:
configMapKeyRef:
name: externalcfg
- key: OrderingBus
+ key: all__EventBusConnection
- name: AzureServiceBusEnabled
valueFrom:
configMapKeyRef:
name: externalcfg
- key: UseAzureServiceBus
+ key: all__UseAzureServiceBus
- name: IdentityUrl
valueFrom:
configMapKeyRef:
name: urls
- key: IdentityUrl
+ key: identity_e
+ - name: CheckUpdateTime
+ valueFrom:
+ configMapKeyRef:
+ name: externalcfg
+ key: GracePeriodManager__CheckUpdateTime
+ - name: GracePeriodTime
+ valueFrom:
+ configMapKeyRef:
+ name: externalcfg
+ key: GracePeriodManager__GracePeriodTime
- name: ApplicationInsights__InstrumentationKey
valueFrom:
configMapKeyRef:
name: externalcfg
- key: Instrumentation_Key
+ key: all__InstrumentationKey
- name: UseLoadTest
valueFrom:
configMapKeyRef:
name: externalcfg
- key: EnableLoadTest
+ key: all__EnableLoadTest
- name: OrchestratorType
value: 'K8S'
ports:
- containerPort: 80
- readinessProbe:
- httpGet:
- path: /hc
- port: 80
- scheme: HTTP
- initialDelaySeconds: 60
- periodSeconds: 60
- livenessProbe:
- httpGet:
- path: /liveness
- port: 80
- scheme: HTTP
- initialDelaySeconds: 120
- periodSeconds: 60
+
imagePullSecrets:
- name: registry-key
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
- name: orderingbackground
+ name: ordering-backgroundtasks
spec:
paused: true
template:
metadata:
labels:
app: eshop
- component: orderingbackground
+ component: ordering-backgroundtasks
spec:
containers:
- - name: orderingbackground
+ - name: ordering-backgroundtasks
image: eshop/ordering.backgroundtasks
imagePullPolicy: Always
- env:
- - name: PATH_BASE
- value: /ordering-backgroundtasks
+ env:
- name: ConnectionString
valueFrom:
configMapKeyRef:
name: externalcfg
- key: OrderingSqlDb
+ key: ordering__ConnectionString
- name: EventBusConnection
valueFrom:
configMapKeyRef:
name: externalcfg
- key: OrderingBus
+ key: all__EventBusConnection
- name: AzureServiceBusEnabled
valueFrom:
configMapKeyRef:
name: externalcfg
- key: UseAzureServiceBus
+ key: all__UseAzureServiceBus
- name: CheckUpdateTime
valueFrom:
configMapKeyRef:
name: externalcfg
- key: GracePeriodManager_CheckUpdateTime
+ key: GracePeriodManager__CheckUpdateTime
- name: GracePeriodTime
valueFrom:
configMapKeyRef:
name: externalcfg
- key: GracePeriodManager_GracePeriodTime
+ key: GracePeriodManager__GracePeriodTime
- name: ApplicationInsights__InstrumentationKey
valueFrom:
configMapKeyRef:
name: externalcfg
- key: Instrumentation_Key
+ key: all__InstrumentationKey
- name: UseLoadTest
valueFrom:
configMapKeyRef:
name: externalcfg
- key: EnableLoadTest
+ key: all__EnableLoadTest
- name: OrchestratorType
- value: 'K8S'
+ value: 'K8S'
+ ports:
+ - containerPort: 80
+ imagePullSecrets:
+ - name: registry-key
+---
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: ordering-signalrhub
+spec:
+ paused: true
+ template:
+ metadata:
+ labels:
+ app: eshop
+ component: ordering-signalrhub
+ spec:
+ containers:
+ - name: ordering-signalrhub
+ image: eshop/ordering.signalrhub
+ imagePullPolicy: Always
+ env:
+ - name: EventBusConnection
+ valueFrom:
+ configMapKeyRef:
+ name: externalcfg
+ key: all__EventBusConnection
+ - name: IdentityUrl
+ valueFrom:
+ configMapKeyRef:
+ name: urls
+ key: identity_e
+ - name: AzureServiceBusEnabled
+ valueFrom:
+ configMapKeyRef:
+ name: externalcfg
+ key: all__UseAzureServiceBus
+ - name: ApplicationInsights__InstrumentationKey
+ valueFrom:
+ configMapKeyRef:
+ name: externalcfg
+ key: all__InstrumentationKey
+ - name: OrchestratorType
+ value: 'K8S'
+ - name: IsClusterEnv
+ value: 'True'
+ - name: SignalrStoreConnectionString
+ valueFrom:
+ configMapKeyRef:
+ name: externalcfg
+ key: keystore
ports:
- containerPort: 80
- readinessProbe:
- httpGet:
- path: /hc
- port: 80
- scheme: HTTP
- initialDelaySeconds: 60
- periodSeconds: 60
- livenessProbe:
- httpGet:
- path: /liveness
- port: 80
- scheme: HTTP
- initialDelaySeconds: 120
- periodSeconds: 60
imagePullSecrets:
- name: registry-key
---
@@ -388,60 +396,47 @@ spec:
valueFrom:
configMapKeyRef:
name: externalcfg
- key: LocationsNoSqlDb
+ key: locations__ConnectionString
- name: Database
valueFrom:
configMapKeyRef:
name: externalcfg
- key: LocationsNoSqlDbName
+ key: locations__Database
- name: AzureServiceBusEnabled
valueFrom:
configMapKeyRef:
name: externalcfg
- key: UseAzureServiceBus
+ key: all__UseAzureServiceBus
- name: EventBusConnection
valueFrom:
configMapKeyRef:
name: externalcfg
- key: LocationsBus
+ key: all__EventBusConnection
- name: IdentityUrl
valueFrom:
configMapKeyRef:
- name: urls
- key: IdentityUrl
+ name: internalurls
+ key: identity
- name: IdentityUrlExternal
valueFrom:
configMapKeyRef:
name: urls
- key: IdentityUrl
+ key: identity_e
- name: ApplicationInsights__InstrumentationKey
valueFrom:
configMapKeyRef:
name: externalcfg
- key: Instrumentation_Key
+ key: all__InstrumentationKey
- name: UseLoadTest
valueFrom:
configMapKeyRef:
name: externalcfg
- key: EnableLoadTest
+ key: all__EnableLoadTest
- name: OrchestratorType
value: 'K8S'
ports:
- containerPort: 80
- readinessProbe:
- httpGet:
- path: /hc
- port: 80
- scheme: HTTP
- initialDelaySeconds: 50
- periodSeconds: 60
- livenessProbe:
- httpGet:
- path: /liveness
- port: 80
- scheme: HTTP
- initialDelaySeconds: 120
- periodSeconds: 60
+
imagePullSecrets:
- name: registry-key
---
@@ -468,37 +463,37 @@ spec:
valueFrom:
configMapKeyRef:
name: externalcfg
- key: MarketingSqlDb
+ key: marketing__ConnectionString
- name: MongoConnectionString
valueFrom:
configMapKeyRef:
name: externalcfg
- key: MarketingNoSqlDb
+ key: marketing__MongoConnectionString
- name: MongoDatabase
valueFrom:
configMapKeyRef:
name: externalcfg
- key: MarketingNoSqlDbName
+ key: marketing__MongoDatabase
- name: AzureServiceBusEnabled
valueFrom:
configMapKeyRef:
name: externalcfg
- key: UseAzureServiceBus
+ key: all__UseAzureServiceBus
- name: EventBusConnection
valueFrom:
configMapKeyRef:
name: externalcfg
- key: MarketingBus
+ key: all__EventBusConnection
- name: IdentityUrl
valueFrom:
configMapKeyRef:
- name: urls
- key: IdentityUrl
+ name: internalurls
+ key: identity
- name: IdentityUrlExternal
valueFrom:
configMapKeyRef:
name: urls
- key: IdentityUrl
+ key: identity_e
- name: PicBaseUrl
valueFrom:
configMapKeyRef:
@@ -508,30 +503,17 @@ spec:
valueFrom:
configMapKeyRef:
name: externalcfg
- key: Instrumentation_Key
+ key: all__InstrumentationKey
- name: UseLoadTest
valueFrom:
configMapKeyRef:
name: externalcfg
- key: EnableLoadTest
+ key: all__EnableLoadTest
- name: OrchestratorType
value: 'K8S'
ports:
- containerPort: 80
- readinessProbe:
- httpGet:
- path: /hc
- port: 80
- scheme: HTTP
- initialDelaySeconds: 60
- periodSeconds: 60
- livenessProbe:
- httpGet:
- path: /liveness
- port: 80
- scheme: HTTP
- initialDelaySeconds: 120
- periodSeconds: 60
+
imagePullSecrets:
- name: registry-key
---
@@ -558,35 +540,22 @@ spec:
valueFrom:
configMapKeyRef:
name: externalcfg
- key: UseAzureServiceBus
+ key: all__UseAzureServiceBus
- name: EventBusConnection
valueFrom:
configMapKeyRef:
name: externalcfg
- key: PaymentBus
+ key: all__EventBusConnection
- name: ApplicationInsights__InstrumentationKey
valueFrom:
configMapKeyRef:
name: externalcfg
- key: Instrumentation_Key
+ key: all__InstrumentationKey
- name: OrchestratorType
value: 'K8S'
ports:
- containerPort: 80
- readinessProbe:
- httpGet:
- path: /hc
- port: 80
- scheme: HTTP
- initialDelaySeconds: 60
- periodSeconds: 60
- livenessProbe:
- httpGet:
- path: /liveness
- port: 80
- scheme: HTTP
- initialDelaySeconds: 120
- periodSeconds: 60
+
imagePullSecrets:
- name: registry-key
---
@@ -616,99 +585,81 @@ spec:
key: keystore
- name: IsClusterEnv
value: 'True'
- - name: BasketUrl
+ - name: PurchaseUrl
valueFrom:
configMapKeyRef:
- name: urls
- key: MvcClientBasketUrl
- - name: CallBackUrl
+ name: internalurls
+ key: apigwws
+ - name: ExternalPurchaseUrl
valueFrom:
configMapKeyRef:
name: urls
- key: MvcClientExternalUrl
- - name: LocationsUrl
- valueFrom:
- configMapKeyRef:
- name: urls
- key: MvcClientLocationsUrl
- - name: CatalogUrl
+ key: webshoppingapigw_e
+ - name: CallBackUrl
valueFrom:
configMapKeyRef:
name: urls
- key: MvcClientCatalogUrl
+ key: mvc_e
- name: IdentityUrl
valueFrom:
configMapKeyRef:
name: urls
- key: IdentityUrl
- - name: OrderingUrl
- valueFrom:
- configMapKeyRef:
- name: urls
- key: MvcClientOrderingUrl
+ key: identity_e
- name: MarketingUrl
valueFrom:
configMapKeyRef:
- name: urls
- key: MvcClientMarketingUrl
+ name: internalurls
+ key: apigwwm
- name: BasketUrlHC
valueFrom:
configMapKeyRef:
- name: urls
- key: BasketHealthCheckUrl
+ name: internalurls
+ key: basket__hc
- name: CatalogUrlHC
valueFrom:
configMapKeyRef:
- name: urls
- key: CatalogHealthCheckUrl
+ name: internalurls
+ key: catalog__hc
- name: IdentityUrlHC
valueFrom:
configMapKeyRef:
- name: urls
- key: IdentityHealthCheckUrl
+ name: internalurls
+ key: identity__hc
- name: OrderingUrlHC
valueFrom:
configMapKeyRef:
- name: urls
- key: OrderingHealthCheckUrl
+ name: internalurls
+ key: ordering__hc
- name: MarketingUrlHC
valueFrom:
configMapKeyRef:
- name: urls
- key: MarketingHealthCheckUrl
+ name: internalurls
+ key: marketing__hc
- name: PaymentUrlHC
valueFrom:
configMapKeyRef:
- name: urls
- key: PaymentHealthCheckUrl
+ name: internalurls
+ key: payment__hc
- name: ApplicationInsights__InstrumentationKey
valueFrom:
configMapKeyRef:
name: externalcfg
- key: Instrumentation_Key
+ key: all__InstrumentationKey
- name: UseLoadTest
valueFrom:
configMapKeyRef:
name: externalcfg
- key: EnableLoadTest
+ key: all__EnableLoadTest
- name: OrchestratorType
- value: 'K8S'
+ value: 'K8S'
+ - name: SignalrHubUrl
+ valueFrom:
+ configMapKeyRef:
+ name: urls
+ key: webshoppingapigw_e
ports:
- containerPort: 80
- readinessProbe:
- httpGet:
- path: /hc
- port: 80
- scheme: HTTP
- initialDelaySeconds: 60
- periodSeconds: 60
- livenessProbe:
- httpGet:
- path: /liveness
- port: 80
- scheme: HTTP
- initialDelaySeconds: 120
- periodSeconds: 60
+
imagePullSecrets:
- name: registry-key
---
@@ -734,53 +685,58 @@ spec:
- name: BasketUrl
valueFrom:
configMapKeyRef:
- name: urls
- key: BasketHealthCheckUrl
+ name: internalurls
+ key: basket__hc
- name: CatalogUrl
valueFrom:
configMapKeyRef:
- name: urls
- key: CatalogHealthCheckUrl
+ name: internalurls
+ key: catalog__hc
- name: IdentityUrl
valueFrom:
configMapKeyRef:
- name: urls
- key: IdentityHealthCheckUrl
+ name: internalurls
+ key: identity__hc
- name: OrderingUrl
valueFrom:
configMapKeyRef:
- name: urls
- key: OrderingHealthCheckUrl
+ name: internalurls
+ key: ordering__hc
+ - name: OrderingBackgroundTasksUrl
+ valueFrom:
+ configMapKeyRef:
+ name: internalurls
+ key: ordering-background__hc
- name: LocationsUrl
valueFrom:
configMapKeyRef:
- name: urls
- key: LocationsHealthCheckUrl
+ name: internalurls
+ key: locations__hc
- name: MarketingUrl
valueFrom:
configMapKeyRef:
- name: urls
- key: MarketingHealthCheckUrl
+ name: internalurls
+ key: marketing__hc
- name: mvc
valueFrom:
configMapKeyRef:
- name: urls
- key: WebMvcHealthCheckUrl
+ name: internalurls
+ key: mvc__hc
- name: spa
valueFrom:
configMapKeyRef:
- name: urls
- key: WebSpaHealthCheckUrl
+ name: internalurls
+ key: spa__hc
- name: PaymentUrl
valueFrom:
configMapKeyRef:
- name: urls
- key: PaymentHealthCheckUrl
+ name: internalurls
+ key: payment__hc
- name: ApplicationInsights__InstrumentationKey
valueFrom:
configMapKeyRef:
name: externalcfg
- key: Instrumentation_Key
+ key: all__InstrumentationKey
- name: OrchestratorType
value: 'K8S'
ports:
@@ -814,93 +770,159 @@ spec:
key: keystore
- name: IsClusterEnv
value: 'True'
- - name: BasketUrl
+ - name: PurchaseUrl
valueFrom:
configMapKeyRef:
name: urls
- key: SpaClientBasketExternalUrl
+ key: webshoppingapigw_e
- name: CallBackUrl
valueFrom:
configMapKeyRef:
name: urls
- key: SpaClientExternalUrl
- - name: CatalogUrl
- valueFrom:
- configMapKeyRef:
- name: urls
- key: SpaClientCatalogExternalUrl
+ key: spa_e
- name: IdentityUrl
valueFrom:
configMapKeyRef:
name: urls
- key: SpaClientIdentityExternalUrl
- - name: OrderingUrl
- valueFrom:
- configMapKeyRef:
- name: urls
- key: SpaClientOrderingExternalUrl
+ key: identity_e
- name: MarketingUrl
valueFrom:
configMapKeyRef:
name: urls
- key: SpaClientMarketingExternalUrl
- - name: LocationsUrl
- valueFrom:
- configMapKeyRef:
- name: urls
- key: SpaClientLocationsUrl
+ key: marketingapigw_e
- name: BasketUrlHC
valueFrom:
configMapKeyRef:
- name: urls
- key: BasketHealthCheckUrl
+ name: internalurls
+ key: basket__hc
- name: CatalogUrlHC
valueFrom:
configMapKeyRef:
- name: urls
- key: CatalogHealthCheckUrl
+ name: internalurls
+ key: catalog__hc
- name: IdentityUrlHC
valueFrom:
configMapKeyRef:
- name: urls
- key: IdentityHealthCheckUrl
+ name: internalurls
+ key: identity__hc
- name: OrderingUrlHC
valueFrom:
configMapKeyRef:
- name: urls
- key: OrderingHealthCheckUrl
+ name: internalurls
+ key: ordering__hc
- name: MarketingUrlHC
valueFrom:
configMapKeyRef:
- name: urls
- key: MarketingHealthCheckUrl
+ name: internalurls
+ key: marketing__hc
- name: PaymentUrlHC
valueFrom:
configMapKeyRef:
- name: urls
- key: PaymentHealthCheckUrl
+ name: internalurls
+ key: payment__hc
- name: ApplicationInsights__InstrumentationKey
valueFrom:
configMapKeyRef:
name: externalcfg
- key: Instrumentation_Key
+ key: all__InstrumentationKey
- name: OrchestratorType
value: 'K8S'
+ - name: SignalrHubUrl
+ valueFrom:
+ configMapKeyRef:
+ name: urls
+ key: webshoppingapigw_e
+ ports:
+ - containerPort: 80
+
+ imagePullSecrets:
+ - name: registry-key
+---
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: webshoppingagg
+spec:
+ paused: true
+ template:
+ metadata:
+ labels:
+ app: eshop
+ component: webshoppingagg
+ spec:
+ containers:
+ - name: webshoppingagg
+ image: eshop/webshoppingagg
+ imagePullPolicy: Always
+ env:
+ - name: ASPNETCORE_URLS
+ value: http://0.0.0.0:80
+ - name: urls__basket
+ valueFrom:
+ configMapKeyRef:
+ name: internalurls
+ key: basket
+ - name: urls__catalog
+ valueFrom:
+ configMapKeyRef:
+ name: internalurls
+ key: catalog
+ - name: urls__orders
+ valueFrom:
+ configMapKeyRef:
+ name: internalurls
+ key: ordering
+ - name: urls__identity
+ valueFrom:
+ configMapKeyRef:
+ name: internalurls
+ key: identity
ports:
- containerPort: 80
- readinessProbe:
- httpGet:
- path: /hc
- port: 80
- scheme: HTTP
- initialDelaySeconds: 60
- periodSeconds: 60
- livenessProbe:
- httpGet:
- path: /liveness
- port: 80
- scheme: HTTP
- initialDelaySeconds: 120
- periodSeconds: 60
imagePullSecrets:
- name: registry-key
+---
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: mobileshoppingagg
+spec:
+ paused: true
+ template:
+ metadata:
+ labels:
+ app: eshop
+ component: mobileshoppingagg
+ spec:
+ containers:
+ - name: mobileshoppingagg
+ image: eshop/mobileshoppingagg
+ imagePullPolicy: Always
+ env:
+ - name: ASPNETCORE_URLS
+ value: http://0.0.0.0:80
+ - name: urls__basket
+ valueFrom:
+ configMapKeyRef:
+ name: internalurls
+ key: basket
+ - name: urls__catalog
+ valueFrom:
+ configMapKeyRef:
+ name: internalurls
+ key: catalog
+ - name: urls__orders
+ valueFrom:
+ configMapKeyRef:
+ name: internalurls
+ key: ordering
+ - name: urls__identity
+ valueFrom:
+ configMapKeyRef:
+ name: internalurls
+ key: identity
+ ports:
+ - containerPort: 80
+ imagePullSecrets:
+ - name: registry-key
+---
diff --git a/k8s/gen-k8s-env-aks.ps1 b/k8s/gen-k8s-env-aks.ps1
index a22588fa1..727a9ca53 100644
--- a/k8s/gen-k8s-env-aks.ps1
+++ b/k8s/gen-k8s-env-aks.ps1
@@ -1,17 +1,16 @@
Param(
[parameter(Mandatory=$true)][string]$resourceGroupName,
[parameter(Mandatory=$true)][string]$location,
- [parameter(Mandatory=$false)][string]$registryName,
[parameter(Mandatory=$true)][string]$serviceName,
- [parameter(Mandatory=$true)][string]$dnsName,
+ [parameter(Mandatory=$true)][string]$dnsNamePrefix,
+ [parameter(Mandatory=$false)][string]$registryName,
[parameter(Mandatory=$true)][string]$createAcr=$true,
- [parameter(Mandatory=$false)][int]$nodeCount=2,
- [parameter(Mandatory=$false)][string]$nodeVMSize="Standard_D2_v2",
- [parameter(Mandatory=$false)][string]$kubernetesVersion="1.7.7"
+ [parameter(Mandatory=$false)][int]$nodeCount=3,
+ [parameter(Mandatory=$false)][string]$nodeVMSize="Standard_D2_v2"
)
# Create resource group
-Write-Host "Creating resource group..." -ForegroundColor Yellow
+Write-Host "Creating Azure Resource Group..." -ForegroundColor Yellow
az group create --name=$resourceGroupName --location=$location
if ($createAcr -eq $true) {
@@ -20,14 +19,16 @@ if ($createAcr -eq $true) {
az acr create -n $registryName -g $resourceGroupName -l $location --admin-enabled true --sku Basic
}
-# Create kubernetes orchestrator
-Write-Host "Creating kubernetes orchestrator..." -ForegroundColor Yellow
-az aks create --resource-group=$resourceGroupName --name=$serviceName --dns-name-prefix=$dnsName --generate-ssh-keys --node-count=$nodeCount --node-vm-size=$nodeVMSize --kubernetes-version $kubernetesVersion
+# Create kubernetes cluster in AKS
+Write-Host "Creating Kubernetes cluster in AKS..." -ForegroundColor Yellow
+az aks create --resource-group=$resourceGroupName --name=$serviceName --dns-name-prefix=$dnsNamePrefix --generate-ssh-keys --node-count=$nodeCount --node-vm-size=$nodeVMSize
-# Retrieve kubernetes cluster configuration and save it under ~/.kube/config
+# Retrieve kubernetes cluster configuration and save it under ~/.kube/config
+Write-Host "Getting Kubernetes config..." -ForegroundColor Yellow
az aks get-credentials --resource-group=$resourceGroupName --name=$serviceName
if ($createAcr -eq $true) {
# Show ACR credentials
+ Write-Host "ACR credentials" -ForegroundColor Yellow
az acr credential show -n $registryName
-}
\ No newline at end of file
+}
diff --git a/k8s/internalurls.yaml b/k8s/internalurls.yaml
new file mode 100644
index 000000000..df317b5d5
--- /dev/null
+++ b/k8s/internalurls.yaml
@@ -0,0 +1,33 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: internalurls
+ labels:
+ app: eshop
+data:
+# Internal Services & healthchecks
+ basket: http://basket
+ basket__hc: http://basket/hc
+ catalog: http://catalog
+ catalog__hc: http://catalog/hc
+ identity: http://identity
+ identity__hc: http://identity/hc
+ ordering: http://ordering
+ ordering__hc: http://ordering/hc
+ ordering-background: http://ordering-background
+ ordering-background__hc: http://ordering-background/hc
+ marketing: http://marketing
+ marketing__hc: http://marketing/hc
+ locations: http://locations
+ locations__hc: http://locations/hc
+ payment__hc: http://payment/hc
+ mvc__hc: http://webmvc/hc
+ spa__hc: http://webspa/hc
+# Aggreggators
+ mobileshoppingagg: http://mobileshoppingagg
+ webshoppingagg: http://webshoppingagg
+# API GWs
+ apigwmm: http://ocelotapigw-mm
+ apigwms: http://ocelotapigw-ms
+ apigwwm: http://ocelotapigw-wm
+ apigwws: http://ocelotapigw-ws
\ No newline at end of file
diff --git a/k8s/ocelot/configuration-web-shopping.json b/k8s/ocelot/configuration-web-shopping.json
new file mode 100644
index 000000000..021056f43
--- /dev/null
+++ b/k8s/ocelot/configuration-web-shopping.json
@@ -0,0 +1,154 @@
+{
+ "ReRoutes": [
+ {
+ "DownstreamPathTemplate": "/api/{version}/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "catalog",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/api/{version}/c/{everything}",
+ "UpstreamHttpMethod": [ "GET" ]
+ },
+ {
+ "DownstreamPathTemplate": "/api/{version}/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "basket",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/api/{version}/b/{everything}",
+ "UpstreamHttpMethod": [],
+ "AuthenticationOptions": {
+ "AuthenticationProviderKey": "IdentityApiKey",
+ "AllowedScopes": []
+ }
+ },
+ {
+ "DownstreamPathTemplate": "/api/{version}/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "ordering",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/api/{version}/o/{everything}",
+ "UpstreamHttpMethod": [],
+ "AuthenticationOptions": {
+ "AuthenticationProviderKey": "IdentityApiKey",
+ "AllowedScopes": []
+ }
+ },
+ {
+ "DownstreamPathTemplate": "/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "webshoppingagg",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/{everything}",
+ "UpstreamHttpMethod": [ "POST", "PUT", "GET" ],
+ "AuthenticationOptions": {
+ "AuthenticationProviderKey": "IdentityApiKey",
+ "AllowedScopes": []
+ }
+ },
+ {
+ "DownstreamPathTemplate": "/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "ordering",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/orders-api/{everything}",
+ "UpstreamHttpMethod": []
+ },
+ {
+ "DownstreamPathTemplate": "/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "ordering-signalrhub",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/hub/{everything}",
+ "UpstreamHttpMethod": []
+ },
+ {
+ "DownstreamPathTemplate": "/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "basket",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/basket-api/{everything}",
+ "UpstreamHttpMethod": []
+ },
+ {
+ "DownstreamPathTemplate": "/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "catalog",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/catalog-api/{everything}",
+ "UpstreamHttpMethod": []
+ },
+ {
+ "DownstreamPathTemplate": "/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "marketing",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/marketing-api/{everything}",
+ "UpstreamHttpMethod": []
+ },
+ {
+ "DownstreamPathTemplate": "/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "payment",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/payment-api/{everything}",
+ "UpstreamHttpMethod": []
+ },
+ {
+ "DownstreamPathTemplate": "/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "locations.api",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/location-api/{everything}",
+ "UpstreamHttpMethod": []
+ }
+
+ ],
+ "GlobalConfiguration": {
+ "RequestIdKey": "OcRequestId",
+ "AdministrationPath": "/administration"
+ }
+ }
+
\ No newline at end of file
diff --git a/k8s/services.yaml b/k8s/services.yaml
index 805d3dc85..2235c64f7 100644
--- a/k8s/services.yaml
+++ b/k8s/services.yaml
@@ -59,14 +59,28 @@ kind: Service
metadata:
labels:
app: eshop
- component: orderingbackground
- name: orderingbackground
+ component: ordering-backgroundtasks
+ name: ordering-background
spec:
ports:
- port: 80
selector:
app: eshop
- component: orderingbackground
+ component: ordering-backgroundtasks
+---
+apiVersion: v1
+kind: Service
+metadata:
+ labels:
+ app: eshop
+ component: ordering-signalrhub
+ name: ordering-signalrhub
+spec:
+ ports:
+ - port: 80
+ selector:
+ app: eshop
+ component: ordering-signalrhub
---
apiVersion: v1
kind: Service
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 000000000..ba627e674
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,11 @@
+{
+ "requires": true,
+ "lockfileVersion": 1,
+ "dependencies": {
+ "@aspnet/signalr": {
+ "version": "1.0.0-preview1-update1",
+ "resolved": "https://registry.npmjs.org/@aspnet/signalr/-/signalr-1.0.0-preview1-update1.tgz",
+ "integrity": "sha512-TGFCoLa2svN37Ew5ue0kGFxbkmQzq2I9N5TMLFBWRrpTYF4txlE3yPX0EaPt/NToKBaK1A+VK8Q+1MGSYtnqUw=="
+ }
+ }
+}
diff --git a/src/ApiGateways/ApiGw-Base/Program.cs b/src/ApiGateways/ApiGw-Base/Program.cs
new file mode 100644
index 000000000..effd5684e
--- /dev/null
+++ b/src/ApiGateways/ApiGw-Base/Program.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace OcelotApiGw
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ BuildWebHost(args).Run();
+ }
+
+ public static IWebHost BuildWebHost(string[] args)
+ {
+ IWebHostBuilder builder = WebHost.CreateDefaultBuilder(args);
+ builder.ConfigureServices(s => s.AddSingleton(builder))
+ .ConfigureAppConfiguration(ic => ic.AddJsonFile(Path.Combine("configuration", "configuration.json")))
+ .UseStartup();
+ IWebHost host = builder.Build();
+ return host;
+ }
+ }
+}
diff --git a/src/ApiGateways/Mobile.Bff.Shopping/apigw/configuration.json b/src/ApiGateways/Mobile.Bff.Shopping/apigw/configuration.json
new file mode 100644
index 000000000..0fd6d9024
--- /dev/null
+++ b/src/ApiGateways/Mobile.Bff.Shopping/apigw/configuration.json
@@ -0,0 +1,118 @@
+{
+ "ReRoutes": [
+ {
+ "DownstreamPathTemplate": "/api/{version}/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "catalog.api",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/api/{version}/c/{everything}",
+ "UpstreamHttpMethod": [ "GET" ]
+ },
+ {
+ "DownstreamPathTemplate": "/api/{version}/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "basket.api",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/api/{version}/b/{everything}",
+ "UpstreamHttpMethod": [],
+ "AuthenticationOptions": {
+ "AuthenticationProviderKey": "IdentityApiKey",
+ "AllowedScopes": []
+ }
+ },
+ {
+ "DownstreamPathTemplate": "/api/{version}/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "ordering.api",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/api/{version}/o/{everything}",
+ "UpstreamHttpMethod": [],
+ "AuthenticationOptions": {
+ "AuthenticationProviderKey": "IdentityApiKey",
+ "AllowedScopes": []
+ }
+ },
+ {
+ "DownstreamPathTemplate": "/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "mobileshoppingagg",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/{everything}",
+ "UpstreamHttpMethod": [ "POST", "PUT", "GET" ],
+ "AuthenticationOptions": {
+ "AuthenticationProviderKey": "IdentityApiKey",
+ "AllowedScopes": []
+ }
+ },
+ {
+ "DownstreamPathTemplate": "/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "ordering.api",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/orders-api/{everything}",
+ "UpstreamHttpMethod": []
+ },
+ {
+ "DownstreamPathTemplate": "/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "basket.api",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/basket-api/{everything}",
+ "UpstreamHttpMethod": []
+ },
+ {
+ "DownstreamPathTemplate": "/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "catalog.api",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/catalog-api/{everything}",
+ "UpstreamHttpMethod": []
+ },
+ {
+ "DownstreamPathTemplate": "/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "payment.api",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/payment-api/{everything}",
+ "UpstreamHttpMethod": []
+ }
+
+ ],
+ "GlobalConfiguration": {
+ "RequestIdKey": "OcRequestId",
+ "AdministrationPath": "/administration"
+ }
+ }
+
\ No newline at end of file
diff --git a/src/ApiGateways/Web.Bff.Shopping/apigw/configuration.json b/src/ApiGateways/Web.Bff.Shopping/apigw/configuration.json
new file mode 100644
index 000000000..b3e01d773
--- /dev/null
+++ b/src/ApiGateways/Web.Bff.Shopping/apigw/configuration.json
@@ -0,0 +1,130 @@
+{
+ "ReRoutes": [
+ {
+ "DownstreamPathTemplate": "/api/{version}/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "catalog.api",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/api/{version}/c/{everything}",
+ "UpstreamHttpMethod": [ "GET" ]
+ },
+ {
+ "DownstreamPathTemplate": "/api/{version}/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "basket.api",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/api/{version}/b/{everything}",
+ "UpstreamHttpMethod": [],
+ "AuthenticationOptions": {
+ "AuthenticationProviderKey": "IdentityApiKey",
+ "AllowedScopes": []
+ }
+ },
+ {
+ "DownstreamPathTemplate": "/api/{version}/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "ordering.api",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/api/{version}/o/{everything}",
+ "UpstreamHttpMethod": [],
+ "AuthenticationOptions": {
+ "AuthenticationProviderKey": "IdentityApiKey",
+ "AllowedScopes": []
+ }
+ },
+ {
+ "DownstreamPathTemplate": "/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "webshoppingagg",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/{everything}",
+ "UpstreamHttpMethod": [ "POST", "PUT", "GET" ],
+ "AuthenticationOptions": {
+ "AuthenticationProviderKey": "IdentityApiKey",
+ "AllowedScopes": []
+ }
+ },
+ {
+ "DownstreamPathTemplate": "/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "ordering.api",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/orders-api/{everything}",
+ "UpstreamHttpMethod": []
+ },
+ {
+ "DownstreamPathTemplate": "/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "ordering.signalrhub",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/hub/{everything}",
+ "UpstreamHttpMethod": []
+ },
+ {
+ "DownstreamPathTemplate": "/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "basket.api",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/basket-api/{everything}",
+ "UpstreamHttpMethod": []
+ },
+ {
+ "DownstreamPathTemplate": "/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "catalog.api",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/catalog-api/{everything}",
+ "UpstreamHttpMethod": []
+ },
+ {
+ "DownstreamPathTemplate": "/{everything}",
+ "DownstreamScheme": "http",
+ "DownstreamHostAndPorts": [
+ {
+ "Host": "payment.api",
+ "Port": 80
+ }
+ ],
+ "UpstreamPathTemplate": "/payment-api/{everything}",
+ "UpstreamHttpMethod": []
+ }
+
+ ],
+ "GlobalConfiguration": {
+ "RequestIdKey": "OcRequestId",
+ "AdministrationPath": "/administration"
+ }
+ }
+
\ No newline at end of file
diff --git a/src/Services/Basket/Basket.API/Basket.API.csproj b/src/Services/Basket/Basket.API/Basket.API.csproj
index d7ffa46b8..3bc5cee4c 100644
--- a/src/Services/Basket/Basket.API/Basket.API.csproj
+++ b/src/Services/Basket/Basket.API/Basket.API.csproj
@@ -15,7 +15,7 @@
-
+
diff --git a/src/Services/Basket/Basket.API/Controllers/BasketController.cs b/src/Services/Basket/Basket.API/Controllers/BasketController.cs
index 11ecac7c2..b604959b8 100644
--- a/src/Services/Basket/Basket.API/Controllers/BasketController.cs
+++ b/src/Services/Basket/Basket.API/Controllers/BasketController.cs
@@ -55,6 +55,8 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
public async Task Checkout([FromBody]BasketCheckout basketCheckout, [FromHeader(Name = "x-requestid")] string requestId)
{
var userId = _identitySvc.GetUserIdentity();
+ var userName = User.FindFirst(x => x.Type == "unique_name").Value;
+
basketCheckout.RequestId = (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) ?
guid : basketCheckout.RequestId;
@@ -65,7 +67,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
return BadRequest();
}
- var eventMessage = new UserCheckoutAcceptedIntegrationEvent(userId, basketCheckout.City, basketCheckout.Street,
+ var eventMessage = new UserCheckoutAcceptedIntegrationEvent(userId, userName, basketCheckout.City, basketCheckout.Street,
basketCheckout.State, basketCheckout.Country, basketCheckout.ZipCode, basketCheckout.CardNumber, basketCheckout.CardHolderName,
basketCheckout.CardExpiration, basketCheckout.CardSecurityNumber, basketCheckout.CardTypeId, basketCheckout.Buyer, basketCheckout.RequestId, basket);
diff --git a/src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs b/src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs
index e3665451c..18d522cf6 100644
--- a/src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs
+++ b/src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs
@@ -8,6 +8,8 @@ namespace Basket.API.IntegrationEvents.Events
{
public string UserId { get; }
+ public string UserName { get; }
+
public int OrderNumber { get; set; }
public string City { get; set; }
@@ -36,12 +38,13 @@ namespace Basket.API.IntegrationEvents.Events
public CustomerBasket Basket { get; }
- public UserCheckoutAcceptedIntegrationEvent(string userId, string city, string street,
+ public UserCheckoutAcceptedIntegrationEvent(string userId, string userName, string city, string street,
string state, string country, string zipCode, string cardNumber, string cardHolderName,
DateTime cardExpiration, string cardSecurityNumber, int cardTypeId, string buyer, Guid requestId,
CustomerBasket basket)
{
UserId = userId;
+ UserName = userName;
City = city;
Street = street;
State = state;
diff --git a/src/Services/Catalog/Catalog.API/Catalog.API.csproj b/src/Services/Catalog/Catalog.API/Catalog.API.csproj
index 55e7f8be5..ad36cf3b7 100644
--- a/src/Services/Catalog/Catalog.API/Catalog.API.csproj
+++ b/src/Services/Catalog/Catalog.API/Catalog.API.csproj
@@ -37,7 +37,7 @@
-
+
diff --git a/src/Services/Identity/Identity.API/Configuration/Config.cs b/src/Services/Identity/Identity.API/Configuration/Config.cs
index 969b86aa1..b780d420f 100644
--- a/src/Services/Identity/Identity.API/Configuration/Config.cs
+++ b/src/Services/Identity/Identity.API/Configuration/Config.cs
@@ -14,7 +14,10 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
new ApiResource("orders", "Orders Service"),
new ApiResource("basket", "Basket Service"),
new ApiResource("marketing", "Marketing Service"),
- new ApiResource("locations", "Locations Service")
+ new ApiResource("locations", "Locations Service"),
+ new ApiResource("mobileshoppingagg", "Mobile Shopping Aggregator"),
+ new ApiResource("webshoppingagg", "Web Shopping Aggregator"),
+ new ApiResource("orders.signalrhub", "Ordering Signalr Hub")
};
}
@@ -52,7 +55,9 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
"orders",
"basket",
"locations",
- "marketing"
+ "marketing",
+ "webshoppingagg",
+ "orders.signalrhub"
}
},
new Client
@@ -78,7 +83,8 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
"orders",
"basket",
"locations",
- "marketing"
+ "marketing",
+ "mobileshoppingagg"
},
//Allow requesting refresh tokens for long lived API access
AllowOfflineAccess = true,
@@ -114,7 +120,9 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
"orders",
"basket",
"locations",
- "marketing"
+ "marketing",
+ "webshoppingagg",
+ "orders.signalrhub"
},
},
new Client
@@ -146,7 +154,8 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
"orders",
"basket",
"locations",
- "marketing"
+ "marketing",
+ "webshoppingagg"
},
},
new Client
@@ -156,7 +165,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
- RedirectUris = { $"{clientsUrl["LocationsApi"]}/swagger/o2c.html" },
+ RedirectUris = { $"{clientsUrl["LocationsApi"]}/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { $"{clientsUrl["LocationsApi"]}/swagger/" },
AllowedScopes =
@@ -171,7 +180,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
- RedirectUris = { $"{clientsUrl["MarketingApi"]}/swagger/o2c.html" },
+ RedirectUris = { $"{clientsUrl["MarketingApi"]}/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { $"{clientsUrl["MarketingApi"]}/swagger/" },
AllowedScopes =
@@ -186,7 +195,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
- RedirectUris = { $"{clientsUrl["BasketApi"]}/swagger/o2c.html" },
+ RedirectUris = { $"{clientsUrl["BasketApi"]}/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { $"{clientsUrl["BasketApi"]}/swagger/" },
AllowedScopes =
@@ -201,14 +210,45 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
- RedirectUris = { $"{clientsUrl["OrderingApi"]}/swagger/o2c.html" },
+ RedirectUris = { $"{clientsUrl["OrderingApi"]}/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { $"{clientsUrl["OrderingApi"]}/swagger/" },
AllowedScopes =
{
"orders"
}
+ },
+ new Client
+ {
+ ClientId = "mobileshoppingaggswaggerui",
+ ClientName = "Mobile Shopping Aggregattor Swagger UI",
+ AllowedGrantTypes = GrantTypes.Implicit,
+ AllowAccessTokensViaBrowser = true,
+
+ RedirectUris = { $"{clientsUrl["MobileShoppingAgg"]}/swagger/oauth2-redirect.html" },
+ PostLogoutRedirectUris = { $"{clientsUrl["MobileShoppingAgg"]}/swagger/" },
+
+ AllowedScopes =
+ {
+ "mobileshoppingagg"
+ }
+ },
+ new Client
+ {
+ ClientId = "webshoppingaggswaggerui",
+ ClientName = "Web Shopping Aggregattor Swagger UI",
+ AllowedGrantTypes = GrantTypes.Implicit,
+ AllowAccessTokensViaBrowser = true,
+
+ RedirectUris = { $"{clientsUrl["WebShoppingAgg"]}/swagger/oauth2-redirect.html" },
+ PostLogoutRedirectUris = { $"{clientsUrl["WebShoppingAgg"]}/swagger/" },
+
+ AllowedScopes =
+ {
+ "webshoppingagg"
+ }
}
+
};
}
}
diff --git a/src/Services/Identity/Identity.API/Data/ConfigurationDbContextSeed.cs b/src/Services/Identity/Identity.API/Data/ConfigurationDbContextSeed.cs
index b109bf896..3547c053a 100644
--- a/src/Services/Identity/Identity.API/Data/ConfigurationDbContextSeed.cs
+++ b/src/Services/Identity/Identity.API/Data/ConfigurationDbContextSeed.cs
@@ -1,8 +1,10 @@
using IdentityServer4.EntityFramework.DbContexts;
+using IdentityServer4.EntityFramework.Entities;
using IdentityServer4.EntityFramework.Mappers;
-using Microsoft.eShopOnContainers.Services.Identity.API.Configuration;
using Microsoft.EntityFrameworkCore;
+using Microsoft.eShopOnContainers.Services.Identity.API.Configuration;
using Microsoft.Extensions.Configuration;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -11,36 +13,70 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Data
{
public class ConfigurationDbContextSeed
{
- public async Task SeedAsync(ConfigurationDbContext context, IConfiguration configuration)
+ public async Task SeedAsync(ConfigurationDbContext context,IConfiguration configuration)
{
+
//callbacks urls from config:
- var clientUrls = new Dictionary
- {
- {"Mvc", configuration.GetValue("MvcClient")},
- {"Spa", configuration.GetValue("SpaClient")},
- {"Xamarin", configuration.GetValue("XamarinCallback")},
- {"LocationsApi", configuration.GetValue("LocationApiClient")},
- {"MarketingApi", configuration.GetValue("MarketingApiClient")},
- {"BasketApi", configuration.GetValue("BasketApiClient")},
- {"OrderingApi", configuration.GetValue("OrderingApiClient")}
- };
+ var clientUrls = new Dictionary();
- if (!await context.Clients.AnyAsync())
+ clientUrls.Add("Mvc", configuration.GetValue("MvcClient"));
+ clientUrls.Add("Spa", configuration.GetValue("SpaClient"));
+ clientUrls.Add("Xamarin", configuration.GetValue("XamarinCallback"));
+ clientUrls.Add("LocationsApi", configuration.GetValue("LocationApiClient"));
+ clientUrls.Add("MarketingApi", configuration.GetValue("MarketingApiClient"));
+ clientUrls.Add("BasketApi", configuration.GetValue("BasketApiClient"));
+ clientUrls.Add("OrderingApi", configuration.GetValue("OrderingApiClient"));
+ clientUrls.Add("MobileShoppingAgg", configuration.GetValue("MobileShoppingAggClient"));
+ clientUrls.Add("WebShoppingAgg", configuration.GetValue("WebShoppingAggClient"));
+
+ if (!context.Clients.Any())
{
- context.Clients.AddRange(Config.GetClients(clientUrls).Select(client => client.ToEntity()));
+ foreach (var client in Config.GetClients(clientUrls))
+ {
+ context.Clients.Add(client.ToEntity());
+ }
+ await context.SaveChangesAsync();
}
-
- if (!await context.IdentityResources.AnyAsync())
+ // Checking always for old redirects to fix existing deployments
+ // to use new swagger-ui redirect uri as of v3.0.0
+ // There should be no problem for new ones
+ // ref: https://github.com/dotnet-architecture/eShopOnContainers/issues/586
+ else
{
- context.IdentityResources.AddRange(Config.GetResources().Select(resource => resource.ToEntity()));
+ List oldRedirects = (await context.Clients.Include(c => c.RedirectUris).ToListAsync())
+ .SelectMany(c => c.RedirectUris)
+ .Where(ru => ru.RedirectUri.EndsWith("/o2c.html"))
+ .ToList();
+
+ if (oldRedirects.Any())
+ {
+ foreach (var ru in oldRedirects)
+ {
+ ru.RedirectUri = ru.RedirectUri.Replace("/o2c.html", "/oauth2-redirect.html");
+ context.Update(ru.Client);
+ }
+ await context.SaveChangesAsync();
+ }
}
- if (!await context.ApiResources.AnyAsync())
+ if (!context.IdentityResources.Any())
{
- context.ApiResources.AddRange(Config.GetApis().Select(api => api.ToEntity()));
+ foreach (var resource in Config.GetResources())
+ {
+ context.IdentityResources.Add(resource.ToEntity());
+ }
+ await context.SaveChangesAsync();
}
- await context.SaveChangesAsync();
+ if (!context.ApiResources.Any())
+ {
+ foreach (var api in Config.GetApis())
+ {
+ context.ApiResources.Add(api.ToEntity());
+ }
+
+ await context.SaveChangesAsync();
+ }
}
}
}
diff --git a/src/Services/Identity/Identity.API/Identity.API.csproj b/src/Services/Identity/Identity.API/Identity.API.csproj
index 5a30673e6..84a87a231 100644
--- a/src/Services/Identity/Identity.API/Identity.API.csproj
+++ b/src/Services/Identity/Identity.API/Identity.API.csproj
@@ -17,7 +17,7 @@
-
+
diff --git a/src/Services/Identity/Identity.API/Services/ProfileService.cs b/src/Services/Identity/Identity.API/Services/ProfileService.cs
index 204ac3119..b7637fef2 100644
--- a/src/Services/Identity/Identity.API/Services/ProfileService.cs
+++ b/src/Services/Identity/Identity.API/Services/ProfileService.cs
@@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Identity;
using Microsoft.eShopOnContainers.Services.Identity.API.Models;
using System;
using System.Collections.Generic;
+using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
@@ -68,7 +69,8 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Services
var claims = new List
{
new Claim(JwtClaimTypes.Subject, user.Id),
- new Claim(JwtClaimTypes.PreferredUserName, user.UserName)
+ new Claim(JwtClaimTypes.PreferredUserName, user.UserName),
+ new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName)
};
if (!string.IsNullOrWhiteSpace(user.Name))
diff --git a/src/Services/Location/Locations.API/Locations.API.csproj b/src/Services/Location/Locations.API/Locations.API.csproj
index 13cb71821..aef0fe9e9 100644
--- a/src/Services/Location/Locations.API/Locations.API.csproj
+++ b/src/Services/Location/Locations.API/Locations.API.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/src/Services/Marketing/Marketing.API/Marketing.API.csproj b/src/Services/Marketing/Marketing.API/Marketing.API.csproj
index 3f07c3970..36da8fceb 100644
--- a/src/Services/Marketing/Marketing.API/Marketing.API.csproj
+++ b/src/Services/Marketing/Marketing.API/Marketing.API.csproj
@@ -23,7 +23,7 @@
-
+
diff --git a/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommand.cs b/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommand.cs
index 980f9d0b6..43f2c6072 100644
--- a/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommand.cs
+++ b/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommand.cs
@@ -26,6 +26,9 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
[DataMember]
public string UserId { get; private set; }
+ [DataMember]
+ public string UserName { get; private set; }
+
[DataMember]
public string City { get; private set; }
@@ -64,12 +67,13 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
_orderItems = new List();
}
- public CreateOrderCommand(List basketItems, string userId, string city, string street, string state, string country, string zipcode,
+ public CreateOrderCommand(List basketItems, string userId, string userName, string city, string street, string state, string country, string zipcode,
string cardNumber, string cardHolderName, DateTime cardExpiration,
string cardSecurityNumber, int cardTypeId) : this()
{
_orderItems = MapToOrderItems(basketItems);
UserId = userId;
+ UserName = userName;
City = city;
Street = street;
State = state;
diff --git a/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs b/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs
index c63f262fa..e5f154c0c 100644
--- a/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs
@@ -31,7 +31,7 @@
// methods and constructor so validations, invariants and business logic
// make sure that consistency is preserved across the whole aggregate
var address = new Address(message.Street, message.City, message.State, message.Country, message.ZipCode);
- var order = new Order(message.UserId, address, message.CardTypeId, message.CardNumber, message.CardSecurityNumber, message.CardHolderName, message.CardExpiration);
+ var order = new Order(message.UserId, message.UserName, address, message.CardTypeId, message.CardNumber, message.CardSecurityNumber, message.CardHolderName, message.CardExpiration);
foreach (var item in message.OrderItems)
{
diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderCancelled/OrderCancelledDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderCancelled/OrderCancelledDomainEventHandler.cs
new file mode 100644
index 000000000..24a8245d6
--- /dev/null
+++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderCancelled/OrderCancelledDomainEventHandler.cs
@@ -0,0 +1,46 @@
+using MediatR;
+using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
+using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
+using Microsoft.Extensions.Logging;
+using Ordering.API.Application.IntegrationEvents;
+using Ordering.API.Application.IntegrationEvents.Events;
+using Ordering.Domain.Events;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Ordering.API.Application.DomainEventHandlers.OrderCancelled
+{
+ public class OrderCancelledDomainEventHandler
+ : INotificationHandler
+ {
+ private readonly IOrderRepository _orderRepository;
+ private readonly IBuyerRepository _buyerRepository;
+ private readonly ILoggerFactory _logger;
+ private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
+
+ public OrderCancelledDomainEventHandler(
+ IOrderRepository orderRepository,
+ ILoggerFactory logger,
+ IBuyerRepository buyerRepository,
+ IOrderingIntegrationEventService orderingIntegrationEventService)
+ {
+ _orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ _buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository));
+ }
+
+ public async Task Handle(OrderCancelledDomainEvent orderCancelledDomainEvent, CancellationToken cancellationToken)
+ {
+ _logger.CreateLogger(nameof(OrderCancelledDomainEvent))
+ .LogTrace($"Order with Id: {orderCancelledDomainEvent.Order.Id} has been successfully updated with " +
+ $"a status order id: {OrderStatus.Shipped.Id}");
+
+ var order = await _orderRepository.GetAsync(orderCancelledDomainEvent.Order.Id);
+ var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
+
+ var orderStatusChangedToCancelledIntegrationEvent = new OrderStatusChangedToCancelledIntegrationEvent(order.Id, order.OrderStatus.Name, buyer.Name);
+ await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToCancelledIntegrationEvent);
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderGracePeriodConfirmed/OrderStatusChangedToAwaitingValidationDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderGracePeriodConfirmed/OrderStatusChangedToAwaitingValidationDomainEventHandler.cs
index a02d07232..60efead1b 100644
--- a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderGracePeriodConfirmed/OrderStatusChangedToAwaitingValidationDomainEventHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderGracePeriodConfirmed/OrderStatusChangedToAwaitingValidationDomainEventHandler.cs
@@ -1,30 +1,34 @@
namespace Ordering.API.Application.DomainEventHandlers.OrderGracePeriodConfirmed
{
+ using Domain.Events;
using MediatR;
+ using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using Microsoft.Extensions.Logging;
- using Domain.Events;
- using System;
- using System.Threading.Tasks;
using Ordering.API.Application.IntegrationEvents;
- using System.Linq;
using Ordering.API.Application.IntegrationEvents.Events;
+ using System;
+ using System.Linq;
using System.Threading;
+ using System.Threading.Tasks;
public class OrderStatusChangedToAwaitingValidationDomainEventHandler
: INotificationHandler
{
private readonly IOrderRepository _orderRepository;
private readonly ILoggerFactory _logger;
+ private readonly IBuyerRepository _buyerRepository;
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
public OrderStatusChangedToAwaitingValidationDomainEventHandler(
IOrderRepository orderRepository, ILoggerFactory logger,
+ IBuyerRepository buyerRepository,
IOrderingIntegrationEventService orderingIntegrationEventService)
{
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
- _orderingIntegrationEventService = orderingIntegrationEventService;
+ _buyerRepository = buyerRepository;
+ _orderingIntegrationEventService = orderingIntegrationEventService;
}
public async Task Handle(OrderStatusChangedToAwaitingValidationDomainEvent orderStatusChangedToAwaitingValidationDomainEvent, CancellationToken cancellationToken)
@@ -33,11 +37,15 @@
.LogTrace($"Order with Id: {orderStatusChangedToAwaitingValidationDomainEvent.OrderId} has been successfully updated with " +
$"a status order id: {OrderStatus.AwaitingValidation.Id}");
+ var order = await _orderRepository.GetAsync(orderStatusChangedToAwaitingValidationDomainEvent.OrderId);
+
+ var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
+
var orderStockList = orderStatusChangedToAwaitingValidationDomainEvent.OrderItems
.Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits()));
var orderStatusChangedToAwaitingValidationIntegrationEvent = new OrderStatusChangedToAwaitingValidationIntegrationEvent(
- orderStatusChangedToAwaitingValidationDomainEvent.OrderId, orderStockList);
+ order.Id, order.OrderStatus.Name, buyer.Name, orderStockList);
await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToAwaitingValidationIntegrationEvent);
}
}
diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderPaid/OrderStatusChangedToPaidDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderPaid/OrderStatusChangedToPaidDomainEventHandler.cs
index 071cd90fc..59c1e4708 100644
--- a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderPaid/OrderStatusChangedToPaidDomainEventHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderPaid/OrderStatusChangedToPaidDomainEventHandler.cs
@@ -1,30 +1,36 @@
namespace Ordering.API.Application.DomainEventHandlers.OrderPaid
{
+ using Domain.Events;
using MediatR;
+ using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using Microsoft.Extensions.Logging;
- using Domain.Events;
- using System;
- using System.Threading.Tasks;
using Ordering.API.Application.IntegrationEvents;
- using System.Linq;
using Ordering.API.Application.IntegrationEvents.Events;
+ using System;
+ using System.Linq;
using System.Threading;
+ using System.Threading.Tasks;
public class OrderStatusChangedToPaidDomainEventHandler
: INotificationHandler
{
private readonly IOrderRepository _orderRepository;
private readonly ILoggerFactory _logger;
+ private readonly IBuyerRepository _buyerRepository;
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
+
public OrderStatusChangedToPaidDomainEventHandler(
IOrderRepository orderRepository, ILoggerFactory logger,
- IOrderingIntegrationEventService orderingIntegrationEventService)
+ IBuyerRepository buyerRepository,
+ IOrderingIntegrationEventService orderingIntegrationEventService
+ )
{
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
- _orderingIntegrationEventService = orderingIntegrationEventService;
+ _buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository));
+ _orderingIntegrationEventService = orderingIntegrationEventService ?? throw new ArgumentNullException(nameof(orderingIntegrationEventService));
}
public async Task Handle(OrderStatusChangedToPaidDomainEvent orderStatusChangedToPaidDomainEvent, CancellationToken cancellationToken)
@@ -33,12 +39,19 @@
.LogTrace($"Order with Id: {orderStatusChangedToPaidDomainEvent.OrderId} has been successfully updated with " +
$"a status order id: {OrderStatus.Paid.Id}");
+ var order = await _orderRepository.GetAsync(orderStatusChangedToPaidDomainEvent.OrderId);
+ var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
+
var orderStockList = orderStatusChangedToPaidDomainEvent.OrderItems
.Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits()));
- var orderStatusChangedToPaidIntegrationEvent = new OrderStatusChangedToPaidIntegrationEvent(orderStatusChangedToPaidDomainEvent.OrderId,
+ var orderStatusChangedToPaidIntegrationEvent = new OrderStatusChangedToPaidIntegrationEvent(
+ orderStatusChangedToPaidDomainEvent.OrderId,
+ order.OrderStatus.Name,
+ buyer.Name,
orderStockList);
- await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToPaidIntegrationEvent);
+
+ await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToPaidIntegrationEvent);
}
}
}
\ No newline at end of file
diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderShipped/OrderShippedDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderShipped/OrderShippedDomainEventHandler.cs
new file mode 100644
index 000000000..0bf4cabcd
--- /dev/null
+++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderShipped/OrderShippedDomainEventHandler.cs
@@ -0,0 +1,47 @@
+using MediatR;
+using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
+using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
+using Microsoft.Extensions.Logging;
+using Ordering.API.Application.IntegrationEvents;
+using Ordering.API.Application.IntegrationEvents.Events;
+using Ordering.Domain.Events;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Ordering.API.Application.DomainEventHandlers.OrderShipped
+{
+ public class OrderShippedDomainEventHandler
+ : INotificationHandler
+ {
+ private readonly IOrderRepository _orderRepository;
+ private readonly IBuyerRepository _buyerRepository;
+ private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
+ private readonly ILoggerFactory _logger;
+
+ public OrderShippedDomainEventHandler(
+ IOrderRepository orderRepository,
+ ILoggerFactory logger,
+ IBuyerRepository buyerRepository,
+ IOrderingIntegrationEventService orderingIntegrationEventService)
+ {
+ _orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ _buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository));
+ _orderingIntegrationEventService = orderingIntegrationEventService;
+ }
+
+ public async Task Handle(OrderShippedDomainEvent orderShippedDomainEvent, CancellationToken cancellationToken)
+ {
+ _logger.CreateLogger(nameof(OrderShippedDomainEvent))
+ .LogTrace($"Order with Id: {orderShippedDomainEvent.Order.Id} has been successfully updated with " +
+ $"a status order id: {OrderStatus.Shipped.Id}");
+
+ var order = await _orderRepository.GetAsync(orderShippedDomainEvent.Order.Id);
+ var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
+
+ var orderStatusChangedToShippedIntegrationEvent = new OrderStatusChangedToShippedIntegrationEvent(order.Id, order.OrderStatus.Name, buyer.Name);
+ await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToShippedIntegrationEvent);
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStartedEvent/ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStartedEvent/ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler.cs
index d222c574c..0a8366893 100644
--- a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStartedEvent/ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStartedEvent/ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler.cs
@@ -1,7 +1,10 @@
using MediatR;
+using Microsoft.AspNetCore.Http;
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
using Microsoft.Extensions.Logging;
+using Ordering.API.Application.IntegrationEvents;
+using Ordering.API.Application.IntegrationEvents.Events;
using Ordering.Domain.Events;
using System;
using System.Threading;
@@ -15,23 +18,29 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent
private readonly ILoggerFactory _logger;
private readonly IBuyerRepository _buyerRepository;
private readonly IIdentityService _identityService;
+ private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
- public ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler(ILoggerFactory logger, IBuyerRepository buyerRepository, IIdentityService identityService)
+ public ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler(
+ ILoggerFactory logger,
+ IBuyerRepository buyerRepository,
+ IIdentityService identityService,
+ IOrderingIntegrationEventService orderingIntegrationEventService)
{
_buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository));
_identityService = identityService ?? throw new ArgumentNullException(nameof(identityService));
+ _orderingIntegrationEventService = orderingIntegrationEventService ?? throw new ArgumentNullException(nameof(orderingIntegrationEventService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task Handle(OrderStartedDomainEvent orderStartedEvent, CancellationToken cancellationToken)
- {
+ {
var cardTypeId = (orderStartedEvent.CardTypeId != 0) ? orderStartedEvent.CardTypeId : 1;
var buyer = await _buyerRepository.FindAsync(orderStartedEvent.UserId);
bool buyerOriginallyExisted = (buyer == null) ? false : true;
if (!buyerOriginallyExisted)
{
- buyer = new Buyer(orderStartedEvent.UserId);
+ buyer = new Buyer(orderStartedEvent.UserId, orderStartedEvent.UserName);
}
buyer.VerifyOrAddPaymentMethod(cardTypeId,
@@ -42,11 +51,16 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent
orderStartedEvent.CardExpiration,
orderStartedEvent.Order.Id);
- var buyerUpdated = buyerOriginallyExisted ? _buyerRepository.Update(buyer) : _buyerRepository.Add(buyer);
+ var buyerUpdated = buyerOriginallyExisted ?
+ _buyerRepository.Update(buyer) :
+ _buyerRepository.Add(buyer);
await _buyerRepository.UnitOfWork
.SaveEntitiesAsync();
+ var orderStatusChangedTosubmittedIntegrationEvent = new OrderStatusChangedToSubmittedIntegrationEvent(orderStartedEvent.Order.Id, orderStartedEvent.Order.OrderStatus.Name, buyer.Name);
+ await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedTosubmittedIntegrationEvent);
+
_logger.CreateLogger(nameof(ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler)).LogTrace($"Buyer {buyerUpdated.Id} and related payment method were validated or updated for orderId: {orderStartedEvent.Order.Id}.");
}
}
diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmed/OrderStatusChangedToStockConfirmedDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmed/OrderStatusChangedToStockConfirmedDomainEventHandler.cs
index 3b24e43e6..910d764cf 100644
--- a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmed/OrderStatusChangedToStockConfirmedDomainEventHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmed/OrderStatusChangedToStockConfirmedDomainEventHandler.cs
@@ -1,27 +1,32 @@
namespace Ordering.API.Application.DomainEventHandlers.OrderStockConfirmed
{
+ using Domain.Events;
using MediatR;
+ using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using Microsoft.Extensions.Logging;
- using Domain.Events;
- using System;
- using System.Threading.Tasks;
using Ordering.API.Application.IntegrationEvents;
using Ordering.API.Application.IntegrationEvents.Events;
+ using System;
using System.Threading;
+ using System.Threading.Tasks;
public class OrderStatusChangedToStockConfirmedDomainEventHandler
: INotificationHandler
{
private readonly IOrderRepository _orderRepository;
+ private readonly IBuyerRepository _buyerRepository;
private readonly ILoggerFactory _logger;
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
public OrderStatusChangedToStockConfirmedDomainEventHandler(
- IOrderRepository orderRepository, ILoggerFactory logger,
+ IOrderRepository orderRepository,
+ IBuyerRepository buyerRepository,
+ ILoggerFactory logger,
IOrderingIntegrationEventService orderingIntegrationEventService)
{
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
+ _buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_orderingIntegrationEventService = orderingIntegrationEventService;
}
@@ -32,8 +37,11 @@
.LogTrace($"Order with Id: {orderStatusChangedToStockConfirmedDomainEvent.OrderId} has been successfully updated with " +
$"a status order id: {OrderStatus.StockConfirmed.Id}");
- var orderStatusChangedToStockConfirmedIntegrationEvent = new OrderStatusChangedToStockConfirmedIntegrationEvent(orderStatusChangedToStockConfirmedDomainEvent.OrderId);
- await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToStockConfirmedIntegrationEvent);
+ var order = await _orderRepository.GetAsync(orderStatusChangedToStockConfirmedDomainEvent.OrderId);
+ var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
+
+ var orderStatusChangedToStockConfirmedIntegrationEvent = new OrderStatusChangedToStockConfirmedIntegrationEvent(order.Id, order.OrderStatus.Name, buyer.Name);
+ await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToStockConfirmedIntegrationEvent);
}
}
}
\ No newline at end of file
diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSuccededIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSuccededIntegrationEventHandler.cs
index 0e8598dcc..1dbe59e10 100644
--- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSuccededIntegrationEventHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSuccededIntegrationEventHandler.cs
@@ -17,6 +17,9 @@
public async Task Handle(OrderPaymentSuccededIntegrationEvent @event)
{
+ // Simulate a work time for validating the payment
+ await Task.Delay(10000);
+
var orderToUpdate = await _orderRepository.GetAsync(@event.OrderId);
orderToUpdate.SetPaidStatus();
diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs
index fa7463041..c08554066 100644
--- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs
@@ -17,6 +17,9 @@
public async Task Handle(OrderStockConfirmedIntegrationEvent @event)
{
+ // Simulate a work time for confirming the stock
+ await Task.Delay(10000);
+
var orderToUpdate = await _orderRepository.GetAsync(@event.OrderId);
orderToUpdate.SetStockConfirmedStatus();
diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs
index e2beff9f3..f46c5683c 100644
--- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs
@@ -41,7 +41,7 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling
if (eventMsg.RequestId != Guid.Empty)
{
- var createOrderCommand = new CreateOrderCommand(eventMsg.Basket.Items, eventMsg.UserId, eventMsg.City, eventMsg.Street,
+ var createOrderCommand = new CreateOrderCommand(eventMsg.Basket.Items, eventMsg.UserId, eventMsg.UserName, eventMsg.City, eventMsg.Street,
eventMsg.State, eventMsg.Country, eventMsg.ZipCode,
eventMsg.CardNumber, eventMsg.CardHolderName, eventMsg.CardExpiration,
eventMsg.CardSecurityNumber, eventMsg.CardTypeId);
diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToAwaitingValidationIntegrationEvent.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToAwaitingValidationIntegrationEvent.cs
index 63ae02246..a104215af 100644
--- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToAwaitingValidationIntegrationEvent.cs
+++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToAwaitingValidationIntegrationEvent.cs
@@ -6,13 +6,17 @@
public class OrderStatusChangedToAwaitingValidationIntegrationEvent : IntegrationEvent
{
public int OrderId { get; }
+ public string OrderStatus { get; }
+ public string BuyerName { get; }
public IEnumerable OrderStockItems { get; }
- public OrderStatusChangedToAwaitingValidationIntegrationEvent(int orderId,
+ public OrderStatusChangedToAwaitingValidationIntegrationEvent(int orderId, string orderStatus, string buyerName,
IEnumerable orderStockItems)
{
OrderId = orderId;
OrderStockItems = orderStockItems;
+ OrderStatus = orderStatus;
+ BuyerName = buyerName;
}
}
diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToCancelledIntegrationEvent.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToCancelledIntegrationEvent.cs
new file mode 100644
index 000000000..6ff92a1d3
--- /dev/null
+++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToCancelledIntegrationEvent.cs
@@ -0,0 +1,22 @@
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Ordering.API.Application.IntegrationEvents.Events
+{
+ public class OrderStatusChangedToCancelledIntegrationEvent : IntegrationEvent
+ {
+ public int OrderId { get; }
+ public string OrderStatus { get; }
+ public string BuyerName { get; }
+
+ public OrderStatusChangedToCancelledIntegrationEvent(int orderId, string orderStatus, string buyerName)
+ {
+ OrderId = orderId;
+ OrderStatus = orderStatus;
+ BuyerName = buyerName;
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToPaidIntegrationEvent.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToPaidIntegrationEvent.cs
index 115592308..6bcbc3494 100644
--- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToPaidIntegrationEvent.cs
+++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToPaidIntegrationEvent.cs
@@ -6,13 +6,19 @@
public class OrderStatusChangedToPaidIntegrationEvent : IntegrationEvent
{
public int OrderId { get; }
+ public string OrderStatus { get; }
+ public string BuyerName { get; }
public IEnumerable OrderStockItems { get; }
public OrderStatusChangedToPaidIntegrationEvent(int orderId,
+ string orderStatus,
+ string buyerName,
IEnumerable orderStockItems)
{
OrderId = orderId;
OrderStockItems = orderStockItems;
+ OrderStatus = orderStatus;
+ BuyerName = buyerName;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToShippedIntegrationEvent.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToShippedIntegrationEvent.cs
new file mode 100644
index 000000000..1753fcc78
--- /dev/null
+++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToShippedIntegrationEvent.cs
@@ -0,0 +1,22 @@
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Ordering.API.Application.IntegrationEvents.Events
+{
+ public class OrderStatusChangedToShippedIntegrationEvent : IntegrationEvent
+ {
+ public int OrderId { get; }
+ public string OrderStatus { get; }
+ public string BuyerName { get; }
+
+ public OrderStatusChangedToShippedIntegrationEvent(int orderId, string orderStatus, string buyerName)
+ {
+ OrderId = orderId;
+ OrderStatus = orderStatus;
+ BuyerName = buyerName;
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToStockConfirmedIntegrationEvent.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToStockConfirmedIntegrationEvent.cs
index d0b1ef2c4..24e51f55b 100644
--- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToStockConfirmedIntegrationEvent.cs
+++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToStockConfirmedIntegrationEvent.cs
@@ -5,8 +5,14 @@
public class OrderStatusChangedToStockConfirmedIntegrationEvent : IntegrationEvent
{
public int OrderId { get; }
+ public string OrderStatus { get; }
+ public string BuyerName { get; }
- public OrderStatusChangedToStockConfirmedIntegrationEvent(int orderId)
- => OrderId = orderId;
+ public OrderStatusChangedToStockConfirmedIntegrationEvent(int orderId, string orderStatus, string buyerName)
+ {
+ OrderId = orderId;
+ OrderStatus = orderStatus;
+ BuyerName = buyerName;
+ }
}
}
\ No newline at end of file
diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedTosubmittedIntegrationEvent.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedTosubmittedIntegrationEvent.cs
new file mode 100644
index 000000000..816c8bddf
--- /dev/null
+++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedTosubmittedIntegrationEvent.cs
@@ -0,0 +1,22 @@
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Ordering.API.Application.IntegrationEvents.Events
+{
+ public class OrderStatusChangedToSubmittedIntegrationEvent : IntegrationEvent
+ {
+ public int OrderId { get; }
+ public string OrderStatus { get; }
+ public string BuyerName { get; }
+
+ public OrderStatusChangedToSubmittedIntegrationEvent(int orderId, string orderStatus, string buyerName)
+ {
+ OrderId = orderId;
+ OrderStatus = orderStatus;
+ BuyerName = buyerName;
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs
index c23e59332..2cb49aae0 100644
--- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs
+++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs
@@ -8,6 +8,8 @@ namespace Ordering.API.Application.IntegrationEvents.Events
{
public string UserId { get; }
+ public string UserName { get; }
+
public string City { get; set; }
public string Street { get; set; }
@@ -34,7 +36,7 @@ namespace Ordering.API.Application.IntegrationEvents.Events
public CustomerBasket Basket { get; }
- public UserCheckoutAcceptedIntegrationEvent(string userId, string city, string street,
+ public UserCheckoutAcceptedIntegrationEvent(string userId, string userName, string city, string street,
string state, string country, string zipCode, string cardNumber, string cardHolderName,
DateTime cardExpiration, string cardSecurityNumber, int cardTypeId, string buyer, Guid requestId,
CustomerBasket basket)
@@ -53,6 +55,7 @@ namespace Ordering.API.Application.IntegrationEvents.Events
Buyer = buyer;
Basket = basket;
RequestId = requestId;
+ UserName = userName;
}
}
diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20180412143935_NamePropertyInBuyer.Designer.cs b/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20180412143935_NamePropertyInBuyer.Designer.cs
new file mode 100644
index 000000000..2a035f5e0
--- /dev/null
+++ b/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20180412143935_NamePropertyInBuyer.Designer.cs
@@ -0,0 +1,238 @@
+//
+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.Infrastructure.Migrations
+{
+ [DbContext(typeof(OrderingContext))]
+ [Migration("20180412143935_NamePropertyInBuyer")]
+ partial class NamePropertyInBuyer
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "2.0.1-rtm-125")
+ .HasAnnotation("Relational:Sequence:.orderitemseq", "'orderitemseq', '', '1', '10', '', '', 'Int64', 'False'")
+ .HasAnnotation("Relational:Sequence:ordering.buyerseq", "'buyerseq', 'ordering', '1', '10', '', '', 'Int64', 'False'")
+ .HasAnnotation("Relational:Sequence:ordering.orderseq", "'orderseq', 'ordering', '1', '10', '', '', 'Int64', 'False'")
+ .HasAnnotation("Relational:Sequence:ordering.paymentseq", "'paymentseq', 'ordering', '1', '10', '', '', 'Int64', 'False'")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasAnnotation("SqlServer:HiLoSequenceName", "buyerseq")
+ .HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
+
+ b.Property("IdentityGuid")
+ .IsRequired()
+ .HasMaxLength(200);
+
+ b.Property("Name");
+
+ b.HasKey("Id");
+
+ b.HasIndex("IdentityGuid")
+ .IsUnique();
+
+ b.ToTable("buyers","ordering");
+ });
+
+ modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.CardType", b =>
+ {
+ b.Property("Id")
+ .HasDefaultValue(1);
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(200);
+
+ b.HasKey("Id");
+
+ b.ToTable("cardtypes","ordering");
+ });
+
+ modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasAnnotation("SqlServer:HiLoSequenceName", "paymentseq")
+ .HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
+
+ b.Property("Alias")
+ .IsRequired()
+ .HasMaxLength(200);
+
+ b.Property("BuyerId");
+
+ b.Property("CardHolderName")
+ .IsRequired()
+ .HasMaxLength(200);
+
+ b.Property("CardNumber")
+ .IsRequired()
+ .HasMaxLength(25);
+
+ b.Property("CardTypeId");
+
+ b.Property("Expiration");
+
+ b.HasKey("Id");
+
+ b.HasIndex("BuyerId");
+
+ b.HasIndex("CardTypeId");
+
+ b.ToTable("paymentmethods","ordering");
+ });
+
+ modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasAnnotation("SqlServer:HiLoSequenceName", "orderseq")
+ .HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
+
+ b.Property("BuyerId");
+
+ b.Property("Description");
+
+ b.Property("OrderDate");
+
+ b.Property("OrderStatusId");
+
+ b.Property("PaymentMethodId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("BuyerId");
+
+ b.HasIndex("OrderStatusId");
+
+ b.HasIndex("PaymentMethodId");
+
+ b.ToTable("orders","ordering");
+ });
+
+ modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderItem", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasAnnotation("SqlServer:HiLoSequenceName", "orderitemseq")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
+
+ b.Property("Discount");
+
+ b.Property("OrderId");
+
+ b.Property("PictureUrl");
+
+ b.Property("ProductId");
+
+ b.Property("ProductName")
+ .IsRequired();
+
+ b.Property("UnitPrice");
+
+ b.Property("Units");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OrderId");
+
+ b.ToTable("orderItems","ordering");
+ });
+
+ modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderStatus", b =>
+ {
+ b.Property("Id")
+ .HasDefaultValue(1);
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(200);
+
+ b.HasKey("Id");
+
+ b.ToTable("orderstatus","ordering");
+ });
+
+ modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency.ClientRequest", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Name")
+ .IsRequired();
+
+ b.Property("Time");
+
+ b.HasKey("Id");
+
+ b.ToTable("requests","ordering");
+ });
+
+ modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", b =>
+ {
+ b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer")
+ .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);
+
+ b.OwnsOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", "Address", b1 =>
+ {
+ b1.Property("OrderId");
+
+ b1.ToTable("orders","ordering");
+
+ b1.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order")
+ .WithOne("Address")
+ .HasForeignKey("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", "OrderId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+ });
+
+ 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);
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20180412143935_NamePropertyInBuyer.cs b/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20180412143935_NamePropertyInBuyer.cs
new file mode 100644
index 000000000..7a2637384
--- /dev/null
+++ b/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20180412143935_NamePropertyInBuyer.cs
@@ -0,0 +1,86 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+using System;
+using System.Collections.Generic;
+
+namespace Ordering.API.Infrastructure.Migrations
+{
+ public partial class NamePropertyInBuyer : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropForeignKey(
+ name: "FK_orderItems_orders_OrderId",
+ schema: "ordering",
+ table: "orderItems");
+
+ migrationBuilder.AddColumn(
+ name: "Name",
+ schema: "ordering",
+ table: "buyers",
+ nullable: true);
+
+ migrationBuilder.AddForeignKey(
+ name: "FK_orderItems_orders_OrderId",
+ schema: "ordering",
+ table: "orderItems",
+ column: "OrderId",
+ principalSchema: "ordering",
+ principalTable: "orders",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropForeignKey(
+ name: "FK_orderItems_orders_OrderId",
+ schema: "ordering",
+ table: "orderItems");
+
+ migrationBuilder.DropColumn(
+ name: "Name",
+ schema: "ordering",
+ table: "buyers");
+
+ migrationBuilder.AddColumn(
+ name: "City",
+ schema: "ordering",
+ table: "orders",
+ nullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "Country",
+ schema: "ordering",
+ table: "orders",
+ nullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "State",
+ schema: "ordering",
+ table: "orders",
+ nullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "Street",
+ schema: "ordering",
+ table: "orders",
+ nullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "ZipCode",
+ schema: "ordering",
+ table: "orders",
+ nullable: true);
+
+ migrationBuilder.AddForeignKey(
+ name: "FK_orderItems_orders_OrderId",
+ schema: "ordering",
+ table: "orderItems",
+ column: "OrderId",
+ principalSchema: "ordering",
+ principalTable: "orders",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/OrderingContextModelSnapshot.cs b/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/OrderingContextModelSnapshot.cs
index 9e455568d..fc5e0d1da 100644
--- a/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/OrderingContextModelSnapshot.cs
+++ b/src/Services/Ordering/Ordering.API/Infrastructure/Migrations/OrderingContextModelSnapshot.cs
@@ -17,7 +17,7 @@ namespace Ordering.API.Migrations
{
#pragma warning disable 612, 618
modelBuilder
- .HasAnnotation("ProductVersion", "2.0.0-preview2-25794")
+ .HasAnnotation("ProductVersion", "2.0.1-rtm-125")
.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'")
@@ -36,6 +36,8 @@ namespace Ordering.API.Migrations
.IsRequired()
.HasMaxLength(200);
+ b.Property("Name");
+
b.HasKey("Id");
b.HasIndex("IdentityGuid")
@@ -180,25 +182,6 @@ 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")
@@ -227,6 +210,18 @@ namespace Ordering.API.Migrations
.WithMany()
.HasForeignKey("PaymentMethodId")
.OnDelete(DeleteBehavior.Restrict);
+
+ b.OwnsOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", "Address", b1 =>
+ {
+ b1.Property("OrderId");
+
+ b1.ToTable("orders","ordering");
+
+ b1.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order")
+ .WithOne("Address")
+ .HasForeignKey("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", "OrderId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
});
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderItem", b =>
@@ -236,14 +231,6 @@ 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/Services/IIdentityService.cs b/src/Services/Ordering/Ordering.API/Infrastructure/Services/IIdentityService.cs
index 4864234dc..dedf7b34f 100644
--- a/src/Services/Ordering/Ordering.API/Infrastructure/Services/IIdentityService.cs
+++ b/src/Services/Ordering/Ordering.API/Infrastructure/Services/IIdentityService.cs
@@ -8,5 +8,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Servi
public interface IIdentityService
{
string GetUserIdentity();
+
+ string GetUserName();
}
}
diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/Services/IdentityService.cs b/src/Services/Ordering/Ordering.API/Infrastructure/Services/IdentityService.cs
index 48975b6c1..f152e290c 100644
--- a/src/Services/Ordering/Ordering.API/Infrastructure/Services/IdentityService.cs
+++ b/src/Services/Ordering/Ordering.API/Infrastructure/Services/IdentityService.cs
@@ -20,5 +20,10 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Servi
{
return _context.HttpContext.User.FindFirst("sub").Value;
}
+
+ public string GetUserName()
+ {
+ return _context.HttpContext.User.Identity.Name;
+ }
}
}
diff --git a/src/Services/Ordering/Ordering.API/Ordering.API.csproj b/src/Services/Ordering/Ordering.API/Ordering.API.csproj
index c1ee1f57c..c95cff6e1 100644
--- a/src/Services/Ordering/Ordering.API/Ordering.API.csproj
+++ b/src/Services/Ordering/Ordering.API/Ordering.API.csproj
@@ -35,7 +35,7 @@
-
+
diff --git a/src/Services/Ordering/Ordering.API/Startup.cs b/src/Services/Ordering/Ordering.API/Startup.cs
index bf715c235..2948a3997 100644
--- a/src/Services/Ordering/Ordering.API/Startup.cs
+++ b/src/Services/Ordering/Ordering.API/Startup.cs
@@ -26,7 +26,6 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.HealthChecks;
- using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Ordering.Infrastructure;
using RabbitMQ.Client;
@@ -199,7 +198,7 @@
}
- public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
+ public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
@@ -220,6 +219,7 @@
app.UseCors("CorsPolicy");
ConfigureAuth(app);
+
app.UseMvcWithDefaultRoute();
app.UseSwagger()
@@ -266,7 +266,7 @@
private void ConfigureAuthService(IServiceCollection services)
{
// prevent from mapping "sub" claim to nameidentifier.
- JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
+ JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");
var identityUrl = Configuration.GetValue("IdentityUrl");
@@ -279,7 +279,7 @@
{
options.Authority = identityUrl;
options.RequireHttpsMetadata = false;
- options.Audience = "orders";
+ options.Audience = "orders";
});
}
diff --git a/src/Services/Ordering/Ordering.API/settings.json b/src/Services/Ordering/Ordering.API/settings.json
index 77ed2e4dc..679cd23f4 100644
--- a/src/Services/Ordering/Ordering.API/settings.json
+++ b/src/Services/Ordering/Ordering.API/settings.json
@@ -17,5 +17,6 @@
"ApplicationInsights": {
"InstrumentationKey": ""
},
- "EventBusRetryCount": 5
+ "EventBusRetryCount": 5,
+ "EventBusConnection": "localhost"
}
diff --git a/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/Buyer.cs b/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/Buyer.cs
index c806cebeb..2fd52917e 100644
--- a/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/Buyer.cs
+++ b/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/Buyer.cs
@@ -11,6 +11,8 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.B
{
public string IdentityGuid { get; private set; }
+ public string Name { get; private set; }
+
private List _paymentMethods;
public IEnumerable PaymentMethods => _paymentMethods.AsReadOnly();
@@ -20,9 +22,10 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.B
_paymentMethods = new List();
}
- public Buyer(string identity) : this()
+ public Buyer(string identity, string name) : this()
{
IdentityGuid = !string.IsNullOrWhiteSpace(identity) ? identity : throw new ArgumentNullException(nameof(identity));
+ Name = !string.IsNullOrWhiteSpace(name) ? name : throw new ArgumentNullException(nameof(name));
}
public PaymentMethod VerifyOrAddPaymentMethod(
diff --git a/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/IBuyerRepository.cs b/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/IBuyerRepository.cs
index d5a612614..197f725f6 100644
--- a/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/IBuyerRepository.cs
+++ b/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/IBuyerRepository.cs
@@ -11,5 +11,6 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.B
Buyer Add(Buyer buyer);
Buyer Update(Buyer buyer);
Task FindAsync(string BuyerIdentityGuid);
+ Task FindByIdAsync(string id);
}
}
diff --git a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs
index 428d97580..99b3154d8 100644
--- a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs
+++ b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs
@@ -18,6 +18,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
// Address is a Value Object pattern example persisted as EF Core 2.0 owned entity
public Address Address { get; private set; }
+ public int? GetBuyerId => _buyerId;
private int? _buyerId;
public OrderStatus OrderStatus { get; private set; }
@@ -25,6 +26,10 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
private string _description;
+
+ // Draft orders have this set to true. Currently we don't check anywhere the draft status of an Order, but we could do it if needed
+ private bool _isDraft;
+
// DDD Patterns comment
// Using a private collection field, better for DDD Aggregate's encapsulation
// so OrderItems cannot be added from "outside the AggregateRoot" directly to the collection,
@@ -34,12 +39,21 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
private int? _paymentMethodId;
- protected Order() { _orderItems = new List(); }
-
- public Order(string userId, Address address, int cardTypeId, string cardNumber, string cardSecurityNumber,
- string cardHolderName, DateTime cardExpiration, int? buyerId = null, int? paymentMethodId = null)
+ public static Order NewDraft()
{
+ var order = new Order();
+ order._isDraft = true;
+ return order;
+ }
+
+ protected Order() {
_orderItems = new List();
+ _isDraft = false;
+ }
+
+ public Order(string userId, string userName, Address address, int cardTypeId, string cardNumber, string cardSecurityNumber,
+ string cardHolderName, DateTime cardExpiration, int? buyerId = null, int? paymentMethodId = null) : this()
+ {
_buyerId = buyerId;
_paymentMethodId = paymentMethodId;
_orderStatusId = OrderStatus.Submitted.Id;
@@ -48,7 +62,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
// Add the OrderStarterDomainEvent to the domain events collection
// to be raised/dispatched when comitting changes into the Database [ After DbContext.SaveChanges() ]
- AddOrderStartedDomainEvent(userId, cardTypeId, cardNumber,
+ AddOrderStartedDomainEvent(userId, userName, cardTypeId, cardNumber,
cardSecurityNumber, cardHolderName, cardExpiration);
}
@@ -92,35 +106,34 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
}
public void SetAwaitingValidationStatus()
- {
+ {
if (_orderStatusId == OrderStatus.Submitted.Id)
{
- _orderStatusId = OrderStatus.AwaitingValidation.Id;
-
AddDomainEvent(new OrderStatusChangedToAwaitingValidationDomainEvent(Id, _orderItems));
- }
+ _orderStatusId = OrderStatus.AwaitingValidation.Id;
+ }
}
public void SetStockConfirmedStatus()
{
if (_orderStatusId == OrderStatus.AwaitingValidation.Id)
{
+ AddDomainEvent(new OrderStatusChangedToStockConfirmedDomainEvent(Id));
+
_orderStatusId = OrderStatus.StockConfirmed.Id;
_description = "All the items were confirmed with available stock.";
-
- AddDomainEvent(new OrderStatusChangedToStockConfirmedDomainEvent(Id));
- }
+ }
}
public void SetPaidStatus()
{
if (_orderStatusId == OrderStatus.StockConfirmed.Id)
{
+ AddDomainEvent(new OrderStatusChangedToPaidDomainEvent(Id, OrderItems));
+
_orderStatusId = OrderStatus.Paid.Id;
_description = "The payment was performed at a simulated \"American Bank checking bank account endinf on XX35071\"";
-
- AddDomainEvent(new OrderStatusChangedToPaidDomainEvent(Id, OrderItems));
- }
+ }
}
public void SetShippedStatus()
@@ -132,6 +145,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
_orderStatusId = OrderStatus.Shipped.Id;
_description = "The order was shipped.";
+ AddDomainEvent(new OrderShippedDomainEvent(this));
}
public void SetCancelledStatus()
@@ -144,6 +158,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
_orderStatusId = OrderStatus.Cancelled.Id;
_description = $"The order was cancelled.";
+ AddDomainEvent(new OrderCancelledDomainEvent(this));
}
public void SetCancelledStatusWhenStockIsRejected(IEnumerable orderStockRejectedItems)
@@ -158,13 +173,13 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
var itemsStockRejectedDescription = string.Join(", ", itemsStockRejectedProductNames);
_description = $"The product items don't have stock: ({itemsStockRejectedDescription}).";
- }
+ }
}
- private void AddOrderStartedDomainEvent(string userId, int cardTypeId, string cardNumber,
+ private void AddOrderStartedDomainEvent(string userId, string userName, int cardTypeId, string cardNumber,
string cardSecurityNumber, string cardHolderName, DateTime cardExpiration)
{
- var orderStartedDomainEvent = new OrderStartedDomainEvent(this, userId, cardTypeId,
+ var orderStartedDomainEvent = new OrderStartedDomainEvent(this, userId, userName, cardTypeId,
cardNumber, cardSecurityNumber,
cardHolderName, cardExpiration);
diff --git a/src/Services/Ordering/Ordering.Domain/Events/OrderCancelledDomainEvent.cs b/src/Services/Ordering/Ordering.Domain/Events/OrderCancelledDomainEvent.cs
new file mode 100644
index 000000000..2e53c82c1
--- /dev/null
+++ b/src/Services/Ordering/Ordering.Domain/Events/OrderCancelledDomainEvent.cs
@@ -0,0 +1,18 @@
+using MediatR;
+using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Ordering.Domain.Events
+{
+ public class OrderCancelledDomainEvent : INotification
+ {
+ public Order Order { get; }
+
+ public OrderCancelledDomainEvent(Order order)
+ {
+ Order = order;
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.Domain/Events/OrderShippedDomainEvent.cs b/src/Services/Ordering/Ordering.Domain/Events/OrderShippedDomainEvent.cs
new file mode 100644
index 000000000..cad23ecfe
--- /dev/null
+++ b/src/Services/Ordering/Ordering.Domain/Events/OrderShippedDomainEvent.cs
@@ -0,0 +1,15 @@
+using MediatR;
+using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
+
+namespace Ordering.Domain.Events
+{
+ public class OrderShippedDomainEvent : INotification
+ {
+ public Order Order { get; }
+
+ public OrderShippedDomainEvent(Order order)
+ {
+ Order = order;
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.Domain/Events/OrderStartedDomainEvent.cs b/src/Services/Ordering/Ordering.Domain/Events/OrderStartedDomainEvent.cs
index 1b47ae901..3ab95b3f2 100644
--- a/src/Services/Ordering/Ordering.Domain/Events/OrderStartedDomainEvent.cs
+++ b/src/Services/Ordering/Ordering.Domain/Events/OrderStartedDomainEvent.cs
@@ -12,6 +12,7 @@ namespace Ordering.Domain.Events
public class OrderStartedDomainEvent : INotification
{
public string UserId { get; }
+ public string UserName { get; }
public int CardTypeId { get; }
public string CardNumber { get; }
public string CardSecurityNumber { get; }
@@ -19,13 +20,14 @@ namespace Ordering.Domain.Events
public DateTime CardExpiration { get; }
public Order Order { get; }
- public OrderStartedDomainEvent(Order order, string userId,
+ public OrderStartedDomainEvent(Order order, string userId, string userName,
int cardTypeId, string cardNumber,
string cardSecurityNumber, string cardHolderName,
DateTime cardExpiration)
{
Order = order;
UserId = userId;
+ UserName = userName;
CardTypeId = cardTypeId;
CardNumber = cardNumber;
CardSecurityNumber = cardSecurityNumber;
diff --git a/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/BuyerEntityTYpeConfiguration.cs b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/BuyerEntityTYpeConfiguration.cs
index 177f68d91..fde29b265 100644
--- a/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/BuyerEntityTYpeConfiguration.cs
+++ b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/BuyerEntityTYpeConfiguration.cs
@@ -26,6 +26,8 @@ namespace Ordering.Infrastructure.EntityConfigurations
buyerConfiguration.HasIndex("IdentityGuid")
.IsUnique(true);
+ buyerConfiguration.Property(b => b.Name);
+
buyerConfiguration.HasMany(b => b.PaymentMethods)
.WithOne()
.HasForeignKey("BuyerId")
diff --git a/src/Services/Ordering/Ordering.Infrastructure/Repositories/BuyerRepository.cs b/src/Services/Ordering/Ordering.Infrastructure/Repositories/BuyerRepository.cs
index efc478092..e879c423b 100644
--- a/src/Services/Ordering/Ordering.Infrastructure/Repositories/BuyerRepository.cs
+++ b/src/Services/Ordering/Ordering.Infrastructure/Repositories/BuyerRepository.cs
@@ -54,5 +54,15 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositor
return buyer;
}
+
+ public async Task FindByIdAsync(string id)
+ {
+ var buyer = await _context.Buyers
+ .Include(b => b.PaymentMethods)
+ .Where(b => b.Id == int.Parse(id))
+ .SingleOrDefaultAsync();
+
+ return buyer;
+ }
}
}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/AutofacModules/ApplicationModule.cs b/src/Services/Ordering/Ordering.SignalrHub/AutofacModules/ApplicationModule.cs
new file mode 100644
index 000000000..030d3b8b5
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/AutofacModules/ApplicationModule.cs
@@ -0,0 +1,30 @@
+using Autofac;
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
+using Ordering.SignalrHub.IntegrationEvents;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+
+namespace Ordering.SignalrHub.AutofacModules
+{
+ public class ApplicationModule
+ : Autofac.Module
+ {
+
+ public string QueriesConnectionString { get; }
+
+ public ApplicationModule()
+ {
+ }
+
+ protected override void Load(ContainerBuilder builder)
+ {
+
+ builder.RegisterAssemblyTypes(typeof(OrderStatusChangedToAwaitingValidationIntegrationEvent).GetTypeInfo().Assembly)
+ .AsClosedTypesOf(typeof(IIntegrationEventHandler<>));
+
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/Dockerfile b/src/Services/Ordering/Ordering.SignalrHub/Dockerfile
new file mode 100644
index 000000000..005eea8cf
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/Dockerfile
@@ -0,0 +1,20 @@
+FROM microsoft/aspnetcore:2.0 AS base
+WORKDIR /app
+EXPOSE 80
+
+FROM microsoft/aspnetcore-build:2.0 AS build
+WORKDIR /src
+COPY eShopOnContainers-ServicesAndWebApps.sln ./
+COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/
+RUN dotnet restore -nowarn:msb3202,nu1503
+COPY . .
+WORKDIR /src/src/Services/Ordering/Ordering.SignalrHub
+RUN dotnet build Ordering.SignalrHub.csproj -c Release -o /app
+
+FROM build AS publish
+RUN dotnet publish Ordering.SignalrHub.csproj -c Release -o /app
+
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app .
+ENTRYPOINT ["dotnet", "Ordering.SignalrHub.dll"]
diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToCancelledIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToCancelledIntegrationEventHandler.cs
new file mode 100644
index 000000000..171eb81f7
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToCancelledIntegrationEventHandler.cs
@@ -0,0 +1,28 @@
+using Microsoft.AspNetCore.SignalR;
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
+using Ordering.SignalrHub.IntegrationEvents.Events;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Ordering.SignalrHub.IntegrationEvents.EventHandling
+{
+ public class OrderStatusChangedToCancelledIntegrationEventHandler : IIntegrationEventHandler
+ {
+ private readonly IHubContext _hubContext;
+
+ public OrderStatusChangedToCancelledIntegrationEventHandler(IHubContext hubContext)
+ {
+ _hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
+ }
+
+
+ public async Task Handle(OrderStatusChangedToCancelledIntegrationEvent @event)
+ {
+ await _hubContext.Clients
+ .Group(@event.BuyerName)
+ .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs
new file mode 100644
index 000000000..4b0eb780c
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs
@@ -0,0 +1,26 @@
+using Microsoft.AspNetCore.SignalR;
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
+using Ordering.SignalrHub.IntegrationEvents.Events;
+using System;
+using System.Threading.Tasks;
+
+namespace Ordering.SignalrHub.IntegrationEvents.EventHandling
+{
+ public class OrderStatusChangedToPaidIntegrationEventHandler : IIntegrationEventHandler
+ {
+ private readonly IHubContext _hubContext;
+
+ public OrderStatusChangedToPaidIntegrationEventHandler(IHubContext hubContext)
+ {
+ _hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
+ }
+
+
+ public async Task Handle(OrderStatusChangedToPaidIntegrationEvent @event)
+ {
+ await _hubContext.Clients
+ .Group(@event.BuyerName)
+ .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToShippedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToShippedIntegrationEventHandler.cs
new file mode 100644
index 000000000..7a19a0659
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToShippedIntegrationEventHandler.cs
@@ -0,0 +1,28 @@
+using Microsoft.AspNetCore.SignalR;
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
+using Ordering.SignalrHub.IntegrationEvents.Events;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Ordering.SignalrHub.IntegrationEvents.EventHandling
+{
+ public class OrderStatusChangedToShippedIntegrationEventHandler : IIntegrationEventHandler
+ {
+ private readonly IHubContext _hubContext;
+
+ public OrderStatusChangedToShippedIntegrationEventHandler(IHubContext hubContext)
+ {
+ _hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
+ }
+
+
+ public async Task Handle(OrderStatusChangedToShippedIntegrationEvent @event)
+ {
+ await _hubContext.Clients
+ .Group(@event.BuyerName)
+ .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs
new file mode 100644
index 000000000..324ea6259
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs
@@ -0,0 +1,29 @@
+using Microsoft.AspNetCore.SignalR;
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
+using Ordering.SignalrHub.IntegrationEvents.Events;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Ordering.SignalrHub.IntegrationEvents.EventHandling
+{
+ public class OrderStatusChangedToStockConfirmedIntegrationEventHandler :
+ IIntegrationEventHandler
+ {
+ private readonly IHubContext _hubContext;
+
+ public OrderStatusChangedToStockConfirmedIntegrationEventHandler(IHubContext hubContext)
+ {
+ _hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
+ }
+
+
+ public async Task Handle(OrderStatusChangedToStockConfirmedIntegrationEvent @event)
+ {
+ await _hubContext.Clients
+ .Group(@event.BuyerName)
+ .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToSubmittedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToSubmittedIntegrationEventHandler.cs
new file mode 100644
index 000000000..5fac4c1da
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToSubmittedIntegrationEventHandler.cs
@@ -0,0 +1,29 @@
+using Microsoft.AspNetCore.SignalR;
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
+using Ordering.SignalrHub.IntegrationEvents.Events;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Ordering.SignalrHub.IntegrationEvents.EventHandling
+{
+ public class OrderStatusChangedToSubmittedIntegrationEventHandler :
+ IIntegrationEventHandler
+ {
+ private readonly IHubContext _hubContext;
+
+ public OrderStatusChangedToSubmittedIntegrationEventHandler(IHubContext hubContext)
+ {
+ _hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
+ }
+
+
+ public async Task Handle(OrderStatusChangedToSubmittedIntegrationEvent @event)
+ {
+ await _hubContext.Clients
+ .Group(@event.BuyerName)
+ .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/orderStatusChangedToAwaitingValidationIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/orderStatusChangedToAwaitingValidationIntegrationEventHandler.cs
new file mode 100644
index 000000000..6c2733b77
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/orderStatusChangedToAwaitingValidationIntegrationEventHandler.cs
@@ -0,0 +1,27 @@
+using Microsoft.AspNetCore.SignalR;
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Ordering.SignalrHub.IntegrationEvents
+{
+ public class OrderStatusChangedToAwaitingValidationIntegrationEventHandler : IIntegrationEventHandler
+ {
+ private readonly IHubContext _hubContext;
+
+ public OrderStatusChangedToAwaitingValidationIntegrationEventHandler(IHubContext hubContext)
+ {
+ _hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
+ }
+
+
+ public async Task Handle(OrderStatusChangedToAwaitingValidationIntegrationEvent @event)
+ {
+ await _hubContext.Clients
+ .Group(@event.BuyerName)
+ .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToAwaitingValidationIntegrationEvent.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToAwaitingValidationIntegrationEvent.cs
new file mode 100644
index 000000000..2c5ecee27
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToAwaitingValidationIntegrationEvent.cs
@@ -0,0 +1,19 @@
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
+using System.Collections.Generic;
+
+namespace Ordering.SignalrHub.IntegrationEvents
+{
+ public class OrderStatusChangedToAwaitingValidationIntegrationEvent : IntegrationEvent
+ {
+ public int OrderId { get; }
+ public string OrderStatus { get; }
+ public string BuyerName { get; }
+
+ public OrderStatusChangedToAwaitingValidationIntegrationEvent(int orderId, string orderStatus, string buyerName)
+ {
+ OrderId = orderId;
+ OrderStatus = orderStatus;
+ BuyerName = buyerName;
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToCancelledIntegrationEvent.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToCancelledIntegrationEvent.cs
new file mode 100644
index 000000000..e9ac5b39b
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToCancelledIntegrationEvent.cs
@@ -0,0 +1,22 @@
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Ordering.SignalrHub.IntegrationEvents.Events
+{
+ public class OrderStatusChangedToCancelledIntegrationEvent : IntegrationEvent
+ {
+ public int OrderId { get; }
+ public string OrderStatus { get; }
+ public string BuyerName { get; }
+
+ public OrderStatusChangedToCancelledIntegrationEvent(int orderId, string orderStatus, string buyerName)
+ {
+ OrderId = orderId;
+ OrderStatus = orderStatus;
+ BuyerName = buyerName;
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToPaidIntegrationEvent.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToPaidIntegrationEvent.cs
new file mode 100644
index 000000000..beb49965d
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToPaidIntegrationEvent.cs
@@ -0,0 +1,23 @@
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Ordering.SignalrHub.IntegrationEvents.Events
+{
+ public class OrderStatusChangedToPaidIntegrationEvent : IntegrationEvent
+ {
+ public int OrderId { get; }
+ public string OrderStatus { get; }
+ public string BuyerName { get; }
+
+ public OrderStatusChangedToPaidIntegrationEvent(int orderId,
+ string orderStatus, string buyerName)
+ {
+ OrderId = orderId;
+ OrderStatus = orderStatus;
+ BuyerName = buyerName;
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToShippedIntegrationEvent.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToShippedIntegrationEvent.cs
new file mode 100644
index 000000000..0768c7f4e
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToShippedIntegrationEvent.cs
@@ -0,0 +1,22 @@
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Ordering.SignalrHub.IntegrationEvents.Events
+{
+ public class OrderStatusChangedToShippedIntegrationEvent : IntegrationEvent
+ {
+ public int OrderId { get; }
+ public string OrderStatus { get; }
+ public string BuyerName { get; }
+
+ public OrderStatusChangedToShippedIntegrationEvent(int orderId, string orderStatus, string buyerName)
+ {
+ OrderId = orderId;
+ OrderStatus = orderStatus;
+ BuyerName = buyerName;
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToStockConfirmedIntegrationEvent.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToStockConfirmedIntegrationEvent.cs
new file mode 100644
index 000000000..588505c8f
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToStockConfirmedIntegrationEvent.cs
@@ -0,0 +1,18 @@
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
+
+namespace Ordering.SignalrHub.IntegrationEvents.Events
+{
+ public class OrderStatusChangedToStockConfirmedIntegrationEvent : IntegrationEvent
+ {
+ public int OrderId { get; }
+ public string OrderStatus { get; }
+ public string BuyerName { get; }
+
+ public OrderStatusChangedToStockConfirmedIntegrationEvent(int orderId, string orderStatus, string buyerName)
+ {
+ OrderId = orderId;
+ OrderStatus = orderStatus;
+ BuyerName = buyerName;
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToSubmittedIntegrationEvent.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToSubmittedIntegrationEvent.cs
new file mode 100644
index 000000000..5ea0cec71
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToSubmittedIntegrationEvent.cs
@@ -0,0 +1,22 @@
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Ordering.SignalrHub.IntegrationEvents.Events
+{
+ public class OrderStatusChangedToSubmittedIntegrationEvent : IntegrationEvent
+ {
+ public int OrderId { get; }
+ public string OrderStatus { get; }
+ public string BuyerName { get; }
+
+ public OrderStatusChangedToSubmittedIntegrationEvent(int orderId, string orderStatus, string buyerName)
+ {
+ OrderId = orderId;
+ OrderStatus = orderStatus;
+ BuyerName = buyerName;
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/NotificationHub.cs b/src/Services/Ordering/Ordering.SignalrHub/NotificationHub.cs
new file mode 100644
index 000000000..8a4c1c90f
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/NotificationHub.cs
@@ -0,0 +1,26 @@
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.SignalR;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Ordering.SignalrHub
+{
+ [Authorize]
+ public class NotificationsHub : Hub
+ {
+
+ public override async Task OnConnectedAsync()
+ {
+ await Groups.AddAsync(Context.ConnectionId, Context.User.Identity.Name);
+ await base.OnConnectedAsync();
+ }
+
+ public override async Task OnDisconnectedAsync(Exception ex)
+ {
+ await Groups.RemoveAsync(Context.ConnectionId, Context.User.Identity.Name);
+ await base.OnDisconnectedAsync(ex);
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj b/src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj
new file mode 100644
index 000000000..8b8aa5832
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj
@@ -0,0 +1,26 @@
+
+
+
+ netcoreapp2.0
+ ..\..\..\..\docker-compose.dcproj
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Services/Ordering/Ordering.SignalrHub/Program.cs b/src/Services/Ordering/Ordering.SignalrHub/Program.cs
new file mode 100644
index 000000000..6598e5504
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/Program.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+
+namespace Ordering.SignalrHub
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ BuildWebHost(args).Run();
+ }
+
+ public static IWebHost BuildWebHost(string[] args) =>
+ WebHost.CreateDefaultBuilder(args)
+ .UseStartup()
+ .Build();
+ }
+}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/Properties/launchSettings.json b/src/Services/Ordering/Ordering.SignalrHub/Properties/launchSettings.json
new file mode 100644
index 000000000..3ff683a08
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/Properties/launchSettings.json
@@ -0,0 +1,27 @@
+{
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:51311/",
+ "sslPort": 0
+ }
+ },
+ "profiles": {
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "Ordering.SignalrHub": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "applicationUrl": "http://localhost:51312/"
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/Startup.cs b/src/Services/Ordering/Ordering.SignalrHub/Startup.cs
new file mode 100644
index 000000000..b2bc2346a
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/Startup.cs
@@ -0,0 +1,214 @@
+using Autofac;
+using Autofac.Extensions.DependencyInjection;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.AspNetCore.Builder;
+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 Ordering.SignalrHub.AutofacModules;
+using Ordering.SignalrHub.IntegrationEvents;
+using Ordering.SignalrHub.IntegrationEvents.EventHandling;
+using Ordering.SignalrHub.IntegrationEvents.Events;
+using RabbitMQ.Client;
+using StackExchange.Redis;
+using System;
+using System.IdentityModel.Tokens.Jwt;
+
+namespace Ordering.SignalrHub
+{
+ public class Startup
+ {
+ public Startup(IConfiguration configuration)
+ {
+ Configuration = configuration;
+ }
+
+ // 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 https://go.microsoft.com/fwlink/?LinkID=398940
+ public IServiceProvider ConfigureServices(IServiceCollection services)
+ {
+ services.AddCors(options =>
+ {
+ options.AddPolicy("CorsPolicy",
+ builder => builder.AllowAnyOrigin()
+ .AllowAnyMethod()
+ .AllowAnyHeader()
+ .AllowCredentials());
+ });
+
+ if (Configuration.GetValue("IsClusterEnv") == bool.TrueString)
+ {
+ services
+ .AddSignalR()
+ .AddRedis(Configuration["SignalrStoreConnectionString"]);
+ }
+ else
+ {
+ services.AddSignalR();
+ }
+
+ 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"]
+ };
+
+ if (!string.IsNullOrEmpty(Configuration["EventBusUserName"]))
+ {
+ factory.UserName = Configuration["EventBusUserName"];
+ }
+
+ if (!string.IsNullOrEmpty(Configuration["EventBusPassword"]))
+ {
+ factory.Password = Configuration["EventBusPassword"];
+ }
+
+ var retryCount = 5;
+ if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
+ {
+ retryCount = int.Parse(Configuration["EventBusRetryCount"]);
+ }
+
+ return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount);
+ });
+ }
+
+ ConfigureAuthService(services);
+
+ RegisterEventBus(services);
+
+ services.AddOptions();
+
+ //configure autofac
+ var container = new ContainerBuilder();
+ container.RegisterModule(new ApplicationModule());
+ container.Populate(services);
+
+ return new AutofacServiceProvider(container.Build());
+ }
+
+ public IConfiguration Configuration { get; }
+
+ // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+ public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
+ {
+ loggerFactory.AddConsole(Configuration.GetSection("Logging"));
+ loggerFactory.AddDebug();
+ loggerFactory.AddAzureWebAppDiagnostics();
+ loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
+
+ var pathBase = Configuration["PATH_BASE"];
+ if (!string.IsNullOrEmpty(pathBase))
+ {
+ loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
+ app.UsePathBase(pathBase);
+ }
+
+ app.UseCors("CorsPolicy");
+
+ app.UseAuthentication();
+
+ app.UseSignalR(routes =>
+ {
+ routes.MapHub("/notificationhub", options =>
+ options.Transports = Microsoft.AspNetCore.Http.Connections.TransportType.All);
+ });
+
+ ConfigureEventBus(app);
+ }
+
+ private void ConfigureEventBus(IApplicationBuilder app)
+ {
+ var eventBus = app.ApplicationServices.GetRequiredService();
+
+ eventBus.Subscribe();
+ eventBus.Subscribe();
+ eventBus.Subscribe();
+ eventBus.Subscribe();
+ eventBus.Subscribe();
+ eventBus.Subscribe();
+ }
+
+ private void ConfigureAuthService(IServiceCollection services)
+ {
+ // prevent from mapping "sub" claim to nameidentifier.
+ JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");
+
+ var identityUrl = Configuration.GetValue("IdentityUrl");
+
+ services.AddAuthentication(options =>
+ {
+ options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
+ options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
+
+ }).AddJwtBearer(options =>
+ {
+ options.Authority = identityUrl;
+ options.RequireHttpsMetadata = false;
+ options.Audience = "orders.signalrhub";
+ });
+ }
+
+ private void RegisterEventBus(IServiceCollection services)
+ {
+ var subscriptionClientName = Configuration["SubscriptionClientName"];
+
+ if (Configuration.GetValue("AzureServiceBusEnabled"))
+ {
+ services.AddSingleton(sp =>
+ {
+ var serviceBusPersisterConnection = sp.GetRequiredService();
+ var iLifetimeScope = sp.GetRequiredService();
+ var logger = sp.GetRequiredService>();
+ var eventBusSubcriptionsManager = sp.GetRequiredService();
+
+ return new EventBusServiceBus(serviceBusPersisterConnection, logger,
+ eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope);
+ });
+ }
+ else
+ {
+ services.AddSingleton(sp =>
+ {
+ var rabbitMQPersistentConnection = sp.GetRequiredService();
+ var iLifetimeScope = sp.GetRequiredService();
+ var logger = sp.GetRequiredService>();
+ var eventBusSubcriptionsManager = sp.GetRequiredService();
+
+ var retryCount = 5;
+ if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
+ {
+ retryCount = int.Parse(Configuration["EventBusRetryCount"]);
+ }
+
+ return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
+ });
+ }
+
+ services.AddSingleton();
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/appsettings.json b/src/Services/Ordering/Ordering.SignalrHub/appsettings.json
new file mode 100644
index 000000000..ab02fda0f
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/appsettings.json
@@ -0,0 +1,15 @@
+{
+ "IdentityUrl": "http://localhost:5105",
+ "Logging": {
+ "IncludeScopes": false,
+ "LogLevel": {
+ "Default": "Trace",
+ "System": "Information",
+ "Microsoft": "Information"
+ }
+ },
+ "AzureServiceBusEnabled": false,
+ "SubscriptionClientName": "Ordering.signalrhub",
+ "EventBusRetryCount": 5,
+ "EventBusConnection": "localhost"
+}
\ 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 e7e4fc739..278dcc6cb 100644
--- a/src/Services/Payment/Payment.API/Payment.API.csproj
+++ b/src/Services/Payment/Payment.API/Payment.API.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/src/Web/WebMVC/AppSettings.cs b/src/Web/WebMVC/AppSettings.cs
index 42100ab62..30403aa9d 100644
--- a/src/Web/WebMVC/AppSettings.cs
+++ b/src/Web/WebMVC/AppSettings.cs
@@ -8,11 +8,10 @@ namespace Microsoft.eShopOnContainers.WebMVC
public class AppSettings
{
public Connectionstrings ConnectionStrings { get; set; }
- public string CatalogUrl { get; set; }
- public string OrderingUrl { get; set; }
- public string BasketUrl { get; set; }
public string MarketingUrl { get; set; }
- public string LocationsUrl { get; set; }
+
+ public string PurchaseUrl { get; set; }
+ public string SignalrHubUrl { get; set; }
public bool ActivateCampaignDetailFunction { get; set; }
public Logging Logging { get; set; }
public bool UseCustomizationData { get; set; }
diff --git a/src/Web/WebMVC/Startup.cs b/src/Web/WebMVC/Startup.cs
index 105b1ed9e..a83bfa644 100644
--- a/src/Web/WebMVC/Startup.cs
+++ b/src/Web/WebMVC/Startup.cs
@@ -130,6 +130,8 @@ namespace Microsoft.eShopOnContainers.WebMVC
options.Scope.Add("basket");
options.Scope.Add("marketing");
options.Scope.Add("locations");
+ options.Scope.Add("webshoppingagg");
+ options.Scope.Add("orders.signalrhub");
});
}
diff --git a/src/Web/WebMVC/Views/Order/Index.cshtml b/src/Web/WebMVC/Views/Order/Index.cshtml
index dcb1f2a08..524219922 100644
--- a/src/Web/WebMVC/Views/Order/Index.cshtml
+++ b/src/Web/WebMVC/Views/Order/Index.cshtml
@@ -8,9 +8,9 @@
@Html.Partial("_Header", new List
-
+
+
+
+
diff --git a/src/Web/WebMVC/Views/Shared/_Layout.cshtml b/src/Web/WebMVC/Views/Shared/_Layout.cshtml
index ee01b5b65..5d616afaf 100644
--- a/src/Web/WebMVC/Views/Shared/_Layout.cshtml
+++ b/src/Web/WebMVC/Views/Shared/_Layout.cshtml
@@ -20,6 +20,8 @@
+
+
@RenderSection("scripts", required: false)
+
+
+ @using Microsoft.AspNetCore.Authentication;
+ @using Microsoft.Extensions.Options
+ @inject IOptions settings
+
+