Browse Source

Merge branch 'dev' of https://github.com/dotnet-architecture/eShopOnContainers into dev

# Conflicts:
#	eShopOnContainers-ServicesAndWebApps.sln
#	k8s/deployments.yaml
#	k8s/gen-k8s-env-aks.ps1
#	k8s/internalurls.yaml
#	k8s/ocelot/configuration-web-shopping.json
#	src/ApiGateways/ApiGw-Base/Program.cs
#	src/ApiGateways/Mobile.Bff.Shopping/apigw/configuration.json
#	src/ApiGateways/Web.Bff.Shopping/apigw/configuration.json
#	src/Services/Identity/Identity.API/Configuration/Config.cs
#	src/Services/Identity/Identity.API/Data/ConfigurationDbContextSeed.cs
#	src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs
#	src/Web/WebMVC/AppSettings.cs
#	src/Web/WebMVC/Startup.cs
#	src/Web/WebSPA/AppSettings.cs
#	src/Web/WebSPA/Client/modules/shared/models/configuration.model.ts
#	src/Web/WebSPA/Client/modules/shared/services/configuration.service.ts
#	src/Web/WebSPA/Client/modules/shared/services/security.service.ts
pull/616/head
ddrsql 6 years ago
parent
commit
91103a4a01
129 changed files with 10159 additions and 622 deletions
  1. +2
    -0
      .dockerignore
  2. +2
    -0
      .gitignore
  3. +4
    -6
      README.md
  4. +37
    -0
      build/acr-build/queue-all.ps1
  5. +10
    -0
      docker-compose-windows.yml
  6. +0
    -19
      docker-compose.ci.build.yml
  7. +0
    -1
      docker-compose.dcproj
  8. +5
    -0
      docker-compose.override.windows.yml
  9. +39
    -2
      docker-compose.override.yml
  10. +20
    -0
      docker-compose.prod.yml
  11. +15
    -0
      docker-compose.yml
  12. +285
    -51
      eShopOnContainers-ServicesAndWebApps.sln
  13. +3
    -3
      global.json
  14. +11
    -4
      k8s/README.k8s.md
  15. +72
    -0
      k8s/build-push-images.ps1
  16. +0
    -0
      k8s/conf_cloud.yaml
  17. +0
    -0
      k8s/conf_local.yaml
  18. +12
    -2
      k8s/deploy.ps1
  19. +309
    -287
      k8s/deployments.yaml
  20. +12
    -11
      k8s/gen-k8s-env-aks.ps1
  21. +33
    -0
      k8s/internalurls.yaml
  22. +154
    -0
      k8s/ocelot/configuration-web-shopping.json
  23. +17
    -3
      k8s/services.yaml
  24. +11
    -0
      package-lock.json
  25. +31
    -0
      src/ApiGateways/ApiGw-Base/Program.cs
  26. +118
    -0
      src/ApiGateways/Mobile.Bff.Shopping/apigw/configuration.json
  27. +130
    -0
      src/ApiGateways/Web.Bff.Shopping/apigw/configuration.json
  28. +1
    -1
      src/Services/Basket/Basket.API/Basket.API.csproj
  29. +3
    -1
      src/Services/Basket/Basket.API/Controllers/BasketController.cs
  30. +4
    -1
      src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs
  31. +1
    -1
      src/Services/Catalog/Catalog.API/Catalog.API.csproj
  32. +49
    -9
      src/Services/Identity/Identity.API/Configuration/Config.cs
  33. +56
    -20
      src/Services/Identity/Identity.API/Data/ConfigurationDbContextSeed.cs
  34. +1
    -1
      src/Services/Identity/Identity.API/Identity.API.csproj
  35. +3
    -1
      src/Services/Identity/Identity.API/Services/ProfileService.cs
  36. +1
    -1
      src/Services/Location/Locations.API/Locations.API.csproj
  37. +1
    -1
      src/Services/Marketing/Marketing.API/Marketing.API.csproj
  38. +5
    -1
      src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommand.cs
  39. +1
    -1
      src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs
  40. +46
    -0
      src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderCancelled/OrderCancelledDomainEventHandler.cs
  41. +14
    -6
      src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderGracePeriodConfirmed/OrderStatusChangedToAwaitingValidationDomainEventHandler.cs
  42. +21
    -8
      src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderPaid/OrderStatusChangedToPaidDomainEventHandler.cs
  43. +47
    -0
      src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderShipped/OrderShippedDomainEventHandler.cs
  44. +18
    -4
      src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStartedEvent/ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler.cs
  45. +14
    -6
      src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmed/OrderStatusChangedToStockConfirmedDomainEventHandler.cs
  46. +3
    -0
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSuccededIntegrationEventHandler.cs
  47. +3
    -0
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs
  48. +1
    -1
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs
  49. +5
    -1
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToAwaitingValidationIntegrationEvent.cs
  50. +22
    -0
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToCancelledIntegrationEvent.cs
  51. +7
    -1
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToPaidIntegrationEvent.cs
  52. +22
    -0
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToShippedIntegrationEvent.cs
  53. +8
    -2
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToStockConfirmedIntegrationEvent.cs
  54. +22
    -0
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedTosubmittedIntegrationEvent.cs
  55. +4
    -1
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs
  56. +238
    -0
      src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20180412143935_NamePropertyInBuyer.Designer.cs
  57. +86
    -0
      src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20180412143935_NamePropertyInBuyer.cs
  58. +15
    -28
      src/Services/Ordering/Ordering.API/Infrastructure/Migrations/OrderingContextModelSnapshot.cs
  59. +2
    -0
      src/Services/Ordering/Ordering.API/Infrastructure/Services/IIdentityService.cs
  60. +5
    -0
      src/Services/Ordering/Ordering.API/Infrastructure/Services/IdentityService.cs
  61. +1
    -1
      src/Services/Ordering/Ordering.API/Ordering.API.csproj
  62. +4
    -4
      src/Services/Ordering/Ordering.API/Startup.cs
  63. +2
    -1
      src/Services/Ordering/Ordering.API/settings.json
  64. +4
    -1
      src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/Buyer.cs
  65. +1
    -0
      src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/IBuyerRepository.cs
  66. +33
    -18
      src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs
  67. +18
    -0
      src/Services/Ordering/Ordering.Domain/Events/OrderCancelledDomainEvent.cs
  68. +15
    -0
      src/Services/Ordering/Ordering.Domain/Events/OrderShippedDomainEvent.cs
  69. +3
    -1
      src/Services/Ordering/Ordering.Domain/Events/OrderStartedDomainEvent.cs
  70. +2
    -0
      src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/BuyerEntityTYpeConfiguration.cs
  71. +10
    -0
      src/Services/Ordering/Ordering.Infrastructure/Repositories/BuyerRepository.cs
  72. +30
    -0
      src/Services/Ordering/Ordering.SignalrHub/AutofacModules/ApplicationModule.cs
  73. +20
    -0
      src/Services/Ordering/Ordering.SignalrHub/Dockerfile
  74. +28
    -0
      src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToCancelledIntegrationEventHandler.cs
  75. +26
    -0
      src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs
  76. +28
    -0
      src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToShippedIntegrationEventHandler.cs
  77. +29
    -0
      src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs
  78. +29
    -0
      src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToSubmittedIntegrationEventHandler.cs
  79. +27
    -0
      src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/orderStatusChangedToAwaitingValidationIntegrationEventHandler.cs
  80. +19
    -0
      src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToAwaitingValidationIntegrationEvent.cs
  81. +22
    -0
      src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToCancelledIntegrationEvent.cs
  82. +23
    -0
      src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToPaidIntegrationEvent.cs
  83. +22
    -0
      src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToShippedIntegrationEvent.cs
  84. +18
    -0
      src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToStockConfirmedIntegrationEvent.cs
  85. +22
    -0
      src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToSubmittedIntegrationEvent.cs
  86. +26
    -0
      src/Services/Ordering/Ordering.SignalrHub/NotificationHub.cs
  87. +26
    -0
      src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj
  88. +25
    -0
      src/Services/Ordering/Ordering.SignalrHub/Program.cs
  89. +27
    -0
      src/Services/Ordering/Ordering.SignalrHub/Properties/launchSettings.json
  90. +214
    -0
      src/Services/Ordering/Ordering.SignalrHub/Startup.cs
  91. +15
    -0
      src/Services/Ordering/Ordering.SignalrHub/appsettings.json
  92. +1
    -1
      src/Services/Payment/Payment.API/Payment.API.csproj
  93. +3
    -4
      src/Web/WebMVC/AppSettings.cs
  94. +2
    -0
      src/Web/WebMVC/Startup.cs
  95. +26
    -27
      src/Web/WebMVC/Views/Order/Index.cshtml
  96. +51
    -0
      src/Web/WebMVC/Views/Shared/_Layout.cshtml
  97. +2
    -1
      src/Web/WebMVC/WebMVC.csproj
  98. +14
    -0
      src/Web/WebMVC/bundleconfig.json
  99. +26
    -0
      src/Web/WebMVC/package-lock.json
  100. +10
    -0
      src/Web/WebMVC/package.json

+ 2
- 0
.dockerignore View File

@ -28,5 +28,7 @@ cli-linux
**/node_modules/
**/bower_components/
**/wwwroot/lib/
!**/wwwroot/lib/signalr/*
!**/wwwroot/lib/toastr/*
global.json
src/Web/WebSPA/wwwroot/

+ 2
- 0
.gitignore View File

@ -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*/


+ 4
- 6
README.md View File

@ -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.
> <p>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.
> <p>
> <img src="img/exploring-to-production-ready.png">
![image](https://user-images.githubusercontent.com/1712635/40397331-059a7ec6-5de7-11e8-8542-a597eca16fef.png)
> Read the planned <a href='https://github.com/dotnet/eShopOnContainers/wiki/01.-Roadmap-and-Milestones-for-future-releases'>Roadmap and Milestones for future releases of eShopOnContainers</a> within the Wiki for further info about possible new implementations and provide feedback at the <a href='https://github.com/dotnet/eShopOnContainers/issues'>ISSUES section</a> if you'd like to see any specific scenario implemented or improved. Also, feel free to discuss on any current issue.
### Architecture overview


+ 37
- 0
build/acr-build/queue-all.ps1 View File

@ -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

+ 10
- 0
docker-compose-windows.yml View File

@ -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:


+ 0
- 19
docker-compose.ci.build.yml View File

@ -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"

+ 0
- 1
docker-compose.dcproj View File

@ -10,7 +10,6 @@
</PropertyGroup>
<ItemGroup>
<None Include=".dockerignore" />
<None Include="docker-compose.ci.build.yml" />
<None Include="docker-compose.override.yml">
<DependentUpon>docker-compose.yml</DependentUpon>
</None>


+ 5
- 0
docker-compose.override.windows.yml View File

@ -54,5 +54,10 @@ services:
locations.api:
environment:
- EventBusUserName=admin
- EventBusPassword=password
ordering.signalrhub:
environment:
- EventBusUserName=admin
- EventBusPassword=password

+ 39
- 2
docker-compose.override.yml View File

@ -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).
# 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"

+ 20
- 0
docker-compose.prod.yml View File

@ -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


+ 15
- 0
docker-compose.yml View File

@ -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

+ 285
- 51
eShopOnContainers-ServicesAndWebApps.sln View File

@ -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}


+ 3
- 3
global.json View File

@ -1,5 +1,5 @@
{
"sdk": {
"version":"2.1.2"
}
"sdk": {
"version": "2.1.4"
}
}

+ 11
- 4
k8s/README.k8s.md View File

@ -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`.


+ 72
- 0
k8s/build-push-images.ps1 View File

@ -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
}
}

k8s/conf_cloud.yml → k8s/conf_cloud.yaml View File


k8s/conf_local.yml → k8s/conf_local.yaml View File


+ 12
- 2
k8s/deploy.ps1 View File

@ -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

+ 309
- 287
k8s/deployments.yaml View File

@ -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
---

+ 12
- 11
k8s/gen-k8s-env-aks.ps1 View File

@ -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
}
}

+ 33
- 0
k8s/internalurls.yaml View File

@ -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

+ 154
- 0
k8s/ocelot/configuration-web-shopping.json View File

@ -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"
}
}

+ 17
- 3
k8s/services.yaml View File

@ -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


+ 11
- 0
package-lock.json View File

@ -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=="
}
}
}

+ 31
- 0
src/ApiGateways/ApiGw-Base/Program.cs View File

@ -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<Startup>();
IWebHost host = builder.Build();
return host;
}
}
}

+ 118
- 0
src/ApiGateways/Mobile.Bff.Shopping/apigw/configuration.json View File

@ -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"
}
}

+ 130
- 0
src/ApiGateways/Web.Bff.Shopping/apigw/configuration.json View File

@ -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"
}
}

+ 1
- 1
src/Services/Basket/Basket.API/Basket.API.csproj View File

@ -15,7 +15,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.5.1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta5" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta6" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.1-beta1" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />


+ 3
- 1
src/Services/Basket/Basket.API/Controllers/BasketController.cs View File

@ -55,6 +55,8 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
public async Task<IActionResult> 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);


+ 4
- 1
src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs View File

@ -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;


+ 1
- 1
src/Services/Catalog/Catalog.API/Catalog.API.csproj View File

@ -37,7 +37,7 @@
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.5.1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta5" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta6" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.1-beta1" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.2.0" />


+ 49
- 9
src/Services/Identity/Identity.API/Configuration/Config.cs View File

@ -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"
}
}
};
}
}

+ 56
- 20
src/Services/Identity/Identity.API/Data/ConfigurationDbContextSeed.cs View File

@ -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<string, string>
{
{"Mvc", configuration.GetValue<string>("MvcClient")},
{"Spa", configuration.GetValue<string>("SpaClient")},
{"Xamarin", configuration.GetValue<string>("XamarinCallback")},
{"LocationsApi", configuration.GetValue<string>("LocationApiClient")},
{"MarketingApi", configuration.GetValue<string>("MarketingApiClient")},
{"BasketApi", configuration.GetValue<string>("BasketApiClient")},
{"OrderingApi", configuration.GetValue<string>("OrderingApiClient")}
};
var clientUrls = new Dictionary<string, string>();
if (!await context.Clients.AnyAsync())
clientUrls.Add("Mvc", configuration.GetValue<string>("MvcClient"));
clientUrls.Add("Spa", configuration.GetValue<string>("SpaClient"));
clientUrls.Add("Xamarin", configuration.GetValue<string>("XamarinCallback"));
clientUrls.Add("LocationsApi", configuration.GetValue<string>("LocationApiClient"));
clientUrls.Add("MarketingApi", configuration.GetValue<string>("MarketingApiClient"));
clientUrls.Add("BasketApi", configuration.GetValue<string>("BasketApiClient"));
clientUrls.Add("OrderingApi", configuration.GetValue<string>("OrderingApiClient"));
clientUrls.Add("MobileShoppingAgg", configuration.GetValue<string>("MobileShoppingAggClient"));
clientUrls.Add("WebShoppingAgg", configuration.GetValue<string>("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<ClientRedirectUri> 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();
}
}
}
}

+ 1
- 1
src/Services/Identity/Identity.API/Identity.API.csproj View File

@ -17,7 +17,7 @@
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.5.1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta5" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta6" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.1-beta1" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="2.1.0" />


+ 3
- 1
src/Services/Identity/Identity.API/Services/ProfileService.cs View File

@ -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<Claim>
{
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))


+ 1
- 1
src/Services/Location/Locations.API/Locations.API.csproj View File

@ -9,7 +9,7 @@
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.5.1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta5" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta6" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.1-beta1" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
<PackageReference Include="mongocsharpdriver" Version="2.5.0" />


+ 1
- 1
src/Services/Marketing/Marketing.API/Marketing.API.csproj View File

@ -23,7 +23,7 @@
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.5.1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta5" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta6" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.1-beta1" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
<PackageReference Include="mongocsharpdriver" Version="2.5.0" />


+ 5
- 1
src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommand.cs View File

@ -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<OrderItemDTO>();
}
public CreateOrderCommand(List<BasketItem> basketItems, string userId, string city, string street, string state, string country, string zipcode,
public CreateOrderCommand(List<BasketItem> 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;


+ 1
- 1
src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs View File

@ -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)
{


+ 46
- 0
src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderCancelled/OrderCancelledDomainEventHandler.cs View File

@ -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<OrderCancelledDomainEvent>
{
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);
}
}
}

+ 14
- 6
src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderGracePeriodConfirmed/OrderStatusChangedToAwaitingValidationDomainEventHandler.cs View File

@ -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<OrderStatusChangedToAwaitingValidationDomainEvent>
{
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);
}
}

+ 21
- 8
src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderPaid/OrderStatusChangedToPaidDomainEventHandler.cs View File

@ -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<OrderStatusChangedToPaidDomainEvent>
{
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);
}
}
}

+ 47
- 0
src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderShipped/OrderShippedDomainEventHandler.cs View File

@ -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<OrderShippedDomainEvent>
{
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);
}
}
}

+ 18
- 4
src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStartedEvent/ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler.cs View File

@ -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}.");
}
}


+ 14
- 6
src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmed/OrderStatusChangedToStockConfirmedDomainEventHandler.cs View File

@ -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<OrderStatusChangedToStockConfirmedDomainEvent>
{
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);
}
}
}

+ 3
- 0
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSuccededIntegrationEventHandler.cs View File

@ -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();


+ 3
- 0
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs View File

@ -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();


+ 1
- 1
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs View File

@ -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);


+ 5
- 1
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToAwaitingValidationIntegrationEvent.cs View File

@ -6,13 +6,17 @@
public class OrderStatusChangedToAwaitingValidationIntegrationEvent : IntegrationEvent
{
public int OrderId { get; }
public string OrderStatus { get; }
public string BuyerName { get; }
public IEnumerable<OrderStockItem> OrderStockItems { get; }
public OrderStatusChangedToAwaitingValidationIntegrationEvent(int orderId,
public OrderStatusChangedToAwaitingValidationIntegrationEvent(int orderId, string orderStatus, string buyerName,
IEnumerable<OrderStockItem> orderStockItems)
{
OrderId = orderId;
OrderStockItems = orderStockItems;
OrderStatus = orderStatus;
BuyerName = buyerName;
}
}


+ 22
- 0
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToCancelledIntegrationEvent.cs View File

@ -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;
}
}
}

+ 7
- 1
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToPaidIntegrationEvent.cs View File

@ -6,13 +6,19 @@
public class OrderStatusChangedToPaidIntegrationEvent : IntegrationEvent
{
public int OrderId { get; }
public string OrderStatus { get; }
public string BuyerName { get; }
public IEnumerable<OrderStockItem> OrderStockItems { get; }
public OrderStatusChangedToPaidIntegrationEvent(int orderId,
string orderStatus,
string buyerName,
IEnumerable<OrderStockItem> orderStockItems)
{
OrderId = orderId;
OrderStockItems = orderStockItems;
OrderStatus = orderStatus;
BuyerName = buyerName;
}
}
}
}

+ 22
- 0
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToShippedIntegrationEvent.cs View File

@ -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;
}
}
}

+ 8
- 2
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToStockConfirmedIntegrationEvent.cs View File

@ -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;
}
}
}

+ 22
- 0
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedTosubmittedIntegrationEvent.cs View File

@ -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;
}
}
}

+ 4
- 1
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs View File

@ -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;
}
}


+ 238
- 0
src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20180412143935_NamePropertyInBuyer.Designer.cs View File

@ -0,0 +1,238 @@
// <auto-generated />
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<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:HiLoSequenceName", "buyerseq")
.HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
b.Property<string>("IdentityGuid")
.IsRequired()
.HasMaxLength(200);
b.Property<string>("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<int>("Id")
.HasDefaultValue(1);
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200);
b.HasKey("Id");
b.ToTable("cardtypes","ordering");
});
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:HiLoSequenceName", "paymentseq")
.HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
b.Property<string>("Alias")
.IsRequired()
.HasMaxLength(200);
b.Property<int>("BuyerId");
b.Property<string>("CardHolderName")
.IsRequired()
.HasMaxLength(200);
b.Property<string>("CardNumber")
.IsRequired()
.HasMaxLength(25);
b.Property<int>("CardTypeId");
b.Property<DateTime>("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<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:HiLoSequenceName", "orderseq")
.HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
b.Property<int?>("BuyerId");
b.Property<string>("Description");
b.Property<DateTime>("OrderDate");
b.Property<int>("OrderStatusId");
b.Property<int?>("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<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:HiLoSequenceName", "orderitemseq")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
b.Property<decimal>("Discount");
b.Property<int>("OrderId");
b.Property<string>("PictureUrl");
b.Property<int>("ProductId");
b.Property<string>("ProductName")
.IsRequired();
b.Property<decimal>("UnitPrice");
b.Property<int>("Units");
b.HasKey("Id");
b.HasIndex("OrderId");
b.ToTable("orderItems","ordering");
});
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderStatus", b =>
{
b.Property<int>("Id")
.HasDefaultValue(1);
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200);
b.HasKey("Id");
b.ToTable("orderstatus","ordering");
});
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency.ClientRequest", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Name")
.IsRequired();
b.Property<DateTime>("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<int>("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
}
}
}

+ 86
- 0
src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20180412143935_NamePropertyInBuyer.cs View File

@ -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<string>(
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<string>(
name: "City",
schema: "ordering",
table: "orders",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Country",
schema: "ordering",
table: "orders",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "State",
schema: "ordering",
table: "orders",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Street",
schema: "ordering",
table: "orders",
nullable: true);
migrationBuilder.AddColumn<string>(
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);
}
}
}

+ 15
- 28
src/Services/Ordering/Ordering.API/Infrastructure/Migrations/OrderingContextModelSnapshot.cs View File

@ -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<string>("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<int?>("OrderId");
b.Property<string>("City");
b.Property<string>("Country");
b.Property<string>("State");
b.Property<string>("Street");
b.Property<string>("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<int>("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
}
}


+ 2
- 0
src/Services/Ordering/Ordering.API/Infrastructure/Services/IIdentityService.cs View File

@ -8,5 +8,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Servi
public interface IIdentityService
{
string GetUserIdentity();
string GetUserName();
}
}

+ 5
- 0
src/Services/Ordering/Ordering.API/Infrastructure/Services/IdentityService.cs View File

@ -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;
}
}
}

+ 1
- 1
src/Services/Ordering/Ordering.API/Ordering.API.csproj View File

@ -35,7 +35,7 @@
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.5.1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta5" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta6" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.1-beta1" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
<PackageReference Include="MediatR" Version="4.0.1" />


+ 4
- 4
src/Services/Ordering/Ordering.API/Startup.cs View File

@ -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<string>("IdentityUrl");
@ -279,7 +279,7 @@
{
options.Authority = identityUrl;
options.RequireHttpsMetadata = false;
options.Audience = "orders";
options.Audience = "orders";
});
}


+ 2
- 1
src/Services/Ordering/Ordering.API/settings.json View File

@ -17,5 +17,6 @@
"ApplicationInsights": {
"InstrumentationKey": ""
},
"EventBusRetryCount": 5
"EventBusRetryCount": 5,
"EventBusConnection": "localhost"
}

+ 4
- 1
src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/Buyer.cs View File

@ -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<PaymentMethod> _paymentMethods;
public IEnumerable<PaymentMethod> PaymentMethods => _paymentMethods.AsReadOnly();
@ -20,9 +22,10 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.B
_paymentMethods = new List<PaymentMethod>();
}
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(


+ 1
- 0
src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/IBuyerRepository.cs View File

@ -11,5 +11,6 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.B
Buyer Add(Buyer buyer);
Buyer Update(Buyer buyer);
Task<Buyer> FindAsync(string BuyerIdentityGuid);
Task<Buyer> FindByIdAsync(string id);
}
}

+ 33
- 18
src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs View File

@ -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<OrderItem>(); }
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<OrderItem>();
_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<int> 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);


+ 18
- 0
src/Services/Ordering/Ordering.Domain/Events/OrderCancelledDomainEvent.cs View File

@ -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;
}
}
}

+ 15
- 0
src/Services/Ordering/Ordering.Domain/Events/OrderShippedDomainEvent.cs View File

@ -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;
}
}
}

+ 3
- 1
src/Services/Ordering/Ordering.Domain/Events/OrderStartedDomainEvent.cs View File

@ -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;


+ 2
- 0
src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/BuyerEntityTYpeConfiguration.cs View File

@ -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")


+ 10
- 0
src/Services/Ordering/Ordering.Infrastructure/Repositories/BuyerRepository.cs View File

@ -54,5 +54,15 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositor
return buyer;
}
public async Task<Buyer> FindByIdAsync(string id)
{
var buyer = await _context.Buyers
.Include(b => b.PaymentMethods)
.Where(b => b.Id == int.Parse(id))
.SingleOrDefaultAsync();
return buyer;
}
}
}

+ 30
- 0
src/Services/Ordering/Ordering.SignalrHub/AutofacModules/ApplicationModule.cs View File

@ -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<>));
}
}
}

+ 20
- 0
src/Services/Ordering/Ordering.SignalrHub/Dockerfile View File

@ -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"]

+ 28
- 0
src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToCancelledIntegrationEventHandler.cs View File

@ -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<OrderStatusChangedToCancelledIntegrationEvent>
{
private readonly IHubContext<NotificationsHub> _hubContext;
public OrderStatusChangedToCancelledIntegrationEventHandler(IHubContext<NotificationsHub> 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 });
}
}
}

+ 26
- 0
src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs View File

@ -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<OrderStatusChangedToPaidIntegrationEvent>
{
private readonly IHubContext<NotificationsHub> _hubContext;
public OrderStatusChangedToPaidIntegrationEventHandler(IHubContext<NotificationsHub> 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 });
}
}
}

+ 28
- 0
src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToShippedIntegrationEventHandler.cs View File

@ -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<OrderStatusChangedToShippedIntegrationEvent>
{
private readonly IHubContext<NotificationsHub> _hubContext;
public OrderStatusChangedToShippedIntegrationEventHandler(IHubContext<NotificationsHub> 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 });
}
}
}

+ 29
- 0
src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs View File

@ -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<OrderStatusChangedToStockConfirmedIntegrationEvent>
{
private readonly IHubContext<NotificationsHub> _hubContext;
public OrderStatusChangedToStockConfirmedIntegrationEventHandler(IHubContext<NotificationsHub> 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 });
}
}
}

+ 29
- 0
src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToSubmittedIntegrationEventHandler.cs View File

@ -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<OrderStatusChangedToSubmittedIntegrationEvent>
{
private readonly IHubContext<NotificationsHub> _hubContext;
public OrderStatusChangedToSubmittedIntegrationEventHandler(IHubContext<NotificationsHub> 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 });
}
}
}

+ 27
- 0
src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/orderStatusChangedToAwaitingValidationIntegrationEventHandler.cs View File

@ -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<OrderStatusChangedToAwaitingValidationIntegrationEvent>
{
private readonly IHubContext<NotificationsHub> _hubContext;
public OrderStatusChangedToAwaitingValidationIntegrationEventHandler(IHubContext<NotificationsHub> 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 });
}
}
}

+ 19
- 0
src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToAwaitingValidationIntegrationEvent.cs View File

@ -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;
}
}
}

+ 22
- 0
src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToCancelledIntegrationEvent.cs View File

@ -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;
}
}
}

+ 23
- 0
src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToPaidIntegrationEvent.cs View File

@ -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;
}
}
}

+ 22
- 0
src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToShippedIntegrationEvent.cs View File

@ -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;
}
}
}

+ 18
- 0
src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToStockConfirmedIntegrationEvent.cs View File

@ -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;
}
}
}

+ 22
- 0
src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToSubmittedIntegrationEvent.cs View File

@ -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;
}
}
}

+ 26
- 0
src/Services/Ordering/Ordering.SignalrHub/NotificationHub.cs View File

@ -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);
}
}
}

+ 26
- 0
src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj View File

@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.6" />
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.0.0-preview2-final" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Core" Version="1.0.0-preview2-final" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Redis" Version="1.0.0-preview2-final" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" />
</ItemGroup>
</Project>

+ 25
- 0
src/Services/Ordering/Ordering.SignalrHub/Program.cs View File

@ -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<Startup>()
.Build();
}
}

+ 27
- 0
src/Services/Ordering/Ordering.SignalrHub/Properties/launchSettings.json View File

@ -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/"
}
}
}

+ 214
- 0
src/Services/Ordering/Ordering.SignalrHub/Startup.cs View File

@ -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<string>("IsClusterEnv") == bool.TrueString)
{
services
.AddSignalR()
.AddRedis(Configuration["SignalrStoreConnectionString"]);
}
else
{
services.AddSignalR();
}
if (Configuration.GetValue<bool>("AzureServiceBusEnabled"))
{
services.AddSingleton<IServiceBusPersisterConnection>(sp =>
{
var logger = sp.GetRequiredService<ILogger<DefaultServiceBusPersisterConnection>>();
var serviceBusConnectionString = Configuration["EventBusConnection"];
var serviceBusConnection = new ServiceBusConnectionStringBuilder(serviceBusConnectionString);
return new DefaultServiceBusPersisterConnection(serviceBusConnection, logger);
});
}
else
{
services.AddSingleton<IRabbitMQPersistentConnection>(sp =>
{
var logger = sp.GetRequiredService<ILogger<DefaultRabbitMQPersistentConnection>>();
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<NotificationsHub>("/notificationhub", options =>
options.Transports = Microsoft.AspNetCore.Http.Connections.TransportType.All);
});
ConfigureEventBus(app);
}
private void ConfigureEventBus(IApplicationBuilder app)
{
var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();
eventBus.Subscribe<OrderStatusChangedToAwaitingValidationIntegrationEvent, OrderStatusChangedToAwaitingValidationIntegrationEventHandler>();
eventBus.Subscribe<OrderStatusChangedToPaidIntegrationEvent, OrderStatusChangedToPaidIntegrationEventHandler>();
eventBus.Subscribe<OrderStatusChangedToStockConfirmedIntegrationEvent, OrderStatusChangedToStockConfirmedIntegrationEventHandler>();
eventBus.Subscribe<OrderStatusChangedToShippedIntegrationEvent, OrderStatusChangedToShippedIntegrationEventHandler>();
eventBus.Subscribe<OrderStatusChangedToCancelledIntegrationEvent, OrderStatusChangedToCancelledIntegrationEventHandler>();
eventBus.Subscribe<OrderStatusChangedToSubmittedIntegrationEvent, OrderStatusChangedToSubmittedIntegrationEventHandler>();
}
private void ConfigureAuthService(IServiceCollection services)
{
// prevent from mapping "sub" claim to nameidentifier.
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");
var identityUrl = Configuration.GetValue<string>("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<bool>("AzureServiceBusEnabled"))
{
services.AddSingleton<IEventBus, EventBusServiceBus>(sp =>
{
var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>();
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>();
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
return new EventBusServiceBus(serviceBusPersisterConnection, logger,
eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope);
});
}
else
{
services.AddSingleton<IEventBus, EventBusRabbitMQ>(sp =>
{
var rabbitMQPersistentConnection = sp.GetRequiredService<IRabbitMQPersistentConnection>();
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
var logger = sp.GetRequiredService<ILogger<EventBusRabbitMQ>>();
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
var retryCount = 5;
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
}
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
});
}
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
}
}
}

+ 15
- 0
src/Services/Ordering/Ordering.SignalrHub/appsettings.json View File

@ -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"
}

+ 1
- 1
src/Services/Payment/Payment.API/Payment.API.csproj View File

@ -10,7 +10,7 @@
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.5.1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta5" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta6" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.1-beta1" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
</ItemGroup>


+ 3
- 4
src/Web/WebMVC/AppSettings.cs View File

@ -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; }


+ 2
- 0
src/Web/WebMVC/Startup.cs View File

@ -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");
});
}


+ 26
- 27
src/Web/WebMVC/Views/Order/Index.cshtml View File

@ -8,9 +8,9 @@
<div class="esh-orders">
@Html.Partial("_Header", new List<Header>() {
new Header() { Controller = "Catalog", Text = "Back to catalog" },
new Header() { Text = " / " },
new Header() { Controller = "OrderManagement", Text = "Orders Management" } })
new Header() { Controller = "Catalog", Text = "Back to catalog" },
new Header() { Text = " / " },
new Header() { Controller = "OrderManagement", Text = "Orders Management" } })
<div class="container">
<article class="esh-orders-titles row">
@ -20,31 +20,30 @@
<section class="esh-orders-title col-xs-2">Status</section>
<section class="esh-orders-title col-xs-2"></section>
</article>
@if (Model != null && Model.Any())
{
foreach (var item in Model)
@if (Model != null && Model.Any())
{
<article class="esh-orders-items row">
<section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.OrderNumber)</section>
<section class="esh-orders-item col-xs-4">@Html.DisplayFor(modelItem => item.Date)</section>
<section class="esh-orders-item col-xs-2">$ @Html.DisplayFor(modelItem => item.Total)</section>
<section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.Status)</section>
<section class="esh-orders-item col-xs-1">
<a class="esh-orders-link" asp-controller="Order" asp-action="Detail" asp-route-orderId="@item.OrderNumber">Detail</a>
</section>
<section class="esh-orders-item col-xs-1">
@if (item.Status.ToLower() == "submitted")
{
<a class="esh-orders-link" asp-controller="Order" asp-action="cancel" asp-route-orderId="@item.OrderNumber">Cancel</a>
}
</section>
</article>
foreach (var item in Model)
{
<article class="esh-orders-items row">
<section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.OrderNumber)</section>
<section class="esh-orders-item col-xs-4">@Html.DisplayFor(modelItem => item.Date)</section>
<section class="esh-orders-item col-xs-2">$ @Html.DisplayFor(modelItem => item.Total)</section>
<section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.Status)</section>
<section class="esh-orders-item col-xs-1">
<a class="esh-orders-link" asp-controller="Order" asp-action="Detail" asp-route-orderId="@item.OrderNumber">Detail</a>
</section>
<section class="esh-orders-item col-xs-1">
@if (item.Status.ToLower() == "submitted")
{
<a class="esh-orders-link" asp-controller="Order" asp-action="cancel" asp-route-orderId="@item.OrderNumber">Cancel</a>
}
</section>
</article>
}
}
}
</div>
</div>
<script>
setTimeout(function () {
window.location.reload(true);
}, 5000);
</script>

+ 51
- 0
src/Web/WebMVC/Views/Shared/_Layout.cshtml View File

@ -20,6 +20,8 @@
<link rel="stylesheet" href="~/css/orders/orders-detail/orders-detail.component.css" />
<link rel="stylesheet" href="~/css/orders/orders-new/orders-new.component.css" />
<link rel="stylesheet" href="~/css/override.css" type="text/css" />
<link rel="stylesheet" href="~/css/site.min.css" type="text/css" />
</environment>
<environment names="Staging,Production">
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
@ -84,5 +86,54 @@
</environment>
@RenderSection("scripts", required: false)
@using Microsoft.AspNetCore.Authentication;
@using Microsoft.Extensions.Options
@inject IOptions<AppSettings> settings
<script type="text/javascript">
if ('@User.Identity.IsAuthenticated' === 'True') {
var timerId;
let connection = stablishConnection();
connection.start().then(function () {
console.log('User Registered to Signalr Hub');
});
registerNotificationHandlers(connection);
}
function stablishConnection() {
let hubHttpConnection = new signalR.HttpConnection('@settings.Value.SignalrHubUrl/hub/notificationhub', {
transport: signalR.TransportType.LongPolling,
accessTokenFactory: () => {
return "Authorization", getToken();
}
});
return new signalR.HubConnection(hubHttpConnection);
}
function registerNotificationHandlers(connection) {
connection.on("UpdatedOrderState", (message) => {
toastr.success('Updated to status: ' + message.status, 'Order Id: ' + message.orderId);
if (window.location.pathname.split("/").pop() === 'Order') {
refreshOrderList();
}
});
}
function getToken() {
return '@Context.GetTokenAsync("access_token").Result';
}
function refreshOrderList() {
clearTimeout(timerId);
timerId = setTimeout(function () {
window.location.reload();
}, 1000);
}
</script>
</body>
</html>

+ 2
- 1
src/Web/WebMVC/WebMVC.csproj View File

@ -18,9 +18,10 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="BuildBundlerMinifier" Version="2.6.375" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.5.1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta5" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta6" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.1-beta1" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.Redis" Version="0.3.1" />


+ 14
- 0
src/Web/WebMVC/bundleconfig.json View File

@ -8,6 +8,20 @@
"wwwroot/css/**/*.css"
]
},
{
"outputFileName": "wwwroot/js/site.js",
"inputFiles": [
"wwwroot/lib/signalr/signalr.js",
"wwwroot/lib/toastr/toastr.js"
],
// Optionally specify minification options
"minify": {
"enabled": false,
"renameLocals": true
},
// Optinally generate .map file
"sourceMap": false
},
{
"outputFileName": "wwwroot/js/site.min.js",
"inputFiles": [


+ 26
- 0
src/Web/WebMVC/package-lock.json View File

@ -0,0 +1,26 @@
{
"name": "asp.net",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@aspnet/signalr": {
"version": "1.0.0-preview2-final",
"resolved": "https://registry.npmjs.org/@aspnet/signalr/-/signalr-1.0.0-preview2-final.tgz",
"integrity": "sha512-XbqGbAG9Ow4L5Sc4n81A2S8lHSlxBNTjFm3WZQA94cIolPnW0bPK2u14UMooXRXxzjBtJViJMN/aoxWRwTWxig=="
},
"jquery": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
"integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg=="
},
"toastr": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/toastr/-/toastr-2.1.4.tgz",
"integrity": "sha1-i0O+ZPudDEFIcURvLbjoyk6V8YE=",
"requires": {
"jquery": "3.3.1"
}
}
}
}

+ 10
- 0
src/Web/WebMVC/package.json View File

@ -0,0 +1,10 @@
{
"version": "1.0.0",
"name": "asp.net",
"private": true,
"devDependencies": {},
"dependencies": {
"@aspnet/signalr": "^1.0.0-preview2-final",
"toastr": "^2.1.4"
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save