diff --git a/.dockerignore b/.dockerignore
index dd3d41423..5fbf98f1e 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -7,7 +7,6 @@
docker-compose*.yml
docker-compose.dcproj
*.sln
-!eShopOnContainers-ServicesAndWebApps.sln
*.md
hosts
LICENSE
@@ -31,4 +30,13 @@ cli-linux
**/wwwroot/lib/*
global.json
**/appsettings.localhost.json
-src/Web/WebSPA/wwwroot/
\ No newline at end of file
+src/Web/WebSPA/wwwroot/
+packages/
+csproj-files/
+test-results/
+TestResults/
+src/Mobile/
+src/Web/Catalog.WebForms/
+src/Web/WebMonolithic/
+src/BuildingBlocks/CommandBus/
+src/Services/Marketing/Infrastructure/
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 6bc27551d..f3fdf2b8f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,6 +25,13 @@ bld/
# Visual Studio 2015 cache/options directory
.vs/
+
+# Dockerfile projects folder for restore-packages script
+csproj-files/
+
+# .js files created on build:
+src/Web/WebMVC/wwwroot/js/site*
+
# Uncomment if you have tasks that create the project's static files in wwwroot
**/wwwroot/lib/
!/wwwroot/lib/signalr
@@ -38,6 +45,8 @@ bld/
*.VisualState.xml
TestResult.xml
+tests-results/
+
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
@@ -265,4 +274,9 @@ pub/
.mfractor
# Ignore HealthCheckdb
-*healthchecksdb*
\ No newline at end of file
+*healthchecksdb*
+
+# Ignores all extra inf.yaml and app.yaml that are copied by prepare-devspaces.ps1
+src/**/app.yaml
+src/**/inf.yaml
+
diff --git a/README.md b/README.md
index ffdf6450a..b7f92ffa0 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,25 @@
-# eShopOnContainers - Microservices Architecture and Containers based Reference Application (**BETA state** - Visual Studio 2017 and CLI environments compatible)
+# eShopOnContainers - Microservices Architecture and Containers based Reference Application (**BETA state** - Visual Studio and CLI environments compatible)
Sample .NET Core reference application, powered by Microsoft, based on a simplified microservices architecture and Docker containers.
-[![Build status (Linux images)](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/All%20Microservices%20Linux)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=184)
+## Linux Build Status for 'dev' branch
+Dev branch contains the latest "stable" code, and their images are tagged with `:dev` in our [Docker Hub](https://cloud.docker.com/u/eshop/repository/list):
+
+| Basket API | Catalog API | Identity API | Location API |
+| ------------- | ------------- | ------------- | ------------- |
+| [![Basket API](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/basket?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=199&branchName=dev) | [![Catalog API](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/catalog?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=197&branchName=dev) | [![Identity API](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/identity?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=200&branchName=dev) | [![Location API](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/location?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=202&branchName=dev) |
+
+| Marketing API | Ordering API | Payment API | Api Gateways base image |
+| ------------- | ------------- | ------------- | ------------- |
+| [![Marketing API](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/marketing?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=203&branchName=dev) | [![Ordering API](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/ordering?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=198&branchName=dev) | [![Payment API](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/payment?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=205&branchName=dev) | [![Api Gateways base image](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/apigws?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=201&branchName=dev)
+
+| Web Shopping Aggregator | Mobile Shopping Aggregator | WebMVC Client | WebSPA Client |
+| ------------- | ------------- | ------------- | ------------- |
+| [![Web Shopping Aggregator](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/web-shopping-agg?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=206&branchName=dev) | [![Mobile Shopping Aggregator](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/mobile-shopping-agg?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=204&branchName=dev) | [![WebMVC Client](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/webmvc?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=209&branchName=dev) | [![WebSPA Client](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/webspa?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=210&branchName=dev) |
+
+| Web Status | Webhooks API | Webbhooks demo client |
+| ------------- | ------------- | ------------- |
+ [![Web Status](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/webstatus?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=211&branchName=dev) | [![Webhooks API](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/webhooks?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=207&branchName=dev) | [![Webhooks demo client](https://msftdevtools.visualstudio.com/eShopOnContainers/_apis/build/status/microservices/webhooks-client?branchName=dev)](https://msftdevtools.visualstudio.com/eShopOnContainers/_build/latest?definitionId=208&branchName=dev) |
## IMPORTANT NOTES!
**You can use either the latest version of Visual Studio or simply Docker CLI and .NET CLI for Windows, Mac and Linux**.
@@ -63,6 +80,12 @@ The architecture proposes a microservice oriented architecture implementation wi
>
A similar case is defined in regard to Redis cache running as a container for the development environment. Or a No-SQL database (MongoDB) running as a container.
>
However, in a real production environment it is recommended to have your databases (SQL Server, Redis, and the NO-SQL database, in this case) in HA (High Available) services like Azure SQL Database, Redis as a service and Azure CosmosDB instead the MongoDB container (as both systems share the same access protocol). If you want to change to a production configuration, you'll just need to change the connection strings once you have set up the servers in an HA cloud or on-premises.
+> ### Important Note on EventBus
+> In this solution's current EventBus is a simplified implementation, mainly used for learning purposes (development and testing), so it doesn't handle all production scenarios, most notably on error handling.
+> The following forks provide production environment level implementation examples with eShopOnContainers :
+> * Implementation with [CAP](https://github.com/dotnetcore/CAP) : https://github.com/yang-xiaodong/eShopOnContainers
+> * Implementation with [NServiceBus](https://github.com/Particular/NServiceBus) : https://github.com/Particular/eShopOnContainers
+
## Related documentation and guidance
While developing this reference application, we've been creating a reference Guide/eBook focusing on architecting and developing containerized and microservice based .NET Applications (download link available below) which explains in detail how to develop this kind of architectural style (microservices, Docker containers, Domain-Driven Design for certain microservices) plus other simpler architectural styles, like monolithic apps that can also live as Docker containers.
@@ -106,7 +129,7 @@ Finally, those microservices are consumed by multiple client web and mobile apps
## Setting up your development environment for eShopOnContainers
-### Visual Studio 2017 and Windows based
+### Visual Studio 2017 (or above) and Windows based
This is the more straightforward way to get started:
https://github.com/dotnet-architecture/eShopOnContainers/wiki/02.-Setting-eShopOnContainers-in-a-Visual-Studio-2017-environment
@@ -126,5 +149,5 @@ As mentioned, we'd appreciate your feedback, improvements and ideas.
You can create new issues at the issues section, do pull requests and/or send emails to **eshop_feedback@service.microsoft.com**
## Questions
-[QUESTION] Answer +1 if the solution is working for you (Through VS2017 or CLI environment):
+[QUESTION] Answer +1 if the solution is working for you (Through VS or CLI environment):
https://github.com/dotnet/eShopOnContainers/issues/107
diff --git a/build/azure-devops/apigws/azure-pipelines.yml b/build/azure-devops/apigws/azure-pipelines.yml
new file mode 100644
index 000000000..6fedf33a6
--- /dev/null
+++ b/build/azure-devops/apigws/azure-pipelines.yml
@@ -0,0 +1,52 @@
+variables:
+ registryEndpoint: eshop-registry
+trigger:
+ branches:
+ include:
+ - master
+ - dev
+ paths:
+ include:
+ - src/ApiGateways/*
+ - k8s/helm/apigwmm/*
+ - k8s/helm/apigwms/*
+ - k8s/helm/apigwwm/*
+ - k8s/helm/apigwws/*
+ exclude:
+ - src/ApiGateways/Mobile.Bff.Shopping/aggregator/*
+ - src/ApiGateways/Web.Bff.Shopping/aggregator/*
+jobs:
+- job: BuildLinux
+ pool:
+ vmImage: 'ubuntu-16.04'
+ steps:
+ - task: DockerCompose@0
+ displayName: Compose build apigws
+ inputs:
+ dockerComposeCommand: 'build mobileshoppingapigw mobilemarketingapigw webshoppingapigw webmarketingapigw'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+ - task: DockerCompose@0
+ displayName: Compose push apigws
+ inputs:
+ dockerComposeCommand: 'push mobileshoppingapigw mobilemarketingapigw webshoppingapigw webmarketingapigw'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+ - task: CopyFiles@2
+ inputs:
+ sourceFolder: $(Build.SourcesDirectory)/k8s/helm
+ targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm
+ - task: PublishBuildArtifacts@1
+ inputs:
+ pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm
+ artifactName: helm
diff --git a/build/azure-devops/basket-api/azure-pipelines.yml b/build/azure-devops/basket-api/azure-pipelines.yml
new file mode 100644
index 000000000..6d94c5918
--- /dev/null
+++ b/build/azure-devops/basket-api/azure-pipelines.yml
@@ -0,0 +1,45 @@
+pool:
+ vmImage: 'ubuntu-16.04'
+variables:
+ registryEndpoint: eshop-registry
+trigger:
+ branches:
+ include:
+ - master
+ - dev
+ paths:
+ include:
+ - src/BuildingBlocks/*
+ - src/Services/Basket/*
+ - k8s/helm/basket-api/*
+steps:
+- task: DockerCompose@0
+ displayName: Compose build basket
+ inputs:
+ dockerComposeCommand: 'build basket.api'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: DockerCompose@0
+ displayName: Compose push basket
+ inputs:
+ dockerComposeCommand: 'push basket.api'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: CopyFiles@2
+ inputs:
+ sourceFolder: $(Build.SourcesDirectory)/k8s/helm
+ targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm
+- task: PublishBuildArtifacts@1
+ inputs:
+ pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm
+ artifactName: helm
diff --git a/build/azure-devops/catalog-api/azure-pipelines.yml b/build/azure-devops/catalog-api/azure-pipelines.yml
new file mode 100644
index 000000000..d277d4777
--- /dev/null
+++ b/build/azure-devops/catalog-api/azure-pipelines.yml
@@ -0,0 +1,45 @@
+pool:
+ vmImage: 'ubuntu-16.04'
+variables:
+ registryEndpoint: eshop-registry
+trigger:
+ branches:
+ include:
+ - master
+ - dev
+ paths:
+ include:
+ - src/BuildingBlocks/*
+ - src/Services/Catalog/*
+ - k8s/helm/catalog-api/*
+steps:
+- task: DockerCompose@0
+ displayName: Compose build catalog
+ inputs:
+ dockerComposeCommand: 'build catalog.api'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: DockerCompose@0
+ displayName: Compose push catalog
+ inputs:
+ dockerComposeCommand: 'push catalog.api'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: CopyFiles@2
+ inputs:
+ sourceFolder: $(Build.SourcesDirectory)/k8s/helm
+ targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm
+- task: PublishBuildArtifacts@1
+ inputs:
+ pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm
+ artifactName: helm
diff --git a/build/azure-devops/identity-api/azure-pipelines.yml b/build/azure-devops/identity-api/azure-pipelines.yml
new file mode 100644
index 000000000..454c03d16
--- /dev/null
+++ b/build/azure-devops/identity-api/azure-pipelines.yml
@@ -0,0 +1,45 @@
+pool:
+ vmImage: 'ubuntu-16.04'
+variables:
+ registryEndpoint: eshop-registry
+trigger:
+ branches:
+ include:
+ - master
+ - dev
+ paths:
+ include:
+ - src/BuildingBlocks/*
+ - src/Services/Identity/*
+ - k8s/helm/identity-api/*
+steps:
+- task: DockerCompose@0
+ displayName: Compose build identity
+ inputs:
+ dockerComposeCommand: 'build identity.api'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: DockerCompose@0
+ displayName: Compose push identity
+ inputs:
+ dockerComposeCommand: 'push identity.api'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: CopyFiles@2
+ inputs:
+ sourceFolder: $(Build.SourcesDirectory)/k8s/helm
+ targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm
+- task: PublishBuildArtifacts@1
+ inputs:
+ pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm
+ artifactName: helm
diff --git a/build/azure-devops/infrastructure/azure-pipelines.yml b/build/azure-devops/infrastructure/azure-pipelines.yml
new file mode 100644
index 000000000..50296d457
--- /dev/null
+++ b/build/azure-devops/infrastructure/azure-pipelines.yml
@@ -0,0 +1,25 @@
+pool:
+ vmImage: 'ubuntu-16.04'
+variables:
+ registryEndpoint: eshop-registry
+trigger:
+ branches:
+ include:
+ - master
+ - dev
+ paths:
+ include:
+ - k8s/helm/basket-data/*
+ - k8s/helm/keystore-data/*
+ - k8s/helm/nosql-data/*
+ - k8s/helm/rabbitmq/*
+ - k8s/helm/sql-data/*
+steps:
+- task: CopyFiles@2
+ inputs:
+ sourceFolder: $(Build.SourcesDirectory)/k8s/helm
+ targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm
+- task: PublishBuildArtifacts@1
+ inputs:
+ pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm
+ artifactName: helm
diff --git a/build/azure-devops/location-api/azure-pipelines.yml b/build/azure-devops/location-api/azure-pipelines.yml
new file mode 100644
index 000000000..ab3d31b3f
--- /dev/null
+++ b/build/azure-devops/location-api/azure-pipelines.yml
@@ -0,0 +1,45 @@
+pool:
+ vmImage: 'ubuntu-16.04'
+variables:
+ registryEndpoint: eshop-registry
+trigger:
+ branches:
+ include:
+ - master
+ - dev
+ paths:
+ include:
+ - src/BuildingBlocks/*
+ - src/Services/Location/*
+ - k8s/helm/locations-api/*
+steps:
+- task: DockerCompose@0
+ displayName: Compose build locations
+ inputs:
+ dockerComposeCommand: 'build locations.api'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: DockerCompose@0
+ displayName: Compose push locations
+ inputs:
+ dockerComposeCommand: 'push locations.api'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: CopyFiles@2
+ inputs:
+ sourceFolder: $(Build.SourcesDirectory)/k8s/helm
+ targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm
+- task: PublishBuildArtifacts@1
+ inputs:
+ pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm
+ artifactName: helm
diff --git a/build/azure-devops/marketing-api/azure-pipelines.yml b/build/azure-devops/marketing-api/azure-pipelines.yml
new file mode 100644
index 000000000..193a0cccf
--- /dev/null
+++ b/build/azure-devops/marketing-api/azure-pipelines.yml
@@ -0,0 +1,45 @@
+pool:
+ vmImage: 'ubuntu-16.04'
+variables:
+ registryEndpoint: eshop-registry
+trigger:
+ branches:
+ include:
+ - master
+ - dev
+ paths:
+ include:
+ - src/BuildingBlocks/*
+ - src/Services/Marketing/*
+ - k8s/helm/marketing-api/*
+steps:
+- task: DockerCompose@0
+ displayName: Compose build marketing
+ inputs:
+ dockerComposeCommand: 'build marketing.api'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: DockerCompose@0
+ displayName: Compose push marketing
+ inputs:
+ dockerComposeCommand: 'push marketing.api'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: CopyFiles@2
+ inputs:
+ sourceFolder: $(Build.SourcesDirectory)/k8s/helm
+ targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm
+- task: PublishBuildArtifacts@1
+ inputs:
+ pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm
+ artifactName: helm
diff --git a/build/azure-devops/mobile-shopping-agg/azure-pipelines.yml b/build/azure-devops/mobile-shopping-agg/azure-pipelines.yml
new file mode 100644
index 000000000..6fb0018a1
--- /dev/null
+++ b/build/azure-devops/mobile-shopping-agg/azure-pipelines.yml
@@ -0,0 +1,44 @@
+pool:
+ vmImage: 'ubuntu-16.04'
+variables:
+ registryEndpoint: eshop-registry
+trigger:
+ branches:
+ include:
+ - master
+ - dev
+ paths:
+ include:
+ - src/ApiGateways/Mobile.Bff.Shopping/aggregator/*
+ - k8s/helm/mobileshoppingagg/*
+steps:
+- task: DockerCompose@0
+ displayName: Compose build mobileshoppingagg
+ inputs:
+ dockerComposeCommand: 'build mobileshoppingagg'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: DockerCompose@0
+ displayName: Compose push mobileshoppingagg
+ inputs:
+ dockerComposeCommand: 'push mobileshoppingagg'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: CopyFiles@2
+ inputs:
+ sourceFolder: $(Build.SourcesDirectory)/k8s/helm
+ targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm
+- task: PublishBuildArtifacts@1
+ inputs:
+ pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm
+ artifactName: helm
diff --git a/build/azure-devops/ordering-api/azure-pipelines.yml b/build/azure-devops/ordering-api/azure-pipelines.yml
new file mode 100644
index 000000000..ef0b17a32
--- /dev/null
+++ b/build/azure-devops/ordering-api/azure-pipelines.yml
@@ -0,0 +1,47 @@
+pool:
+ vmImage: 'ubuntu-16.04'
+variables:
+ registryEndpoint: eshop-registry
+trigger:
+ branches:
+ include:
+ - master
+ - dev
+ paths:
+ include:
+ - src/BuildingBlocks/*
+ - src/Services/Ordering/*
+ - k8s/helm/ordering-api/*
+ - k8s/helm/ordering-backgroundtasks/*
+ - k8s/helm/ordering-signalrhub/*
+steps:
+- task: DockerCompose@0
+ displayName: Compose build ordering
+ inputs:
+ dockerComposeCommand: 'build ordering.api ordering.backgroundtasks ordering.signalrhub'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: DockerCompose@0
+ displayName: Compose push ordering
+ inputs:
+ dockerComposeCommand: 'push ordering.api ordering.backgroundtasks ordering.signalrhub'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: CopyFiles@2
+ inputs:
+ sourceFolder: $(Build.SourcesDirectory)/k8s/helm
+ targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm
+- task: PublishBuildArtifacts@1
+ inputs:
+ pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm
+ artifactName: helm
diff --git a/build/azure-devops/payment-api/azure-pipelines.yml b/build/azure-devops/payment-api/azure-pipelines.yml
new file mode 100644
index 000000000..8518c8841
--- /dev/null
+++ b/build/azure-devops/payment-api/azure-pipelines.yml
@@ -0,0 +1,45 @@
+pool:
+ vmImage: 'ubuntu-16.04'
+variables:
+ registryEndpoint: eshop-registry
+trigger:
+ branches:
+ include:
+ - master
+ - dev
+ paths:
+ include:
+ - src/BuildingBlocks/*
+ - src/Services/Payment/*
+ - k8s/helm/payment-api/*
+steps:
+- task: DockerCompose@0
+ displayName: Compose build payment
+ inputs:
+ dockerComposeCommand: 'build payment.api'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: DockerCompose@0
+ displayName: Compose push payment
+ inputs:
+ dockerComposeCommand: 'push payment.api'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: CopyFiles@2
+ inputs:
+ sourceFolder: $(Build.SourcesDirectory)/k8s/helm
+ targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm
+- task: PublishBuildArtifacts@1
+ inputs:
+ pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm
+ artifactName: helm
diff --git a/build/azure-devops/readme.md b/build/azure-devops/readme.md
new file mode 100644
index 000000000..b7216d4de
--- /dev/null
+++ b/build/azure-devops/readme.md
@@ -0,0 +1,5 @@
+# Azure Devops build definitions
+
+This folder contains the Azure Devops build definitions in YAML format. Each folder contains one `azure-pipelines.yml` that contains the build definition for one microservice (usually a Docker image, but some microservices generates more than one Docker image).
+
+For more information about YAML builds read the [Azure DevOps documentation](https://docs.microsoft.com/en-us/azure/devops/pipelines/get-started-yaml?view=azure-devops).
\ No newline at end of file
diff --git a/build/azure-devops/web-shopping-agg/azure-pipelines.yml b/build/azure-devops/web-shopping-agg/azure-pipelines.yml
new file mode 100644
index 000000000..70a4df950
--- /dev/null
+++ b/build/azure-devops/web-shopping-agg/azure-pipelines.yml
@@ -0,0 +1,44 @@
+pool:
+ vmImage: 'ubuntu-16.04'
+variables:
+ registryEndpoint: eshop-registry
+trigger:
+ branches:
+ include:
+ - master
+ - dev
+ paths:
+ include:
+ - src/ApiGateways/Web.Bff.Shopping/aggregator/*
+ - k8s/helm/webshoppingagg/*
+steps:
+- task: DockerCompose@0
+ displayName: Compose build webshoppingagg
+ inputs:
+ dockerComposeCommand: 'build webshoppingagg'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: DockerCompose@0
+ displayName: Compose push webshoppingagg
+ inputs:
+ dockerComposeCommand: 'push webshoppingagg'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: CopyFiles@2
+ inputs:
+ sourceFolder: $(Build.SourcesDirectory)/k8s/helm
+ targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm
+- task: PublishBuildArtifacts@1
+ inputs:
+ pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm
+ artifactName: helm
diff --git a/build/azure-devops/webhooks-api/azure-pipelines.yml b/build/azure-devops/webhooks-api/azure-pipelines.yml
new file mode 100644
index 000000000..b48948111
--- /dev/null
+++ b/build/azure-devops/webhooks-api/azure-pipelines.yml
@@ -0,0 +1,45 @@
+pool:
+ vmImage: 'ubuntu-16.04'
+variables:
+ registryEndpoint: eshop-registry
+trigger:
+ branches:
+ include:
+ - master
+ - dev
+ paths:
+ include:
+ - src/BuildingBlocks/*
+ - src/Services/Webhooks/*
+ - k8s/helm/webhooks-api/*
+steps:
+- task: DockerCompose@0
+ displayName: Compose build webhooks
+ inputs:
+ dockerComposeCommand: 'build webhooks.api'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: DockerCompose@0
+ displayName: Compose push webhooks
+ inputs:
+ dockerComposeCommand: 'push webhooks.api'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: CopyFiles@2
+ inputs:
+ sourceFolder: $(Build.SourcesDirectory)/k8s/helm
+ targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm
+- task: PublishBuildArtifacts@1
+ inputs:
+ pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm
+ artifactName: helm
diff --git a/build/azure-devops/webhooks-client/azure-pipelines.yml b/build/azure-devops/webhooks-client/azure-pipelines.yml
new file mode 100644
index 000000000..71e3bbe16
--- /dev/null
+++ b/build/azure-devops/webhooks-client/azure-pipelines.yml
@@ -0,0 +1,45 @@
+pool:
+ vmImage: 'ubuntu-16.04'
+variables:
+ registryEndpoint: eshop-registry
+trigger:
+ branches:
+ include:
+ - master
+ - dev
+ paths:
+ include:
+ - src/BuildingBlocks/*
+ - src/Web/WebhookClient/*
+ - k8s/helm/webhooks-web/*
+steps:
+- task: DockerCompose@0
+ displayName: Compose build webhooks.client
+ inputs:
+ dockerComposeCommand: 'build webhooks.client'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: DockerCompose@0
+ displayName: Compose push webhooks.client
+ inputs:
+ dockerComposeCommand: 'push webhooks.client'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: CopyFiles@2
+ inputs:
+ sourceFolder: $(Build.SourcesDirectory)/k8s/helm
+ targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm
+- task: PublishBuildArtifacts@1
+ inputs:
+ pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm
+ artifactName: helm
diff --git a/build/azure-devops/webmvc/azure-pipelines.yml b/build/azure-devops/webmvc/azure-pipelines.yml
new file mode 100644
index 000000000..66b8518fa
--- /dev/null
+++ b/build/azure-devops/webmvc/azure-pipelines.yml
@@ -0,0 +1,45 @@
+pool:
+ vmImage: 'ubuntu-16.04'
+variables:
+ registryEndpoint: eshop-registry
+trigger:
+ branches:
+ include:
+ - master
+ - dev
+ paths:
+ include:
+ - src/BuildingBlocks/*
+ - src/Web/WebMVC/*
+ - k8s/helm/webmvc/*
+steps:
+- task: DockerCompose@0
+ displayName: Compose build webmvc
+ inputs:
+ dockerComposeCommand: 'build webmvc'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: DockerCompose@0
+ displayName: Compose push webmvc
+ inputs:
+ dockerComposeCommand: 'push webmvc'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: CopyFiles@2
+ inputs:
+ sourceFolder: $(Build.SourcesDirectory)/k8s/helm
+ targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm
+- task: PublishBuildArtifacts@1
+ inputs:
+ pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm
+ artifactName: helm
diff --git a/build/azure-devops/webspa/azure-pipelines.yml b/build/azure-devops/webspa/azure-pipelines.yml
new file mode 100644
index 000000000..eee8cd25d
--- /dev/null
+++ b/build/azure-devops/webspa/azure-pipelines.yml
@@ -0,0 +1,45 @@
+pool:
+ vmImage: 'ubuntu-16.04'
+variables:
+ registryEndpoint: eshop-registry
+trigger:
+ branches:
+ include:
+ - master
+ - dev
+ paths:
+ include:
+ - src/BuildingBlocks/*
+ - src/Web/WebSPA/*
+ - k8s/helm/webspa/*
+steps:
+- task: DockerCompose@0
+ displayName: Compose build webspa
+ inputs:
+ dockerComposeCommand: 'build webspa'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: DockerCompose@0
+ displayName: Compose push webspa
+ inputs:
+ dockerComposeCommand: 'push webspa'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: CopyFiles@2
+ inputs:
+ sourceFolder: $(Build.SourcesDirectory)/k8s/helm
+ targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm
+- task: PublishBuildArtifacts@1
+ inputs:
+ pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm
+ artifactName: helm
diff --git a/build/azure-devops/webstatus/azure-pipelines.yml b/build/azure-devops/webstatus/azure-pipelines.yml
new file mode 100644
index 000000000..311c457e2
--- /dev/null
+++ b/build/azure-devops/webstatus/azure-pipelines.yml
@@ -0,0 +1,45 @@
+pool:
+ vmImage: 'ubuntu-16.04'
+variables:
+ registryEndpoint: eshop-registry
+trigger:
+ branches:
+ include:
+ - master
+ - dev
+ paths:
+ include:
+ - src/BuildingBlocks/*
+ - src/Web/WebStatus/*
+ - k8s/helm/webstatus/*
+steps:
+- task: DockerCompose@0
+ displayName: Compose build webstatus
+ inputs:
+ dockerComposeCommand: 'build webstatus'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: DockerCompose@0
+ displayName: Compose push webstatus
+ inputs:
+ dockerComposeCommand: 'push webstatus'
+ containerregistrytype: Container Registry
+ dockerRegistryEndpoint: $(registryEndpoint)
+ dockerComposeFile: docker-compose.yml
+ qualifyImageNames: true
+ projectName: ""
+ dockerComposeFileArgs: |
+ TAG=$(Build.SourceBranchName)
+- task: CopyFiles@2
+ inputs:
+ sourceFolder: $(Build.SourcesDirectory)/k8s/helm
+ targetFolder: $(Build.ArtifactStagingDirectory)/k8s/helm
+- task: PublishBuildArtifacts@1
+ inputs:
+ pathtoPublish: $(Build.ArtifactStagingDirectory)/k8s/helm
+ artifactName: helm
diff --git a/build/multiarch-manifests/create-manifests.ps1 b/build/multiarch-manifests/create-manifests.ps1
new file mode 100644
index 000000000..cc7f05194
--- /dev/null
+++ b/build/multiarch-manifests/create-manifests.ps1
@@ -0,0 +1,26 @@
+Param(
+ [parameter(Mandatory=$true)][string]$registry
+)
+
+if ([String]::IsNullOrEmpty($registry)) {
+ Write-Host "Registry must be set to docker registry to use" -ForegroundColor Red
+ exit 1
+}
+
+Write-Host "This script creates the local manifests, for pushing the multi-arch manifests" -ForegroundColor Yellow
+Write-Host "Tags used are linux-master, win-master, linux-dev, win-dev, linux-latest, win-latest" -ForegroundColor Yellow
+Write-Host "Multiarch images tags will be master, dev, latest" -ForegroundColor Yellow
+
+
+$services = "identity.api", "basket.api", "catalog.api", "ordering.api", "ordering.backgroundtasks", "marketing.api", "payment.api", "locations.api", "webhooks.api", "ocelotapigw", "mobileshoppingagg", "webshoppingagg", "ordering.signalrhub", "webstatus", "webspa", "webmvc", "webhooks.client"
+
+foreach ($svc in $services) {
+ Write-Host "Creating manifest for $svc and tags :latest, :master, and :dev"
+ docker manifest create $registry/${svc}:master $registry/${svc}:linux-master $registry/${svc}:win-master
+ docker manifest create $registry/${svc}:dev $registry/${svc}:linux-dev $registry/${svc}:win-dev
+ docker manifest create $registry/${svc}:latest $registry/${svc}:linux-latest $registry/${svc}:win-latest
+ Write-Host "Pushing manifest for $svc and tags :latest, :master, and :dev"
+ docker manifest push $registry/${svc}:latest
+ docker manifest push $registry/${svc}:dev
+ docker manifest push $registry/${svc}:master
+}
\ No newline at end of file
diff --git a/cli-windows/set-dockernat-networkategory-to-private.ps1 b/cli-windows/set-dockernat-networkategory-to-private.ps1
new file mode 100644
index 000000000..6614c8e8a
--- /dev/null
+++ b/cli-windows/set-dockernat-networkategory-to-private.ps1
@@ -0,0 +1,2 @@
+ #Requires -RunAsAdministrator
+ Get-NetConnectionProfile | Where-Object { $_.InterfaceAlias -match "(DockerNAT)" } | ForEach-Object { Set-NetConnectionProfile -InterfaceIndex $_.InterfaceIndex -NetworkCategory Private }
diff --git a/deploy/az/servicebus/readme.md b/deploy/az/servicebus/readme.md
index 16da4c7b2..886b3ec60 100644
--- a/deploy/az/servicebus/readme.md
+++ b/deploy/az/servicebus/readme.md
@@ -8,7 +8,7 @@ The ARM template `sbusdeploy.json` and its parameter file (`sbusdeploy.parameter
## Editing sbusdeploy.parameters.json file
-You can edit the `sbusdeploy.parameters.parameters.json` file to set your values, but is not needed. The only parameter than can
+You can edit the `sbusdeploy.parameters.json` file to set your values, but is not needed. The only parameter than can
be set is:
1. `namespaceprefix` is a string that is used to create the namespace. ARM script creates unique values by appending a unique string to this parameter value, so you can leave the default value.
@@ -21,4 +21,4 @@ i. e. if you are in windows, to deploy servicebus in a new resourcegroup located
```
create-resources.cmd servicebus\sbusdeploy newResourceGroup -c westus
-```
\ No newline at end of file
+```
diff --git a/docker-compose.elk.yml b/docker-compose.elk.yml
new file mode 100644
index 000000000..04e6c8a05
--- /dev/null
+++ b/docker-compose.elk.yml
@@ -0,0 +1,37 @@
+version: '3.4'
+
+services:
+
+ elasticsearch:
+ build:
+ context: elk/elasticsearch/
+ volumes:
+ - ./elk/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro
+ ports:
+ - "9200:9200"
+ - "9300:9300"
+ environment:
+ ES_JAVA_OPTS: "-Xmx256m -Xms256m"
+
+ logstash:
+ build:
+ context: elk/logstash/
+ volumes:
+ - ./elk/logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml:ro
+ - ./elk/logstash/pipeline:/usr/share/logstash/pipeline:ro
+ ports:
+ - "8080:8080"
+ environment:
+ LS_JAVA_OPTS: "-Xmx256m -Xms256m"
+ depends_on:
+ - elasticsearch
+
+ kibana:
+ build:
+ context: elk/kibana/
+ volumes:
+ - ./elk/kibana/config/:/usr/share/kibana/config:ro
+ ports:
+ - "5601:5601"
+ depends_on:
+ - elasticsearch
\ No newline at end of file
diff --git a/docker-compose.override.yml b/docker-compose.override.yml
index f8d608a27..e59a9a2e6 100644
--- a/docker-compose.override.yml
+++ b/docker-compose.override.yml
@@ -7,6 +7,12 @@ version: '3.4'
# An external IP or DNS name has to be used (instead localhost and the 10.0.75.1 IP) when testing the Web apps and the Xamarin apps from remote machines/devices using the same WiFi, for instance.
services:
+ seq:
+ environment:
+ - ACCEPT_EULA=Y
+ ports:
+ - "5340:80"
+
sql.data:
environment:
- SA_PASSWORD=Pass@word
@@ -318,7 +324,7 @@ services:
webstatus:
environment:
- - ASPNETCORE_ENVIRONMENT=Development
+ - ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://0.0.0.0:80
- HealthChecks-UI__HealthChecks__1__Name=WebMVC HTTP Check
- HealthChecks-UI__HealthChecks__1__Uri=http://webmvc/hc
diff --git a/docker-compose.yml b/docker-compose.yml
index 194d7e06c..8c523e122 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,6 +1,10 @@
version: '3.4'
services:
+
+ seq:
+ image: datalust/seq:latest
+
sql.data:
image: microsoft/mssql-server-linux:2017-latest
@@ -14,7 +18,7 @@ services:
image: rabbitmq:3-management-alpine
identity.api:
- image: ${REGISTRY:-eshop}/identity.api:${TAG:-latest}
+ image: ${REGISTRY:-eshop}/identity.api:${PLATFORM:-linux}-${TAG:-latest}
build:
context: .
dockerfile: src/Services/Identity/Identity.API/Dockerfile
@@ -22,7 +26,7 @@ services:
- sql.data
basket.api:
- image: ${REGISTRY:-eshop}/basket.api:${TAG:-latest}
+ image: ${REGISTRY:-eshop}/basket.api:${PLATFORM:-linux}-${TAG:-latest}
build:
context: .
dockerfile: src/Services/Basket/Basket.API/Dockerfile
@@ -32,7 +36,7 @@ services:
- rabbitmq
catalog.api:
- image: ${REGISTRY:-eshop}/catalog.api:${TAG:-latest}
+ image: ${REGISTRY:-eshop}/catalog.api:${PLATFORM:-linux}-${TAG:-latest}
build:
context: .
dockerfile: src/Services/Catalog/Catalog.API/Dockerfile
@@ -41,7 +45,7 @@ services:
- rabbitmq
ordering.api:
- image: ${REGISTRY:-eshop}/ordering.api:${TAG:-latest}
+ image: ${REGISTRY:-eshop}/ordering.api:${PLATFORM:-linux}-${TAG:-latest}
build:
context: .
dockerfile: src/Services/Ordering/Ordering.API/Dockerfile
@@ -50,7 +54,7 @@ services:
- rabbitmq
ordering.backgroundtasks:
- image: ${REGISTRY:-eshop}/ordering.backgroundtasks:${TAG:-latest}
+ image: ${REGISTRY:-eshop}/ordering.backgroundtasks:${PLATFORM:-linux}-${TAG:-latest}
build:
context: .
dockerfile: src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile
@@ -59,7 +63,7 @@ services:
- rabbitmq
marketing.api:
- image: ${REGISTRY:-eshop}/marketing.api:${TAG:-latest}
+ image: ${REGISTRY:-eshop}/marketing.api:${PLATFORM:-linux}-${TAG:-latest}
build:
context: .
dockerfile: src/Services/Marketing/Marketing.API/Dockerfile
@@ -70,7 +74,7 @@ services:
- rabbitmq
payment.api:
- image: ${REGISTRY:-eshop}/payment.api:${TAG:-latest}
+ image: ${REGISTRY:-eshop}/payment.api:${PLATFORM:-linux}-${TAG:-latest}
build:
context: .
dockerfile: src/Services/Payment/Payment.API/Dockerfile
@@ -78,7 +82,7 @@ services:
- rabbitmq
locations.api:
- image: ${REGISTRY:-eshop}/locations.api:${TAG:-latest}
+ image: ${REGISTRY:-eshop}/locations.api:${PLATFORM:-linux}-${TAG:-latest}
build:
context: .
dockerfile: src/Services/Location/Locations.API/Dockerfile
@@ -87,7 +91,7 @@ services:
- rabbitmq
webhooks.api:
- image: ${REGISTRY:-eshop}/webhooks.api:${TAG:-latest}
+ image: ${REGISTRY:-eshop}/webhooks.api:${PLATFORM:-linux}-${TAG:-latest}
build:
context: .
dockerfile: src/Services/Webhooks/Webhooks.API/Dockerfile
@@ -95,7 +99,7 @@ services:
- sql.data
mobileshoppingapigw:
- image: ${REGISTRY:-eshop}/ocelotapigw:${TAG:-latest}
+ image: ${REGISTRY:-eshop}/ocelotapigw:${PLATFORM:-linux}-${TAG:-latest}
build:
context: .
dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile
@@ -110,7 +114,7 @@ services:
- basket.api
mobilemarketingapigw:
- image: ${REGISTRY:-eshop}/ocelotapigw:${TAG:-latest}
+ image: ${REGISTRY:-eshop}/ocelotapigw:${PLATFORM:-linux}-${TAG:-latest}
build:
context: .
dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile
@@ -125,7 +129,7 @@ services:
- basket.api
webshoppingapigw:
- image: ${REGISTRY:-eshop}/ocelotapigw:${TAG:-latest}
+ image: ${REGISTRY:-eshop}/ocelotapigw:${PLATFORM:-linux}-${TAG:-latest}
build:
context: .
dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile
@@ -140,7 +144,7 @@ services:
- basket.api
webmarketingapigw:
- image: ${REGISTRY:-eshop}/ocelotapigw:${TAG:-latest}
+ image: ${REGISTRY:-eshop}/ocelotapigw:${PLATFORM:-linux}-${TAG:-latest}
build:
context: .
dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile
@@ -155,7 +159,7 @@ services:
- basket.api
mobileshoppingagg:
- image: ${REGISTRY:-eshop}/mobileshoppingagg:${TAG:-latest}
+ image: ${REGISTRY:-eshop}/mobileshoppingagg:${PLATFORM:-linux}-${TAG:-latest}
build:
context: .
dockerfile: src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile
@@ -170,7 +174,7 @@ services:
- basket.api
webshoppingagg:
- image: ${REGISTRY:-eshop}/webshoppingagg:${TAG:-latest}
+ image: ${REGISTRY:-eshop}/webshoppingagg:${PLATFORM:-linux}-${TAG:-latest}
build:
context: .
dockerfile: src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile
@@ -185,7 +189,7 @@ services:
- basket.api
ordering.signalrhub:
- image: ${REGISTRY:-eshop}/ordering.signalrhub:${TAG:-latest}
+ image: ${REGISTRY:-eshop}/ordering.signalrhub:${PLATFORM:-linux}-${TAG:-latest}
build:
context: .
dockerfile: src/Services/Ordering/Ordering.SignalrHub/Dockerfile
@@ -200,13 +204,13 @@ services:
- basket.api
webstatus:
- image: ${REGISTRY:-eshop}/webstatus:${TAG:-latest}
+ image: ${REGISTRY:-eshop}/webstatus:${PLATFORM:-linux}-${TAG:-latest}
build:
context: .
dockerfile: src/Web/WebStatus/Dockerfile
webspa:
- image: ${REGISTRY:-eshop}/webspa:${TAG:-latest}
+ image: ${REGISTRY:-eshop}/webspa:${PLATFORM:-linux}-${TAG:-latest}
build:
context: .
dockerfile: src/Web/WebSPA/Dockerfile
@@ -216,7 +220,7 @@ services:
# - webmarketingapigw
webmvc:
- image: ${REGISTRY:-eshop}/webmvc:${TAG:-latest}
+ image: ${REGISTRY:-eshop}/webmvc:${PLATFORM:-linux}-${TAG:-latest}
build:
context: .
dockerfile: src/Web/WebMVC/Dockerfile
@@ -226,7 +230,7 @@ services:
- webmarketingapigw
webhooks.client:
- image: ${REGISTRY:-eshop}/webhooks.client:${TAG:-latest}
+ image: ${REGISTRY:-eshop}/webhooks.client:${PLATFORM:-linux}-${TAG:-latest}
build:
context: .
dockerfile: src/Web/WebhookClient/Dockerfile
diff --git a/docker-scripts/linux/install-node.sh b/docker-scripts/linux/install-node.sh
deleted file mode 100644
index 73407aae9..000000000
--- a/docker-scripts/linux/install-node.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh
-
-export NODE_DOWNLOAD_SHA 0e20787e2eda4cc31336d8327556ebc7417e8ee0a6ba0de96a09b0ec2b841f60
-curl -SL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz" --output nodejs.tar.gz \
- && echo "$NODE_DOWNLOAD_SHA nodejs.tar.gz" | sha256sum -c - \
- && tar -xzf "nodejs.tar.gz" -C /usr/local --strip-components=1 \
- && rm nodejs.tar.gz \
- && ln -s /usr/local/bin/node /usr/local/bin/nodejs
diff --git a/docker-scripts/win/install-node.cmd b/docker-scripts/win/install-node.cmd
deleted file mode 100644
index eaa4e356c..000000000
--- a/docker-scripts/win/install-node.cmd
+++ /dev/null
@@ -1,4 +0,0 @@
-set NODE_VERSION=8.11.1
-curl -SL "https://nodejs.org/dist/v%NODE_VERSION%/node-v%NODE_VERSION%-win-x64.zip" --output nodejs.zip
-tar -xf nodejs.zip -C c:\
-setx PATH "%PATH%;c:\node-v%NODE_VERSION%-win-x64"
\ No newline at end of file
diff --git a/eShopOnContainers-ServicesAndWebApps.sln b/eShopOnContainers-ServicesAndWebApps.sln
index 447b73073..882bca09f 100644
--- a/eShopOnContainers-ServicesAndWebApps.sln
+++ b/eShopOnContainers-ServicesAndWebApps.sln
@@ -142,9 +142,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Payment.API", "src\Services
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Webhooks", "Webhooks", "{E0AA11C4-2873-461D-8F82-53392530FB7A}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Webhooks.API", "src\Services\Webhooks\Webhooks.API\Webhooks.API.csproj", "{84E2016E-0435-44C6-8020-3D288AA38B2C}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Webhooks.API", "src\Services\Webhooks\Webhooks.API\Webhooks.API.csproj", "{84E2016E-0435-44C6-8020-3D288AA38B2C}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebhookClient", "src\Web\WebhookClient\WebhookClient.csproj", "{766D7E92-6AF0-476C-ADD5-282BF4D8C576}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebhookClient", "src\Web\WebhookClient\WebhookClient.csproj", "{766D7E92-6AF0-476C-ADD5-282BF4D8C576}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Devspace.Support", "Devspace.Support", "{68F5041D-51F2-4630-94B6-B49789F5E51A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Devspaces.Support", "src\BuildingBlocks\Devspaces.Support\Devspaces.Support.csproj", "{56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -1744,6 +1748,54 @@ Global
{766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Release|x64.Build.0 = Release|Any CPU
{766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Release|x86.ActiveCfg = Release|Any CPU
{766D7E92-6AF0-476C-ADD5-282BF4D8C576}.Release|x86.Build.0 = Release|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.AppStore|ARM.ActiveCfg = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.AppStore|ARM.Build.0 = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.AppStore|x64.ActiveCfg = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.AppStore|x64.Build.0 = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.AppStore|x86.ActiveCfg = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.AppStore|x86.Build.0 = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Debug|ARM.Build.0 = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Debug|x64.Build.0 = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Debug|x86.Build.0 = Debug|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|Any CPU.Build.0 = Release|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|ARM.ActiveCfg = Release|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|ARM.Build.0 = Release|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|iPhone.Build.0 = Release|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|x64.ActiveCfg = Release|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|x64.Build.0 = Release|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|x86.ActiveCfg = Release|Any CPU
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1808,6 +1860,8 @@ Global
{E0AA11C4-2873-461D-8F82-53392530FB7A} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8}
{84E2016E-0435-44C6-8020-3D288AA38B2C} = {E0AA11C4-2873-461D-8F82-53392530FB7A}
{766D7E92-6AF0-476C-ADD5-282BF4D8C576} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04}
+ {68F5041D-51F2-4630-94B6-B49789F5E51A} = {DB0EFB20-B024-4E5E-A75C-52143C131D25}
+ {56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35} = {68F5041D-51F2-4630-94B6-B49789F5E51A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {25728519-5F0F-4973-8A64-0A81EB4EA8D9}
diff --git a/eShopOnContainers.sln b/eShopOnContainers.sln
index 999203557..8e08a05fa 100644
--- a/eShopOnContainers.sln
+++ b/eShopOnContainers.sln
@@ -55,20 +55,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBusRabbitMQ", "src\Bui
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationEventLogEF", "src\BuildingBlocks\EventBus\IntegrationEventLogEF\IntegrationEventLogEF.csproj", "{9EE28E45-1533-472B-8267-56C48855BA0E}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HealthChecks", "HealthChecks", "{A81ECBC2-6B00-4DCD-8388-469174033379}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.HealthChecks", "src\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj", "{942ED6E8-0050-495F-A0EA-01E97F63760C}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebStatus", "src\Web\WebStatus\WebStatus.csproj", "{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Payment", "Payment", "{022E145D-1593-47EE-9608-8E323D3C63F5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Payment.API", "src\Services\Payment\Payment.API\Payment.API.csproj", "{1A01AF82-6FCB-464C-B39C-F127AEBD315D}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HealthChecks", "src\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj", "{22A0F9C1-2D4A-4107-95B7-8459E6688BC5}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.HealthChecks.SqlServer", "src\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.SqlServer\Microsoft.Extensions.HealthChecks.SqlServer.csproj", "{4BD76717-3102-4969-8C2C-BAAA3F0263B6}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Location", "Location", "{41139F64-4046-4F16-96B7-D941D96FA9C6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Locations.API", "src\Services\Location\Locations.API\Locations.API.csproj", "{E7581357-FC34-474C-B8F5-307EE3CE05EF}"
@@ -79,8 +71,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Marketing.API", "src\Servic
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBusServiceBus", "src\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj", "{69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.HealthChecks.AzureStorage", "src\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.AzureStorage\Microsoft.Extensions.HealthChecks.AzureStorage.csproj", "{768C887F-C229-4B94-ACD8-0C7F65686524}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebHost", "WebHost", "{1815B651-941C-466B-AE33-D1D7EEB8F77F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebHost.Customization", "src\BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj", "{15F4B3AA-89B6-4A0D-9051-414305974781}"
@@ -141,6 +131,36 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{DA1786E4
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{30308DE0-8128-4613-BCAD-B0BEFFB20E38}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ApiGateways", "ApiGateways", "{79C64C7A-ED74-4F01-921F-92F4F9FC1E1D}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ApiGw-Base", "ApiGw-Base", "{56AD1FCA-6E16-4798-BF29-941C5B3277D2}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mobile.Bff.Marketing", "Mobile.Bff.Marketing", "{34ED3311-2B30-4C8B-823B-312B50FFC32A}"
+ 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", "{A32A5254-BA36-46FC-8C75-F7B8FFE8FCD0}"
+ 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", "{696D2B7E-6B75-401D-964A-BFE6F4D7AF73}"
+ 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", "{424BC53E-17EA-4E12-BC07-64BAA927ABCB}"
+ 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", "{0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mobile.Shopping.HttpAggregator", "src\ApiGateways\Mobile.Bff.Shopping\aggregator\Mobile.Shopping.HttpAggregator.csproj", "{98E0B3BA-6601-4C59-A9AA-24A00A17D835}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Web.Shopping.HttpAggregator", "src\ApiGateways\Web.Bff.Shopping\aggregator\Web.Shopping.HttpAggregator.csproj", "{E39BD762-BC86-459D-B818-B6BF2D9F1352}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
@@ -635,54 +655,6 @@ Global
{9EE28E45-1533-472B-8267-56C48855BA0E}.Release|x64.Build.0 = Release|Any CPU
{9EE28E45-1533-472B-8267-56C48855BA0E}.Release|x86.ActiveCfg = Release|Any CPU
{9EE28E45-1533-472B-8267-56C48855BA0E}.Release|x86.Build.0 = Release|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|Any CPU.Build.0 = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|ARM.ActiveCfg = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|ARM.Build.0 = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|iPhone.Build.0 = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|x64.ActiveCfg = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|x64.Build.0 = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|x86.ActiveCfg = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.AppStore|x86.Build.0 = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|ARM.Build.0 = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|iPhone.Build.0 = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|x64.ActiveCfg = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|x64.Build.0 = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|x86.ActiveCfg = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Debug|x86.Build.0 = Debug|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|Any CPU.Build.0 = Release|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|ARM.ActiveCfg = Release|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|ARM.Build.0 = Release|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|iPhone.ActiveCfg = Release|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|iPhone.Build.0 = Release|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|x64.ActiveCfg = Release|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|x64.Build.0 = Release|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|x86.ActiveCfg = Release|Any CPU
- {942ED6E8-0050-495F-A0EA-01E97F63760C}.Release|x86.Build.0 = Release|Any CPU
{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
@@ -779,102 +751,6 @@ Global
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|x64.Build.0 = Release|Any CPU
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|x86.ActiveCfg = Release|Any CPU
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|x86.Build.0 = Release|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|Any CPU.Build.0 = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|ARM.ActiveCfg = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|ARM.Build.0 = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|iPhone.Build.0 = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|x64.ActiveCfg = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|x64.Build.0 = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|x86.ActiveCfg = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.AppStore|x86.Build.0 = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|ARM.Build.0 = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|iPhone.Build.0 = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|x64.ActiveCfg = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|x64.Build.0 = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|x86.ActiveCfg = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Debug|x86.Build.0 = Debug|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|Any CPU.Build.0 = Release|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|ARM.ActiveCfg = Release|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|ARM.Build.0 = Release|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|iPhone.ActiveCfg = Release|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|iPhone.Build.0 = Release|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|x64.ActiveCfg = Release|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|x64.Build.0 = Release|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|x86.ActiveCfg = Release|Any CPU
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Release|x86.Build.0 = Release|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|Any CPU.Build.0 = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|ARM.ActiveCfg = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|ARM.Build.0 = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|iPhone.Build.0 = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|x64.ActiveCfg = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|x64.Build.0 = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|x86.ActiveCfg = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.AppStore|x86.Build.0 = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|ARM.Build.0 = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|iPhone.Build.0 = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|x64.ActiveCfg = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|x64.Build.0 = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|x86.ActiveCfg = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Debug|x86.Build.0 = Debug|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|Any CPU.Build.0 = Release|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|ARM.ActiveCfg = Release|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|ARM.Build.0 = Release|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|iPhone.ActiveCfg = Release|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|iPhone.Build.0 = Release|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|x64.ActiveCfg = Release|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|x64.Build.0 = Release|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|x86.ActiveCfg = Release|Any CPU
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|x86.Build.0 = Release|Any CPU
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
@@ -1019,54 +895,6 @@ Global
{69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8}.Release|x64.Build.0 = Release|Any CPU
{69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8}.Release|x86.ActiveCfg = Release|Any CPU
{69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8}.Release|x86.Build.0 = Release|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|Any CPU.Build.0 = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|ARM.ActiveCfg = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|ARM.Build.0 = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|iPhone.Build.0 = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|x64.ActiveCfg = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|x64.Build.0 = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|x86.ActiveCfg = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.AppStore|x86.Build.0 = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|ARM.Build.0 = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|iPhone.Build.0 = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|x64.ActiveCfg = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|x64.Build.0 = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|x86.ActiveCfg = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Debug|x86.Build.0 = Debug|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|Any CPU.Build.0 = Release|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|ARM.ActiveCfg = Release|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|ARM.Build.0 = Release|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|iPhone.ActiveCfg = Release|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|iPhone.Build.0 = Release|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|x64.ActiveCfg = Release|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|x64.Build.0 = Release|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|x86.ActiveCfg = Release|Any CPU
- {768C887F-C229-4B94-ACD8-0C7F65686524}.Release|x86.Build.0 = Release|Any CPU
{15F4B3AA-89B6-4A0D-9051-414305974781}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{15F4B3AA-89B6-4A0D-9051-414305974781}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{15F4B3AA-89B6-4A0D-9051-414305974781}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
@@ -2067,6 +1895,150 @@ Global
{3572B4E2-4399-4797-B5C2-3720D870E0C3}.Release|x64.Build.0 = Release|Any CPU
{3572B4E2-4399-4797-B5C2-3720D870E0C3}.Release|x86.ActiveCfg = Release|Any CPU
{3572B4E2-4399-4797-B5C2-3720D870E0C3}.Release|x86.Build.0 = Release|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|ARM.ActiveCfg = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|ARM.Build.0 = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|x64.ActiveCfg = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|x64.Build.0 = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|x86.ActiveCfg = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.AppStore|x86.Build.0 = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|ARM.Build.0 = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|x64.Build.0 = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Debug|x86.Build.0 = Debug|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|ARM.ActiveCfg = Release|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|ARM.Build.0 = Release|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|iPhone.Build.0 = Release|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|x64.ActiveCfg = Release|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|x64.Build.0 = Release|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|x86.ActiveCfg = Release|Any CPU
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC}.Release|x86.Build.0 = Release|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|ARM.ActiveCfg = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|ARM.Build.0 = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|x64.ActiveCfg = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|x64.Build.0 = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|x86.ActiveCfg = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.AppStore|x86.Build.0 = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|ARM.Build.0 = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|x64.Build.0 = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Debug|x86.Build.0 = Debug|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|Any CPU.Build.0 = Release|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|ARM.ActiveCfg = Release|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|ARM.Build.0 = Release|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|iPhone.Build.0 = Release|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|x64.ActiveCfg = Release|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|x64.Build.0 = Release|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|x86.ActiveCfg = Release|Any CPU
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835}.Release|x86.Build.0 = Release|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|ARM.ActiveCfg = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|ARM.Build.0 = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|x64.ActiveCfg = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|x64.Build.0 = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|x86.ActiveCfg = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.AppStore|x86.Build.0 = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|ARM.Build.0 = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|x64.Build.0 = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Debug|x86.Build.0 = Debug|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|ARM.ActiveCfg = Release|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|ARM.Build.0 = Release|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|iPhone.Build.0 = Release|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|x64.ActiveCfg = Release|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|x64.Build.0 = Release|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|x86.ActiveCfg = Release|Any CPU
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2092,19 +2064,14 @@ Global
{0044B293-1DCC-4224-B948-00CF6DC7F510} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F}
{8088F3FC-6787-45FA-A924-816EC81CBFAC} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F}
{9EE28E45-1533-472B-8267-56C48855BA0E} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F}
- {A81ECBC2-6B00-4DCD-8388-469174033379} = {DB0EFB20-B024-4E5E-A75C-52143C131D25}
- {942ED6E8-0050-495F-A0EA-01E97F63760C} = {A81ECBC2-6B00-4DCD-8388-469174033379}
{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04}
{022E145D-1593-47EE-9608-8E323D3C63F5} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8}
{1A01AF82-6FCB-464C-B39C-F127AEBD315D} = {022E145D-1593-47EE-9608-8E323D3C63F5}
- {22A0F9C1-2D4A-4107-95B7-8459E6688BC5} = {A81ECBC2-6B00-4DCD-8388-469174033379}
- {4BD76717-3102-4969-8C2C-BAAA3F0263B6} = {A81ECBC2-6B00-4DCD-8388-469174033379}
{41139F64-4046-4F16-96B7-D941D96FA9C6} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8}
{E7581357-FC34-474C-B8F5-307EE3CE05EF} = {41139F64-4046-4F16-96B7-D941D96FA9C6}
{A5260DE0-1FDD-467E-9CC1-A028AB081CEE} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8}
{DF395F85-B010-465D-857A-7EBCC512C0C2} = {A5260DE0-1FDD-467E-9CC1-A028AB081CEE}
{69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F}
- {768C887F-C229-4B94-ACD8-0C7F65686524} = {A81ECBC2-6B00-4DCD-8388-469174033379}
{1815B651-941C-466B-AE33-D1D7EEB8F77F} = {DB0EFB20-B024-4E5E-A75C-52143C131D25}
{15F4B3AA-89B6-4A0D-9051-414305974781} = {1815B651-941C-466B-AE33-D1D7EEB8F77F}
{EF3EDC78-E864-43FF-8E80-CF33DD9508A3} = {932D8224-11F6-4D07-B109-DA28AD288A63}
@@ -2135,6 +2102,15 @@ Global
{2B26A7AA-6D61-42FA-8AB7-C0F05AAE7F1C} = {41139F64-4046-4F16-96B7-D941D96FA9C6}
{DA1786E4-30AB-434E-A827-92896390B79D} = {A5260DE0-1FDD-467E-9CC1-A028AB081CEE}
{30308DE0-8128-4613-BCAD-B0BEFFB20E38} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B}
+ {79C64C7A-ED74-4F01-921F-92F4F9FC1E1D} = {932D8224-11F6-4D07-B109-DA28AD288A63}
+ {56AD1FCA-6E16-4798-BF29-941C5B3277D2} = {79C64C7A-ED74-4F01-921F-92F4F9FC1E1D}
+ {34ED3311-2B30-4C8B-823B-312B50FFC32A} = {79C64C7A-ED74-4F01-921F-92F4F9FC1E1D}
+ {A32A5254-BA36-46FC-8C75-F7B8FFE8FCD0} = {79C64C7A-ED74-4F01-921F-92F4F9FC1E1D}
+ {696D2B7E-6B75-401D-964A-BFE6F4D7AF73} = {79C64C7A-ED74-4F01-921F-92F4F9FC1E1D}
+ {424BC53E-17EA-4E12-BC07-64BAA927ABCB} = {79C64C7A-ED74-4F01-921F-92F4F9FC1E1D}
+ {0A328C44-4C4E-49BE-9FB4-9D851CEC28AC} = {56AD1FCA-6E16-4798-BF29-941C5B3277D2}
+ {98E0B3BA-6601-4C59-A9AA-24A00A17D835} = {A32A5254-BA36-46FC-8C75-F7B8FFE8FCD0}
+ {E39BD762-BC86-459D-B818-B6BF2D9F1352} = {424BC53E-17EA-4E12-BC07-64BAA927ABCB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {25728519-5F0F-4973-8A64-0A81EB4EA8D9}
diff --git a/elk/Readme.md b/elk/Readme.md
new file mode 100644
index 000000000..dddeab3fd
--- /dev/null
+++ b/elk/Readme.md
@@ -0,0 +1,88 @@
+This article contains a brief introduction to centralized structured logging with [Serilog](https://serilog.net/) and event viewing with [ELK](https://www.elastic.co/elk-stack) in eShopOnContainers. ELK is an acronym of ElasticSearch, LogStash and Kibana. This is one of the most used tools in the industry standards.
+
+![](img/elk/kibana-working.png)
+
+## Wiring eshopOnContainers with ELK in Localhost
+
+eshopOnContainers is ready for work with ELK, you only need to setup the configuration parameter **LogstashUrl**, in **Serilog** Section, for achieve this, you can do it modifing this parameter in every appsettings.json of every service, or via Environment Variable **Serilog:LogstashUrl**.
+
+There is another option, a zero-configuration environment for testing the integration launching via ```docker-compose``` command, on the root directory of eshopOnContainers:
+
+```sh
+docker-compose -f docker-compose.yml -f docker-compose.override.yml -f docker-compose.elk.yml build
+
+docker-compose -f docker-compose.yml -f docker-compose.override.yml -f docker-compose.elk.yml up
+```
+
+### Configuring Logstash index on Kibana
+
+Once time you have started and configured your application, you only need to configure the logstash index on kibana.
+You can address to Kibana, with docker-compose setup is at [http://localhost:5601](http://localhost:5601)
+
+If you have accessed to kibana too early, you can see this error. It's normal, depending of your machine the kibana stack needs a bit of time to startup.
+![](img/elk/kibana_startup.png)
+
+You can wait a bit and refresh the page, the first time you enter, you need to configure and index pattern, in the ```docker-compose``` configuration, the index pattern name is **eshops-\***.
+![](img/elk/kibana_eshops_index.png)
+
+With the index pattern configured, you can enter in the discover section and start viewing how the tool is recollecting the logging information.
+
+![](img/elk/kibana_result.png)
+
+## Configuring ELK on Azure VM
+Another option is to use a preconfigured virtual machine with Logstash, ElasticSearch and Kibana and point the configuration parameter **LogstashUrl**. For doing this you can address to Microsoft Azure, and start searching a Certified ELK Virtual Machine
+
+![](img/elk/create-vm-elk-azure.png)
+
+This options it have a certified preconfigured options (Network, VirtualMachine type, OS, RAM, Disks) for having a good starting point of ELK with good performance.
+
+![](img/elk/create-vm-elk-azure-summary.png)
+
+When you have configured the main aspects of your virtual machine, you will have a "review & create" last step like this:
+![](img/elk/create-vm-elk-azure-last-step.png)
+
+### Configuring the bitnami environment
+
+ This virtual machine has a lot of configuration pipeing done. If you want to change something of the default configuration you can address this documentation:
+ [https://docs.bitnami.com/virtual-machine/apps/elk/get-started/](https://docs.bitnami.com/virtual-machine/apps/elk/get-started/)
+
+ The only thing you have to change is the logstash configuration inside the machine. This configuration is at the file ```/opt/bitnami/logstash/conf/logstash.conf```
+ You must edit the file and overwrite with this configuration:
+ ```conf
+ input {
+ http {
+ #default host 0.0.0.0:8080
+ codec => json
+ }
+}
+
+## Add your filters / logstash plugins configuration here
+filter {
+ split {
+ field => "events"
+ target => "e"
+ remove_field => "events"
+ }
+}
+
+output {
+ elasticsearch {
+ hosts => "elasticsearch:9200"
+ index=>"eshops-%{+xxxx.ww}"
+ }
+}
+```
+
+For doing this you can connect via ssh to the vm and edit the file using the vi editor for example.
+When the file will be edited, check there are Inbound Port Rules created for the logstash service. You can do it going to Networking Menu on your ELK Virtual Machine Resource in Azure.
+
+![](img/elk/azure-nsg-inboundportsConfig.png)
+
+The only thing that remains is to connect to your vm vía browser. And check the bitnami splash page is showing.
+
+![](img/elk/bitnami_splash.png)
+
+You can get the password for accessing going to your virtual machine in azure and check the boot diagnostics, theres a message that shows to you which is your password.
+
+When you have the user and password you can access to the kibana tool, and create the ```eshops-*``` index pattern that is well documented at the beggining of this documentation and then start to discover.
+![](img/elk/)
\ No newline at end of file
diff --git a/elk/elasticsearch/Dockerfile b/elk/elasticsearch/Dockerfile
new file mode 100644
index 000000000..0ad46d887
--- /dev/null
+++ b/elk/elasticsearch/Dockerfile
@@ -0,0 +1,5 @@
+# https://github.com/elastic/elasticsearch-docker
+FROM docker.elastic.co/elasticsearch/elasticsearch-oss:6.0.0
+
+# Add your elasticsearch plugins setup here
+# Example: RUN elasticsearch-plugin install analysis-icu
diff --git a/elk/elasticsearch/config/elasticsearch.yml b/elk/elasticsearch/config/elasticsearch.yml
new file mode 100644
index 000000000..e97577084
--- /dev/null
+++ b/elk/elasticsearch/config/elasticsearch.yml
@@ -0,0 +1,16 @@
+---
+## Default Elasticsearch configuration from elasticsearch-docker.
+## from https://github.com/elastic/elasticsearch-docker/blob/master/build/elasticsearch/elasticsearch.yml
+#
+cluster.name: "docker-cluster"
+network.host: 0.0.0.0
+
+# minimum_master_nodes need to be explicitly set when bound on a public IP
+# set to 1 to allow single node clusters
+# Details: https://github.com/elastic/elasticsearch/pull/17288
+discovery.zen.minimum_master_nodes: 1
+
+## Use single node discovery in order to disable production mode and avoid bootstrap checks
+## see https://www.elastic.co/guide/en/elasticsearch/reference/current/bootstrap-checks.html
+#
+discovery.type: single-node
diff --git a/elk/kibana/Dockerfile b/elk/kibana/Dockerfile
new file mode 100644
index 000000000..1785734aa
--- /dev/null
+++ b/elk/kibana/Dockerfile
@@ -0,0 +1,5 @@
+# https://github.com/elastic/kibana-docker
+FROM docker.elastic.co/kibana/kibana-oss:6.0.0
+
+# Add your kibana plugins setup here
+# Example: RUN kibana-plugin install
diff --git a/elk/kibana/config/kibana.yml b/elk/kibana/config/kibana.yml
new file mode 100644
index 000000000..4b34a1606
--- /dev/null
+++ b/elk/kibana/config/kibana.yml
@@ -0,0 +1,7 @@
+---
+## Default Kibana configuration from kibana-docker.
+## from https://github.com/elastic/kibana-docker/blob/master/build/kibana/config/kibana.yml
+#
+server.name: kibana
+server.host: "0"
+elasticsearch.url: http://elasticsearch:9200
diff --git a/elk/logstash/Dockerfile b/elk/logstash/Dockerfile
new file mode 100644
index 000000000..d8bb475a5
--- /dev/null
+++ b/elk/logstash/Dockerfile
@@ -0,0 +1,6 @@
+# https://github.com/elastic/logstash-docker
+FROM docker.elastic.co/logstash/logstash-oss:6.0.0
+
+# Add your logstash plugins setup here
+# Example: RUN logstash-plugin install logstash-filter-json
+RUN logstash-plugin install logstash-input-http
\ No newline at end of file
diff --git a/elk/logstash/config/logstash.yml b/elk/logstash/config/logstash.yml
new file mode 100644
index 000000000..d4f28f778
--- /dev/null
+++ b/elk/logstash/config/logstash.yml
@@ -0,0 +1,6 @@
+---
+## Default Logstash configuration from logstash-docker.
+## from https://github.com/elastic/logstash-docker/blob/master/build/logstash/config/logstash-oss.yml
+#
+http.host: "0.0.0.0"
+path.config: /usr/share/logstash/pipeline
\ No newline at end of file
diff --git a/elk/logstash/pipeline/logstash.conf b/elk/logstash/pipeline/logstash.conf
new file mode 100644
index 000000000..b38a681d7
--- /dev/null
+++ b/elk/logstash/pipeline/logstash.conf
@@ -0,0 +1,22 @@
+input {
+ http {
+ #default host 0.0.0.0:8080
+ codec => json
+ }
+}
+
+## Add your filters / logstash plugins configuration here
+filter {
+ split {
+ field => "events"
+ target => "e"
+ remove_field => "events"
+ }
+}
+
+output {
+ elasticsearch {
+ hosts => "elasticsearch:9200"
+ index=>"eshops-%{+xxxx.ww}"
+ }
+}
diff --git a/hosts b/hosts
deleted file mode 100644
index 19e812a15..000000000
--- a/hosts
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright (c) 1993-2009 Microsoft Corp.
-#
-# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
-#
-# This file contains the mappings of IP addresses to host names. Each
-# entry should be kept on an individual line. The IP address should
-# be placed in the first column followed by the corresponding host name.
-# The IP address and the host name should be separated by at least one
-# space.
-#
-# Additionally, comments (such as these) may be inserted on individual
-# lines or following the machine name denoted by a '#' symbol.
-#
-# For example:
-#
-# 102.54.94.97 rhino.acme.com # source server
-# 38.25.63.10 x.acme.com # x client host
-
-# localhost name resolution is handled within DNS itself.
-# 127.0.0.1 localhost
-# ::1 localhost
-
- 10.0.75.1 identity.service
\ No newline at end of file
diff --git a/img/elk/azure-nsg-inboundportsConfig.png b/img/elk/azure-nsg-inboundportsConfig.png
new file mode 100644
index 000000000..5a0371e66
Binary files /dev/null and b/img/elk/azure-nsg-inboundportsConfig.png differ
diff --git a/img/elk/bitnami_splash.png b/img/elk/bitnami_splash.png
new file mode 100644
index 000000000..a34643864
Binary files /dev/null and b/img/elk/bitnami_splash.png differ
diff --git a/img/elk/create-vm-elk-azure-last-step.png b/img/elk/create-vm-elk-azure-last-step.png
new file mode 100644
index 000000000..348f8843c
Binary files /dev/null and b/img/elk/create-vm-elk-azure-last-step.png differ
diff --git a/img/elk/create-vm-elk-azure-summary.png b/img/elk/create-vm-elk-azure-summary.png
new file mode 100644
index 000000000..b56ae5af3
Binary files /dev/null and b/img/elk/create-vm-elk-azure-summary.png differ
diff --git a/img/elk/create-vm-elk-azure.png b/img/elk/create-vm-elk-azure.png
new file mode 100644
index 000000000..b7d98bb95
Binary files /dev/null and b/img/elk/create-vm-elk-azure.png differ
diff --git a/img/elk/discover-kibana.png b/img/elk/discover-kibana.png
new file mode 100644
index 000000000..3977042c7
Binary files /dev/null and b/img/elk/discover-kibana.png differ
diff --git a/img/elk/kibana_eshops_index.png b/img/elk/kibana_eshops_index.png
new file mode 100644
index 000000000..5a4be8ec3
Binary files /dev/null and b/img/elk/kibana_eshops_index.png differ
diff --git a/img/elk/kibana_result.png b/img/elk/kibana_result.png
new file mode 100644
index 000000000..55b7fd3ff
Binary files /dev/null and b/img/elk/kibana_result.png differ
diff --git a/img/elk/kibana_startup.png b/img/elk/kibana_startup.png
new file mode 100644
index 000000000..e283d7de8
Binary files /dev/null and b/img/elk/kibana_startup.png differ
diff --git a/img/elk/kibana_working.png b/img/elk/kibana_working.png
new file mode 100644
index 000000000..e310e2710
Binary files /dev/null and b/img/elk/kibana_working.png differ
diff --git a/k8s/README.k8s.md b/k8s/README.k8s.md
index 62841aba1..84d9a72f0 100644
--- a/k8s/README.k8s.md
+++ b/k8s/README.k8s.md
@@ -20,7 +20,7 @@ For AKS:
For ACS:
>```
->./gen-k8s-env -resourceGroupName k8sGroup -location westeurope -registryName k8sregistry -createAcr true -orchestratorName k8s-cluster -dnsName k8s-dns
+>./gen-k8s-env-aks -resourceGroupName k8sGroup -location westeurope -registryName k8sregistry -serviceName k8s-cluster -createAcr true -nodeCount 3 -nodeVMSize Standard_D2_v2
>```
* A Docker development environment with `docker` and `docker-compose`.
diff --git a/k8s/helm/apigwmm/templates/_names.tpl b/k8s/helm/apigwmm/templates/_names.tpl
index a6eeb9965..d44859fea 100644
--- a/k8s/helm/apigwmm/templates/_names.tpl
+++ b/k8s/helm/apigwmm/templates/_names.tpl
@@ -33,14 +33,13 @@
{{- end -}}
+
{{- define "pathBase" -}}
-{{- $name := first .}}
-{{- $ctx := last .}}
-{{- if $ctx.Values.inf.k8s.suffix -}}
-{{- $suffix := include "suffix-name" $ctx -}}
-{{- printf "/%s-%s" $name $suffix -}}
+{{- if .Values.inf.k8s.suffix -}}
+{{- $suffix := include "suffix-name" . -}}
+{{- printf "%s-%s" .Values.pathBase $suffix -}}
{{- else -}}
-{{- printf "/%s" $name -}}
+{{- .Values.pathBase -}}
{{- end -}}
{{- end -}}
diff --git a/k8s/helm/apigwmm/templates/deployment.yaml b/k8s/helm/apigwmm/templates/deployment.yaml
index 6dc58bf50..c9abb0b62 100644
--- a/k8s/helm/apigwmm/templates/deployment.yaml
+++ b/k8s/helm/apigwmm/templates/deployment.yaml
@@ -61,10 +61,10 @@ spec:
imagePullPolicy: {{ .Values.image.pullPolicy }}
volumeMounts:
- name: config
- mountPath: /app/configuration
+ mountPath: {{ .Values.ocelot.configPath }}
env:
- name: PATH_BASE
- value: {{ include "pathBase" (list .Values.app.ingress.entries.mobilemarketingapigw .) }}
+ value: {{ include "pathBase" . }}
- name: k8sname
value: {{ .Values.clusterName }}
{{- if .Values.env.values -}}
diff --git a/k8s/helm/apigwmm/templates/ingress.yaml b/k8s/helm/apigwmm/templates/ingress.yaml
index 28e2aa84d..290aac0b3 100644
--- a/k8s/helm/apigwmm/templates/ingress.yaml
+++ b/k8s/helm/apigwmm/templates/ingress.yaml
@@ -1,5 +1,6 @@
{{- if .Values.ingress.enabled -}}
-{{- $ingressPath := include "pathBase" (list .Values.app.ingress.entries.mobilemarketingapigw .) -}}
+{{- $ingressPath := include "pathBase" . -}}
+{{- $serviceName := .Values.app.svc.mobilemarketingapigw -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
@@ -23,11 +24,13 @@ spec:
{{- end }}
{{- end }}
rules:
- - host: {{ .Values.inf.k8s.dns }}
+ {{- range .Values.ingress.hosts }}
+ - host: {{ . }}
http:
paths:
- path: {{ $ingressPath }}
backend:
- serviceName: {{ .Values.app.svc.mobilemarketingapigw }}
+ serviceName: {{ $serviceName }}
servicePort: http
+ {{- end }}
{{- end }}
diff --git a/k8s/helm/apigwmm/values.yaml b/k8s/helm/apigwmm/values.yaml
index 501266780..ea87a6c05 100644
--- a/k8s/helm/apigwmm/values.yaml
+++ b/k8s/helm/apigwmm/values.yaml
@@ -62,3 +62,5 @@ probes:
initialDelaySeconds: 90
periodSeconds: 60
port: 80
+ocelot:
+ configPath: /app/configuration
diff --git a/k8s/helm/apigwms/templates/_names.tpl b/k8s/helm/apigwms/templates/_names.tpl
index 1e840c56c..d44859fea 100644
--- a/k8s/helm/apigwms/templates/_names.tpl
+++ b/k8s/helm/apigwms/templates/_names.tpl
@@ -35,13 +35,11 @@
{{- define "pathBase" -}}
-{{- $name := first .}}
-{{- $ctx := last .}}
-{{- if $ctx.Values.inf.k8s.suffix -}}
-{{- $suffix := include "suffix-name" $ctx -}}
-{{- printf "/%s-%s" $name $suffix -}}
+{{- if .Values.inf.k8s.suffix -}}
+{{- $suffix := include "suffix-name" . -}}
+{{- printf "%s-%s" .Values.pathBase $suffix -}}
{{- else -}}
-{{- printf "/%s" $name -}}
+{{- .Values.pathBase -}}
{{- end -}}
{{- end -}}
diff --git a/k8s/helm/apigwms/templates/deployment.yaml b/k8s/helm/apigwms/templates/deployment.yaml
index 8a4fd8942..b22922f89 100644
--- a/k8s/helm/apigwms/templates/deployment.yaml
+++ b/k8s/helm/apigwms/templates/deployment.yaml
@@ -61,10 +61,10 @@ spec:
imagePullPolicy: {{ .Values.image.pullPolicy }}
volumeMounts:
- name: config
- mountPath: /app/configuration
+ mountPath: {{ .Values.ocelot.configPath }}
env:
- name: PATH_BASE
- value: {{ include "pathBase" (list .Values.app.ingress.entries.mobileshoppingapigw .) }}
+ value: {{ include "pathBase" . }}
- name: k8sname
value: {{ .Values.clusterName }}
{{- if .Values.env.values -}}
diff --git a/k8s/helm/apigwms/templates/ingress.yaml b/k8s/helm/apigwms/templates/ingress.yaml
index 7dd50d8dd..e93ddc2c6 100644
--- a/k8s/helm/apigwms/templates/ingress.yaml
+++ b/k8s/helm/apigwms/templates/ingress.yaml
@@ -1,5 +1,7 @@
{{- if .Values.ingress.enabled -}}
-{{- $ingressPath := include "pathBase" (list .Values.app.ingress.entries.mobileshoppingapigw .) -}}
+{{- $ingressPath := include "pathBase" . -}}
+{{- $serviceName := .Values.app.svc.mobileshoppingapigw -}}
+
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
@@ -23,11 +25,13 @@ spec:
{{- end }}
{{- end }}
rules:
- - host: {{ .Values.inf.k8s.dns }}
+ {{- range .Values.ingress.hosts }}
+ - host: {{ . }}
http:
paths:
- path: {{ $ingressPath }}
backend:
- serviceName: {{ .Values.app.svc.mobileshoppingapigw }}
+ serviceName: {{ $serviceName }}
servicePort: http
+ {{- end }}
{{- end }}
diff --git a/k8s/helm/apigwms/values.yaml b/k8s/helm/apigwms/values.yaml
index 58377ec5b..650ab6449 100644
--- a/k8s/helm/apigwms/values.yaml
+++ b/k8s/helm/apigwms/values.yaml
@@ -61,4 +61,6 @@ probes:
timeoutSeconds: 5
initialDelaySeconds: 90
periodSeconds: 60
- port: 80
\ No newline at end of file
+ port: 80
+ocelot:
+ configPath: /app/configuration
\ No newline at end of file
diff --git a/k8s/helm/apigwwm/templates/_names.tpl b/k8s/helm/apigwwm/templates/_names.tpl
index 1e840c56c..d44859fea 100644
--- a/k8s/helm/apigwwm/templates/_names.tpl
+++ b/k8s/helm/apigwwm/templates/_names.tpl
@@ -35,13 +35,11 @@
{{- define "pathBase" -}}
-{{- $name := first .}}
-{{- $ctx := last .}}
-{{- if $ctx.Values.inf.k8s.suffix -}}
-{{- $suffix := include "suffix-name" $ctx -}}
-{{- printf "/%s-%s" $name $suffix -}}
+{{- if .Values.inf.k8s.suffix -}}
+{{- $suffix := include "suffix-name" . -}}
+{{- printf "%s-%s" .Values.pathBase $suffix -}}
{{- else -}}
-{{- printf "/%s" $name -}}
+{{- .Values.pathBase -}}
{{- end -}}
{{- end -}}
diff --git a/k8s/helm/apigwwm/templates/deployment.yaml b/k8s/helm/apigwwm/templates/deployment.yaml
index 5cbce9f22..d1f39ab6c 100644
--- a/k8s/helm/apigwwm/templates/deployment.yaml
+++ b/k8s/helm/apigwwm/templates/deployment.yaml
@@ -61,10 +61,10 @@ spec:
imagePullPolicy: {{ .Values.image.pullPolicy }}
volumeMounts:
- name: config
- mountPath: /app/configuration
+ mountPath: {{ .Values.ocelot.configPath }}
env:
- name: PATH_BASE
- value: {{ include "pathBase" (list .Values.app.ingress.entries.webmarketingapigw .) }}
+ value: {{ include "pathBase" . }}
- name: k8sname
value: {{ .Values.clusterName }}
{{- if .Values.env.values -}}
diff --git a/k8s/helm/apigwwm/templates/ingress.yaml b/k8s/helm/apigwwm/templates/ingress.yaml
index 0a79c4660..297fea52b 100644
--- a/k8s/helm/apigwwm/templates/ingress.yaml
+++ b/k8s/helm/apigwwm/templates/ingress.yaml
@@ -1,5 +1,7 @@
{{- if .Values.ingress.enabled -}}
-{{- $ingressPath := include "pathBase" (list .Values.app.ingress.entries.webmarketingapigw .) -}}
+{{- $ingressPath := include "pathBase" . -}}
+{{- $serviceName := .Values.app.svc.webmarketingapigw -}}
+
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
@@ -23,11 +25,13 @@ spec:
{{- end }}
{{- end }}
rules:
- - host: {{ .Values.inf.k8s.dns }}
+ {{- range .Values.ingress.hosts }}
+ - host: {{ . }}
http:
paths:
- path: {{ $ingressPath }}
backend:
- serviceName: {{ .Values.app.svc.webmarketingapigw }}
+ serviceName: {{ $serviceName }}
servicePort: http
+ {{- end }}
{{- end }}
diff --git a/k8s/helm/apigwwm/values.yaml b/k8s/helm/apigwwm/values.yaml
index 68cbb89c4..63deb5832 100644
--- a/k8s/helm/apigwwm/values.yaml
+++ b/k8s/helm/apigwwm/values.yaml
@@ -61,4 +61,6 @@ probes:
timeoutSeconds: 5
initialDelaySeconds: 90
periodSeconds: 60
- port: 80
\ No newline at end of file
+ port: 80
+ocelot:
+ configPath: /app/configuration
\ No newline at end of file
diff --git a/k8s/helm/apigwws/templates/_names.tpl b/k8s/helm/apigwws/templates/_names.tpl
index a6eeb9965..d44859fea 100644
--- a/k8s/helm/apigwws/templates/_names.tpl
+++ b/k8s/helm/apigwws/templates/_names.tpl
@@ -33,14 +33,13 @@
{{- end -}}
+
{{- define "pathBase" -}}
-{{- $name := first .}}
-{{- $ctx := last .}}
-{{- if $ctx.Values.inf.k8s.suffix -}}
-{{- $suffix := include "suffix-name" $ctx -}}
-{{- printf "/%s-%s" $name $suffix -}}
+{{- if .Values.inf.k8s.suffix -}}
+{{- $suffix := include "suffix-name" . -}}
+{{- printf "%s-%s" .Values.pathBase $suffix -}}
{{- else -}}
-{{- printf "/%s" $name -}}
+{{- .Values.pathBase -}}
{{- end -}}
{{- end -}}
diff --git a/k8s/helm/apigwws/templates/deployment.yaml b/k8s/helm/apigwws/templates/deployment.yaml
index 4912d12bb..327eb50b7 100644
--- a/k8s/helm/apigwws/templates/deployment.yaml
+++ b/k8s/helm/apigwws/templates/deployment.yaml
@@ -60,10 +60,10 @@ spec:
imagePullPolicy: {{ .Values.image.pullPolicy }}
volumeMounts:
- name: config
- mountPath: /app/configuration
+ mountPath: {{ .Values.ocelot.configPath }}
env:
- name: PATH_BASE
- value: {{ include "pathBase" (list .Values.app.ingress.entries.webshoppingapigw .) }}
+ value: {{ include "pathBase" . }}
- name: k8sname
value: {{ .Values.clusterName }}
{{- if .Values.env.values -}}
diff --git a/k8s/helm/apigwws/templates/ingress.yaml b/k8s/helm/apigwws/templates/ingress.yaml
index ee1f681ad..8bd2cfc6d 100644
--- a/k8s/helm/apigwws/templates/ingress.yaml
+++ b/k8s/helm/apigwws/templates/ingress.yaml
@@ -1,5 +1,6 @@
{{- if .Values.ingress.enabled -}}
-{{- $ingressPath := include "pathBase" (list .Values.app.ingress.entries.webshoppingapigw .) -}}
+{{- $ingressPath := include "pathBase" . -}}
+{{- $serviceName := .Values.app.svc.webshoppingapigw -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
@@ -23,11 +24,13 @@ spec:
{{- end }}
{{- end }}
rules:
- - host: {{ .Values.inf.k8s.dns }}
+ {{- range .Values.ingress.hosts }}
+ - host: {{ . }}
http:
paths:
- path: {{ $ingressPath }}
backend:
- serviceName: {{ .Values.app.svc.webshoppingapigw }}
+ serviceName: {{ $serviceName }}
servicePort: http
+ {{- end }}
{{- end }}
diff --git a/k8s/helm/apigwws/values.yaml b/k8s/helm/apigwws/values.yaml
index 94b8a203f..2b047de99 100644
--- a/k8s/helm/apigwws/values.yaml
+++ b/k8s/helm/apigwws/values.yaml
@@ -62,3 +62,5 @@ probes:
initialDelaySeconds: 90
periodSeconds: 60
port: 80
+ocelot:
+ configPath: /app/configuration
\ No newline at end of file
diff --git a/k8s/helm/basket-api/templates/ingress.yaml b/k8s/helm/basket-api/templates/ingress.yaml
new file mode 100644
index 000000000..f99bd55a6
--- /dev/null
+++ b/k8s/helm/basket-api/templates/ingress.yaml
@@ -0,0 +1,37 @@
+{{- if .Values.ingress.enabled -}}
+{{- $ingressPath := include "pathBase" . -}}
+{{- $serviceName := .Values.app.svc.basket -}}
+
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+ name: {{ template "basket-api.fullname" . }}
+ labels:
+ app: {{ template "basket-api.name" . }}
+ chart: {{ template "basket-api.chart" . }}
+ release: {{ .Release.Name }}
+ heritage: {{ .Release.Service }}
+{{- with .Values.ingress.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+spec:
+{{- if .Values.ingress.tls }}
+ tls:
+ {{- range .Values.ingress.tls }}
+ - hosts:
+ - {{ .Values.inf.k8s.dns }}
+ secretName: {{ .secretName }}
+ {{- end }}
+{{- end }}
+ rules:
+ {{- range .Values.ingress.hosts }}
+ - host: {{ . }}
+ http:
+ paths:
+ - path: {{ $ingressPath }}
+ backend:
+ serviceName: {{ $serviceName }}
+ servicePort: http
+ {{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/k8s/helm/basket-api/values.yaml b/k8s/helm/basket-api/values.yaml
index 6c264afba..a773700fe 100644
--- a/k8s/helm/basket-api/values.yaml
+++ b/k8s/helm/basket-api/values.yaml
@@ -53,3 +53,6 @@ probes:
initialDelaySeconds: 90
periodSeconds: 60
port: 80
+
+ingress:
+ enabled: false
\ No newline at end of file
diff --git a/k8s/helm/catalog-api/templates/ingress.yaml b/k8s/helm/catalog-api/templates/ingress.yaml
new file mode 100644
index 000000000..238d7b07e
--- /dev/null
+++ b/k8s/helm/catalog-api/templates/ingress.yaml
@@ -0,0 +1,37 @@
+{{- if .Values.ingress.enabled -}}
+{{- $ingressPath := include "pathBase" . -}}
+{{- $serviceName := .Values.app.svc.catalog -}}
+
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+ name: {{ template "catalog-api.fullname" . }}
+ labels:
+ app: {{ template "catalog-api.name" . }}
+ chart: {{ template "catalog-api.chart" . }}
+ release: {{ .Release.Name }}
+ heritage: {{ .Release.Service }}
+{{- with .Values.ingress.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+spec:
+{{- if .Values.ingress.tls }}
+ tls:
+ {{- range .Values.ingress.tls }}
+ - hosts:
+ - {{ .Values.inf.k8s.dns }}
+ secretName: {{ .secretName }}
+ {{- end }}
+{{- end }}
+ rules:
+ {{- range .Values.ingress.hosts }}
+ - host: {{ . }}
+ http:
+ paths:
+ - path: {{ $ingressPath }}
+ backend:
+ serviceName: {{ $serviceName }}
+ servicePort: http
+ {{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/k8s/helm/deploy-all-istio.ps1 b/k8s/helm/deploy-all-istio.ps1
new file mode 100644
index 000000000..5e05c6dbb
--- /dev/null
+++ b/k8s/helm/deploy-all-istio.ps1
@@ -0,0 +1,116 @@
+Param(
+ [parameter(Mandatory=$false)][string]$registry,
+ [parameter(Mandatory=$false)][bool]$installIstioOnSystem=$false,
+ [parameter(Mandatory=$false)][string]$dockerUser,
+ [parameter(Mandatory=$false)][string]$dockerPassword,
+ [parameter(Mandatory=$false)][string]$externalDns="aks",
+ [parameter(Mandatory=$false)][string]$dnsname="eshoptestistio",
+ [parameter(Mandatory=$false)][string]$appName="eshop",
+ [parameter(Mandatory=$false)][bool]$deployInfrastructure=$true,
+ [parameter(Mandatory=$false)][string]$kialiuser="admin",
+ [parameter(Mandatory=$false)][string]$kialipasswrd="admin",
+ [parameter(Mandatory=$false)][bool]$clean=$true,
+ [parameter(Mandatory=$false)][string]$aksName="",
+ [parameter(Mandatory=$false)][string]$aksRg="",
+ [parameter(Mandatory=$false)][string]$imageTag="latest",
+ [parameter(Mandatory=$false)][bool]$useLocalk8s=$false
+ )
+
+$dns = $externalDns
+
+# Instalamos Istio
+# Specify the Istio version that will be leveraged throughout these instructions
+$ISTIO_VERSION="1.0.6"
+
+# Windows
+$ProgressPreference = 'SilentlyContinue';
+[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+Invoke-WebRequest -URI "https://github.com/istio/istio/releases/download/$ISTIO_VERSION/istio-$ISTIO_VERSION-win.zip" -OutFile "istio-$ISTIO_VERSION.zip"
+Remove-Item istio-$ISTIO_VERSION -Recurse -ErrorAction Ignore
+Expand-Archive -Path "istio-$ISTIO_VERSION.zip" -DestinationPath .
+
+if($installIstioOnSystem -eq $true) {
+ New-Item -ItemType Directory -Force -Path "C:\Program Files\Istio"
+ mv ./istio-$ISTIO_VERSION/bin/istioctl.exe "C:\Program Files/Istio/"
+ $PATH = [environment]::GetEnvironmentVariable("PATH", "User")
+ [environment]::SetEnvironmentVariable("PATH", $PATH + "; C:\Program Files\Istio", "User")
+}
+# Primero Desinstalamos cualquier cosa que haya en el cluster
+if ($clean -eq $true) {
+ Write-Host "Cleaning previous helm releases..." -ForegroundColor Green
+ helm delete --purge $(helm ls -q)
+ kubectl delete -f istio-$ISTIO_VERSION/install/kubernetes/helm/istio/templates/crds.yaml -n istio-system
+ Write-Host "Previous releases deleted" -ForegroundColor Green
+}
+
+Write-Host "Generating Kiali Credentials" -ForegroundColor Green
+#generamos la credenciales para que kiali arranque sin problemas
+kubectl -n istio-system create secret generic kiali --from-literal=username=$kialiuser --from-literal=passphrase=$kialipasswrd
+
+
+Write-Host "Deploying Istio in the cluster" -ForegroundColor Green
+helm install istio-$ISTIO_VERSION/install/kubernetes/helm/istio --wait --name istio --namespace istio-system --set global.controlPlaneSecurityEnabled=true --set grafana.enabled=true --set tracing.enabled=true --set kiali.enabled=true
+
+Write-Host "Setting Up Gateway"
+kubectl delete gateway istio-autogenerated-k8s-ingress -n istio-system
+kubectl apply -f ./istio/gateway.yml
+
+if ($useLocalk8s -eq $true) {
+ $dns="localhost"
+ $externalDns="localhost"
+}
+else {
+ Write-Host "Resolving DNS to Gateway public IP" -ForegroundColor Green
+ $ipaddress = $(kubectl get service istio-ingressgateway -n istio-system)[1] | %{ $_.Split(' ')[9];}
+ $query = "[?ipAddress!=null]|[?contains([ipAddress], '$ipaddress')].[id]"
+ $resid = az network public-ip list --query $query --output tsv
+ $jsonresponse = az network public-ip update --ids $resid --dns-name $dnsname
+ $externalDns = ($jsonresponse | ConvertFrom-Json).dnsSettings.fqdn
+ Write-Host "$externalDns is pointing to Cluster public ip $ipaddress"
+}
+
+$useCustomRegistry=$false
+if (-not [string]::IsNullOrEmpty($registry)) {
+ $useCustomRegistry=$true
+ if ([string]::IsNullOrEmpty($dockerUser) -or [string]::IsNullOrEmpty($dockerPassword)) {
+ Write-Host "Error: Must use -dockerUser AND -dockerPassword if specifying custom registry" -ForegroundColor Red
+ exit 1
+ }
+}
+Write-Host "Begin eShopOnContainers installation using Helm" -ForegroundColor Green
+
+$infras = ("sql-data", "nosql-data", "rabbitmq", "keystore-data", "basket-data")
+$charts = ("eshop-common", "apigwmm", "apigwms", "apigwwm", "apigwws", "basket-api","catalog-api", "identity-api", "locations-api", "marketing-api", "mobileshoppingagg","ordering-api","ordering-backgroundtasks","ordering-signalrhub", "payment-api", "webmvc", "webshoppingagg", "webspa", "webstatus", "webhooks-api", "webhooks-web")
+
+if ($deployInfrastructure) {
+ foreach ($infra in $infras) {
+ Write-Host "Installing infrastructure: $infra" -ForegroundColor Green
+ helm install --values app.yaml --values inf.yaml --set app.name=$appName --set inf.k8s.dns=$externalDns --name="$appName-$infra" $infra
+ }
+}
+
+foreach ($chart in $charts) {
+ Write-Host "Installing: $chart" -ForegroundColor Green
+ if ($useCustomRegistry) {
+ helm install --set inf.registry.server=$registry --set inf.registry.login=$dockerUser --set inf.registry.pwd=$dockerPassword --set inf.registry.secretName=eshop-docker-scret --values app.yaml --values inf.yaml --values $ingressValuesFile --set app.name=$appName --set inf.k8s.dns=$dns --set image.tag=$imageTag --set image.pullPolicy=Always --name="$appName-$chart" $chart
+ }
+ else {
+ if ($chart -ne "eshop-common") { # eshop-common is ignored when no secret must be deployed
+ helm install --values app.yaml --values inf.yaml --set app.name=$appName --set inf.k8s.dns=$externalDns --set image.tag=$imageTag --set image.pullPolicy=Always --name="$appName-$chart" $chart
+ }
+ }
+}
+
+Write-Host "helm charts installed." -ForegroundColor Green
+Write-Host "Appling Virtual Services for routing." -ForegroundColor Green
+kubectl apply -f ./istio/virtualservices.yml
+
+Remove-Item istio-$ISTIO_VERSION -Recurse -ErrorAction Ignore
+Remove-Item istio-$ISTIO_VERSION.zip -Recurse -ErrorAction Ignore
+
+
+
+
+
+
+
diff --git a/k8s/helm/deploy-all.ps1 b/k8s/helm/deploy-all.ps1
index 1819c9a67..a30fc1ee6 100644
--- a/k8s/helm/deploy-all.ps1
+++ b/k8s/helm/deploy-all.ps1
@@ -5,6 +5,7 @@ Param(
[parameter(Mandatory=$false)][string]$externalDns,
[parameter(Mandatory=$false)][string]$appName="eshop",
[parameter(Mandatory=$false)][bool]$deployInfrastructure=$true,
+ [parameter(Mandatory=$false)][bool]$deployCharts=$true,
[parameter(Mandatory=$false)][bool]$clean=$true,
[parameter(Mandatory=$false)][string]$aksName="",
[parameter(Mandatory=$false)][string]$aksRg="",
@@ -44,7 +45,7 @@ if ([string]::IsNullOrEmpty($dns)) {
if ($clean) {
Write-Host "Cleaning previous helm releases..." -ForegroundColor Green
- helm delete --purge $(helm ls -q)
+ helm delete --purge $(helm ls -q eshop)
Write-Host "Previous releases deleted" -ForegroundColor Green
}
@@ -66,24 +67,28 @@ $charts = ("eshop-common", "apigwmm", "apigwms", "apigwwm", "apigwws", "basket-a
if ($deployInfrastructure) {
foreach ($infra in $infras) {
Write-Host "Installing infrastructure: $infra" -ForegroundColor Green
- helm install --values app.yaml --values inf.yaml --values $ingressValuesFile --set app.name=$appName --set inf.k8s.dns=$dns --name="$appName-$infra" $infra
+ helm install --values app.yaml --values inf.yaml --values $ingressValuesFile --set app.name=$appName --set inf.k8s.dns=$dns --set ingress.hosts={$dns} --name="$appName-$infra" $infra
}
}
+else {
+ Write-Host "eShopOnContainers infrastructure (bbdd, redis, ...) charts aren't installed (-deployCharts is false)" -ForegroundColor Yellow
+}
-foreach ($chart in $charts) {
- Write-Host "Installing: $chart" -ForegroundColor Green
- if ($useCustomRegistry) {
- helm install --set inf.registry.server=$registry --set inf.registry.login=$dockerUser --set inf.registry.pwd=$dockerPassword --set inf.registry.secretName=eshop-docker-scret --values app.yaml --values inf.yaml --values $ingressValuesFile --set app.name=$appName --set inf.k8s.dns=$dns --set image.tag=$imageTag --set image.pullPolicy=Always --name="$appName-$chart" $chart
- }
- else {
- if ($chart -ne "eshop-common") { # eshop-common is ignored when no secret must be deployed
- helm install --values app.yaml --values inf.yaml --values $ingressValuesFile --set app.name=$appName --set inf.k8s.dns=$dns --set image.tag=$imageTag --set image.pullPolicy=Always --name="$appName-$chart" $chart
+if ($deployCharts) {
+ foreach ($chart in $charts) {
+ Write-Host "Installing: $chart" -ForegroundColor Green
+ if ($useCustomRegistry) {
+ helm install --set inf.registry.server=$registry --set inf.registry.login=$dockerUser --set inf.registry.pwd=$dockerPassword --set inf.registry.secretName=eshop-docker-scret --values app.yaml --values inf.yaml --values $ingressValuesFile --set app.name=$appName --set inf.k8s.dns=$dns --set ingress.hosts={$dns} --set image.tag=$imageTag --set image.pullPolicy=Always --name="$appName-$chart" $chart
+ }
+ else {
+ if ($chart -ne "eshop-common") { # eshop-common is ignored when no secret must be deployed
+ helm install --values app.yaml --values inf.yaml --values $ingressValuesFile --set app.name=$appName --set inf.k8s.dns=$dns --set ingress.hosts={$dns} --set image.tag=$imageTag --set image.pullPolicy=Always --name="$appName-$chart" $chart
+ }
}
}
}
+else {
+ Write-Host "eShopOnContainers non-infrastructure charts aren't installed (-deployCharts is false)" -ForegroundColor Yellow
+}
Write-Host "helm charts installed." -ForegroundColor Green
-
-
-
-
diff --git a/k8s/helm/deploy-all.sh b/k8s/helm/deploy-all.sh
new file mode 100755
index 000000000..705b172f5
--- /dev/null
+++ b/k8s/helm/deploy-all.sh
@@ -0,0 +1,208 @@
+#!/usr/bin/env bash
+
+# http://redsymbol.net/articles/unofficial-bash-strict-mode
+set -euo pipefail
+
+usage()
+{
+ cat <
+ The name of the AKS cluster. Required when the registry (using the -r parameter) is set to "aks".
+ --aks-rg
+ The resource group for the AKS cluster. Required when the registry (using the -r parameter) is set to "aks".
+ -b | --build-solution
+ Force a solution build before deployment (default: false).
+ -d | --dns
+ Specifies the external DNS/ IP address of the Kubernetes cluster.
+ When --use-local-k8s is specified the external DNS is automatically set to localhost.
+ -h | --help
+ Displays this help text and exits the script.
+ -n | --app-name
+ Specifies the name of the application (default: eshop).
+ -p | --docker-password
+ The Docker password used to logon to the custom registry, supplied using the -r parameter.
+ -r | --registry
+ Specifies the container registry to use (required), e.g. myregistry.azurecr.io.
+ --skip-clean
+ Do not clean the Kubernetes cluster (default is to clean the cluster).
+ --skip-image-build
+ Do not build images (default is to build all images).
+ --skip-image-push
+ Do not upload images to the container registry (just run the Kubernetes deployment portion).
+ Default is to push the images to the container registry.
+ --skip-infrastructure
+ Do not deploy infrastructure resources (like sql-data, no-sql or redis).
+ This is useful for production environments where infrastructure is hosted outside the Kubernetes cluster.
+ -t | --tag
+ The tag used for the newly created docker images. Default: newly created, date-based timestamp, with 1-minute resolution.
+ -u | --docker-user
+ The Docker username used to logon to the custom registry, supplied using the -r parameter.
+ --use-local-k8s
+ Deploy to a locally installed Kubernetes (default: false).
+
+It is assumed that the Kubernetes cluster has been granted access to the container registry.
+If using AKS and ACR see link for more info:
+https://docs.microsoft.com/en-us/azure/container-registry/container-registry-auth-aks
+
+WARNING! THE SCRIPT WILL COMPLETELY DESTROY ALL DEPLOYMENTS AND SERVICES VISIBLE
+FROM THE CURRENT CONFIGURATION CONTEXT.
+It is recommended that you create a separate namespace and confguration context
+for the $app_name application, to isolate it from other applications on the cluster.
+For more information see https://kubernetes.io/docs/tasks/administer-cluster/namespaces/
+You can use namespace.yaml file (in the same directory) to create the namespace.
+
+END
+}
+
+app_name='eshop'
+aks_name=''
+aks_rg=''
+build_images='yes'
+clean='yes'
+build_solution=''
+container_registry=''
+docker_password=''
+docker_username=''
+dns=''
+image_tag=$(date '+%Y%m%d%H%M')
+push_images='yes'
+skip_infrastructure=''
+use_local_k8s=''
+
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ --aks-name )
+ aks_name="$2"; shift 2;;
+ --aks-rg )
+ aks_rg="$2"; shift 2;;
+ -b | --build-solution )
+ build_solution='yes'; shift ;;
+ -d | --dns )
+ dns="$2"; shift 2;;
+ -h | --help )
+ usage; exit 1 ;;
+ -n | --app-name )
+ app_name="$2"; shift 2;;
+ -p | --docker-password )
+ docker_password="$2"; shift;;
+ -r | --registry )
+ container_registry="$2"; shift 2;;
+ --skip-clean )
+ clean=''; shift ;;
+ --skip-image-build )
+ build_images=''; shift ;;
+ --skip-image-push )
+ push_images=''; shift ;;
+ --skip-infrastructure )
+ skip_infrastructure='yes'; shift ;;
+ -t | --tag )
+ image_tag="$2"; shift 2;;
+ -u | --docker-username )
+ docker_username="$2"; shift 2;;
+ --use-local-k8s )
+ use_local_k8s='yes'; shift ;;
+ *)
+ echo "Unknown option $1"
+ usage; exit 2 ;;
+ esac
+done
+
+if [[ $build_solution ]]; then
+ echo "#################### Building $app_name solution ####################"
+ dotnet publish -o obj/Docker/publish ../../eShopOnContainers-ServicesAndWebApps.sln
+fi
+
+export TAG=$image_tag
+
+if [[ $build_images ]]; then
+ echo "#################### Building the $app_name Docker images ####################"
+ docker-compose -p ../.. -f ../../docker-compose.yml build
+
+ # Remove temporary images
+ docker rmi $(docker images -qf "dangling=true")
+fi
+
+if [[ $push_images ]]; then
+ echo "#################### Pushing images to the container registry ####################"
+ services=(basket.api catalog.api identity.api ordering.api marketing.api payment.api locations.api webmvc webspa webstatus)
+
+ for service in "${services[@]}"
+ do
+ echo "Pushing image for service $service..."
+ docker tag "eshop/$service:$image_tag" "$container_registry/$service:$image_tag"
+ docker push "$container_registry/$service:$image_tag"
+ done
+fi
+
+ingress_values_file="ingress_values.yaml"
+
+if [[ $use_local_k8s ]]; then
+ ingress_values_file="ingress_values_dockerk8s.yaml"
+ dns="localhost"
+fi
+
+if [[ $dns == "aks" ]]; then
+ echo "#################### Begin AKS discovery based on the --dns aks setting. ####################"
+ if [[ -z $aks_name ]] || [[ -z $aks_rg ]]; then
+ echo "Error: When using -dns aks, MUST set -aksName and -aksRg too."
+ echo ''
+ usage
+ exit 1
+ fi
+
+ echo "Getting DNS of AKS of AKS $aks_name (in resource group $aks_rg)"
+ dns="$(az aks show -n $aks_name -g $aks_rg --query addonProfiles.httpApplicationRouting.config.HTTPApplicationRoutingZoneName)"
+ if [[ -z dns ]]; then
+ echo "Error: when getting DNS of AKS $aks_name (in resource group $aks_rg). Please ensure AKS has httpRouting enabled AND Azure CLI is logged in and is of version 2.0.37 or higher."
+ exit 1
+ fi
+ $dns=${dns//[\"]/""}
+ echo "DNS base found is $dns. Will use $aks_name.$dns for the app!"
+fi
+
+# Initialization & check commands
+if [[ -z $dns ]]; then
+ echo "No DNS specified. Ingress resources will be bound to public IP."
+fi
+
+if [[ $clean ]]; then
+ echo "Cleaning previous helm releases..."
+ helm delete --purge $(helm ls -q)
+ echo "Previous releases deleted"
+fi
+
+use_custom_registry=''
+
+if [[ -n $container_registry ]]; then
+ use_custom_registry='yes'
+ if [[ -z $docker_user ]] || [[ -z $docker_password ]]; then
+ echo "Error: Must use -u (--docker-username) AND -p (--docker-password) if specifying custom registry"
+ exit 1
+ fi
+fi
+
+echo "#################### Begin $app_name installation using Helm ####################"
+infras=(sql-data nosql-data rabbitmq keystore-data basket-data)
+charts=(eshop-common apigwmm apigwms apigwwm apigwws basket-api catalog-api identity-api locations-api marketing-api mobileshoppingagg ordering-api ordering-backgroundtasks ordering-signalrhub payment-api webmvc webshoppingagg webspa webstatus webhooks-api webhooks-web)
+
+if [[ !$skip_infrastructure ]]; then
+ for infra in "${infras[@]}"
+ do
+ echo "Installing infrastructure: $infra"
+ helm install --values app.yaml --values inf.yaml --values $ingress_values_file --set app.name=$app_name --set inf.k8s.dns=$dns --name="$app_name-$infra" $infra
+ done
+fi
+
+for chart in "${charts[@]}"
+do
+ echo "Installing: $chart"
+ if [[ $use_custom_registry ]]; then
+ helm install --set inf.registry.server=$container_registry --set inf.registry.login=$docker_username --set inf.registry.pwd=$docker_password --set inf.registry.secretName=eshop-docker-scret --values app.yaml --values inf.yaml --values $ingress_values_file --set app.name=$app_name --set inf.k8s.dns=$dns --set image.tag=$image_tag --set image.pullPolicy=Always --name="$app_name-$chart" $chart
+ elif [[ $chart != "eshop-common" ]]; then # eshop-common is ignored when no secret must be deployed
+ helm install --values app.yaml --values inf.yaml --values $ingress_values_file --set app.name=$app_name --set inf.k8s.dns=$dns --set image.tag=$image_tag --set image.pullPolicy=Always --name="$app_name-$chart" $chart
+ fi
+done
+
+echo "FINISHED: Helm charts installed."
diff --git a/k8s/helm/identity-api/templates/configmap.yaml b/k8s/helm/identity-api/templates/configmap.yaml
index 24d71b699..67c0f21cb 100644
--- a/k8s/helm/identity-api/templates/configmap.yaml
+++ b/k8s/helm/identity-api/templates/configmap.yaml
@@ -36,5 +36,4 @@ data:
xamarin_callback_e: http://{{ $xamarincallback }}
webhooksapi_e: http://{{ $webhooks_url }}
webhooksweb_e: http://{{ $webhooksweb_url }}
-
-
+ enableDevspaces: "{{ .Values.enableDevspaces }}"
\ No newline at end of file
diff --git a/k8s/helm/identity-api/templates/ingress.yaml b/k8s/helm/identity-api/templates/ingress.yaml
index 5824f91e2..1d2d3d5d5 100644
--- a/k8s/helm/identity-api/templates/ingress.yaml
+++ b/k8s/helm/identity-api/templates/ingress.yaml
@@ -1,5 +1,6 @@
{{- if .Values.ingress.enabled -}}
{{- $ingressPath := include "pathBase" . -}}
+{{- $serviceName := .Values.app.svc.identity }}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
@@ -23,11 +24,13 @@ spec:
{{- end }}
{{- end }}
rules:
- - host: {{ .Values.inf.k8s.dns }}
+ {{- range .Values.ingress.hosts }}
+ - host: {{ . }}
http:
paths:
- path: {{ $ingressPath }}
backend:
- serviceName: {{ .Values.app.svc.identity }}
+ serviceName: {{ $serviceName }}
servicePort: http
+ {{- end }}
{{- end }}
diff --git a/k8s/helm/identity-api/values.yaml b/k8s/helm/identity-api/values.yaml
index c0fd38192..7b57dfde1 100644
--- a/k8s/helm/identity-api/values.yaml
+++ b/k8s/helm/identity-api/values.yaml
@@ -58,6 +58,8 @@ env:
key: webhooksapi_e
- name: WebhooksWebClient
key: webhooksweb_e
+ - name: EnableDevspaces
+ key: enableDevspaces
values:
- name: ASPNETCORE_ENVIRONMENT
value: Development
@@ -65,6 +67,7 @@ env:
value: 'K8S'
- name: IsClusterEnv
value: 'True'
+
probes:
liveness:
path: /liveness
@@ -76,4 +79,6 @@ probes:
timeoutSeconds: 5
initialDelaySeconds: 90
periodSeconds: 60
- port: 80
\ No newline at end of file
+ port: 80
+
+enableDevspaces: "false"
\ No newline at end of file
diff --git a/k8s/helm/istio/doc.md b/k8s/helm/istio/doc.md
new file mode 100644
index 000000000..b8c0a0257
--- /dev/null
+++ b/k8s/helm/istio/doc.md
@@ -0,0 +1,325 @@
+# Using Helm Charts to deploy eShopOnContainers to AKS with ISTIO
+
+It is possible to deploy eShopOnContainers on a AKS using [Helm](https://helm.sh/) instead of custom scripts (that will be deprecated soon).
+
+## Create Kubernetes cluster in AKS
+You can create the AKS cluster by using two ways:
+
+- A. Use Azure CLI: Follow a procedure suing [Azure CLI like here](https://docs.microsoft.com/en-us/azure/aks/kubernetes-walkthrough), but make sure you **enable RBAC** with `--enable-rbac` in `az aks create` command.
+
+- B. Use Azure's portal
+
+The following steps are using the Azure portal to create the AKS cluster:
+
+- Start the process by providing the general data, like in the following screenshot:
+
+![image](https://user-images.githubusercontent.com/1712635/45787360-c59ecd80-bc29-11e8-9565-c989ad6ad57b.png)
+
+- Then, very important, in the next step, enable RBAC:
+
+![image](https://user-images.githubusercontent.com/1712635/45780917-8bc2cc80-bc13-11e8-87ac-2942b3c7496d.png)
+
+ You can use **basic network** settings since for a test you don't need integration into any existing VNET.
+
+![image](https://user-images.githubusercontent.com/1712635/45780991-b745b700-bc13-11e8-926b-afac57229d0a.png)
+
+- You can also enable monitoring:
+
+![image](https://user-images.githubusercontent.com/1712635/45781148-1277a980-bc14-11e8-8614-f7a239731bec.png)
+
+- Finally, create the cluster. It'll take a few minutes for it to be ready.
+
+### Configure RBAC security for K8s dashboard service-account
+
+In order NOT to get errors in the Kubernetes dashboard, you'll need to set the following service-account steps.
+
+Here you can see the errors you might see:
+![image](https://user-images.githubusercontent.com/1712635/45784384-5622e100-bc1d-11e8-8d33-e22fd955150a.png)
+
+Now, just run the Azure CLI command to browse the Kubernetes Dashboard:
+
+`az aks browse --resource-group pro-eshop-aks-helm-linux-resgrp --name pro-eshop-aks-helm-linux`
+
+![image](https://user-images.githubusercontent.com/1712635/45786406-2d9ee500-bc25-11e8-83e9-bdfc302e80f1.png)
+
+
+## Additional pre-requisites
+
+In addition to having an AKS cluster created in Azure and having kubectl and Azure CLI installed in your local machine and configured to use your Azure subscription, you also need the following pre-requisites:
+
+### Install Helm
+
+You need to have helm installed on your machine, and Tiller must be installed on the AKS. Follow these instructions on how to ['Install applications with Helm in Azure Kubernetes Service (AKS)'](https://docs.microsoft.com/en-us/azure/aks/kubernetes-helm) to setup Helm and Tiller for AKS.
+
+**Note**: If your ASK cluster is not RBAC-enabled (default option in portal) you may receive following error when running a helm command:
+
+```
+Error: Get http://localhost:8080/api/v1/namespaces/kube-system/configmaps?labelSelector=OWNER%!D(MISSING)TILLER: dial tcp [::1]:8080: connect: connection refused
+```
+
+If so, type:
+
+```
+kubectl --namespace=kube-system edit deployment/tiller-deploy
+```
+
+Your default text editor will popup with the YAML definition of the tiller deploy. Search for:
+
+```
+automountServiceAccountToken: false
+```
+
+And change it to:
+
+```
+automountServiceAccountToken: true
+```
+
+Save the file and close the editor. This should reapply the deployment in the cluster. Now Helm commands should work.
+
+## Install eShopOnContainers with Istio using Helm
+
+All steps need to be performed on `/k8s/helm` folder. The easiest way is to use the `deploy-all-istio.ps1` script from a Powershell window:
+
+```
+.\deploy-all-istio.ps1 -dnsname eshoptestistio -externalDns aks -aksName eshoptest -aksRg eshoptest -imageTag dev
+```
+
+This will install all the [eShopOnContainers public images](https://hub.docker.com/u/eshop/) with tag `dev` on the AKS named `eshoptest` in the resource group `eshoptest` and with the dns url: http://**eshoptestistio**.westus.cloudapp.azure.com/ . By default all infrastructure (sql, mongo, rabbit and redis) is installed also in the cluster.
+
+Once the script is run, you should see following output when using `kubectl get deployment`:
+
+```
+NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
+eshop-apigwmm 1 1 1 1 4d
+eshop-apigwms 1 1 1 1 4d
+eshop-apigwwm 1 1 1 1 4d
+eshop-apigwws 1 1 1 1 4d
+eshop-basket-api 1 1 1 1 4d
+eshop-basket-data 1 1 1 1 4d
+eshop-catalog-api 1 1 1 1 4d
+eshop-identity-api 1 1 1 1 4d
+eshop-keystore-data 1 1 1 1 4d
+eshop-locations-api 1 1 1 1 4d
+eshop-marketing-api 1 1 1 1 4d
+eshop-mobileshoppingagg 1 1 1 1 4d
+eshop-nosql-data 1 1 1 1 4d
+eshop-ordering-api 1 1 1 1 4d
+eshop-ordering-backgroundtasks 1 1 1 1 4d
+eshop-ordering-signalrhub 1 1 1 1 4d
+eshop-payment-api 1 1 1 1 4d
+eshop-rabbitmq 1 1 1 1 4d
+eshop-sql-data 1 1 1 1 4d
+eshop-webmvc 1 1 1 1 4d
+eshop-webshoppingagg 1 1 1 1 4d
+eshop-webspa 1 1 1 1 4d
+eshop-webstatus 1 1 1 1 4d
+```
+
+Every public service is exposed through the istio ingress gateway.
+Yo can see the ingress gateway public ip doing `kubectl get services -n istio-system`
+```
+grafana ClusterIP 10.0.204.87 3000/TCP 1h
+istio-citadel ClusterIP 10.0.23.86 8060/TCP,9093/TCP 1h
+istio-egressgateway ClusterIP 10.0.136.169 80/TCP,443/TCP 1h
+istio-galley ClusterIP 10.0.113.51 443/TCP,9093/TCP 1h
+istio-ingressgateway LoadBalancer 10.0.76.80 40.118.189.161 80:31380/TCP,443:31390/TCP,31400:31400/TCP,15011:31276/TCP,8060:30519/TCP,853:31698/TCP,15030:31453/TCP,15031:32362/TCP 1h
+istio-pilot ClusterIP 10.0.164.253 15010/TCP,15011/TCP,8080/TCP,9093/TCP 1h
+istio-policy ClusterIP 10.0.170.49 9091/TCP,15004/TCP,9093/TCP 1h
+istio-sidecar-injector ClusterIP 10.0.251.12 443/TCP 1h
+istio-telemetry ClusterIP 10.0.195.112 9091/TCP,15004/TCP,9093/TCP,42422/TCP 1h
+jaeger-agent ClusterIP None 5775/UDP,6831/UDP,6832/UDP 1h
+jaeger-collector ClusterIP 10.0.123.98 14267/TCP,14268/TCP 1h
+jaeger-query ClusterIP 10.0.244.146 16686/TCP 1h
+kiali ClusterIP 10.0.182.12 20001/TCP 1h
+prometheus ClusterIP 10.0.136.223 9090/TCP 1h
+tracing ClusterIP 10.0.57.236 80/TCP 1h
+zipkin ClusterIP 10.0.30.57 9411/TCP 1h
+```
+
+You can view the MVC client at http://[dns]/
+
+## Customizing the deployment
+
+### Using your own images
+
+To use your own images instead of the public ones, you have to pass following additional parameters to the `deploy-all-istio.ps1` script:
+
+* `registry`: Login server for the Docker registry
+* `dockerUser`: User login for the Docker registry
+* `dockerPassword`: User password for the Docker registry
+
+This will deploy a secret on the cluster to connect to the specified server, and all image names deployed will be prepended with `registry/` value.
+
+### Not deploying infrastructure containers
+
+If you want to use external resources, use `-deployInfrastructure $false` to not deploy infrastructure containers. However **you still have to manually update the scripts to provide your own configuration** (see next section).
+
+### Providing your own configuration
+
+The file `inf.yaml` contains the description of the infrastructure used. File is docummented so take a look on it to understand all of its entries. If using external resources you need to edit this file according to your needs. You'll need to edit:
+
+* `inf.sql.host` with the host name of the SQL Server
+* `inf.sql.common` entries to provide your SQL user, password. `Pid` is not used when using external resources (it is used to set specific product id for the SQL Server container).
+* `inf.sql.catalog`, `inf.sql.ordering`, `inf.sql.identity`: To provide the database names for catalog, ordering and identity services
+* `mongo.host`: With the host name of the Mongo DB
+* `mongo.locations`, `mongo.marketing` with the database names for locations and marketing services
+* `redis.basket.constr` with the connection string to Redis for Basket Service. Note that `redis.basket.svc` is not used when using external services
+* `redis.keystore.constr` with the connection string to Redis for Keystore Service. Note that `redis.keystore.svc` is not used when using external services
+* `eventbus.constr` with the connection string to Azure Service Bus and `eventbus.useAzure` to `true` to use Azure service bus. Note that `eventbus.svc` is not used when using external services
+
+### Using Azure storage for Catalog Photos
+
+Using Azure storage for catalog (and marketing) photos is not directly supported, but you can accomplish it by editing the file `k8s/helm/catalog-api/templates/configmap.yaml`. Search for lines:
+
+```
+catalog__PicBaseUrl: http://{{ $webshoppingapigw }}/api/v1/c/catalog/items/[0]/pic/
+```
+
+And replace it for:
+
+```
+catalog__PicBaseUrl: http:///
+```
+
+In the same way, to use Azure storage for the marketing service, have to edit the file `k8s/helm/marketing-api/templates/configmap.yaml` and replacing the line:
+
+```
+marketing__PicBaseUrl: http://{{ $webshoppingapigw }}/api/v1/c/catalog/items/[0]/pic/
+```
+
+by:
+
+```
+marketing__PicBaseUrl: http:///
+```
+
+# Using Helm Charts to deploy eShopOnContainers to a local Kubernetes in Windows with 'Docker for Windows'
+
+## Additional pre-requisites
+
+In addition to having Docker for Windows/Mac with Kubernetes enabled and having kubectl ayou also need the following pre-requisites:
+
+### Install Helm
+
+You need to have helm installed on your machine, and Tiller must be installed on the local Docker Kubernetes cluster. Once you have [Helm downloaded](https://helm.sh/) and installed on your machine you must:
+
+1. Create the tiller service account, by running `kubectl apply -f helm-rbac.yaml` from `/k8s` folder
+2. Install tiller and configure it to use the tiller service account by typing `helm init --service-account tiller`
+
+## Install eShopOnContainers with Istio using Helm
+
+All steps need to be performed on `/k8s/helm` folder. The easiest way is to use the `deploy-all-istio.ps1` script from a Powershell window:
+
+```
+.\deploy-all-istio.ps1 -imageTag dev -useLocalk8s $true
+```
+
+The parameter `useLocalk8s` to $true, forces the script to use `localhost` as the DNS for all Helm charts.
+
+This will install all the [eShopOnContainers public images](https://hub.docker.com/u/eshop/) with tag `dev` on the Docker local Kubernetes cluster. By default all infrastructure (sql, mongo, rabbit and redis) is installed also in the cluster.
+
+Once the script is run, you should see following output when using `kubectl get deployment`:
+
+```
+NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
+eshop-apigwmm 1 1 1 1 2h
+eshop-apigwms 1 1 1 1 2h
+eshop-apigwwm 1 1 1 1 2h
+eshop-apigwws 1 1 1 1 2h
+eshop-basket-api 1 1 1 1 2h
+eshop-basket-data 1 1 1 1 2h
+eshop-catalog-api 1 1 1 1 2h
+eshop-identity-api 1 1 1 1 2h
+eshop-keystore-data 1 1 1 1 2h
+eshop-locations-api 1 1 1 1 2h
+eshop-marketing-api 1 1 1 1 2h
+eshop-mobileshoppingagg 1 1 1 1 2h
+eshop-nosql-data 1 1 1 1 2h
+eshop-ordering-api 1 1 1 1 2h
+eshop-ordering-backgroundtasks 1 1 1 1 2h
+eshop-ordering-signalrhub 1 1 1 1 2h
+eshop-payment-api 1 1 1 1 2h
+eshop-rabbitmq 1 1 1 1 2h
+eshop-sql-data 1 1 1 1 2h
+eshop-webmvc 1 1 1 1 2h
+eshop-webshoppingagg 1 1 1 1 2h
+eshop-webspa 1 1 1 1 2h
+eshop-webstatus 1 1 1 1 2h
+```
+
+Note that istio ingress gateway is bound to DNS localhost and the host is also "localhost". So, you can access the webspa by typing `http://localhost` and the MVC by typing `http://localhost/`
+
+As this is the Docker local K8s cluster, you can see also the containers running on your machine. If you type `docker ps` you'll see all them:
+
+```
+CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
+fec1e3499416 a3f21ec4bd11 "/entrypoint.sh /ngi…" 9 minutes ago Up 9 minutes k8s_nginx-ingress-controller_nginx-ingress-controller-f88c75bc6-5xs2n_ingress-nginx_f1cc7094-e68f-11e8-b4b6-00155d016146_0
+76485867f032 eshop/payment.api "dotnet Payment.API.…" 2 hours ago Up 2 hours k8s_payment-api_eshop-payment-api-75d5f9bdf6-6zx2v_default_4a3cdab4-e67f-11e8-b4b6-00155d016146_1
+c2c4640ed610 eshop/marketing.api "dotnet Marketing.AP…" 2 hours ago Up 2 hours k8s_marketing-api_eshop-marketing-api-6b8c5989fd-jpxqv_default_45780626-e67f-11e8-b4b6-00155d016146_1
+85301d538574 eshop/ordering.signalrhub "dotnet Ordering.Sig…" 2 hours ago Up 2 hours k8s_ordering-signalrhub_eshop-ordering-signalrhub-58cf5ff6-cnlm8_default_4932c344-e67f-11e8-b4b6-00155d016146_1
+7a408a98000e eshop/ordering.backgroundtasks "dotnet Ordering.Bac…" 2 hours ago Up 2 hours k8s_ordering-backgroundtasks_eshop-ordering-backgroundtasks-cc8f6d4d8-ztfk7_default_47f9cf10-e67f-11e8-b4b6-00155d016146_1
+12c64b3a13e0 eshop/basket.api "dotnet Basket.API.d…" 2 hours ago Up 2 hours k8s_basket-api_eshop-basket-api-658546684d-6hlvd_default_4262d022-e67f-11e8-b4b6-00155d016146_1
+133fccfeeff3 eshop/webstatus "dotnet WebStatus.dll" 2 hours ago Up 2 hours k8s_webstatus_eshop-webstatus-7f46479dc4-bqnq7_default_4dc13eb2-e67f-11e8-b4b6-00155d016146_0
+00c6e4c52135 eshop/webspa "dotnet WebSPA.dll" 2 hours ago Up 2 hours k8s_webspa_eshop-webspa-64cb8df9cb-dcbwg_default_4cd47376-e67f-11e8-b4b6-00155d016146_0
+d4507f1f6b1a eshop/webshoppingagg "dotnet Web.Shopping…" 2 hours ago Up 2 hours k8s_webshoppingagg_eshop-webshoppingagg-cc94fc86-sxd2v_default_4be6cdb9-e67f-11e8-b4b6-00155d016146_0
+9178e26703da eshop/webmvc "dotnet WebMVC.dll" 2 hours ago Up 2 hours k8s_webmvc_eshop-webmvc-985779684-4br5z_default_4addd4d6-e67f-11e8-b4b6-00155d016146_0
+1088c281c710 eshop/ordering.api "dotnet Ordering.API…" 2 hours ago Up 2 hours k8s_ordering-api_eshop-ordering-api-fb8c548cb-k68x9_default_4740958a-e67f-11e8-b4b6-00155d016146_0
+12424156d5c9 eshop/mobileshoppingagg "dotnet Mobile.Shopp…" 2 hours ago Up 2 hours k8s_mobileshoppingagg_eshop-mobileshoppingagg-b54645d7b-rlrgh_default_46c00017-e67f-11e8-b4b6-00155d016146_0
+65463ffd437d eshop/locations.api "dotnet Locations.AP…" 2 hours ago Up 2 hours k8s_locations-api_eshop-locations-api-577fc94696-dfhq8_default_44929c4b-e67f-11e8-b4b6-00155d016146_0
+5b3431873763 eshop/identity.api "dotnet Identity.API…" 2 hours ago Up 2 hours k8s_identity-api_eshop-identity-api-85d9b79f4-s5ks7_default_43d6eb7c-e67f-11e8-b4b6-00155d016146_0
+7c8e77252459 eshop/catalog.api "dotnet Catalog.API.…" 2 hours ago Up 2 hours k8s_catalog-api_eshop-catalog-api-59fd444fb-ztvhz_default_4356705a-e67f-11e8-b4b6-00155d016146_0
+94d95d0d3653 eshop/ocelotapigw "dotnet OcelotApiGw.…" 2 hours ago Up 2 hours k8s_apigwws_eshop-apigwws-65474b979d-n99jw_default_41395473-e67f-11e8-b4b6-00155d016146_0
+bc4bbce71d5f eshop/ocelotapigw "dotnet OcelotApiGw.…" 2 hours ago Up 2 hours k8s_apigwwm_eshop-apigwwm-857c549dd8-8w5gv_default_4098d770-e67f-11e8-b4b6-00155d016146_0
+840aabcceaa9 eshop/ocelotapigw "dotnet OcelotApiGw.…" 2 hours ago Up 2 hours k8s_apigwms_eshop-apigwms-5b94dfb54b-dnmr9_default_401fc611-e67f-11e8-b4b6-00155d016146_0
+aabed7646f5b eshop/ocelotapigw "dotnet OcelotApiGw.…" 2 hours ago Up 2 hours k8s_apigwmm_eshop-apigwmm-85f96cbdb4-dhfwr_default_3ed7967a-e67f-11e8-b4b6-00155d016146_0
+49c5700def5a f06a5773f01e "docker-entrypoint.s…" 2 hours ago Up 2 hours k8s_basket-data_eshop-basket-data-66fbc788cc-csnlw_default_3e0c45fe-e67f-11e8-b4b6-00155d016146_0
+a5db4c521807 f06a5773f01e "docker-entrypoint.s…" 2 hours ago Up 2 hours k8s_keystore-data_eshop-keystore-data-5c9c85cb99-8k56s_default_3ce1a273-e67f-11e8-b4b6-00155d016146_0
+aae88fd2d810 d69a5113ceae "docker-entrypoint.s…" 2 hours ago Up 2 hours k8s_rabbitmq_eshop-rabbitmq-6b68647bc4-gr565_default_3c37ee6a-e67f-11e8-b4b6-00155d016146_0
+65d49ca9589d bbed8d0e01c1 "docker-entrypoint.s…" 2 hours ago Up 2 hours k8s_nosql-data_eshop-nosql-data-579c9d89f8-mtt95_default_3b9c1f89-e67f-11e8-b4b6-00155d016146_0
+090e0dde2ec4 bbe2822dfe38 "/opt/mssql/bin/sqls…" 2 hours ago Up 2 hours k8s_sql-data_eshop-sql-data-5c4fdcccf4-bscdb_default_3afd29b8-e67f-11e8-b4b6-00155d016146_0
+```
+
+## Known issues
+
+Login from the webmvc results in following error: HttpRequestException: Response status code does not indicate success: 404 (Not Found).
+
+The reason is because MVC needs to access the Identity Server from both outside the container (browser) and inside the container (C# code). Thus, the configuration uses always the *external url* of the Identity Server, which in this case is just `http://localhost/identity-api`. But this external url is incorrect when used from C# code, and the web mvc can't access the identity api. This is the only case when this issue happens (and is the reason why we use 10.0.75.1 for local address in web mvc in local development mode)
+
+Solving this requires some manual steps:
+
+Update the configmap of Web MVC by typing (**line breaks are mandatory**) and your cluster dns name has to be the same of your environment:
+
+```
+kubectl patch cm cfg-eshop-webmvc --type strategic --patch @'
+data:
+ urls__IdentityUrl: http://**eshoptest**.westus.cloudapp.azure.com/identity
+ urls__mvc: http://**eshoptest**.westus.cloudapp.azure.com/webmvc
+'@
+```
+
+Update the configmap of Identity API by typing (**line breaks are mandatory**):
+
+```
+kubectl patch cm cfg-eshop-identity-api --type strategic --patch @'
+data:
+ mvc_e: http://**eshoptest**.westus.cloudapp.azure.com/webmvc
+'@
+```
+
+Restart the SQL Server pod to ensure the database is recreated again:
+
+```
+kubectl delete pod --selector app=sql-data
+```
+
+Wait until SQL Server pod is ready to accept connections and then restart all other pods:
+
+```
+kubectl delete pod --selector="app!=sql-data"
+```
+
+**Note:** Pods are deleted to ensure the databases are recreated again, as identity api stores its client names and urls in the database.
+
+Now, you can access the MVC app using: `http://**eshoptest**.westus.cloudapp.azure.com/`.
+
diff --git a/k8s/helm/istio/gateway.yml b/k8s/helm/istio/gateway.yml
new file mode 100644
index 000000000..fbc61dadd
--- /dev/null
+++ b/k8s/helm/istio/gateway.yml
@@ -0,0 +1,15 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: Gateway
+metadata:
+ name: istio-ingressgateway
+ #namespace: istio-system
+spec:
+ selector:
+ istio: ingressgateway # use Istio default gateway implementation
+ servers:
+ - port:
+ number: 80
+ name: http
+ protocol: HTTP
+ hosts:
+ - "*"
\ No newline at end of file
diff --git a/k8s/helm/istio/virtualservices.yml b/k8s/helm/istio/virtualservices.yml
new file mode 100644
index 000000000..e01f4678f
--- /dev/null
+++ b/k8s/helm/istio/virtualservices.yml
@@ -0,0 +1,59 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: webmvcvs
+ namespace: default
+spec:
+ hosts:
+ - "*"
+ gateways:
+ - istio-ingressgateway
+ http:
+ - match:
+ - uri:
+ prefix: /
+ route:
+ - destination:
+ port:
+ number: 80
+ host: webmvc
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: webshoppingapigwvs
+ namespace: default
+spec:
+ hosts:
+ - "*"
+ gateways:
+ - istio-ingressgateway
+ http:
+ - match:
+ - uri:
+ prefix: /webshoppingapigw
+ route:
+ - destination:
+ port:
+ number: 80
+ host: webshoppingapigw
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: identityvs
+ namespace: default
+spec:
+ hosts:
+ - "*"
+ gateways:
+ - istio-ingressgateway
+ http:
+ - match:
+ - uri:
+ prefix: /identity
+ route:
+ - destination:
+ port:
+ number: 80
+ host: identity
\ No newline at end of file
diff --git a/k8s/helm/locations-api/templates/ingress.yaml b/k8s/helm/locations-api/templates/ingress.yaml
new file mode 100644
index 000000000..8c846944e
--- /dev/null
+++ b/k8s/helm/locations-api/templates/ingress.yaml
@@ -0,0 +1,36 @@
+{{- if .Values.ingress.enabled -}}
+{{- $ingressPath := include "pathBase" . -}}
+{{- $serviceName := .Values.app.svc.locations }}
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+ name: {{ template "locations-api.fullname" . }}
+ labels:
+ app: {{ template "locations-api.name" . }}
+ chart: {{ template "locations-api.chart" . }}
+ release: {{ .Release.Name }}
+ heritage: {{ .Release.Service }}
+{{- with .Values.ingress.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+spec:
+{{- if .Values.ingress.tls }}
+ tls:
+ {{- range .Values.ingress.tls }}
+ - hosts:
+ - {{ .Values.inf.k8s.dns }}
+ secretName: {{ .secretName }}
+ {{- end }}
+{{- end }}
+ rules:
+ {{- range .Values.ingress.hosts }}
+ - host: {{ . }}
+ http:
+ paths:
+ - path: {{ $ingressPath }}
+ backend:
+ serviceName: {{ $serviceName }}
+ servicePort: http
+ {{- end }}
+{{- end }}
diff --git a/k8s/helm/marketing-api/templates/ingress.yaml b/k8s/helm/marketing-api/templates/ingress.yaml
new file mode 100644
index 000000000..7a5b29b12
--- /dev/null
+++ b/k8s/helm/marketing-api/templates/ingress.yaml
@@ -0,0 +1,36 @@
+{{- if .Values.ingress.enabled -}}
+{{- $ingressPath := include "pathBase" . -}}
+{{- $serviceName := .Values.app.svc.marketing }}
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+ name: {{ template "marketing-api.fullname" . }}
+ labels:
+ app: {{ template "marketing-api.name" . }}
+ chart: {{ template "marketing-api.chart" . }}
+ release: {{ .Release.Name }}
+ heritage: {{ .Release.Service }}
+{{- with .Values.ingress.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+spec:
+{{- if .Values.ingress.tls }}
+ tls:
+ {{- range .Values.ingress.tls }}
+ - hosts:
+ - {{ .Values.inf.k8s.dns }}
+ secretName: {{ .secretName }}
+ {{- end }}
+{{- end }}
+ rules:
+ {{- range .Values.ingress.hosts }}
+ - host: {{ . }}
+ http:
+ paths:
+ - path: {{ $ingressPath }}
+ backend:
+ serviceName: {{ $serviceName }}
+ servicePort: http
+ {{- end }}
+{{- end }}
diff --git a/k8s/helm/mobileshoppingagg/templates/ingress.yaml b/k8s/helm/mobileshoppingagg/templates/ingress.yaml
new file mode 100644
index 000000000..6c50a574e
--- /dev/null
+++ b/k8s/helm/mobileshoppingagg/templates/ingress.yaml
@@ -0,0 +1,36 @@
+{{- if .Values.ingress.enabled -}}
+{{- $ingressPath := include "pathBase" . -}}
+{{- $serviceName := .Values.app.svc.mobileshoppingagg }}
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+ name: {{ template "mobileshoppingagg.fullname" . }}
+ labels:
+ app: {{ template "mobileshoppingagg.name" . }}
+ chart: {{ template "mobileshoppingagg.chart" . }}
+ release: {{ .Release.Name }}
+ heritage: {{ .Release.Service }}
+{{- with .Values.ingress.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+spec:
+{{- if .Values.ingress.tls }}
+ tls:
+ {{- range .Values.ingress.tls }}
+ - hosts:
+ - {{ .Values.inf.k8s.dns }}
+ secretName: {{ .secretName }}
+ {{- end }}
+{{- end }}
+ rules:
+ {{- range .Values.ingress.hosts }}
+ - host: {{ . }}
+ http:
+ paths:
+ - path: {{ $ingressPath }}
+ backend:
+ serviceName: {{ $serviceName }}
+ servicePort: http
+ {{- end }}
+{{- end }}
diff --git a/k8s/helm/ordering-backgroundtasks/templates/configmap.yaml b/k8s/helm/ordering-backgroundtasks/templates/configmap.yaml
index 54fec785b..23041d4ac 100644
--- a/k8s/helm/ordering-backgroundtasks/templates/configmap.yaml
+++ b/k8s/helm/ordering-backgroundtasks/templates/configmap.yaml
@@ -1,10 +1,11 @@
{{- $name := include "ordering-backgroundtasks.fullname" . -}}
{{- $sqlsrv := include "sql-name" . -}}
+{{- $cfgname := printf "cfg-%s" $name | trunc 63 }}
apiVersion: v1
kind: ConfigMap
metadata:
- name: "cfg-{{ $name }}"
+ name: "{{ $cfgname }}"
labels:
app: {{ template "ordering-backgroundtasks.name" . }}
chart: {{ template "ordering-backgroundtasks.chart" .}}
diff --git a/k8s/helm/ordering-backgroundtasks/templates/deployment.yaml b/k8s/helm/ordering-backgroundtasks/templates/deployment.yaml
index 017f9f3dd..d93c7f764 100644
--- a/k8s/helm/ordering-backgroundtasks/templates/deployment.yaml
+++ b/k8s/helm/ordering-backgroundtasks/templates/deployment.yaml
@@ -1,11 +1,11 @@
{{- $name := include "ordering-backgroundtasks.fullname" . -}}
-{{- $cfgname := printf "%s-%s" "cfg" $name -}}
+{{- $cfgname := printf "cfg-%s" $name | trunc 63 }}
+
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: {{ template "ordering-backgroundtasks.fullname" . }}
labels:
- ufo: {{ $cfgname}}
app: {{ template "ordering-backgroundtasks.name" . }}
chart: {{ template "ordering-backgroundtasks.chart" . }}
release: {{ .Release.Name }}
diff --git a/k8s/helm/webhooks-api/templates/ingress.yaml b/k8s/helm/webhooks-api/templates/ingress.yaml
index 293f8e47e..debf0f84a 100644
--- a/k8s/helm/webhooks-api/templates/ingress.yaml
+++ b/k8s/helm/webhooks-api/templates/ingress.yaml
@@ -1,5 +1,6 @@
{{- if .Values.ingress.enabled -}}
{{- $ingressPath := include "pathBase" . -}}
+{{- $serviceName := .Values.app.svc.webhooks }}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
@@ -23,11 +24,13 @@ spec:
{{- end }}
{{- end }}
rules:
- - host: {{ .Values.inf.k8s.dns }}
+ {{- range .Values.ingress.hosts }}
+ - host: {{ . }}
http:
paths:
- path: {{ $ingressPath }}
backend:
- serviceName: {{ .Values.app.svc.webhooks }}
+ serviceName: {{ $serviceName }}
servicePort: http
+ {{- end }}
{{- end }}
diff --git a/k8s/helm/webmvc/templates/configmap.yaml b/k8s/helm/webmvc/templates/configmap.yaml
index 60dacdadd..55c4e6b33 100644
--- a/k8s/helm/webmvc/templates/configmap.yaml
+++ b/k8s/helm/webmvc/templates/configmap.yaml
@@ -2,7 +2,6 @@
{{- $identity := include "url-of" (list .Values.app.ingress.entries.identity .) -}}
{{- $webshoppingapigw := include "url-of" (list .Values.app.ingress.entries.webshoppingapigw .) -}}
{{- $mvc := include "url-of" (list .Values.app.ingress.entries.mvc .) -}}
-{{- $mongo := include "mongo-name" . -}}
apiVersion: v1
diff --git a/k8s/helm/webmvc/templates/ingress.yaml b/k8s/helm/webmvc/templates/ingress.yaml
index abfb62b2f..892fa4273 100644
--- a/k8s/helm/webmvc/templates/ingress.yaml
+++ b/k8s/helm/webmvc/templates/ingress.yaml
@@ -1,5 +1,6 @@
{{- if .Values.ingress.enabled -}}
{{- $ingressPath := include "pathBase" . -}}
+{{- $serviceName := .Values.app.svc.mvc -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
@@ -23,11 +24,13 @@ spec:
{{- end }}
{{- end }}
rules:
- - host: {{ .Values.inf.k8s.dns }}
+ {{- range .Values.ingress.hosts }}
+ - host: {{ . }}
http:
paths:
- path: {{ $ingressPath }}
backend:
- serviceName: {{ .Values.app.svc.mvc }}
+ serviceName: {{ $serviceName }}
servicePort: http
+ {{- end }}
{{- end }}
diff --git a/k8s/helm/webshoppingagg/templates/ingress.yaml b/k8s/helm/webshoppingagg/templates/ingress.yaml
new file mode 100644
index 000000000..742db4d30
--- /dev/null
+++ b/k8s/helm/webshoppingagg/templates/ingress.yaml
@@ -0,0 +1,36 @@
+{{- if .Values.ingress.enabled -}}
+{{- $ingressPath := include "pathBase" . -}}
+{{- $serviceName := .Values.app.svc.webshoppingagg }}
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+ name: {{ template "webshoppingagg.fullname" . }}
+ labels:
+ app: {{ template "webshoppingagg.name" . }}
+ chart: {{ template "webshoppingagg.chart" . }}
+ release: {{ .Release.Name }}
+ heritage: {{ .Release.Service }}
+{{- with .Values.ingress.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+spec:
+{{- if .Values.ingress.tls }}
+ tls:
+ {{- range .Values.ingress.tls }}
+ - hosts:
+ - {{ .Values.inf.k8s.dns }}
+ secretName: {{ .secretName }}
+ {{- end }}
+{{- end }}
+ rules:
+ {{- range .Values.ingress.hosts }}
+ - host: {{ . }}
+ http:
+ paths:
+ - path: {{ $ingressPath }}
+ backend:
+ serviceName: {{ $serviceName }}
+ servicePort: http
+ {{- end }}
+{{- end }}
diff --git a/k8s/nginx-ingress/mandatory-istio.yaml b/k8s/nginx-ingress/mandatory-istio.yaml
new file mode 100644
index 000000000..56b1cc3b5
--- /dev/null
+++ b/k8s/nginx-ingress/mandatory-istio.yaml
@@ -0,0 +1,238 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: ingress-nginx
+
+---
+
+kind: ConfigMap
+apiVersion: v1
+metadata:
+ name: nginx-configuration
+ namespace: ingress-nginx
+ labels:
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+
+---
+
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: nginx-ingress-serviceaccount
+ namespace: ingress-nginx
+ labels:
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+
+---
+apiVersion: rbac.authorization.k8s.io/v1beta1
+kind: ClusterRole
+metadata:
+ name: nginx-ingress-clusterrole
+ labels:
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+rules:
+ - apiGroups:
+ - ""
+ resources:
+ - configmaps
+ - endpoints
+ - nodes
+ - pods
+ - secrets
+ verbs:
+ - list
+ - watch
+ - apiGroups:
+ - ""
+ resources:
+ - nodes
+ verbs:
+ - get
+ - apiGroups:
+ - ""
+ resources:
+ - services
+ verbs:
+ - get
+ - list
+ - watch
+ - apiGroups:
+ - "extensions"
+ resources:
+ - ingresses
+ verbs:
+ - get
+ - list
+ - watch
+ - apiGroups:
+ - ""
+ resources:
+ - events
+ verbs:
+ - create
+ - patch
+ - apiGroups:
+ - "extensions"
+ resources:
+ - ingresses/status
+ verbs:
+ - update
+
+---
+apiVersion: rbac.authorization.k8s.io/v1beta1
+kind: Role
+metadata:
+ name: nginx-ingress-role
+ namespace: ingress-nginx
+ labels:
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+rules:
+ - apiGroups:
+ - ""
+ resources:
+ - configmaps
+ - pods
+ - secrets
+ - namespaces
+ verbs:
+ - get
+ - apiGroups:
+ - ""
+ resources:
+ - configmaps
+ resourceNames:
+ # Defaults to "-"
+ # Here: "-"
+ # This has to be adapted if you change either parameter
+ # when launching the nginx-ingress-controller.
+ - "ingress-controller-leader-nginx"
+ verbs:
+ - get
+ - update
+ - apiGroups:
+ - ""
+ resources:
+ - configmaps
+ verbs:
+ - create
+ - apiGroups:
+ - ""
+ resources:
+ - endpoints
+ verbs:
+ - get
+
+---
+apiVersion: rbac.authorization.k8s.io/v1beta1
+kind: RoleBinding
+metadata:
+ name: nginx-ingress-role-nisa-binding
+ namespace: ingress-nginx
+ labels:
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+ name: nginx-ingress-role
+subjects:
+ - kind: ServiceAccount
+ name: nginx-ingress-serviceaccount
+ namespace: ingress-nginx
+
+---
+apiVersion: rbac.authorization.k8s.io/v1beta1
+kind: ClusterRoleBinding
+metadata:
+ name: nginx-ingress-clusterrole-nisa-binding
+ labels:
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: nginx-ingress-clusterrole
+subjects:
+ - kind: ServiceAccount
+ name: nginx-ingress-serviceaccount
+ namespace: ingress-nginx
+
+---
+
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: nginx-ingress-controller
+ namespace: ingress-nginx
+ labels:
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ template:
+ metadata:
+ labels:
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ annotations:
+ prometheus.io/port: "10254"
+ prometheus.io/scrape: "true"
+ spec:
+ serviceAccountName: nginx-ingress-serviceaccount
+ containers:
+ - name: nginx-ingress-controller
+ image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.20.0
+ args:
+ - /nginx-ingress-controller
+ - --configmap=$(POD_NAMESPACE)/nginx-configuration
+ - --publish-service=$(POD_NAMESPACE)/ingress-nginx
+ - --annotations-prefix=nginx.ingress.kubernetes.io
+ securityContext:
+ capabilities:
+ drop:
+ - ALL
+ add:
+ - NET_BIND_SERVICE
+ # www-data -> 33
+ runAsUser: 33
+ env:
+ - name: POD_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.name
+ - name: POD_NAMESPACE
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.namespace
+ ports:
+ - name: http
+ containerPort: 80
+ - name: https
+ containerPort: 443
+ livenessProbe:
+ failureThreshold: 3
+ httpGet:
+ path: /healthz
+ port: 10254
+ scheme: HTTP
+ initialDelaySeconds: 10
+ periodSeconds: 10
+ successThreshold: 1
+ timeoutSeconds: 1
+ readinessProbe:
+ failureThreshold: 3
+ httpGet:
+ path: /healthz
+ port: 10254
+ scheme: HTTP
+ periodSeconds: 10
+ successThreshold: 1
+ timeoutSeconds: 1
diff --git a/restore-packages.cmd b/restore-packages.cmd
new file mode 100644
index 000000000..4e99614d6
--- /dev/null
+++ b/restore-packages.cmd
@@ -0,0 +1 @@
+for /R %%f in (*.csproj) do dotnet restore --no-dependencies %%f
diff --git a/run-docker-compose-build.ps1 b/run-docker-compose-build.ps1
index 7d99ee0e7..ed4a14541 100644
--- a/run-docker-compose-build.ps1
+++ b/run-docker-compose-build.ps1
@@ -1,6 +1,6 @@
$startTime = $(Get-Date)
-docker-compose build
+docker-compose build --build-arg RUN=scripts/restore-packages
$elapsedTime = $(Get-Date) - $startTime
diff --git a/scripts/restore-packages b/scripts/restore-packages
new file mode 100644
index 000000000..5ad4abf62
--- /dev/null
+++ b/scripts/restore-packages
@@ -0,0 +1 @@
+echo RESTORING ALL PACKAGES...; for f in /src/csproj-files/*.csproj; do dotnet restore $f; done
diff --git a/scripts/restore-packages.cmd b/scripts/restore-packages.cmd
new file mode 100644
index 000000000..9f3a8434e
--- /dev/null
+++ b/scripts/restore-packages.cmd
@@ -0,0 +1 @@
+for %%p in (csproj-files\*.csproj) do dotnet restore %%p
diff --git a/src/ApiGateways/ApiGw-Base/Dockerfile b/src/ApiGateways/ApiGw-Base/Dockerfile
index eb94675b9..f4751f2d1 100644
--- a/src/ApiGateways/ApiGw-Base/Dockerfile
+++ b/src/ApiGateways/ApiGw-Base/Dockerfile
@@ -1,16 +1,26 @@
-FROM microsoft/dotnet:2.2.0-aspnetcore-runtime AS base
+FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80
-FROM microsoft/dotnet:2.2.100-sdk AS build
+FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
WORKDIR /src
+
+COPY scripts scripts/
+
+COPY src/ApiGateways/*/*.csproj /src/csproj-files/
+COPY src/ApiGateways/*/*/*.csproj /src/csproj-files/
+COPY src/BuildingBlocks/*/*/*.csproj /src/csproj-files/
+COPY src/Services/*/*/*.csproj /src/csproj-files/
+COPY src/Web/*/*.csproj /src/csproj-files/
+
+ARG RUN=pwd
+RUN ${RUN}
+
COPY . .
WORKDIR /src/src/ApiGateways/ApiGw-Base/
-RUN dotnet restore -nowarn:msb3202,nu1503
-RUN dotnet build -c Release -o /app
+RUN dotnet publish -c Release -o /app
FROM build AS publish
-RUN dotnet publish -c Release -o /app
FROM base AS final
WORKDIR /app
diff --git a/src/ApiGateways/ApiGw-Base/Dockerfile.develop b/src/ApiGateways/ApiGw-Base/Dockerfile.develop
new file mode 100644
index 000000000..4da230d68
--- /dev/null
+++ b/src/ApiGateways/ApiGw-Base/Dockerfile.develop
@@ -0,0 +1,14 @@
+FROM microsoft/dotnet:2.2-sdk
+ARG BUILD_CONFIGURATION=Debug
+ENV ASPNETCORE_ENVIRONMENT=Development
+ENV DOTNET_USE_POLLING_FILE_WATCHER=true
+EXPOSE 80
+
+WORKDIR /src
+COPY ["src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj", "src/ApiGateways/ApiGw-Base/"]
+RUN dotnet restore "src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj"
+COPY . .
+WORKDIR "/src/src/ApiGateways/ApiGw-Base"
+RUN dotnet build --no-restore "OcelotApiGw.csproj" -c $BUILD_CONFIGURATION
+
+ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"]
\ No newline at end of file
diff --git a/src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj b/src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj
index cf963debc..b1b6b1db6 100644
--- a/src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj
+++ b/src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj
@@ -5,12 +5,8 @@
-
-
-
-
-
-
+
+
diff --git a/src/ApiGateways/ApiGw-Base/Program.cs b/src/ApiGateways/ApiGw-Base/Program.cs
index c8f8d7993..bcf1c8d60 100644
--- a/src/ApiGateways/ApiGw-Base/Program.cs
+++ b/src/ApiGateways/ApiGw-Base/Program.cs
@@ -25,6 +25,12 @@ namespace OcelotApiGw
builder.ConfigureServices(s => s.AddSingleton(builder))
.ConfigureAppConfiguration(ic => ic.AddJsonFile(Path.Combine("configuration", "configuration.json")))
.UseStartup()
+ .ConfigureLogging((hostingContext, loggingbuilder) =>
+ {
+ loggingbuilder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
+ loggingbuilder.AddConsole();
+ loggingbuilder.AddDebug();
+ })
.UseSerilog((builderContext, config) =>
{
config
diff --git a/src/ApiGateways/ApiGw-Base/Startup.cs b/src/ApiGateways/ApiGw-Base/Startup.cs
index cd90bd7ca..585c26471 100644
--- a/src/ApiGateways/ApiGw-Base/Startup.cs
+++ b/src/ApiGateways/ApiGw-Base/Startup.cs
@@ -76,7 +76,7 @@ namespace OcelotApiGw
services.AddOcelot(_cfg);
}
- public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
+ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
var pathBase = _cfg["PATH_BASE"];
@@ -101,8 +101,6 @@ namespace OcelotApiGw
Predicate = r => r.Name.Contains("self")
});
- loggerFactory.AddConsole(_cfg.GetSection("Logging"));
-
app.UseCors("CorsPolicy");
app.UseOcelot().Wait();
diff --git a/src/ApiGateways/Mobile.Bff.Marketing/apigw/azds.yaml b/src/ApiGateways/Mobile.Bff.Marketing/apigw/azds.yaml
new file mode 100644
index 000000000..46375343b
--- /dev/null
+++ b/src/ApiGateways/Mobile.Bff.Marketing/apigw/azds.yaml
@@ -0,0 +1,44 @@
+kind: helm-release
+apiVersion: 1.1
+build:
+ context: ..\..\..\..\
+ dockerfile: ..\..\..\ApiGateways\ApiGw-Base\Dockerfile
+install:
+ chart: ../../../../k8s/helm/apigwmm
+ set:
+ replicaCount: 1
+ image:
+ tag: $(tag)
+ pullPolicy: Never
+ ingress:
+ annotations:
+ kubernetes.io/ingress.class: traefik-azds
+ hosts:
+ # This expands to [space.s.]webmvc...aksapp.io
+ - $(spacePrefix)eshop$(hostSuffix)
+ inf:
+ k8s:
+ dns: $(spacePrefix)eshop$(hostSuffix)
+ values:
+ - values.dev.yaml?
+ - secrets.dev.yaml?
+ - inf.yaml
+ - app.yaml
+configurations:
+ develop:
+ build:
+ useGitIgnore: true
+ dockerfile: ..\..\..\ApiGateways\ApiGw-Base\Dockerfile.develop
+ args:
+ BUILD_CONFIGURATION: ${BUILD_CONFIGURATION:-Debug}
+ container:
+ sync:
+ - '**/Pages/**'
+ - '**/Views/**'
+ - '**/wwwroot/**'
+ - '!**/*.{sln,csproj}'
+ command: [dotnet, run, --no-restore, --no-build, --no-launch-profile, -c, "${BUILD_CONFIGURATION:-Debug}"]
+ iterate:
+ processesToKill: [dotnet, vsdbg]
+ buildCommands:
+ - [dotnet, build, --no-restore, -c, "${BUILD_CONFIGURATION:-Debug}"]
diff --git a/src/ApiGateways/Mobile.Bff.Marketing/apigw/values.dev.yaml b/src/ApiGateways/Mobile.Bff.Marketing/apigw/values.dev.yaml
new file mode 100644
index 000000000..fb59d98d5
--- /dev/null
+++ b/src/ApiGateways/Mobile.Bff.Marketing/apigw/values.dev.yaml
@@ -0,0 +1,2 @@
+ocelot:
+ configPath: /src/src/ApiGateways/ApiGw-Base/configuration
\ No newline at end of file
diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile
index be89c315f..d29c73b3e 100644
--- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile
+++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile
@@ -1,16 +1,26 @@
-FROM microsoft/dotnet:2.2.0-aspnetcore-runtime AS base
+FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80
-FROM microsoft/dotnet:2.2.100-sdk AS build
+FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
WORKDIR /src
+
+COPY scripts scripts/
+
+COPY src/ApiGateways/*/*.csproj /src/csproj-files/
+COPY src/ApiGateways/*/*/*.csproj /src/csproj-files/
+COPY src/BuildingBlocks/*/*/*.csproj /src/csproj-files/
+COPY src/Services/*/*/*.csproj /src/csproj-files/
+COPY src/Web/*/*.csproj /src/csproj-files/
+
+ARG RUN=pwd
+RUN ${RUN}
+
COPY . .
WORKDIR /src/src/ApiGateways/Mobile.Bff.Shopping/aggregator
-RUN dotnet restore -nowarn:msb3202,nu1503
-RUN dotnet build --no-restore -c Release -o /app
+RUN dotnet publish -c Release -o /app
FROM build AS publish
-RUN dotnet publish --no-restore -c Release -o /app
FROM base AS final
WORKDIR /app
diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile.develop b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile.develop
new file mode 100644
index 000000000..c4330c370
--- /dev/null
+++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile.develop
@@ -0,0 +1,16 @@
+FROM microsoft/dotnet:2.2-sdk
+ARG BUILD_CONFIGURATION=Debug
+ENV ASPNETCORE_ENVIRONMENT=Development
+ENV DOTNET_USE_POLLING_FILE_WATCHER=true
+EXPOSE 80
+
+WORKDIR /src
+COPY ["src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj", "src/ApiGateways/Mobile.Bff.Shopping/aggregator/"]
+COPY ["src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj", "src/BuildingBlocks/Devspaces.Support/"]
+
+RUN dotnet restore src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj -nowarn:msb3202,nu1503
+COPY . .
+WORKDIR "/src/src/ApiGateways/Mobile.Bff.Shopping/aggregator"
+RUN dotnet build --no-restore -c $BUILD_CONFIGURATION
+
+CMD ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"]]
\ No newline at end of file
diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj
index 6300d6711..1dd1ba1b6 100644
--- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj
+++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj
@@ -12,15 +12,19 @@
-
-
+
+
-
+
+
+
+
+
diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Properties/launchSettings.json b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Properties/launchSettings.json
index 925e70b0d..c259d5094 100644
--- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Properties/launchSettings.json
+++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Properties/launchSettings.json
@@ -24,6 +24,13 @@
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:61632/"
+ },
+ "Azure Dev Spaces": {
+ "commandName": "AzureDevSpaces",
+ "launchBrowser": true,
+ "resourceGroup": "eshoptestedu",
+ "aksName": "eshoptestedu",
+ "subscriptionId": "e3035ac1-c06c-4daf-8939-57b3c5f1f759"
}
}
}
\ No newline at end of file
diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs
index eeb58ac3b..eee0d9c6e 100644
--- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs
+++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs
@@ -20,6 +20,7 @@ using Swashbuckle.AspNetCore.Swagger;
using HealthChecks.UI.Client;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.Diagnostics.HealthChecks;
+using Devspaces.Support;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
{
@@ -47,6 +48,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
services.AddCustomMvc(Configuration)
.AddCustomAuthentication(Configuration)
+ .AddDevspaces()
.AddHttpServices();
}
@@ -57,7 +59,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
if (!string.IsNullOrEmpty(pathBase))
{
- loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
+ loggerFactory.CreateLogger().LogDebug("Using PATH BASE '{pathBase}'", pathBase);
app.UsePathBase(pathBase);
}
@@ -188,15 +190,18 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
services.AddHttpClient()
.AddHttpMessageHandler()
.AddPolicyHandler(GetRetryPolicy())
- .AddPolicyHandler(GetCircuitBreakerPolicy());
+ .AddPolicyHandler(GetCircuitBreakerPolicy())
+ .AddDevspacesSupport();
services.AddHttpClient()
.AddPolicyHandler(GetRetryPolicy())
- .AddPolicyHandler(GetCircuitBreakerPolicy());
+ .AddPolicyHandler(GetCircuitBreakerPolicy())
+ .AddDevspacesSupport();
services.AddHttpClient()
.AddPolicyHandler(GetRetryPolicy())
- .AddPolicyHandler(GetCircuitBreakerPolicy());
+ .AddPolicyHandler(GetCircuitBreakerPolicy())
+ .AddDevspacesSupport();
return services;
}
diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/azds.yaml b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/azds.yaml
new file mode 100644
index 000000000..8dbac7128
--- /dev/null
+++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/azds.yaml
@@ -0,0 +1,55 @@
+kind: helm-release
+apiVersion: 1.1
+build:
+ context: ..\..\..\..
+ dockerfile: Dockerfile
+install:
+ chart: ../../../../k8s/helm/mobileshoppingagg
+ set:
+ image:
+ tag: $(tag)
+ pullPolicy: Never
+ ingress:
+ annotations:
+ kubernetes.io/ingress.class: traefik-azds
+ hosts:
+ # This expands to [space.s.]apigwms...aksapp.io
+ - $(spacePrefix)eshop$(hostSuffix)
+ inf:
+ k8s:
+ dns: $(spacePrefix)eshop$(hostSuffix)
+ values:
+ - values.dev.yaml?
+ - secrets.dev.yaml?
+ - app.yaml
+ - inf.yaml
+configurations:
+ develop:
+ build:
+ useGitIgnore: true
+ dockerfile: Dockerfile.develop
+ container:
+ syncTarget: /src
+ sync:
+ - '**/Pages/**'
+ - '**/Views/**'
+ - '**/wwwroot/**'
+ - '!**/*.{sln,csproj}'
+ command:
+ - dotnet
+ - run
+ - --no-restore
+ - --no-build
+ - --no-launch-profile
+ - -c
+ - ${Configuration:-Debug}
+ iterate:
+ processesToKill:
+ - dotnet
+ - vsdbg
+ buildCommands:
+ - - dotnet
+ - build
+ - --no-restore
+ - -c
+ - ${Configuration:-Debug}
diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/values.dev.yaml b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/values.dev.yaml
new file mode 100644
index 000000000..eaed45149
--- /dev/null
+++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/values.dev.yaml
@@ -0,0 +1,3 @@
+ingress:
+ enabled: true
+ tls: []
\ No newline at end of file
diff --git a/src/ApiGateways/Mobile.Bff.Shopping/apigw/azds.yaml b/src/ApiGateways/Mobile.Bff.Shopping/apigw/azds.yaml
new file mode 100644
index 000000000..9e2d09e42
--- /dev/null
+++ b/src/ApiGateways/Mobile.Bff.Shopping/apigw/azds.yaml
@@ -0,0 +1,44 @@
+kind: helm-release
+apiVersion: 1.1
+build:
+ context: ..\..\..\..\
+ dockerfile: ..\..\..\ApiGateways\ApiGw-Base\Dockerfile
+install:
+ chart: ../../../../k8s/helm/apigwms
+ set:
+ replicaCount: 1
+ image:
+ tag: $(tag)
+ pullPolicy: Never
+ ingress:
+ annotations:
+ kubernetes.io/ingress.class: traefik-azds
+ hosts:
+ # This expands to [space.s.]webmvc...aksapp.io
+ - $(spacePrefix)eshop$(hostSuffix)
+ inf:
+ k8s:
+ dns: $(spacePrefix)eshop$(hostSuffix)
+ values:
+ - values.dev.yaml?
+ - secrets.dev.yaml?
+ - inf.yaml
+ - app.yaml
+configurations:
+ develop:
+ build:
+ useGitIgnore: true
+ dockerfile: ..\..\..\ApiGateways\ApiGw-Base\Dockerfile.develop
+ args:
+ BUILD_CONFIGURATION: ${BUILD_CONFIGURATION:-Debug}
+ container:
+ sync:
+ - '**/Pages/**'
+ - '**/Views/**'
+ - '**/wwwroot/**'
+ - '!**/*.{sln,csproj}'
+ command: [dotnet, run, --no-restore, --no-build, --no-launch-profile, -c, "${BUILD_CONFIGURATION:-Debug}"]
+ iterate:
+ processesToKill: [dotnet, vsdbg]
+ buildCommands:
+ - [dotnet, build, --no-restore, -c, "${BUILD_CONFIGURATION:-Debug}"]
diff --git a/src/ApiGateways/Mobile.Bff.Shopping/apigw/values.dev.yaml b/src/ApiGateways/Mobile.Bff.Shopping/apigw/values.dev.yaml
new file mode 100644
index 000000000..fb59d98d5
--- /dev/null
+++ b/src/ApiGateways/Mobile.Bff.Shopping/apigw/values.dev.yaml
@@ -0,0 +1,2 @@
+ocelot:
+ configPath: /src/src/ApiGateways/ApiGw-Base/configuration
\ No newline at end of file
diff --git a/src/ApiGateways/Web.Bff.Marketing/apigw/azds.yaml b/src/ApiGateways/Web.Bff.Marketing/apigw/azds.yaml
new file mode 100644
index 000000000..8f60cbcc7
--- /dev/null
+++ b/src/ApiGateways/Web.Bff.Marketing/apigw/azds.yaml
@@ -0,0 +1,44 @@
+kind: helm-release
+apiVersion: 1.1
+build:
+ context: ..\..\..\..\
+ dockerfile: ..\..\..\ApiGateways\ApiGw-Base\Dockerfile
+install:
+ chart: ../../../../k8s/helm/apigwwm
+ set:
+ replicaCount: 1
+ image:
+ tag: $(tag)
+ pullPolicy: Never
+ ingress:
+ annotations:
+ kubernetes.io/ingress.class: traefik-azds
+ hosts:
+ # This expands to [space.s.]webmvc...aksapp.io
+ - $(spacePrefix)eshop$(hostSuffix)
+ inf:
+ k8s:
+ dns: $(spacePrefix)eshop$(hostSuffix)
+ values:
+ - values.dev.yaml?
+ - secrets.dev.yaml?
+ - inf.yaml
+ - app.yaml
+configurations:
+ develop:
+ build:
+ useGitIgnore: true
+ dockerfile: ..\..\..\ApiGateways\ApiGw-Base\Dockerfile.develop
+ args:
+ BUILD_CONFIGURATION: ${BUILD_CONFIGURATION:-Debug}
+ container:
+ sync:
+ - '**/Pages/**'
+ - '**/Views/**'
+ - '**/wwwroot/**'
+ - '!**/*.{sln,csproj}'
+ command: [dotnet, run, --no-restore, --no-build, --no-launch-profile, -c, "${BUILD_CONFIGURATION:-Debug}"]
+ iterate:
+ processesToKill: [dotnet, vsdbg]
+ buildCommands:
+ - [dotnet, build, --no-restore, -c, "${BUILD_CONFIGURATION:-Debug}"]
diff --git a/src/ApiGateways/Web.Bff.Marketing/apigw/values.dev.yaml b/src/ApiGateways/Web.Bff.Marketing/apigw/values.dev.yaml
new file mode 100644
index 000000000..fb59d98d5
--- /dev/null
+++ b/src/ApiGateways/Web.Bff.Marketing/apigw/values.dev.yaml
@@ -0,0 +1,2 @@
+ocelot:
+ configPath: /src/src/ApiGateways/ApiGw-Base/configuration
\ No newline at end of file
diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile b/src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile
index 236d3705a..8ac850778 100644
--- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile
+++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile
@@ -1,16 +1,26 @@
-FROM microsoft/dotnet:2.2.0-aspnetcore-runtime AS base
+FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80
-FROM microsoft/dotnet:2.2.100-sdk AS build
+FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
WORKDIR /src
+
+COPY scripts scripts/
+
+COPY src/ApiGateways/*/*.csproj /src/csproj-files/
+COPY src/ApiGateways/*/*/*.csproj /src/csproj-files/
+COPY src/BuildingBlocks/*/*/*.csproj /src/csproj-files/
+COPY src/Services/*/*/*.csproj /src/csproj-files/
+COPY src/Web/*/*.csproj /src/csproj-files/
+
+ARG RUN=pwd
+RUN ${RUN}
+
COPY . .
WORKDIR /src/src/ApiGateways/Web.Bff.Shopping/aggregator
-RUN dotnet restore -nowarn:msb3202,nu1503
-RUN dotnet build --no-restore -c Release -o /app
+RUN dotnet publish -c Release -o /app
FROM build AS publish
-RUN dotnet publish --no-restore -c Release -o /app
FROM base AS final
WORKDIR /app
diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile.develop b/src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile.develop
new file mode 100644
index 000000000..3d0d16dd3
--- /dev/null
+++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile.develop
@@ -0,0 +1,16 @@
+FROM microsoft/dotnet:2.2-sdk
+ARG BUILD_CONFIGURATION=Debug
+ENV ASPNETCORE_ENVIRONMENT=Development
+ENV DOTNET_USE_POLLING_FILE_WATCHER=true
+EXPOSE 80
+
+WORKDIR /src
+COPY ["src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj", "src/ApiGateways/Web.Bff.Shopping/aggregator/"]
+COPY ["src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj", "src/BuildingBlocks/Devspaces.Support/"]
+
+RUN dotnet restore src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj -nowarn:msb3202,nu1503
+COPY . .
+WORKDIR "/src/src/ApiGateways/Web.Bff.Shopping/aggregator"
+RUN dotnet build --no-restore -c $BUILD_CONFIGURATION
+
+CMD ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"]]
\ No newline at end of file
diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs
index 0fcd13a41..dd5e1cc8c 100644
--- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs
+++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs
@@ -21,6 +21,7 @@ using System.Net.Http;
using HealthChecks.UI.Client;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.Diagnostics.HealthChecks;
+using Devspaces.Support;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
{
@@ -48,6 +49,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
services.AddCustomMvc(Configuration)
.AddCustomAuthentication(Configuration)
+ .AddDevspaces()
.AddApplicationServices();
}
@@ -57,7 +59,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
var pathBase = Configuration["PATH_BASE"];
if (!string.IsNullOrEmpty(pathBase))
{
- loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
+ loggerFactory.CreateLogger().LogDebug("Using PATH BASE '{pathBase}'", pathBase);
app.UsePathBase(pathBase);
}
@@ -182,21 +184,23 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
services.AddSingleton();
//register http services
-
+
services.AddHttpClient()
.AddHttpMessageHandler()
.AddPolicyHandler(GetRetryPolicy())
- .AddPolicyHandler(GetCircuitBreakerPolicy());
+ .AddPolicyHandler(GetCircuitBreakerPolicy())
+ .AddDevspacesSupport();
services.AddHttpClient()
.AddPolicyHandler(GetRetryPolicy())
- .AddPolicyHandler(GetCircuitBreakerPolicy());
+ .AddPolicyHandler(GetCircuitBreakerPolicy())
+ .AddDevspacesSupport();
services.AddHttpClient()
.AddHttpMessageHandler()
.AddPolicyHandler(GetRetryPolicy())
- .AddPolicyHandler(GetCircuitBreakerPolicy());
-
+ .AddPolicyHandler(GetCircuitBreakerPolicy())
+ .AddDevspacesSupport();
return services;
}
diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj b/src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj
index de2f55ab8..d438e4602 100644
--- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj
+++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj
@@ -12,14 +12,18 @@
-
-
+
+
-
+
+
+
+
+
diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/azds.yaml b/src/ApiGateways/Web.Bff.Shopping/aggregator/azds.yaml
new file mode 100644
index 000000000..189d2261d
--- /dev/null
+++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/azds.yaml
@@ -0,0 +1,55 @@
+kind: helm-release
+apiVersion: 1.1
+build:
+ context: ..\..\..\..
+ dockerfile: Dockerfile
+install:
+ chart: ../../../../k8s/helm/webshoppingagg
+ set:
+ image:
+ tag: $(tag)
+ pullPolicy: Never
+ ingress:
+ annotations:
+ kubernetes.io/ingress.class: traefik-azds
+ hosts:
+ # This expands to [space.s.]apigwms...aksapp.io
+ - $(spacePrefix)eshop$(hostSuffix)
+ inf:
+ k8s:
+ dns: $(spacePrefix)eshop$(hostSuffix)
+ values:
+ - values.dev.yaml?
+ - secrets.dev.yaml?
+ - app.yaml
+ - inf.yaml
+configurations:
+ develop:
+ build:
+ useGitIgnore: true
+ dockerfile: Dockerfile.develop
+ container:
+ syncTarget: /src
+ sync:
+ - '**/Pages/**'
+ - '**/Views/**'
+ - '**/wwwroot/**'
+ - '!**/*.{sln,csproj}'
+ command:
+ - dotnet
+ - run
+ - --no-restore
+ - --no-build
+ - --no-launch-profile
+ - -c
+ - ${Configuration:-Debug}
+ iterate:
+ processesToKill:
+ - dotnet
+ - vsdbg
+ buildCommands:
+ - - dotnet
+ - build
+ - --no-restore
+ - -c
+ - ${Configuration:-Debug}
diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/values.dev.yaml b/src/ApiGateways/Web.Bff.Shopping/aggregator/values.dev.yaml
new file mode 100644
index 000000000..45f664d6a
--- /dev/null
+++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/values.dev.yaml
@@ -0,0 +1,2 @@
+ocelot:
+ configPath: /app/configuration
\ No newline at end of file
diff --git a/src/ApiGateways/Web.Bff.Shopping/apigw/azds.yaml b/src/ApiGateways/Web.Bff.Shopping/apigw/azds.yaml
new file mode 100644
index 000000000..69f26cdca
--- /dev/null
+++ b/src/ApiGateways/Web.Bff.Shopping/apigw/azds.yaml
@@ -0,0 +1,43 @@
+kind: helm-release
+apiVersion: 1.1
+build:
+ context: ..\..\..\..\
+ dockerfile: ..\..\..\..\ApiGateways\ApiGw-Base\Dockerfile
+install:
+ chart: ../../../../k8s/helm/apigwws
+ set:
+ replicaCount: 1
+ image:
+ tag: $(tag)
+ pullPolicy: Never
+ ingress:
+ annotations:
+ kubernetes.io/ingress.class: traefik-azds
+ hosts:
+ - $(spacePrefix)eshop$(hostSuffix)
+ inf:
+ k8s:
+ dns: $(spacePrefix)eshop$(hostSuffix)
+ values:
+ - values.dev.yaml?
+ - secrets.dev.yaml?
+ - inf.yaml
+ - app.yaml
+configurations:
+ develop:
+ build:
+ useGitIgnore: true
+ dockerfile: ..\..\..\ApiGateways\ApiGw-Base\Dockerfile.develop
+ args:
+ BUILD_CONFIGURATION: ${BUILD_CONFIGURATION:-Debug}
+ container:
+ sync:
+ - '**/Pages/**'
+ - '**/Views/**'
+ - '**/wwwroot/**'
+ - '!**/*.{sln,csproj}'
+ command: [dotnet, run, --no-restore, --no-build, --no-launch-profile, -c, "${BUILD_CONFIGURATION:-Debug}"]
+ iterate:
+ processesToKill: [dotnet, vsdbg]
+ buildCommands:
+ - [dotnet, build, --no-restore, -c, "${BUILD_CONFIGURATION:-Debug}"]
diff --git a/src/ApiGateways/Web.Bff.Shopping/apigw/values.dev.yaml b/src/ApiGateways/Web.Bff.Shopping/apigw/values.dev.yaml
new file mode 100644
index 000000000..fb59d98d5
--- /dev/null
+++ b/src/ApiGateways/Web.Bff.Shopping/apigw/values.dev.yaml
@@ -0,0 +1,2 @@
+ocelot:
+ configPath: /src/src/ApiGateways/ApiGw-Base/configuration
\ No newline at end of file
diff --git a/src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj b/src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj
new file mode 100644
index 000000000..81a897bad
--- /dev/null
+++ b/src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj
@@ -0,0 +1,11 @@
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
diff --git a/src/BuildingBlocks/Devspaces.Support/DevspacesMessageHandler.cs b/src/BuildingBlocks/Devspaces.Support/DevspacesMessageHandler.cs
new file mode 100644
index 000000000..0895b752a
--- /dev/null
+++ b/src/BuildingBlocks/Devspaces.Support/DevspacesMessageHandler.cs
@@ -0,0 +1,30 @@
+using Microsoft.AspNetCore.Http;
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Devspaces.Support
+{
+ public class DevspacesMessageHandler : DelegatingHandler
+ {
+ private const string DevspacesHeaderName = "azds-route-as";
+ private readonly IHttpContextAccessor _httpContextAccessor;
+ public DevspacesMessageHandler(IHttpContextAccessor httpContextAccessor)
+ {
+ _httpContextAccessor = httpContextAccessor;
+ }
+
+ protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ var req = _httpContextAccessor.HttpContext.Request;
+
+ if (req.Headers.ContainsKey(DevspacesHeaderName))
+ {
+ request.Headers.Add(DevspacesHeaderName, req.Headers[DevspacesHeaderName] as IEnumerable);
+ }
+ return base.SendAsync(request, cancellationToken);
+ }
+ }
+}
diff --git a/src/BuildingBlocks/Devspaces.Support/HttpClientBuilderDevspacesExtensions.cs b/src/BuildingBlocks/Devspaces.Support/HttpClientBuilderDevspacesExtensions.cs
new file mode 100644
index 000000000..60108301d
--- /dev/null
+++ b/src/BuildingBlocks/Devspaces.Support/HttpClientBuilderDevspacesExtensions.cs
@@ -0,0 +1,16 @@
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Devspaces.Support
+{
+ public static class HttpClientBuilderDevspacesExtensions
+ {
+ public static IHttpClientBuilder AddDevspacesSupport(this IHttpClientBuilder builder)
+ {
+ builder.AddHttpMessageHandler();
+ return builder;
+ }
+ }
+}
diff --git a/src/BuildingBlocks/Devspaces.Support/ServiceCollectionDevspacesExtensions.cs b/src/BuildingBlocks/Devspaces.Support/ServiceCollectionDevspacesExtensions.cs
new file mode 100644
index 000000000..0ac5c9e1b
--- /dev/null
+++ b/src/BuildingBlocks/Devspaces.Support/ServiceCollectionDevspacesExtensions.cs
@@ -0,0 +1,16 @@
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Devspaces.Support
+{
+ public static class ServiceCollectionDevspacesExtensions
+ {
+ public static IServiceCollection AddDevspaces(this IServiceCollection services)
+ {
+ services.AddTransient();
+ return services;
+ }
+ }
+}
diff --git a/src/BuildingBlocks/EventBus/EventBus/Extensions/GenericTypeExtensions.cs b/src/BuildingBlocks/EventBus/EventBus/Extensions/GenericTypeExtensions.cs
new file mode 100644
index 000000000..de5a2cb79
--- /dev/null
+++ b/src/BuildingBlocks/EventBus/EventBus/Extensions/GenericTypeExtensions.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions
+{
+ public static class GenericTypeExtensions
+ {
+ public static string GetGenericTypeName(this Type type)
+ {
+ var typeName = string.Empty;
+
+ if (type.IsGenericType)
+ {
+ var genericTypes = string.Join(",", type.GetGenericArguments().Select(t => t.Name).ToArray());
+ typeName = $"{type.Name.Remove(type.Name.IndexOf('`'))}<{genericTypes}>";
+ }
+ else
+ {
+ typeName = type.Name;
+ }
+
+ return typeName;
+ }
+
+ public static string GetGenericTypeName(this object @object)
+ {
+ return @object.GetType().GetGenericTypeName();
+ }
+ }
+}
diff --git a/src/BuildingBlocks/EventBus/EventBus/InMemoryEventBusSubscriptionsManager.cs b/src/BuildingBlocks/EventBus/EventBus/InMemoryEventBusSubscriptionsManager.cs
index e789081f3..ea1aca61e 100644
--- a/src/BuildingBlocks/EventBus/EventBus/InMemoryEventBusSubscriptionsManager.cs
+++ b/src/BuildingBlocks/EventBus/EventBus/InMemoryEventBusSubscriptionsManager.cs
@@ -115,10 +115,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus
private void RaiseOnEventRemoved(string eventName)
{
var handler = OnEventRemoved;
- if (handler != null)
- {
- OnEventRemoved(this, eventName);
- }
+ handler?.Invoke(this, eventName);
}
diff --git a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/DefaultRabbitMQPersisterConnection.cs b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/DefaultRabbitMQPersistentConnection.cs
similarity index 91%
rename from src/BuildingBlocks/EventBus/EventBusRabbitMQ/DefaultRabbitMQPersisterConnection.cs
rename to src/BuildingBlocks/EventBus/EventBusRabbitMQ/DefaultRabbitMQPersistentConnection.cs
index 2e0555e61..93e5b2917 100644
--- a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/DefaultRabbitMQPersisterConnection.cs
+++ b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/DefaultRabbitMQPersistentConnection.cs
@@ -72,7 +72,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
.Or()
.WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) =>
{
- _logger.LogWarning(ex.ToString());
+ _logger.LogWarning(ex, "RabbitMQ Client could not connect after {TimeOut}s ({ExceptionMessage})", $"{time.TotalSeconds:n1}", ex.Message);
}
);
@@ -88,7 +88,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
_connection.CallbackException += OnCallbackException;
_connection.ConnectionBlocked += OnConnectionBlocked;
- _logger.LogInformation($"RabbitMQ persistent connection acquired a connection {_connection.Endpoint.HostName} and is subscribed to failure events");
+ _logger.LogInformation("RabbitMQ Client acquired a persistent connection to '{HostName}' and is subscribed to failure events", _connection.Endpoint.HostName);
return true;
}
diff --git a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs
index a3b6437ef..397b75017 100644
--- a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs
+++ b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs
@@ -2,6 +2,7 @@
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -76,7 +77,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
.Or()
.WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) =>
{
- _logger.LogWarning(ex.ToString());
+ _logger.LogWarning(ex, "Could not publish event: {EventId} after {Timeout}s ({ExceptionMessage})", @event.Id, $"{time.TotalSeconds:n1}", ex.Message);
});
using (var channel = _persistentConnection.CreateModel())
@@ -97,7 +98,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
channel.BasicPublish(exchange: BROKER_NAME,
routingKey: eventName,
- mandatory:true,
+ mandatory: true,
basicProperties: properties,
body: body);
});
@@ -107,8 +108,11 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
public void SubscribeDynamic(string eventName)
where TH : IDynamicIntegrationEventHandler
{
+ _logger.LogInformation("Subscribing to dynamic event {EventName} with {EventHandler}", eventName, typeof(TH).GetGenericTypeName());
+
DoInternalSubscription(eventName);
_subsManager.AddDynamicSubscription | (eventName);
+ StartBasicConsume();
}
public void Subscribe()
@@ -117,7 +121,11 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
{
var eventName = _subsManager.GetEventKey();
DoInternalSubscription(eventName);
+
+ _logger.LogInformation("Subscribing to event {EventName} with {EventHandler}", eventName, typeof(TH).GetGenericTypeName());
+
_subsManager.AddSubscription();
+ StartBasicConsume();
}
private void DoInternalSubscription(string eventName)
@@ -140,9 +148,13 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
}
public void Unsubscribe()
- where TH : IIntegrationEventHandler
where T : IntegrationEvent
+ where TH : IIntegrationEventHandler
{
+ var eventName = _subsManager.GetEventKey();
+
+ _logger.LogInformation("Unsubscribing from event {EventName}", eventName);
+
_subsManager.RemoveSubscription();
}
@@ -162,6 +174,50 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
_subsManager.Clear();
}
+ private void StartBasicConsume()
+ {
+ if (_consumerChannel != null)
+ {
+ var consumer = new AsyncEventingBasicConsumer(_consumerChannel);
+
+ consumer.Received += Consumer_Received;
+
+ _consumerChannel.BasicConsume(
+ queue: _queueName,
+ autoAck: false,
+ consumer: consumer);
+ }
+ else
+ {
+ _logger.LogError("StartBasicConsume can't call on _consumerChannel == null");
+ }
+ }
+
+ private async Task Consumer_Received(object sender, BasicDeliverEventArgs eventArgs)
+ {
+ var eventName = eventArgs.RoutingKey;
+ var message = Encoding.UTF8.GetString(eventArgs.Body);
+
+ try
+ {
+ if (message.ToLowerInvariant().Contains("throw-fake-exception"))
+ {
+ throw new InvalidOperationException($"Fake exception requested: \"{message}\"");
+ }
+
+ await ProcessEvent(eventName, message);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "----- ERROR Processing message \"{Message}\"", message);
+ }
+
+ // Even on exception we take the message off the queue.
+ // in a REAL WORLD app this should be handled with a Dead Letter Exchange (DLX).
+ // For more information see: https://www.rabbitmq.com/dlx.html
+ _consumerChannel.BasicAck(eventArgs.DeliveryTag, multiple: false);
+ }
+
private IModel CreateConsumerChannel()
{
if (!_persistentConnection.IsConnected)
@@ -172,7 +228,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
var channel = _persistentConnection.CreateModel();
channel.ExchangeDeclare(exchange: BROKER_NAME,
- type: "direct");
+ type: "direct");
channel.QueueDeclare(queue: _queueName,
durable: true,
@@ -180,26 +236,11 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
autoDelete: false,
arguments: null);
-
- var consumer = new EventingBasicConsumer(channel);
- consumer.Received += async (model, ea) =>
- {
- var eventName = ea.RoutingKey;
- var message = Encoding.UTF8.GetString(ea.Body);
-
- await ProcessEvent(eventName, message);
-
- channel.BasicAck(ea.DeliveryTag,multiple:false);
- };
-
- channel.BasicConsume(queue: _queueName,
- autoAck: false,
- consumer: consumer);
-
channel.CallbackException += (sender, ea) =>
{
_consumerChannel.Dispose();
_consumerChannel = CreateConsumerChannel();
+ StartBasicConsume();
};
return channel;
@@ -215,7 +256,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
foreach (var subscription in subscriptions)
{
if (subscription.IsDynamic)
- {
+ {
var handler = scope.ResolveOptional(subscription.HandlerType) as IDynamicIntegrationEventHandler;
if (handler == null) continue;
dynamic eventData = JObject.Parse(message);
diff --git a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj
index 6e0215c29..62373d1b3 100644
--- a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj
+++ b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj
@@ -8,7 +8,7 @@
-
+
diff --git a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/IRabbitMQPersisterConnection.cs b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/IRabbitMQPersistentConnection.cs
similarity index 100%
rename from src/BuildingBlocks/EventBus/EventBusRabbitMQ/IRabbitMQPersisterConnection.cs
rename to src/BuildingBlocks/EventBus/EventBusRabbitMQ/IRabbitMQPersistentConnection.cs
diff --git a/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.cs b/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.cs
index d16eb4625..cd2dc557f 100644
--- a/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.cs
+++ b/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.cs
@@ -27,7 +27,7 @@
ILifetimeScope autofac)
{
_serviceBusPersisterConnection = serviceBusPersisterConnection;
- _logger = logger;
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
_subsManager = subsManager ?? new InMemoryEventBusSubscriptionsManager();
_subscriptionClient = new SubscriptionClient(serviceBusPersisterConnection.ServiceBusConnectionStringBuilder,
@@ -61,6 +61,8 @@
public void SubscribeDynamic(string eventName)
where TH : IDynamicIntegrationEventHandler
{
+ _logger.LogInformation("Subscribing to dynamic event {EventName} with {EventHandler}", eventName, nameof(TH));
+
_subsManager.AddDynamicSubscription | (eventName);
}
@@ -83,10 +85,12 @@
}
catch (ServiceBusException)
{
- _logger.LogInformation($"The messaging entity {eventName} already exists.");
+ _logger.LogWarning("The messaging entity {eventName} already exists.", eventName);
}
}
+ _logger.LogInformation("Subscribing to event {EventName} with {EventHandler}", eventName, nameof(TH));
+
_subsManager.AddSubscription();
}
@@ -105,15 +109,19 @@
}
catch (MessagingEntityNotFoundException)
{
- _logger.LogInformation($"The messaging entity {eventName} Could not be found.");
+ _logger.LogWarning("The messaging entity {eventName} Could not be found.", eventName);
}
+ _logger.LogInformation("Unsubscribing from event {EventName}", eventName);
+
_subsManager.RemoveSubscription();
}
public void UnsubscribeDynamic(string eventName)
where TH : IDynamicIntegrationEventHandler
{
+ _logger.LogInformation("Unsubscribing from dynamic event {EventName}", eventName);
+
_subsManager.RemoveDynamicSubscription | (eventName);
}
@@ -136,17 +144,16 @@
await _subscriptionClient.CompleteAsync(message.SystemProperties.LockToken);
}
},
- new MessageHandlerOptions(ExceptionReceivedHandler) { MaxConcurrentCalls = 10, AutoComplete = false });
+ new MessageHandlerOptions(ExceptionReceivedHandler) { MaxConcurrentCalls = 10, AutoComplete = false });
}
private Task ExceptionReceivedHandler(ExceptionReceivedEventArgs exceptionReceivedEventArgs)
{
- Console.WriteLine($"Message handler encountered an exception {exceptionReceivedEventArgs.Exception}.");
+ var ex = exceptionReceivedEventArgs.Exception;
var context = exceptionReceivedEventArgs.ExceptionReceivedContext;
- Console.WriteLine("Exception context for troubleshooting:");
- Console.WriteLine($"- Endpoint: {context.Endpoint}");
- Console.WriteLine($"- Entity Path: {context.EntityPath}");
- Console.WriteLine($"- Executing Action: {context.Action}");
+
+ _logger.LogError(ex, "ERROR handling message: {ExceptionMessage} - Context: {@ExceptionContext}", ex.Message, context);
+
return Task.CompletedTask;
}
@@ -172,7 +179,7 @@
var handler = scope.ResolveOptional(subscription.HandlerType);
if (handler == null) continue;
var eventType = _subsManager.GetEventTypeByName(eventName);
- var integrationEvent = JsonConvert.DeserializeObject(message, eventType);
+ var integrationEvent = JsonConvert.DeserializeObject(message, eventType);
var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType);
await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent });
}
@@ -194,7 +201,7 @@
}
catch (MessagingEntityNotFoundException)
{
- _logger.LogInformation($"The messaging entity { RuleDescription.DefaultRuleName } Could not be found.");
+ _logger.LogWarning("The messaging entity {DefaultRuleName} Could not be found.", RuleDescription.DefaultRuleName);
}
}
}
diff --git a/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj b/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj
index 288c4256a..3de07e329 100644
--- a/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj
+++ b/src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj
index 731953225..ef3463cca 100644
--- a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj
+++ b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj
@@ -6,10 +6,10 @@
-
-
-
-
+
+
+
+
diff --git a/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHostExtensions.cs b/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHostExtensions.cs
index 0da18f581..fa06e0a0b 100644
--- a/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHostExtensions.cs
+++ b/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHostExtensions.cs
@@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Hosting
try
{
- logger.LogInformation($"Migrating database associated with context {typeof(TContext).Name}");
+ logger.LogInformation("Migrating database associated with context {DbContextName}", typeof(TContext).Name);
if (underK8s)
{
@@ -55,11 +55,11 @@ namespace Microsoft.AspNetCore.Hosting
retry.Execute(() => InvokeSeeder(seeder, context, services));
}
- logger.LogInformation($"Migrated database associated with context {typeof(TContext).Name}");
+ logger.LogInformation("Migrated database associated with context {DbContextName}", typeof(TContext).Name);
}
catch (Exception ex)
{
- logger.LogError(ex, $"An error occurred while migrating the database used on context {typeof(TContext).Name}");
+ logger.LogError(ex, "An error occurred while migrating the database used on context {DbContextName}", typeof(TContext).Name);
if (underK8s)
{
throw; // Rethrow under k8s because we rely on k8s to re-run the pod
diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.iOS/eShopOnContainers.TestRunner.iOS.csproj.bak b/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.iOS/eShopOnContainers.TestRunner.iOS.csproj.bak
deleted file mode 100644
index 0d45fd280..000000000
--- a/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.iOS/eShopOnContainers.TestRunner.iOS.csproj.bak
+++ /dev/null
@@ -1,175 +0,0 @@
-
-
-
- Debug
- iPhoneSimulator
- {B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}
- {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Exe
- eShopOnContainers.TestRunner.iOS
- Resources
- eShopOnContainers.TestRunner.iOS
-
-
-
-
- true
- full
- false
- bin\iPhoneSimulator\Debug
- DEBUG
- prompt
- 4
- false
- x86_64
- SdkOnly
- True
- 10.1
- False
- False
- False
- False
- False
- False
- False
- True
- Default
- HttpClientHandler
- False
-
-
- none
- true
- bin\iPhoneSimulator\Release
- prompt
- 4
- None
- x86_64
- false
-
-
- true
- full
- false
- bin\iPhone\Debug
- DEBUG
- prompt
- 4
- false
- ARMv7, ARM64
- Entitlements.plist
- iPhone Developer
- true
-
-
- none
- true
- bin\iPhone\Release
- prompt
- 4
- Entitlements.plist
- ARMv7, ARM64
- false
- iPhone Developer
-
-
- none
- True
- bin\iPhone\Ad-Hoc
- prompt
- 4
- False
- ARMv7, ARM64
- Entitlements.plist
- True
- Automatic:AdHoc
- iPhone Distribution
-
-
- none
- True
- bin\iPhone\AppStore
- prompt
- 4
- False
- ARMv7, ARM64
- Entitlements.plist
- Automatic:AppStore
- iPhone Distribution
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ..\..\packages\Xamarin.Forms.2.3.3.166-pre4\lib\Xamarin.iOS10\Xamarin.Forms.Core.dll
- True
-
-
- ..\..\packages\Xamarin.Forms.2.3.3.166-pre4\lib\Xamarin.iOS10\Xamarin.Forms.Platform.dll
- True
-
-
- ..\..\packages\Xamarin.Forms.2.3.3.166-pre4\lib\Xamarin.iOS10\Xamarin.Forms.Platform.iOS.dll
- True
-
-
- ..\..\packages\Xamarin.Forms.2.3.3.166-pre4\lib\Xamarin.iOS10\Xamarin.Forms.Xaml.dll
- True
-
-
-
- ..\..\packages\xunit.abstractions.2.0.1\lib\netstandard1.0\xunit.abstractions.dll
- True
-
-
- ..\..\packages\xunit.assert.2.2.0-beta4-build3444\lib\netstandard1.0\xunit.assert.dll
- True
-
-
- ..\..\packages\xunit.extensibility.core.2.2.0-beta4-build3444\lib\netstandard1.0\xunit.core.dll
- True
-
-
- ..\..\packages\xunit.extensibility.execution.2.2.0-beta4-build3444\lib\netstandard1.0\xunit.execution.dotnet.dll
- True
-
-
- ..\..\packages\xunit.runner.devices.2.1.0\lib\Xamarin.iOS\xunit.runner.devices.dll
- True
-
-
- ..\..\packages\xunit.runner.utility.2.2.0-beta4-build3444\lib\netstandard1.1\xunit.runner.utility.dotnet.dll
- True
-
-
-
-
-
-
-
-
- {f7b6a162-bc4d-4924-b16a-713f9b0344e7}
- eShopOnContainers.UnitTests
-
-
-
-
-
-
- Este proyecto hace referencia a los paquetes NuGet que faltan en este equipo. Use la restauración de paquetes NuGet para descargarlos. Para obtener más información, consulte http://go.microsoft.com/fwlink/?LinkID=322105. El archivo que falta es {0}.
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Services/Basket/Basket.API/.dockerignore b/src/Services/Basket/Basket.API/.dockerignore
new file mode 100644
index 000000000..04f7b133d
--- /dev/null
+++ b/src/Services/Basket/Basket.API/.dockerignore
@@ -0,0 +1,14 @@
+.dockerignore
+.git
+.gitignore
+.vs
+.vscode
+**/*.*proj.user
+**/azds.yaml
+**/bin
+**/charts
+**/Dockerfile
+**/Dockerfile.develop
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
\ No newline at end of file
diff --git a/src/Services/Basket/Basket.API/Basket.API.csproj b/src/Services/Basket/Basket.API/Basket.API.csproj
index 4add803b6..d5fc0a301 100644
--- a/src/Services/Basket/Basket.API/Basket.API.csproj
+++ b/src/Services/Basket/Basket.API/Basket.API.csproj
@@ -13,25 +13,29 @@
-
-
+
+
+
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
+
-
diff --git a/src/Services/Basket/Basket.API/Controllers/BasketController.cs b/src/Services/Basket/Basket.API/Controllers/BasketController.cs
index 0e15e65dd..69f601579 100644
--- a/src/Services/Basket/Basket.API/Controllers/BasketController.cs
+++ b/src/Services/Basket/Basket.API/Controllers/BasketController.cs
@@ -5,6 +5,8 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
using Microsoft.eShopOnContainers.Services.Basket.API.Model;
using Microsoft.eShopOnContainers.Services.Basket.API.Services;
+using Microsoft.Extensions.Logging;
+using Serilog.Context;
using System;
using System.Net;
using System.Threading.Tasks;
@@ -19,9 +21,15 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
private readonly IBasketRepository _repository;
private readonly IIdentityService _identityService;
private readonly IEventBus _eventBus;
+ private readonly ILogger _logger;
- public BasketController(IBasketRepository repository, IIdentityService identityService, IEventBus eventBus)
+ public BasketController(
+ ILogger logger,
+ IBasketRepository repository,
+ IIdentityService identityService,
+ IEventBus eventBus)
{
+ _logger = logger;
_repository = repository;
_identityService = identityService;
_eventBus = eventBus;
@@ -33,14 +41,14 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
{
var basket = await _repository.GetBasketAsync(id);
- return basket ?? new CustomerBasket(id);
+ return Ok(basket ?? new CustomerBasket(id));
}
[HttpPost]
[ProducesResponseType(typeof(CustomerBasket), (int)HttpStatusCode.OK)]
public async Task> UpdateBasketAsync([FromBody]CustomerBasket value)
{
- return await _repository.UpdateBasketAsync(value);
+ return Ok(await _repository.UpdateBasketAsync(value));
}
[Route("checkout")]
@@ -50,7 +58,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
public async Task CheckoutAsync([FromBody]BasketCheckout basketCheckout, [FromHeader(Name = "x-requestid")] string requestId)
{
var userId = _identityService.GetUserIdentity();
-
+
basketCheckout.RequestId = (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) ?
guid : basketCheckout.RequestId;
@@ -70,7 +78,18 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
// Once basket is checkout, sends an integration event to
// ordering.api to convert basket to order and proceeds with
// order creation process
- _eventBus.Publish(eventMessage);
+ try
+ {
+ _logger.LogInformation("----- Publishing integration event: {IntegrationEventId} from {AppName} - ({@IntegrationEvent})", eventMessage.Id, Program.AppName, eventMessage);
+
+ _eventBus.Publish(eventMessage);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "ERROR Publishing integration event: {IntegrationEventId} from {AppName}", eventMessage.Id, Program.AppName);
+
+ throw;
+ }
return Accepted();
}
diff --git a/src/Services/Basket/Basket.API/Dockerfile b/src/Services/Basket/Basket.API/Dockerfile
index a5ccd56f5..81955e178 100644
--- a/src/Services/Basket/Basket.API/Dockerfile
+++ b/src/Services/Basket/Basket.API/Dockerfile
@@ -1,22 +1,32 @@
-FROM microsoft/dotnet:2.2.0-aspnetcore-runtime AS base
+FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80
-FROM microsoft/dotnet:2.2.100-sdk AS build
+FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
WORKDIR /src
+
+COPY scripts scripts/
+
+COPY src/ApiGateways/*/*.csproj /src/csproj-files/
+COPY src/ApiGateways/*/*/*.csproj /src/csproj-files/
+COPY src/BuildingBlocks/*/*/*.csproj /src/csproj-files/
+COPY src/Services/*/*/*.csproj /src/csproj-files/
+COPY src/Web/*/*.csproj /src/csproj-files/
+
+ARG RUN=pwd
+RUN ${RUN}
+
COPY . .
WORKDIR /src/src/Services/Basket/Basket.API
-RUN dotnet restore -nowarn:msb3202,nu1503
-RUN dotnet build --no-restore -c Release -o /app
-
-FROM build as functionaltest
-WORKDIR /src/src/Services/Basket/Basket.FunctionalTests
+RUN dotnet publish -c Release -o /app
FROM build as unittest
WORKDIR /src/src/Services/Basket/Basket.UnitTests
+FROM build as functionaltest
+WORKDIR /src/src/Services/Basket/Basket.FunctionalTests
+
FROM build AS publish
-RUN dotnet publish --no-restore -c Release -o /app
FROM base AS final
WORKDIR /app
diff --git a/src/Services/Basket/Basket.API/Dockerfile.develop b/src/Services/Basket/Basket.API/Dockerfile.develop
new file mode 100644
index 000000000..5ae5cc235
--- /dev/null
+++ b/src/Services/Basket/Basket.API/Dockerfile.develop
@@ -0,0 +1,19 @@
+FROM microsoft/dotnet:2.2-sdk
+ARG BUILD_CONFIGURATION=Debug
+ENV ASPNETCORE_ENVIRONMENT=Development
+ENV DOTNET_USE_POLLING_FILE_WATCHER=true
+EXPOSE 80
+
+WORKDIR /src
+
+COPY ["src/BuildingBlocks/EventBus/EventBus/EventBus.csproj", "src/BuildingBlocks/EventBus/EventBus/"]
+COPY ["src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "src/BuildingBlocks/EventBus/EventBusRabbitMQ/"]
+COPY ["src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "src/BuildingBlocks/EventBus/EventBusServiceBus/"]
+COPY ["src/Services/Basket/Basket.API/Basket.API.csproj", "src/Services/Basket/Basket.API/"]
+
+RUN dotnet restore src/Services/Basket/Basket.API/Basket.API.csproj -nowarn:msb3202,nu1503
+COPY . .
+WORKDIR /src/src/Services/Basket/Basket.API
+RUN dotnet build --no-restore -c $BUILD_CONFIGURATION
+
+ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"]
\ No newline at end of file
diff --git a/src/Services/Basket/Basket.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs b/src/Services/Basket/Basket.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs
index 7caa9740d..f1c7b08d0 100644
--- a/src/Services/Basket/Basket.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs
+++ b/src/Services/Basket/Basket.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs
@@ -19,11 +19,13 @@ namespace Basket.API.Infrastructure.Filters
operation.Responses.Add("401", new Response { Description = "Unauthorized" });
operation.Responses.Add("403", new Response { Description = "Forbidden" });
- operation.Security = new List>>();
- operation.Security.Add(new Dictionary>
+ operation.Security = new List>>
{
- { "oauth2", new [] { "basketapi" } }
- });
+ new Dictionary>
+ {
+ { "oauth2", new [] { "basketapi" } }
+ }
+ };
}
}
}
diff --git a/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/OrderStartedIntegrationEventHandler.cs b/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/OrderStartedIntegrationEventHandler.cs
index 19ae1b594..cb7b6a2d6 100644
--- a/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/OrderStartedIntegrationEventHandler.cs
+++ b/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/OrderStartedIntegrationEventHandler.cs
@@ -1,6 +1,9 @@
using Basket.API.IntegrationEvents.Events;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
+using Microsoft.eShopOnContainers.Services.Basket.API;
using Microsoft.eShopOnContainers.Services.Basket.API.Model;
+using Microsoft.Extensions.Logging;
+using Serilog.Context;
using System;
using System.Threading.Tasks;
@@ -9,15 +12,24 @@ namespace Basket.API.IntegrationEvents.EventHandling
public class OrderStartedIntegrationEventHandler : IIntegrationEventHandler
{
private readonly IBasketRepository _repository;
+ private readonly ILogger _logger;
- public OrderStartedIntegrationEventHandler(IBasketRepository repository)
+ public OrderStartedIntegrationEventHandler(
+ IBasketRepository repository,
+ ILogger logger)
{
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task Handle(OrderStartedIntegrationEvent @event)
{
- await _repository.DeleteBasketAsync(@event.UserId.ToString());
+ using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
+ {
+ _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
+
+ await _repository.DeleteBasketAsync(@event.UserId.ToString());
+ }
}
}
}
diff --git a/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/ProductPriceChangedIntegrationEventHandler.cs b/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/ProductPriceChangedIntegrationEventHandler.cs
index 546483b40..c27200e6f 100644
--- a/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/ProductPriceChangedIntegrationEventHandler.cs
+++ b/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/ProductPriceChangedIntegrationEventHandler.cs
@@ -1,6 +1,8 @@
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
using Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Events;
using Microsoft.eShopOnContainers.Services.Basket.API.Model;
+using Microsoft.Extensions.Logging;
+using Serilog.Context;
using System;
using System.Linq;
using System.Threading.Tasks;
@@ -9,22 +11,31 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Even
{
public class ProductPriceChangedIntegrationEventHandler : IIntegrationEventHandler
{
+ private readonly ILogger _logger;
private readonly IBasketRepository _repository;
- public ProductPriceChangedIntegrationEventHandler(IBasketRepository repository)
+ public ProductPriceChangedIntegrationEventHandler(
+ ILogger logger,
+ IBasketRepository repository)
{
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
}
public async Task Handle(ProductPriceChangedIntegrationEvent @event)
{
- var userIds = _repository.GetUsers();
-
- foreach (var id in userIds)
+ using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
{
- var basket = await _repository.GetBasketAsync(id);
+ _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
- await UpdatePriceInBasketItems(@event.ProductId, @event.NewPrice, @event.OldPrice, basket);
+ var userIds = _repository.GetUsers();
+
+ foreach (var id in userIds)
+ {
+ var basket = await _repository.GetBasketAsync(id);
+
+ await UpdatePriceInBasketItems(@event.ProductId, @event.NewPrice, @event.OldPrice, basket);
+ }
}
}
@@ -35,17 +46,19 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Even
if (itemsToUpdate != null)
{
+ _logger.LogInformation("----- ProductPriceChangedIntegrationEventHandler - Updating items in basket for user: {BuyerId} ({@Items})", basket.BuyerId, itemsToUpdate);
+
foreach (var item in itemsToUpdate)
{
- if(item.UnitPrice == oldPrice)
- {
+ if (item.UnitPrice == oldPrice)
+ {
var originalPrice = item.UnitPrice;
item.UnitPrice = newPrice;
item.OldUnitPrice = originalPrice;
}
}
await _repository.UpdateBasketAsync(basket);
- }
+ }
}
}
}
diff --git a/src/Services/Basket/Basket.API/Program.cs b/src/Services/Basket/Basket.API/Program.cs
index e4328645e..40cc0eebc 100644
--- a/src/Services/Basket/Basket.API/Program.cs
+++ b/src/Services/Basket/Basket.API/Program.cs
@@ -12,51 +12,81 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
{
public class Program
{
- public static void Main(string[] args)
+ public static readonly string Namespace = typeof(Program).Namespace;
+ public static readonly string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1);
+
+ public static int Main(string[] args)
{
- BuildWebHost(args).Run();
+ var configuration = GetConfiguration();
+
+ Log.Logger = CreateSerilogLogger(configuration);
+
+ try
+ {
+ Log.Information("Configuring web host ({ApplicationContext})...", AppName);
+ var host = BuildWebHost(configuration, args);
+
+ Log.Information("Starting web host ({ApplicationContext})...", AppName);
+ host.Run();
+
+ return 0;
+ }
+ catch (Exception ex)
+ {
+ Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
+ return 1;
+ }
+ finally
+ {
+ Log.CloseAndFlush();
+ }
}
- public static IWebHost BuildWebHost(string[] args) =>
+ private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
WebHost.CreateDefaultBuilder(args)
+ .CaptureStartupErrors(false)
.UseFailing(options =>
- {
- options.ConfigPath = "/Failing";
- })
- .UseContentRoot(Directory.GetCurrentDirectory())
+ options.ConfigPath = "/Failing")
.UseStartup()
- .ConfigureAppConfiguration((builderContext, config) =>
- {
- var builtConfig = config.Build();
-
- var configurationBuilder = new ConfigurationBuilder();
-
- if (Convert.ToBoolean(builtConfig["UseVault"]))
- {
- configurationBuilder.AddAzureKeyVault(
- $"https://{builtConfig["Vault:Name"]}.vault.azure.net/",
- builtConfig["Vault:ClientId"],
- builtConfig["Vault:ClientSecret"]);
- }
-
- configurationBuilder.AddEnvironmentVariables();
-
- config.AddConfiguration(configurationBuilder.Build());
- })
- .ConfigureLogging((hostingContext, builder) =>
- {
- builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
- builder.AddConsole();
- builder.AddDebug();
- })
- .UseSerilog((builderContext, config) =>
- {
- config
- .MinimumLevel.Information()
- .Enrich.FromLogContext()
- .WriteTo.Console();
- })
.UseApplicationInsights()
+ .UseContentRoot(Directory.GetCurrentDirectory())
+ .UseConfiguration(configuration)
+ .UseSerilog()
.Build();
+
+ private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
+ {
+ var seqServerUrl = configuration["Serilog:SeqServerUrl"];
+ var logstashUrl = configuration["Serilog:LogstashgUrl"];
+ return new LoggerConfiguration()
+ .MinimumLevel.Verbose()
+ .Enrich.WithProperty("ApplicationContext", AppName)
+ .Enrich.FromLogContext()
+ .WriteTo.Console()
+ .WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
+ .WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://logstash:8080" : logstashUrl)
+ .ReadFrom.Configuration(configuration)
+ .CreateLogger();
+ }
+
+ private static IConfiguration GetConfiguration()
+ {
+ var builder = new ConfigurationBuilder()
+ .SetBasePath(Directory.GetCurrentDirectory())
+ .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
+ .AddEnvironmentVariables();
+
+ var config = builder.Build();
+
+ if (config.GetValue("UseVault", false))
+ {
+ builder.AddAzureKeyVault(
+ $"https://{config["Vault:Name"]}.vault.azure.net/",
+ config["Vault:ClientId"],
+ config["Vault:ClientSecret"]);
+ }
+
+ return builder.Build();
+ }
}
}
diff --git a/src/Services/Basket/Basket.API/Startup.cs b/src/Services/Basket/Basket.API/Startup.cs
index eecc8bdd4..97ede1879 100644
--- a/src/Services/Basket/Basket.API/Startup.cs
+++ b/src/Services/Basket/Basket.API/Startup.cs
@@ -50,7 +50,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
- RegisterAppInsights(services);
+ RegisterAppInsights(services);
// Add framework services.
services.AddMvc(options =>
@@ -66,7 +66,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
services.AddCustomHealthCheck(Configuration);
- services.Configure(Configuration);
+ services.Configure(Configuration);
//By connecting here we are making sure that our service
//cannot start until redis is ready. This might slow down startup,
@@ -105,7 +105,8 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
var factory = new ConnectionFactory()
{
- HostName = Configuration["EventBusConnection"]
+ HostName = Configuration["EventBusConnection"],
+ DispatchConsumersAsync = true
};
if (!string.IsNullOrEmpty(Configuration["EventBusUserName"]))
@@ -181,8 +182,8 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
- loggerFactory.AddAzureWebAppDiagnostics();
- loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
+ //loggerFactory.AddAzureWebAppDiagnostics();
+ //loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
var pathBase = Configuration["PATH_BASE"];
if (!string.IsNullOrEmpty(pathBase))
@@ -228,7 +229,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
if (orchestratorType?.ToUpper() == "K8S")
{
// Enable K8s telemetry initializer
- services.EnableKubernetes();
+ services.AddApplicationInsightsKubernetesEnricher();
}
if (orchestratorType?.ToUpper() == "SF")
{
diff --git a/src/Services/Basket/Basket.API/appsettings.json b/src/Services/Basket/Basket.API/appsettings.json
index 4bff4d70d..fc8fc544a 100644
--- a/src/Services/Basket/Basket.API/appsettings.json
+++ b/src/Services/Basket/Basket.API/appsettings.json
@@ -1,10 +1,14 @@
{
- "Logging": {
- "IncludeScopes": false,
- "LogLevel": {
- "Default": "Debug",
- "System": "Information",
- "Microsoft": "Information"
+ "Serilog": {
+ "SeqServerUrl": null,
+ "LogstashgUrl": null,
+ "MinimumLevel": {
+ "Default": "Information",
+ "Override": {
+ "Microsoft": "Warning",
+ "Microsoft.eShopOnContainers": "Information",
+ "System": "Warning"
+ }
}
},
"IdentityUrl": "http://localhost:5105",
diff --git a/src/Services/Basket/Basket.API/azds.yaml b/src/Services/Basket/Basket.API/azds.yaml
new file mode 100644
index 000000000..4fbbb7be4
--- /dev/null
+++ b/src/Services/Basket/Basket.API/azds.yaml
@@ -0,0 +1,56 @@
+kind: helm-release
+apiVersion: 1.1
+build:
+ context: ..\..\..\..
+ dockerfile: Dockerfile
+install:
+ chart: ../../../../k8s/helm/basket-api
+ set:
+ replicaCount: 1
+ image:
+ tag: $(tag)
+ pullPolicy: Never
+ ingress:
+ annotations:
+ kubernetes.io/ingress.class: traefik-azds
+ hosts:
+ - $(spacePrefix)eshop$(hostSuffix)
+ inf:
+ k8s:
+ dns: $(spacePrefix)eshop$(hostSuffix)
+ values:
+ - values.dev.yaml?
+ - secrets.dev.yaml?
+ - inf.yaml
+ - app.yaml
+configurations:
+ develop:
+ build:
+ useGitIgnore: true
+ dockerfile: Dockerfile.develop
+ args:
+ BUILD_CONFIGURATION: ${BUILD_CONFIGURATION:-Debug}
+ container:
+ sync:
+ - '**/Pages/**'
+ - '**/Views/**'
+ - '**/wwwroot/**'
+ - '!**/*.{sln,csproj}'
+ command:
+ - dotnet
+ - run
+ - --no-restore
+ - --no-build
+ - --no-launch-profile
+ - -c
+ - ${BUILD_CONFIGURATION:-Debug}
+ iterate:
+ processesToKill:
+ - dotnet
+ - vsdbg
+ buildCommands:
+ - - dotnet
+ - build
+ - --no-restore
+ - -c
+ - ${BUILD_CONFIGURATION:-Debug}
diff --git a/src/Services/Basket/Basket.API/values.dev.yaml b/src/Services/Basket/Basket.API/values.dev.yaml
new file mode 100644
index 000000000..eaed45149
--- /dev/null
+++ b/src/Services/Basket/Basket.API/values.dev.yaml
@@ -0,0 +1,3 @@
+ingress:
+ enabled: true
+ tls: []
\ No newline at end of file
diff --git a/src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj b/src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj
index 2a2635354..4fd8cb9ec 100644
--- a/src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj
+++ b/src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj
@@ -17,12 +17,17 @@
-
+
+
+
-
-
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
-
+
diff --git a/src/Services/Basket/Basket.FunctionalTests/BasketScenarios.cs b/src/Services/Basket/Basket.FunctionalTests/BasketScenarios.cs
index 5c7ecdef5..83d507ade 100644
--- a/src/Services/Basket/Basket.FunctionalTests/BasketScenarios.cs
+++ b/src/Services/Basket/Basket.FunctionalTests/BasketScenarios.cs
@@ -5,7 +5,7 @@ using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
-using WebMVC.Models;
+using WebMVC.Services.ModelDTOs;
using Xunit;
namespace Basket.FunctionalTests
diff --git a/src/Services/Basket/Basket.UnitTests/Application/BasketWebApiTest.cs b/src/Services/Basket/Basket.UnitTests/Application/BasketWebApiTest.cs
index a2e382b92..2864b8b9f 100644
--- a/src/Services/Basket/Basket.UnitTests/Application/BasketWebApiTest.cs
+++ b/src/Services/Basket/Basket.UnitTests/Application/BasketWebApiTest.cs
@@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
using Microsoft.eShopOnContainers.Services.Basket.API.Controllers;
using Microsoft.eShopOnContainers.Services.Basket.API.Model;
+using Microsoft.Extensions.Logging;
using Moq;
using System;
using System.Collections.Generic;
@@ -20,12 +21,14 @@ namespace UnitTest.Basket.Application
private readonly Mock _basketRepositoryMock;
private readonly Mock _identityServiceMock;
private readonly Mock _serviceBusMock;
+ private readonly Mock> _loggerMock;
public BasketWebApiTest()
{
_basketRepositoryMock = new Mock();
_identityServiceMock = new Mock();
_serviceBusMock = new Mock();
+ _loggerMock = new Mock>();
}
[Fact]
@@ -43,12 +46,16 @@ namespace UnitTest.Basket.Application
//Act
var basketController = new BasketController(
- _basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object);
+ _loggerMock.Object,
+ _basketRepositoryMock.Object,
+ _identityServiceMock.Object,
+ _serviceBusMock.Object);
+
var actionResult = await basketController.GetBasketByIdAsync(fakeCustomerId);
//Assert
Assert.Equal((actionResult.Result as OkObjectResult).StatusCode, (int)System.Net.HttpStatusCode.OK);
- Assert.Equal(((CustomerBasket)actionResult.Value).BuyerId, fakeCustomerId);
+ Assert.Equal((((ObjectResult)actionResult.Result).Value as CustomerBasket).BuyerId, fakeCustomerId);
}
[Fact]
@@ -65,14 +72,17 @@ namespace UnitTest.Basket.Application
//Act
var basketController = new BasketController(
- _basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object);
+ _loggerMock.Object,
+ _basketRepositoryMock.Object,
+ _identityServiceMock.Object,
+ _serviceBusMock.Object);
var actionResult = await basketController.UpdateBasketAsync(fakeCustomerBasket);
//Assert
Assert.Equal((actionResult.Result as OkObjectResult).StatusCode, (int)System.Net.HttpStatusCode.OK);
- Assert.Equal(((CustomerBasket)actionResult.Value).BuyerId, fakeCustomerId);
- }
+ Assert.Equal((((ObjectResult)actionResult.Result).Value as CustomerBasket).BuyerId, fakeCustomerId);
+ }
[Fact]
public async Task Doing_Checkout_Without_Basket_Should_Return_Bad_Request()
@@ -84,7 +94,10 @@ namespace UnitTest.Basket.Application
//Act
var basketController = new BasketController(
- _basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object);
+ _loggerMock.Object,
+ _basketRepositoryMock.Object,
+ _identityServiceMock.Object,
+ _serviceBusMock.Object);
var result = await basketController.CheckoutAsync(new BasketCheckout(), Guid.NewGuid().ToString()) as BadRequestResult;
Assert.NotNull(result);
@@ -102,7 +115,10 @@ namespace UnitTest.Basket.Application
_identityServiceMock.Setup(x => x.GetUserIdentity()).Returns(fakeCustomerId);
var basketController = new BasketController(
- _basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object);
+ _loggerMock.Object,
+ _basketRepositoryMock.Object,
+ _identityServiceMock.Object,
+ _serviceBusMock.Object);
basketController.ControllerContext = new ControllerContext()
{
@@ -122,7 +138,7 @@ namespace UnitTest.Basket.Application
}
private CustomerBasket GetCustomerBasketFake(string fakeCustomerId)
- {
+ {
return new CustomerBasket(fakeCustomerId)
{
Items = new List()
diff --git a/src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj b/src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj
index 071bbf52b..27a851767 100644
--- a/src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj
+++ b/src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj
@@ -7,12 +7,17 @@
-
-
-
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
-
+
diff --git a/src/Services/Catalog/Catalog.API/Catalog.API.csproj b/src/Services/Catalog/Catalog.API/Catalog.API.csproj
index a2be6b522..6150179ee 100644
--- a/src/Services/Catalog/Catalog.API/Catalog.API.csproj
+++ b/src/Services/Catalog/Catalog.API/Catalog.API.csproj
@@ -34,24 +34,26 @@
-
+
-
-
+
+
+
-
-
-
+
+
+
+
diff --git a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs
index d9fa4002e..5dfb10a96 100644
--- a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs
+++ b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs
@@ -60,6 +60,15 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
.Take(pageSize)
.ToListAsync();
+ /* The "awesome" fix for testing Devspaces */
+
+ /*
+ foreach (var pr in itemsOnPage) {
+ pr.Name = "Awesome " + pr.Name;
+ }
+
+ */
+
itemsOnPage = ChangeUriPlaceholder(itemsOnPage);
var model = new PaginatedItemsViewModel(pageIndex, pageSize, totalItems, itemsOnPage);
diff --git a/src/Services/Catalog/Catalog.API/Dockerfile b/src/Services/Catalog/Catalog.API/Dockerfile
index a9fefb765..70a97da27 100644
--- a/src/Services/Catalog/Catalog.API/Dockerfile
+++ b/src/Services/Catalog/Catalog.API/Dockerfile
@@ -1,13 +1,24 @@
-FROM microsoft/dotnet:2.2.0-aspnetcore-runtime AS base
+FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80
-FROM microsoft/dotnet:2.2.100-sdk AS build
+FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
WORKDIR /src
+
+COPY scripts scripts/
+
+COPY src/ApiGateways/*/*.csproj /src/csproj-files/
+COPY src/ApiGateways/*/*/*.csproj /src/csproj-files/
+COPY src/BuildingBlocks/*/*/*.csproj /src/csproj-files/
+COPY src/Services/*/*/*.csproj /src/csproj-files/
+COPY src/Web/*/*.csproj /src/csproj-files/
+
+ARG RUN=pwd
+RUN ${RUN}
+
COPY . .
WORKDIR /src/src/Services/Catalog/Catalog.API
-RUN dotnet restore -nowarn:msb3202,nu1503
-RUN dotnet build --no-restore -c Release -o /app
+RUN dotnet publish -c Release -o /app
FROM build as unittest
WORKDIR /src/src/Services/Catalog/Catalog.UnitTests
@@ -16,7 +27,6 @@ FROM build as functionaltest
WORKDIR /src/src/Services/Catalog/Catalog.FunctionalTests
FROM build AS publish
-RUN dotnet publish --no-restore -c Release -o /app
FROM base AS final
WORKDIR /app
diff --git a/src/Services/Catalog/Catalog.API/Dockerfile.develop b/src/Services/Catalog/Catalog.API/Dockerfile.develop
new file mode 100644
index 000000000..11034a2bc
--- /dev/null
+++ b/src/Services/Catalog/Catalog.API/Dockerfile.develop
@@ -0,0 +1,21 @@
+FROM microsoft/dotnet:2.2-sdk
+ARG BUILD_CONFIGURATION=Debug
+ENV ASPNETCORE_ENVIRONMENT=Development
+ENV DOTNET_USE_POLLING_FILE_WATCHER=true
+EXPOSE 80
+
+WORKDIR /src
+
+COPY ["src/BuildingBlocks/EventBus/EventBus/EventBus.csproj", "src/BuildingBlocks/EventBus/EventBus/"]
+COPY ["src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "src/BuildingBlocks/EventBus/EventBusRabbitMQ/"]
+COPY ["src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "src/BuildingBlocks/EventBus/EventBusServiceBus/"]
+COPY ["src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj", "src/BuildingBlocks/EventBus/IntegrationEventLogEF/"]
+COPY ["src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj", "src/BuildingBlocks/WebHostCustomization/WebHost.Customization/"]
+COPY ["src/Services/Catalog/Catalog.API/Catalog.API.csproj", "src/Services/Catalog/Catalog.API/"]
+
+RUN dotnet restore src/Services/Catalog/Catalog.API/Catalog.API.csproj -nowarn:msb3202,nu1503
+COPY . .
+WORKDIR "/src/src/Services/Catalog/Catalog.API"
+RUN dotnet build --no-restore -c $BUILD_CONFIGURATION
+
+ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"]
\ No newline at end of file
diff --git a/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs
index e7ea1e09d..8bdd2a401 100644
--- a/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs
+++ b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs
@@ -76,14 +76,14 @@
}
catch (Exception ex)
{
- logger.LogError(ex.Message);
+ logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message);
return GetPreconfiguredCatalogBrands();
}
return File.ReadAllLines(csvFileCatalogBrands)
.Skip(1) // skip header row
.SelectTry(x => CreateCatalogBrand(x))
- .OnCaughtException(ex => { logger.LogError(ex.Message); return null; })
+ .OnCaughtException(ex => { logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); return null; })
.Where(x => x != null);
}
@@ -131,14 +131,14 @@
}
catch (Exception ex)
{
- logger.LogError(ex.Message);
+ logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message);
return GetPreconfiguredCatalogTypes();
}
return File.ReadAllLines(csvFileCatalogTypes)
.Skip(1) // skip header row
.SelectTry(x => CreateCatalogType(x))
- .OnCaughtException(ex => { logger.LogError(ex.Message); return null; })
+ .OnCaughtException(ex => { logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); return null; })
.Where(x => x != null);
}
@@ -186,7 +186,7 @@
}
catch (Exception ex)
{
- logger.LogError(ex.Message);
+ logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message);
return GetPreconfiguredItems();
}
@@ -197,7 +197,7 @@
.Skip(1) // skip header row
.Select(row => Regex.Split(row, ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)") )
.SelectTry(column => CreateCatalogItem(column, csvheaders, catalogTypeIdLookup, catalogBrandIdLookup))
- .OnCaughtException(ex => { logger.LogError(ex.Message); return null; })
+ .OnCaughtException(ex => { logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); return null; })
.Where(x => x != null);
}
@@ -377,7 +377,7 @@
sleepDurationProvider: retry => TimeSpan.FromSeconds(5),
onRetry: (exception, timeSpan, retry, ctx) =>
{
- logger.LogTrace($"[{prefix}] Exception {exception.GetType().Name} with message ${exception.Message} detected on attempt {retry} of {retries}");
+ logger.LogWarning(exception, "[{prefix}] Exception {ExceptionType} with message {Message} detected on attempt {retry} of {retries}", prefix, exception.GetType().Name, exception.Message, retry, retries);
}
);
}
diff --git a/src/Services/Catalog/Catalog.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs b/src/Services/Catalog/Catalog.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs
index 4c4c746a6..1c1dfd45f 100644
--- a/src/Services/Catalog/Catalog.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs
+++ b/src/Services/Catalog/Catalog.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs
@@ -49,7 +49,7 @@ namespace Catalog.API.Infrastructure.Filters
if (env.IsDevelopment())
{
- json.DeveloperMeesage = context.Exception;
+ json.DeveloperMessage = context.Exception;
}
context.Result = new InternalServerErrorObjectResult(json);
@@ -62,7 +62,7 @@ namespace Catalog.API.Infrastructure.Filters
{
public string[] Messages { get; set; }
- public object DeveloperMeesage { get; set; }
+ public object DeveloperMessage { get; set; }
}
}
}
diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/CatalogIntegrationEventService.cs b/src/Services/Catalog/Catalog.API/IntegrationEvents/CatalogIntegrationEventService.cs
index 8c550bf27..3b9476b9f 100644
--- a/src/Services/Catalog/Catalog.API/IntegrationEvents/CatalogIntegrationEventService.cs
+++ b/src/Services/Catalog/Catalog.API/IntegrationEvents/CatalogIntegrationEventService.cs
@@ -4,7 +4,10 @@ using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services;
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Utilities;
+using Microsoft.eShopOnContainers.Services.Catalog.API;
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
+using Microsoft.Extensions.Logging;
+using Serilog.Context;
using System;
using System.Data.Common;
using System.Threading.Tasks;
@@ -17,10 +20,15 @@ namespace Catalog.API.IntegrationEvents
private readonly IEventBus _eventBus;
private readonly CatalogContext _catalogContext;
private readonly IIntegrationEventLogService _eventLogService;
+ private readonly ILogger _logger;
- public CatalogIntegrationEventService(IEventBus eventBus, CatalogContext catalogContext,
- Func integrationEventLogServiceFactory)
+ public CatalogIntegrationEventService(
+ ILogger logger,
+ IEventBus eventBus,
+ CatalogContext catalogContext,
+ Func integrationEventLogServiceFactory)
{
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
_catalogContext = catalogContext ?? throw new ArgumentNullException(nameof(catalogContext));
_integrationEventLogServiceFactory = integrationEventLogServiceFactory ?? throw new ArgumentNullException(nameof(integrationEventLogServiceFactory));
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
@@ -31,26 +39,31 @@ namespace Catalog.API.IntegrationEvents
{
try
{
+ _logger.LogInformation("----- Publishing integration event: {IntegrationEventId_published} from {AppName} - ({@IntegrationEvent})", evt.Id, Program.AppName, evt);
+
await _eventLogService.MarkEventAsInProgressAsync(evt.Id);
_eventBus.Publish(evt);
await _eventLogService.MarkEventAsPublishedAsync(evt.Id);
}
- catch (Exception)
+ catch (Exception ex)
{
+ _logger.LogError(ex, "ERROR Publishing integration event: {IntegrationEventId} from {AppName} - ({@IntegrationEvent})", evt.Id, Program.AppName, evt);
await _eventLogService.MarkEventAsFailedAsync(evt.Id);
- }
+ }
}
public async Task SaveEventAndCatalogContextChangesAsync(IntegrationEvent evt)
{
+ _logger.LogInformation("----- CatalogIntegrationEventService - Saving changes and integrationEvent: {IntegrationEventId}", evt.Id);
+
//Use of an EF Core resiliency strategy when using multiple DbContexts within an explicit BeginTransaction():
//See: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
- await ResilientTransaction.New(_catalogContext)
- .ExecuteAsync(async () => {
- // Achieving atomicity between original catalog database operation and the IntegrationEventLog thanks to a local transaction
- await _catalogContext.SaveChangesAsync();
- await _eventLogService.SaveEventAsync(evt, _catalogContext.Database.CurrentTransaction.GetDbTransaction());
- });
+ await ResilientTransaction.New(_catalogContext).ExecuteAsync(async () =>
+ {
+ // Achieving atomicity between original catalog database operation and the IntegrationEventLog thanks to a local transaction
+ await _catalogContext.SaveChangesAsync();
+ await _eventLogService.SaveEventAsync(evt, _catalogContext.Database.CurrentTransaction.GetDbTransaction());
+ });
}
}
}
diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/OrderStatusChangedToAwaitingValidationIntegrationEventHandler.cs b/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/OrderStatusChangedToAwaitingValidationIntegrationEventHandler.cs
index 0f30a3e0a..493a271cc 100644
--- a/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/OrderStatusChangedToAwaitingValidationIntegrationEventHandler.cs
+++ b/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/OrderStatusChangedToAwaitingValidationIntegrationEventHandler.cs
@@ -8,39 +8,51 @@
using System.Linq;
using global::Catalog.API.IntegrationEvents;
using IntegrationEvents.Events;
+ using Serilog.Context;
+ using Microsoft.Extensions.Logging;
public class OrderStatusChangedToAwaitingValidationIntegrationEventHandler :
IIntegrationEventHandler
{
private readonly CatalogContext _catalogContext;
private readonly ICatalogIntegrationEventService _catalogIntegrationEventService;
+ private readonly ILogger _logger;
- public OrderStatusChangedToAwaitingValidationIntegrationEventHandler(CatalogContext catalogContext,
- ICatalogIntegrationEventService catalogIntegrationEventService)
+ public OrderStatusChangedToAwaitingValidationIntegrationEventHandler(
+ CatalogContext catalogContext,
+ ICatalogIntegrationEventService catalogIntegrationEventService,
+ ILogger logger)
{
_catalogContext = catalogContext;
_catalogIntegrationEventService = catalogIntegrationEventService;
+ _logger = logger ?? throw new System.ArgumentNullException(nameof(logger));
}
- public async Task Handle(OrderStatusChangedToAwaitingValidationIntegrationEvent command)
+ public async Task Handle(OrderStatusChangedToAwaitingValidationIntegrationEvent @event)
{
- var confirmedOrderStockItems = new List();
-
- foreach (var orderStockItem in command.OrderStockItems)
+ using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
{
- var catalogItem = _catalogContext.CatalogItems.Find(orderStockItem.ProductId);
- var hasStock = catalogItem.AvailableStock >= orderStockItem.Units;
- var confirmedOrderStockItem = new ConfirmedOrderStockItem(catalogItem.Id, hasStock);
+ _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
- confirmedOrderStockItems.Add(confirmedOrderStockItem);
- }
+ var confirmedOrderStockItems = new List();
+
+ foreach (var orderStockItem in @event.OrderStockItems)
+ {
+ var catalogItem = _catalogContext.CatalogItems.Find(orderStockItem.ProductId);
+ var hasStock = catalogItem.AvailableStock >= orderStockItem.Units;
+ var confirmedOrderStockItem = new ConfirmedOrderStockItem(catalogItem.Id, hasStock);
- var confirmedIntegrationEvent = confirmedOrderStockItems.Any(c => !c.HasStock)
- ? (IntegrationEvent) new OrderStockRejectedIntegrationEvent(command.OrderId, confirmedOrderStockItems)
- : new OrderStockConfirmedIntegrationEvent(command.OrderId);
+ confirmedOrderStockItems.Add(confirmedOrderStockItem);
+ }
- await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(confirmedIntegrationEvent);
- await _catalogIntegrationEventService.PublishThroughEventBusAsync(confirmedIntegrationEvent);
+ var confirmedIntegrationEvent = confirmedOrderStockItems.Any(c => !c.HasStock)
+ ? (IntegrationEvent)new OrderStockRejectedIntegrationEvent(@event.OrderId, confirmedOrderStockItems)
+ : new OrderStockConfirmedIntegrationEvent(@event.OrderId);
+
+ await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(confirmedIntegrationEvent);
+ await _catalogIntegrationEventService.PublishThroughEventBusAsync(confirmedIntegrationEvent);
+
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs b/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs
index 0a45547f9..7d383254f 100644
--- a/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs
+++ b/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs
@@ -4,28 +4,40 @@
using System.Threading.Tasks;
using Infrastructure;
using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events;
+ using Microsoft.Extensions.Logging;
+ using Serilog.Context;
public class OrderStatusChangedToPaidIntegrationEventHandler :
IIntegrationEventHandler
{
private readonly CatalogContext _catalogContext;
+ private readonly ILogger _logger;
- public OrderStatusChangedToPaidIntegrationEventHandler(CatalogContext catalogContext)
+ public OrderStatusChangedToPaidIntegrationEventHandler(
+ CatalogContext catalogContext,
+ ILogger logger)
{
_catalogContext = catalogContext;
+ _logger = logger ?? throw new System.ArgumentNullException(nameof(logger));
}
- public async Task Handle(OrderStatusChangedToPaidIntegrationEvent command)
+ public async Task Handle(OrderStatusChangedToPaidIntegrationEvent @event)
{
- //we're not blocking stock/inventory
- foreach (var orderStockItem in command.OrderStockItems)
+ using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
{
- var catalogItem = _catalogContext.CatalogItems.Find(orderStockItem.ProductId);
+ _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
- catalogItem.RemoveStock(orderStockItem.Units);
- }
+ //we're not blocking stock/inventory
+ foreach (var orderStockItem in @event.OrderStockItems)
+ {
+ var catalogItem = _catalogContext.CatalogItems.Find(orderStockItem.ProductId);
+
+ catalogItem.RemoveStock(orderStockItem.Units);
+ }
- await _catalogContext.SaveChangesAsync();
+ await _catalogContext.SaveChangesAsync();
+
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Services/Catalog/Catalog.API/Model/CatalogItem.cs b/src/Services/Catalog/Catalog.API/Model/CatalogItem.cs
index 459c60098..2e4579f7f 100644
--- a/src/Services/Catalog/Catalog.API/Model/CatalogItem.cs
+++ b/src/Services/Catalog/Catalog.API/Model/CatalogItem.cs
@@ -64,7 +64,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Model
if (quantityDesired <= 0)
{
- throw new CatalogDomainException($"Item units desired should be greater than cero");
+ throw new CatalogDomainException($"Item units desired should be greater than zero");
}
int removed = Math.Min(quantityDesired, this.AvailableStock);
diff --git a/src/Services/Catalog/Catalog.API/Program.cs b/src/Services/Catalog/Catalog.API/Program.cs
index 3f4c19955..39b071c46 100644
--- a/src/Services/Catalog/Catalog.API/Program.cs
+++ b/src/Services/Catalog/Catalog.API/Program.cs
@@ -9,65 +9,98 @@ using Microsoft.Extensions.Options;
using Serilog;
using System;
using System.IO;
+
namespace Microsoft.eShopOnContainers.Services.Catalog.API
{
public class Program
{
- public static void Main(string[] args)
+ public static readonly string Namespace = typeof(Program).Namespace;
+ public static readonly string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1);
+
+ public static int Main(string[] args)
{
- BuildWebHost(args)
- .MigrateDbContext((context,services)=>
+ var configuration = GetConfiguration();
+
+ Log.Logger = CreateSerilogLogger(configuration);
+
+ try
+ {
+ Log.Information("Configuring web host ({ApplicationContext})...", AppName);
+ var host = BuildWebHost(configuration, args);
+
+ Log.Information("Applying migrations ({ApplicationContext})...", AppName);
+ host.MigrateDbContext((context, services) =>
{
var env = services.GetService();
var settings = services.GetService>();
var logger = services.GetService>();
new CatalogContextSeed()
- .SeedAsync(context,env,settings,logger)
- .Wait();
-
+ .SeedAsync(context, env, settings, logger)
+ .Wait();
})
- .MigrateDbContext((_,__)=> { })
- .Run();
+ .MigrateDbContext((_, __) => { });
+
+ Log.Information("Starting web host ({ApplicationContext})...", AppName);
+ host.Run();
+
+ return 0;
+ }
+ catch (Exception ex)
+ {
+ Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
+ return 1;
+ }
+ finally
+ {
+ Log.CloseAndFlush();
+ }
}
- public static IWebHost BuildWebHost(string[] args) =>
+ private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
WebHost.CreateDefaultBuilder(args)
- .UseStartup()
+ .CaptureStartupErrors(false)
+ .UseStartup()
.UseApplicationInsights()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseWebRoot("Pics")
- .ConfigureAppConfiguration((builderContext, config) =>
- {
- var builtConfig = config.Build();
+ .UseConfiguration(configuration)
+ .UseSerilog()
+ .Build();
- var configurationBuilder = new ConfigurationBuilder();
+ private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
+ {
+ var seqServerUrl = configuration["Serilog:SeqServerUrl"];
+ var logstashUrl = configuration["Serilog:LogstashgUrl"];
+ return new LoggerConfiguration()
+ .MinimumLevel.Verbose()
+ .Enrich.WithProperty("ApplicationContext", AppName)
+ .Enrich.FromLogContext()
+ .WriteTo.Console()
+ .WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
+ .WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://logstash:8080" : logstashUrl)
+ .ReadFrom.Configuration(configuration)
+ .CreateLogger();
+ }
- if (Convert.ToBoolean(builtConfig["UseVault"]))
- {
- configurationBuilder.AddAzureKeyVault(
- $"https://{builtConfig["Vault:Name"]}.vault.azure.net/",
- builtConfig["Vault:ClientId"],
- builtConfig["Vault:ClientSecret"]);
- }
+ private static IConfiguration GetConfiguration()
+ {
+ var builder = new ConfigurationBuilder()
+ .SetBasePath(Directory.GetCurrentDirectory())
+ .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
+ .AddEnvironmentVariables();
- configurationBuilder.AddEnvironmentVariables();
+ var config = builder.Build();
- config.AddConfiguration(configurationBuilder.Build());
- })
- .ConfigureLogging((hostingContext, builder) =>
- {
- builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
- builder.AddConsole();
- builder.AddDebug();
- })
- .UseSerilog((builderContext, config) =>
- {
- config
- .MinimumLevel.Information()
- .Enrich.FromLogContext()
- .WriteTo.Console();
- })
- .Build();
+ if (config.GetValue("UseVault", false))
+ {
+ builder.AddAzureKeyVault(
+ $"https://{config["Vault:Name"]}.vault.azure.net/",
+ config["Vault:ClientId"],
+ config["Vault:ClientSecret"]);
+ }
+
+ return builder.Build();
+ }
}
}
\ No newline at end of file
diff --git a/src/Services/Catalog/Catalog.API/Properties/launchSettings.json b/src/Services/Catalog/Catalog.API/Properties/launchSettings.json
index 2b21ca280..f842f80d0 100644
--- a/src/Services/Catalog/Catalog.API/Properties/launchSettings.json
+++ b/src/Services/Catalog/Catalog.API/Properties/launchSettings.json
@@ -13,7 +13,11 @@
"launchBrowser": true,
"launchUrl": "/swagger",
"environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
+ "ConnectionString": "server=localhost,5433;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word",
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "EventBusConnection": "localhost",
+ "Serilog:SeqServerUrl": "http://locahost:5340",
+ "Serilog:LogstashgUrl":"http://locahost:8080",
}
},
"Microsoft.eShopOnContainers.Services.Catalog.API": {
@@ -23,6 +27,13 @@
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
+ },
+ "Azure Dev Spaces": {
+ "commandName": "AzureDevSpaces",
+ "launchBrowser": true,
+ "resourceGroup": "edu-devspaces3",
+ "aksName": "edu-devspaces3",
+ "subscriptionId": "e3035ac1-c06c-4daf-8939-57b3c5f1f759"
}
}
}
\ No newline at end of file
diff --git a/src/Services/Catalog/Catalog.API/Startup.cs b/src/Services/Catalog/Catalog.API/Startup.cs
index 5c77d37c8..1a51a86fb 100644
--- a/src/Services/Catalog/Catalog.API/Startup.cs
+++ b/src/Services/Catalog/Catalog.API/Startup.cs
@@ -64,14 +64,14 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API
{
//Configure logs
- loggerFactory.AddAzureWebAppDiagnostics();
- loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
+ //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}'");
+ loggerFactory.CreateLogger().LogDebug("Using PATH BASE '{pathBase}'", pathBase);
app.UsePathBase(pathBase);
}
@@ -117,7 +117,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API
if (orchestratorType?.ToUpper() == "K8S")
{
// Enable K8s telemetry initializer
- services.EnableKubernetes();
+ services.AddApplicationInsightsKubernetesEnricher();
}
if (orchestratorType?.ToUpper() == "SF")
{
@@ -297,7 +297,8 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API
var factory = new ConnectionFactory()
{
- HostName = configuration["EventBusConnection"]
+ HostName = configuration["EventBusConnection"],
+ DispatchConsumersAsync = true
};
if (!string.IsNullOrEmpty(configuration["EventBusUserName"]))
diff --git a/src/Services/Catalog/Catalog.API/appsettings.json b/src/Services/Catalog/Catalog.API/appsettings.json
index 0bf489699..cc7b1b1fb 100644
--- a/src/Services/Catalog/Catalog.API/appsettings.json
+++ b/src/Services/Catalog/Catalog.API/appsettings.json
@@ -2,12 +2,16 @@
"ConnectionString": "Server=tcp:127.0.0.1,5433;Initial Catalog=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word",
"PicBaseUrl": "http://localhost:5101/api/v1/catalog/items/[0]/pic/",
"UseCustomizationData": false,
- "Logging": {
- "IncludeScopes": false,
- "LogLevel": {
- "Default": "Trace",
- "System": "Information",
- "Microsoft": "Information"
+ "Serilog": {
+ "SeqServerUrl": null,
+ "LogstashgUrl": null,
+ "MinimumLevel": {
+ "Default": "Information",
+ "Override": {
+ "Microsoft": "Warning",
+ "Microsoft.eShopOnContainers": "Information",
+ "System": "Warning"
+ }
}
},
"AzureServiceBusEnabled": false,
diff --git a/src/Services/Catalog/Catalog.API/azds.yaml b/src/Services/Catalog/Catalog.API/azds.yaml
new file mode 100644
index 000000000..9f98a3793
--- /dev/null
+++ b/src/Services/Catalog/Catalog.API/azds.yaml
@@ -0,0 +1,54 @@
+kind: helm-release
+apiVersion: 1.1
+build:
+ context: ..\..\..\..
+ dockerfile: Dockerfile
+install:
+ chart: ../../../../k8s/helm/catalog-api
+ set:
+ image:
+ tag: $(tag)
+ pullPolicy: Never
+ ingress:
+ annotations:
+ kubernetes.io/ingress.class: traefik-azds
+ hosts:
+ - $(spacePrefix)eshop$(hostSuffix)
+ inf:
+ k8s:
+ dns: $(spacePrefix)eshop$(hostSuffix)
+ values:
+ - values.dev.yaml?
+ - secrets.dev.yaml?
+ - inf.yaml
+ - app.yaml
+configurations:
+ develop:
+ build:
+ useGitIgnore: true
+ dockerfile: Dockerfile.develop
+ container:
+ syncTarget: /src
+ sync:
+ - '**/Pages/**'
+ - '**/Views/**'
+ - '**/wwwroot/**'
+ - '!**/*.{sln,csproj}'
+ command:
+ - dotnet
+ - run
+ - --no-restore
+ - --no-build
+ - --no-launch-profile
+ - -c
+ - ${Configuration:-Debug}
+ iterate:
+ processesToKill:
+ - dotnet
+ - vsdbg
+ buildCommands:
+ - - dotnet
+ - build
+ - --no-restore
+ - -c
+ - ${Configuration:-Debug}
diff --git a/src/Services/Catalog/Catalog.API/values.dev.yaml b/src/Services/Catalog/Catalog.API/values.dev.yaml
new file mode 100644
index 000000000..eaed45149
--- /dev/null
+++ b/src/Services/Catalog/Catalog.API/values.dev.yaml
@@ -0,0 +1,3 @@
+ingress:
+ enabled: true
+ tls: []
\ No newline at end of file
diff --git a/src/Services/Catalog/Catalog.API/web.config b/src/Services/Catalog/Catalog.API/web.config
index e04a0397b..2157aef31 100644
--- a/src/Services/Catalog/Catalog.API/web.config
+++ b/src/Services/Catalog/Catalog.API/web.config
@@ -2,8 +2,10 @@
-
+
-
+
+
+
\ No newline at end of file
diff --git a/src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj b/src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj
index b38d20ff1..455dfb0bc 100644
--- a/src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj
+++ b/src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj
@@ -33,10 +33,15 @@
-
+
+
+
-
-
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
diff --git a/src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj b/src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj
index 9e6a4a4ba..efa9d56a4 100644
--- a/src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj
+++ b/src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj
@@ -7,11 +7,16 @@
-
-
-
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
-
+
diff --git a/src/Services/Identity/Identity.API/.dockerignore b/src/Services/Identity/Identity.API/.dockerignore
new file mode 100644
index 000000000..04f7b133d
--- /dev/null
+++ b/src/Services/Identity/Identity.API/.dockerignore
@@ -0,0 +1,14 @@
+.dockerignore
+.git
+.gitignore
+.vs
+.vscode
+**/*.*proj.user
+**/azds.yaml
+**/bin
+**/charts
+**/Dockerfile
+**/Dockerfile.develop
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
\ No newline at end of file
diff --git a/src/Services/Identity/Identity.API/Controllers/AccountController.cs b/src/Services/Identity/Identity.API/Controllers/AccountController.cs
index 7a1fea312..6e9bbce16 100644
--- a/src/Services/Identity/Identity.API/Controllers/AccountController.cs
+++ b/src/Services/Identity/Identity.API/Controllers/AccountController.cs
@@ -20,7 +20,7 @@ using Microsoft.Extensions.Logging;
namespace Microsoft.eShopOnContainers.Services.Identity.API.Controllers
{
///
- /// This sample controller implements a typical login/logout/provision workflow for local and external accounts.
+ /// This sample controller implements a typical login/logout/provision workflow for local accounts.
/// The login service encapsulates the interactions with the user data store. This data store is in-memory only and cannot be used for production!
/// The interaction service provides a way for the UI to communicate with identityserver for validation and context retrieval
///
@@ -58,8 +58,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Controllers
var context = await _interaction.GetAuthorizationContextAsync(returnUrl);
if (context?.IdP != null)
{
- // if IdP is passed, then bypass showing the login screen
- return ExternalLogin(context.IdP, returnUrl);
+ throw new NotImplementedException("External login is not implemented!");
}
var vm = await BuildLoginViewModelAsync(returnUrl, context);
@@ -209,7 +208,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Controllers
}
catch (Exception ex)
{
- _logger.LogCritical(ex.Message);
+ _logger.LogError(ex, "LOGOUT ERROR: {ExceptionMessage}", ex.Message);
}
}
@@ -238,28 +237,6 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Controllers
return Redirect(redirectUrl);
}
- ///
- /// initiate roundtrip to external authentication provider
- ///
- [HttpGet]
- public IActionResult ExternalLogin(string provider, string returnUrl)
- {
- if (returnUrl != null)
- {
- returnUrl = UrlEncoder.Default.Encode(returnUrl);
- }
- returnUrl = "/account/externallogincallback?returnUrl=" + returnUrl;
-
- // start challenge and roundtrip the return URL
- var props = new AuthenticationProperties
- {
- RedirectUri = returnUrl,
- Items = { { "scheme", provider } }
- };
- return new ChallengeResult(provider, props);
- }
-
-
// GET: /Account/Register
[HttpGet]
[AllowAnonymous]
diff --git a/src/Services/Identity/Identity.API/Data/ApplicationDbContextSeed.cs b/src/Services/Identity/Identity.API/Data/ApplicationDbContextSeed.cs
index 3dbf28171..a1fda6455 100644
--- a/src/Services/Identity/Identity.API/Data/ApplicationDbContextSeed.cs
+++ b/src/Services/Identity/Identity.API/Data/ApplicationDbContextSeed.cs
@@ -51,7 +51,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Data
{
retryForAvaiability++;
- logger.LogError(ex.Message,$"There is an error migrating data for ApplicationDbContext");
+ logger.LogError(ex, "EXCEPTION ERROR while migrating {DbContextName}", nameof(ApplicationDbContext));
await SeedAsync(context,env,logger,settings, retryForAvaiability);
}
@@ -80,7 +80,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Data
}
catch (Exception ex)
{
- logger.LogError(ex.Message);
+ logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message);
return GetDefaultUser();
}
@@ -89,7 +89,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Data
.Skip(1) // skip header column
.Select(row => Regex.Split(row, ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)") )
.SelectTry(column => CreateApplicationUser(column, csvheaders))
- .OnCaughtException(ex => { logger.LogError(ex.Message); return null; })
+ .OnCaughtException(ex => { logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); return null; })
.Where(x => x != null)
.ToList();
@@ -199,7 +199,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Data
string imagesZipFile = Path.Combine(contentRootPath, "Setup", "images.zip");
if (!File.Exists(imagesZipFile))
{
- logger.LogError($" zip file '{imagesZipFile}' does not exists.");
+ logger.LogError("Zip file '{ZipFileName}' does not exists.", imagesZipFile);
return;
}
@@ -221,14 +221,14 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Data
}
else
{
- logger.LogWarning($"Skip file '{entry.Name}' in zipfile '{imagesZipFile}'");
+ logger.LogWarning("Skipped file '{FileName}' in zipfile '{ZipFileName}'", entry.Name, imagesZipFile);
}
}
}
}
catch (Exception ex)
{
- logger.LogError($"Exception in method GetPreconfiguredImages WebMVC. Exception Message={ex.Message}");
+ logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); ;
}
}
}
diff --git a/src/Services/Identity/Identity.API/Devspaces/DevspacesRedirectUriValidator.cs b/src/Services/Identity/Identity.API/Devspaces/DevspacesRedirectUriValidator.cs
new file mode 100644
index 000000000..53e497b59
--- /dev/null
+++ b/src/Services/Identity/Identity.API/Devspaces/DevspacesRedirectUriValidator.cs
@@ -0,0 +1,31 @@
+using IdentityServer4.Models;
+using IdentityServer4.Validation;
+using Microsoft.Extensions.Logging;
+using System.Threading.Tasks;
+
+
+namespace Microsoft.eShopOnContainers.Services.Identity.API.Devspaces
+{
+ public class DevspacesRedirectUriValidator : IRedirectUriValidator
+ {
+ private readonly ILogger _logger;
+ public DevspacesRedirectUriValidator(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ public Task IsPostLogoutRedirectUriValidAsync(string requestedUri, Client client)
+ {
+
+ _logger.LogInformation($"Client {client.ClientName} used post logout uri {requestedUri}.");
+ return Task.FromResult(true);
+ }
+
+ public Task IsRedirectUriValidAsync(string requestedUri, Client client)
+ {
+ _logger.LogInformation($"Client {client.ClientName} used redirect uri {requestedUri}.");
+ return Task.FromResult(true);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Services/Identity/Identity.API/Devspaces/IdentityDevspacesBuilderExtensions.cs b/src/Services/Identity/Identity.API/Devspaces/IdentityDevspacesBuilderExtensions.cs
new file mode 100644
index 000000000..4dadb0e54
--- /dev/null
+++ b/src/Services/Identity/Identity.API/Devspaces/IdentityDevspacesBuilderExtensions.cs
@@ -0,0 +1,20 @@
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Microsoft.eShopOnContainers.Services.Identity.API.Devspaces
+{
+ static class IdentityDevspacesBuilderExtensions
+ {
+ public static IIdentityServerBuilder AddDevspacesIfNeeded(this IIdentityServerBuilder builder, bool useDevspaces)
+ {
+ if (useDevspaces)
+ {
+ builder.AddRedirectUriValidator();
+ }
+ return builder;
+ }
+ }
+}
diff --git a/src/Services/Identity/Identity.API/Dockerfile b/src/Services/Identity/Identity.API/Dockerfile
index f3d18f113..ed1502208 100644
--- a/src/Services/Identity/Identity.API/Dockerfile
+++ b/src/Services/Identity/Identity.API/Dockerfile
@@ -1,16 +1,26 @@
-FROM microsoft/dotnet:2.2.0-aspnetcore-runtime AS base
+FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80
-FROM microsoft/dotnet:2.2.100-sdk AS build
+FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
WORKDIR /src
+
+COPY scripts scripts/
+
+COPY src/ApiGateways/*/*.csproj /src/csproj-files/
+COPY src/ApiGateways/*/*/*.csproj /src/csproj-files/
+COPY src/BuildingBlocks/*/*/*.csproj /src/csproj-files/
+COPY src/Services/*/*/*.csproj /src/csproj-files/
+COPY src/Web/*/*.csproj /src/csproj-files/
+
+ARG RUN=pwd
+RUN ${RUN}
+
COPY . .
WORKDIR /src/src/Services/Identity/Identity.API
-RUN dotnet restore -nowarn:msb3202,nu1503
-RUN dotnet build --no-restore -c Release -o /app
+RUN dotnet publish -c Release -o /app
FROM build AS publish
-RUN dotnet publish --no-restore -c Release -o /app
FROM base AS final
WORKDIR /app
diff --git a/src/Services/Identity/Identity.API/Dockerfile.develop b/src/Services/Identity/Identity.API/Dockerfile.develop
new file mode 100644
index 000000000..3ab1fbe7c
--- /dev/null
+++ b/src/Services/Identity/Identity.API/Dockerfile.develop
@@ -0,0 +1,15 @@
+FROM microsoft/dotnet:2.2-sdk
+ARG BUILD_CONFIGURATION=Debug
+ENV ASPNETCORE_ENVIRONMENT=Development
+ENV DOTNET_USE_POLLING_FILE_WATCHER=true
+EXPOSE 80
+
+WORKDIR /src
+COPY ["src/Services/Identity/Identity.API/Identity.API.csproj", "src/Services/Identity/Identity.API/"]
+COPY ["src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj", "src/BuildingBlocks/WebHostCustomization/WebHost.Customization/"]
+RUN dotnet restore src/Services/Identity/Identity.API/Identity.API.csproj -nowarn:msb3202,nu1503
+COPY . .
+WORKDIR "/src/src/Services/Identity/Identity.API"
+RUN dotnet build --no-restore -c $BUILD_CONFIGURATION
+
+ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"]
diff --git a/src/Services/Identity/Identity.API/Identity.API.csproj b/src/Services/Identity/Identity.API/Identity.API.csproj
index 077d6c624..728843f71 100644
--- a/src/Services/Identity/Identity.API/Identity.API.csproj
+++ b/src/Services/Identity/Identity.API/Identity.API.csproj
@@ -13,25 +13,29 @@
-
-
-
+
+
+
-
-
-
+
+
+
+
+
+
-
-
-
+
+
+
+
-
+
+
-
diff --git a/src/Services/Identity/Identity.API/Models/AccountViewModels/ExternalLoginConfirmationViewModel.cs b/src/Services/Identity/Identity.API/Models/AccountViewModels/ExternalLoginConfirmationViewModel.cs
deleted file mode 100644
index 5d4f597a2..000000000
--- a/src/Services/Identity/Identity.API/Models/AccountViewModels/ExternalLoginConfirmationViewModel.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System.ComponentModel.DataAnnotations;
-
-namespace Microsoft.eShopOnContainers.Services.Identity.API.Models.AccountViewModels
-{
- public class ExternalLoginConfirmationViewModel
- {
- [Required]
- [EmailAddress]
- public string Email { get; set; }
- }
-}
diff --git a/src/Services/Identity/Identity.API/Models/ManageViewModels/ManageLoginsViewModel.cs b/src/Services/Identity/Identity.API/Models/ManageViewModels/ManageLoginsViewModel.cs
deleted file mode 100644
index 0b24c3b7c..000000000
--- a/src/Services/Identity/Identity.API/Models/ManageViewModels/ManageLoginsViewModel.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using Microsoft.AspNetCore.Http.Authentication;
-using Microsoft.AspNetCore.Identity;
-using System.Collections.Generic;
-
-namespace Microsoft.eShopOnContainers.Services.Identity.API.Models.ManageViewModels
-{
- public class ManageLoginsViewModel
- {
- public IList CurrentLogins { get; set; }
-
- public IList OtherLogins { get; set; }
- }
-}
diff --git a/src/Services/Identity/Identity.API/Models/ManageViewModels/RemoveLoginViewModel.cs b/src/Services/Identity/Identity.API/Models/ManageViewModels/RemoveLoginViewModel.cs
deleted file mode 100644
index c9171fcf3..000000000
--- a/src/Services/Identity/Identity.API/Models/ManageViewModels/RemoveLoginViewModel.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace Microsoft.eShopOnContainers.Services.Identity.API.Models.ManageViewModels
-{
- public class RemoveLoginViewModel
- {
- public string LoginProvider { get; set; }
- public string ProviderKey { get; set; }
- }
-}
diff --git a/src/Services/Identity/Identity.API/Program.cs b/src/Services/Identity/Identity.API/Program.cs
index d06d49492..784f63a1e 100644
--- a/src/Services/Identity/Identity.API/Program.cs
+++ b/src/Services/Identity/Identity.API/Program.cs
@@ -14,69 +14,100 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API
{
public class Program
{
- public static void Main(string[] args)
+ public static readonly string Namespace = typeof(Program).Namespace;
+ public static readonly string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1);
+
+ public static int Main(string[] args)
{
- BuildWebHost(args)
- .MigrateDbContext((_, __) => { })
- .MigrateDbContext((context, services) =>
- {
- var env = services.GetService();
- var logger = services.GetService>();
- var settings = services.GetService>();
-
- new ApplicationDbContextSeed()
- .SeedAsync(context, env, logger, settings)
- .Wait();
- })
- .MigrateDbContext((context,services)=>
- {
- var configuration = services.GetService();
-
- new ConfigurationDbContextSeed()
- .SeedAsync(context, configuration)
- .Wait();
- }).Run();
- }
+ var configuration = GetConfiguration();
- public static IWebHost BuildWebHost(string[] args) =>
- WebHost.CreateDefaultBuilder(args)
- .UseKestrel()
- .UseContentRoot(Directory.GetCurrentDirectory())
- .UseIISIntegration()
- .UseStartup()
- .ConfigureAppConfiguration((builderContext, config) =>
- {
- var builtConfig = config.Build();
+ Log.Logger = CreateSerilogLogger(configuration);
+
+ try
+ {
+ Log.Information("Configuring web host ({ApplicationContext})...", AppName);
+ var host = BuildWebHost(configuration, args);
- var configurationBuilder = new ConfigurationBuilder();
+ Log.Information("Applying migrations ({ApplicationContext})...", AppName);
+ host.MigrateDbContext((_, __) => { })
+ .MigrateDbContext((context, services) =>
+ {
+ var env = services.GetService();
+ var logger = services.GetService>();
+ var settings = services.GetService>();
- if (Convert.ToBoolean(builtConfig["UseVault"]))
+ new ApplicationDbContextSeed()
+ .SeedAsync(context, env, logger, settings)
+ .Wait();
+ })
+ .MigrateDbContext((context, services) =>
{
- configurationBuilder.AddAzureKeyVault(
- $"https://{builtConfig["Vault:Name"]}.vault.azure.net/",
- builtConfig["Vault:ClientId"],
- builtConfig["Vault:ClientSecret"]);
- }
-
- configurationBuilder.AddEnvironmentVariables();
-
- config.AddConfiguration(configurationBuilder.Build());
- })
- .ConfigureLogging((hostingContext, builder) =>
- {
- builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
- builder.AddConsole();
- builder.AddDebug();
- })
+ new ConfigurationDbContextSeed()
+ .SeedAsync(context, configuration)
+ .Wait();
+ });
+
+ Log.Information("Starting web host ({ApplicationContext})...", AppName);
+ host.Run();
+
+ return 0;
+ }
+ catch (Exception ex)
+ {
+ Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
+ return 1;
+ }
+ finally
+ {
+ Log.CloseAndFlush();
+ }
+ }
+
+ private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
+ WebHost.CreateDefaultBuilder(args)
+ .CaptureStartupErrors(false)
+ .UseStartup()
.UseApplicationInsights()
- .UseSerilog((builderContext, config) =>
- {
- config
- .MinimumLevel.Information()
- .Enrich.FromLogContext()
- .WriteTo.Console();
- })
+ .UseContentRoot(Directory.GetCurrentDirectory())
+ .UseConfiguration(configuration)
+ .UseSerilog()
.Build();
+
+ private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
+ {
+ var seqServerUrl = configuration["Serilog:SeqServerUrl"];
+ var logstashUrl = configuration["Serilog:LogstashgUrl"];
+ return new LoggerConfiguration()
+ .MinimumLevel.Verbose()
+ .Enrich.WithProperty("ApplicationContext", AppName)
+ .Enrich.FromLogContext()
+ .WriteTo.Console()
+ .WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
+ .WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://localhost:8080" : logstashUrl)
+ .ReadFrom.Configuration(configuration)
+ .CreateLogger();
+ }
+
+ private static IConfiguration GetConfiguration()
+ {
+ var builder = new ConfigurationBuilder()
+ .SetBasePath(Directory.GetCurrentDirectory())
+ .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
+ .AddEnvironmentVariables();
+
+ var config = builder.Build();
+
+ if (config.GetValue("UseVault", false))
+ {
+ builder.AddAzureKeyVault(
+ $"https://{config["Vault:Name"]}.vault.azure.net/",
+ config["Vault:ClientId"],
+ config["Vault:ClientSecret"]);
+ }
+
+ return builder.Build();
+ }
+
}
}
diff --git a/src/Services/Identity/Identity.API/README.md b/src/Services/Identity/Identity.API/README.md
index 76e599dea..ffaaed531 100644
--- a/src/Services/Identity/Identity.API/README.md
+++ b/src/Services/Identity/Identity.API/README.md
@@ -2,10 +2,10 @@
Sample reference containerized application, cross-platform and microservices architecture.
Powered by Microsoft
-#Overview
+## Overview
This sample runs a microservices oriented application and a .net core Mvc application that consumes this services. You can find more information about how to set up docker in your machine in the global directory solution.
-#Setup
+## Setup
This service is a identity provider or STS (Security Token Service) currently implemented with IdentityServer 4 wrapping ASP.NET Identity underneath.
Check procedures on how to get the sample app started at the Wiki:
diff --git a/src/Services/Identity/Identity.API/Startup.cs b/src/Services/Identity/Identity.API/Startup.cs
index aa390779e..6ea7e3888 100644
--- a/src/Services/Identity/Identity.API/Startup.cs
+++ b/src/Services/Identity/Identity.API/Startup.cs
@@ -13,6 +13,7 @@ using Microsoft.eShopOnContainers.Services.Identity.API.Certificates;
using Microsoft.eShopOnContainers.Services.Identity.API.Data;
using Microsoft.eShopOnContainers.Services.Identity.API.Models;
using Microsoft.eShopOnContainers.Services.Identity.API.Services;
+using Microsoft.eShopOnContainers.Services.Identity.API.Devspaces;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -42,12 +43,12 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API
// Add framework services.
services.AddDbContext(options =>
options.UseSqlServer(Configuration["ConnectionString"],
- sqlServerOptionsAction: sqlOptions =>
- {
- sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
- //Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
- sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
- }));
+ sqlServerOptionsAction: sqlOptions =>
+ {
+ sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
+ //Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
+ sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
+ }));
services.AddIdentity()
.AddEntityFrameworkStores()
@@ -85,27 +86,28 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API
x.IssuerUri = "null";
x.Authentication.CookieLifetime = TimeSpan.FromHours(2);
})
+ .AddDevspacesIfNeeded(Configuration.GetValue("EnableDevspaces", false))
.AddSigningCredential(Certificate.Get())
.AddAspNetIdentity()
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString,
- sqlServerOptionsAction: sqlOptions =>
- {
- sqlOptions.MigrationsAssembly(migrationsAssembly);
- //Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
- sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
- });
+ sqlServerOptionsAction: sqlOptions =>
+ {
+ sqlOptions.MigrationsAssembly(migrationsAssembly);
+ //Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
+ sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
+ });
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString,
- sqlServerOptionsAction: sqlOptions =>
- {
- sqlOptions.MigrationsAssembly(migrationsAssembly);
- //Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
- sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
- });
+ sqlServerOptionsAction: sqlOptions =>
+ {
+ sqlOptions.MigrationsAssembly(migrationsAssembly);
+ //Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
+ sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
+ });
})
.Services.AddTransient();
@@ -118,10 +120,10 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
- loggerFactory.AddConsole(Configuration.GetSection("Logging"));
- loggerFactory.AddDebug();
- loggerFactory.AddAzureWebAppDiagnostics();
- loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
+ //loggerFactory.AddConsole(Configuration.GetSection("Logging"));
+ //loggerFactory.AddDebug();
+ //loggerFactory.AddAzureWebAppDiagnostics();
+ //loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
if (env.IsDevelopment())
{
@@ -136,7 +138,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API
var pathBase = Configuration["PATH_BASE"];
if (!string.IsNullOrEmpty(pathBase))
{
- loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
+ loggerFactory.CreateLogger().LogDebug("Using PATH BASE '{pathBase}'", pathBase);
app.UsePathBase(pathBase);
}
@@ -182,7 +184,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API
if (orchestratorType?.ToUpper() == "K8S")
{
// Enable K8s telemetry initializer
- services.EnableKubernetes();
+ services.AddApplicationInsightsKubernetesEnricher();
}
if (orchestratorType?.ToUpper() == "SF")
{
diff --git a/src/Services/Identity/Identity.API/Views/Consent/Index.cshtml b/src/Services/Identity/Identity.API/Views/Consent/Index.cshtml
index 03f026bda..08c316553 100644
--- a/src/Services/Identity/Identity.API/Views/Consent/Index.cshtml
+++ b/src/Services/Identity/Identity.API/Views/Consent/Index.cshtml
@@ -16,7 +16,7 @@
- @Html.Partial("_ValidationSummary")
+
@@ -49,7 +49,7 @@
@foreach (var scope in Model.ResourceScopes)
{
- @Html.Partial("_ScopeListItem", scope)
+
}
diff --git a/src/Services/Identity/Identity.API/Views/Shared/_LoginPartial.cshtml b/src/Services/Identity/Identity.API/Views/Shared/_LoginPartial.cshtml
index 3d0a461f5..e110e459c 100644
--- a/src/Services/Identity/Identity.API/Views/Shared/_LoginPartial.cshtml
+++ b/src/Services/Identity/Identity.API/Views/Shared/_LoginPartial.cshtml
@@ -7,7 +7,7 @@
@if (SignInManager.IsSignedIn(User))
{
-
-
-
+
+
-
+
+
+
-
-
+
+
+
+
diff --git a/src/Services/Marketing/Marketing.API/Program.cs b/src/Services/Marketing/Marketing.API/Program.cs
index a885a3af6..4d07e7e0f 100644
--- a/src/Services/Marketing/Marketing.API/Program.cs
+++ b/src/Services/Marketing/Marketing.API/Program.cs
@@ -12,58 +12,90 @@
public class Program
{
- public static void Main(string[] args)
+ public static readonly string Namespace = typeof(Program).Namespace;
+ public static readonly string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1);
+
+ public static int Main(string[] args)
{
- BuildWebHost(args)
- .MigrateDbContext((context, services) =>
+ var configuration = GetConfiguration();
+
+ Log.Logger = CreateSerilogLogger(configuration);
+
+ try
{
- var logger = services.GetService>();
+ Log.Information("Configuring web host ({ApplicationContext})...", AppName);
+ var host = BuildWebHost(configuration, args);
+
+ Log.Information("Applying migrations ({ApplicationContext})...", AppName);
+ host.MigrateDbContext((context, services) =>
+ {
+ var logger = services.GetService>();
+
+ new MarketingContextSeed()
+ .SeedAsync(context, logger)
+ .Wait();
+ });
- new MarketingContextSeed()
- .SeedAsync(context,logger)
- .Wait();
+ Log.Information("Starting web host ({ApplicationContext})...", AppName);
+ host.Run();
- }).Run();
+ return 0;
+ }
+ catch (Exception ex)
+ {
+ Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
+ return 1;
+ }
+ finally
+ {
+ Log.CloseAndFlush();
+ }
}
- public static IWebHost BuildWebHost(string[] args) =>
+ private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
WebHost.CreateDefaultBuilder(args)
+ .CaptureStartupErrors(false)
+ .UseStartup()
.UseApplicationInsights()
.UseContentRoot(Directory.GetCurrentDirectory())
- .UseStartup()
.UseWebRoot("Pics")
- .ConfigureAppConfiguration((builderContext, config) =>
- {
- var builtConfig = config.Build();
+ .UseConfiguration(configuration)
+ .UseSerilog()
+ .Build();
- var configurationBuilder = new ConfigurationBuilder();
+ private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
+ {
+ var seqServerUrl = configuration["Serilog:SeqServerUrl"];
+ var logstashUrl = configuration["Serilog:LogstashgUrl"];
+ return new LoggerConfiguration()
+ .MinimumLevel.Verbose()
+ .Enrich.WithProperty("ApplicationContext", AppName)
+ .Enrich.FromLogContext()
+ .WriteTo.Console()
+ .WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
+ .WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://logstash:8080" : logstashUrl)
+ .ReadFrom.Configuration(configuration)
+ .CreateLogger();
+ }
- if (Convert.ToBoolean(builtConfig["UseVault"]))
- {
- configurationBuilder.AddAzureKeyVault(
- $"https://{builtConfig["Vault:Name"]}.vault.azure.net/",
- builtConfig["Vault:ClientId"],
- builtConfig["Vault:ClientSecret"]);
- }
+ private static IConfiguration GetConfiguration()
+ {
+ var builder = new ConfigurationBuilder()
+ .SetBasePath(Directory.GetCurrentDirectory())
+ .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
+ .AddEnvironmentVariables();
- configurationBuilder.AddEnvironmentVariables();
+ var config = builder.Build();
- config.AddConfiguration(configurationBuilder.Build());
- })
- .ConfigureLogging((hostingContext, builder) =>
- {
- builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
- builder.AddConsole();
- builder.AddDebug();
- })
- .UseApplicationInsights()
- .UseSerilog((builderContext, config) =>
- {
- config
- .MinimumLevel.Information()
- .Enrich.FromLogContext()
- .WriteTo.Console();
- })
- .Build();
+ if (config.GetValue("UseVault", false))
+ {
+ builder.AddAzureKeyVault(
+ $"https://{config["Vault:Name"]}.vault.azure.net/",
+ config["Vault:ClientId"],
+ config["Vault:ClientSecret"]);
+ }
+
+ return builder.Build();
+ }
}
}
diff --git a/src/Services/Marketing/Marketing.API/Startup.cs b/src/Services/Marketing/Marketing.API/Startup.cs
index 826c8cb81..7f990e3ad 100644
--- a/src/Services/Marketing/Marketing.API/Startup.cs
+++ b/src/Services/Marketing/Marketing.API/Startup.cs
@@ -101,7 +101,8 @@
var factory = new ConnectionFactory()
{
- HostName = Configuration["EventBusConnection"]
+ HostName = Configuration["EventBusConnection"],
+ DispatchConsumersAsync = true
};
if (!string.IsNullOrEmpty(Configuration["EventBusUserName"]))
@@ -179,8 +180,8 @@
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env,ILoggerFactory loggerFactory)
{
- loggerFactory.AddAzureWebAppDiagnostics();
- loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
+ //loggerFactory.AddAzureWebAppDiagnostics();
+ //loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
var pathBase = Configuration["PATH_BASE"];
@@ -225,7 +226,7 @@
if (orchestratorType?.ToUpper() == "K8S")
{
// Enable K8s telemetry initializer
- services.EnableKubernetes();
+ services.AddApplicationInsightsKubernetesEnricher();
}
if (orchestratorType?.ToUpper() == "SF")
{
diff --git a/src/Services/Marketing/Marketing.API/appsettings.json b/src/Services/Marketing/Marketing.API/appsettings.json
index 2af660446..d4a58cc8e 100644
--- a/src/Services/Marketing/Marketing.API/appsettings.json
+++ b/src/Services/Marketing/Marketing.API/appsettings.json
@@ -1,8 +1,14 @@
{
- "Logging": {
- "IncludeScopes": false,
- "LogLevel": {
- "Default": "Trace"
+ "Serilog": {
+ "SeqServerUrl": null,
+ "LogstashgUrl": null,
+ "MinimumLevel": {
+ "Default": "Information",
+ "Override": {
+ "Microsoft": "Warning",
+ "Microsoft.eShopOnContainers": "Information",
+ "System": "Warning"
+ }
}
},
"ConnectionString": "Server=tcp:127.0.0.1,5433;Initial Catalog=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word",
diff --git a/src/Services/Marketing/Marketing.API/azds.yaml b/src/Services/Marketing/Marketing.API/azds.yaml
new file mode 100644
index 000000000..5d6418f83
--- /dev/null
+++ b/src/Services/Marketing/Marketing.API/azds.yaml
@@ -0,0 +1,56 @@
+kind: helm-release
+apiVersion: 1.1
+build:
+ context: ..\..\..\..
+ dockerfile: Dockerfile
+install:
+ chart: ../../../../k8s/helm/marketing-api
+ set:
+ replicaCount: 1
+ image:
+ tag: $(tag)
+ pullPolicy: Never
+ ingress:
+ annotations:
+ kubernetes.io/ingress.class: traefik-azds
+ hosts:
+ - $(spacePrefix)eshop$(hostSuffix)
+ inf:
+ k8s:
+ dns: $(spacePrefix)eshop$(hostSuffix)
+ values:
+ - values.dev.yaml?
+ - secrets.dev.yaml?
+ - inf.yaml
+ - app.yaml
+configurations:
+ develop:
+ build:
+ useGitIgnore: true
+ dockerfile: Dockerfile.develop
+ args:
+ BUILD_CONFIGURATION: ${BUILD_CONFIGURATION:-Debug}
+ container:
+ sync:
+ - '**/Pages/**'
+ - '**/Views/**'
+ - '**/wwwroot/**'
+ - '!**/*.{sln,csproj}'
+ command:
+ - dotnet
+ - run
+ - --no-restore
+ - --no-build
+ - --no-launch-profile
+ - -c
+ - ${BUILD_CONFIGURATION:-Debug}
+ iterate:
+ processesToKill:
+ - dotnet
+ - vsdbg
+ buildCommands:
+ - - dotnet
+ - build
+ - --no-restore
+ - -c
+ - ${BUILD_CONFIGURATION:-Debug}
diff --git a/src/Services/Marketing/Marketing.API/values.dev.yaml b/src/Services/Marketing/Marketing.API/values.dev.yaml
new file mode 100644
index 000000000..eaed45149
--- /dev/null
+++ b/src/Services/Marketing/Marketing.API/values.dev.yaml
@@ -0,0 +1,3 @@
+ingress:
+ enabled: true
+ tls: []
\ No newline at end of file
diff --git a/src/Services/Marketing/Marketing.FunctionalTests/CampaignScenarios.cs b/src/Services/Marketing/Marketing.FunctionalTests/CampaignScenarios.cs
index 7085e27b5..abeb4a504 100644
--- a/src/Services/Marketing/Marketing.FunctionalTests/CampaignScenarios.cs
+++ b/src/Services/Marketing/Marketing.FunctionalTests/CampaignScenarios.cs
@@ -27,7 +27,7 @@ namespace Marketing.FunctionalTests
[Fact]
public async Task Get_get_campaign_by_id_and_response_ok_status_code()
{
- var campaignId = 81;
+ var campaignId = 2;
using (var server = CreateServer())
{
var response = await server.CreateClient()
diff --git a/src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj b/src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj
index 2ffe9600b..eaedddbd5 100644
--- a/src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj
+++ b/src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj
@@ -17,15 +17,19 @@
-
+
+
+
-
-
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
-
diff --git a/src/Services/Marketing/Marketing.FunctionalTests/Properties/launchSettings.json b/src/Services/Marketing/Marketing.FunctionalTests/Properties/launchSettings.json
new file mode 100644
index 000000000..5a92d63ac
--- /dev/null
+++ b/src/Services/Marketing/Marketing.FunctionalTests/Properties/launchSettings.json
@@ -0,0 +1,27 @@
+{
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:7496/",
+ "sslPort": 0
+ }
+ },
+ "profiles": {
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "Marketing.FunctionalTests": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "applicationUrl": "http://localhost:7497/"
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Services/Marketing/Marketing.FunctionalTests/UserLocationRoleScenarios.cs b/src/Services/Marketing/Marketing.FunctionalTests/UserLocationRoleScenarios.cs
index fa734bbdf..b8ee38e17 100644
--- a/src/Services/Marketing/Marketing.FunctionalTests/UserLocationRoleScenarios.cs
+++ b/src/Services/Marketing/Marketing.FunctionalTests/UserLocationRoleScenarios.cs
@@ -28,7 +28,7 @@ namespace Marketing.FunctionalTests
[Fact]
public async Task Post_add_new_user_location_rule_and_response_ok_status_code()
{
- var campaignId = 81;
+ var campaignId = 2;
using (var server = CreateServer())
{
@@ -44,7 +44,7 @@ namespace Marketing.FunctionalTests
[Fact]
public async Task Delete_delete_user_location_role_and_response_not_content_status_code()
{
- var campaignId = 81;
+ var campaignId = 2;
using (var server = CreateServer())
{
diff --git a/src/Services/Ordering/Ordering.API/.dockerignore b/src/Services/Ordering/Ordering.API/.dockerignore
new file mode 100644
index 000000000..04f7b133d
--- /dev/null
+++ b/src/Services/Ordering/Ordering.API/.dockerignore
@@ -0,0 +1,14 @@
+.dockerignore
+.git
+.gitignore
+.vs
+.vscode
+**/*.*proj.user
+**/azds.yaml
+**/bin
+**/charts
+**/Dockerfile
+**/Dockerfile.develop
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
\ No newline at end of file
diff --git a/src/Services/Ordering/Ordering.API/Application/Behaviors/LoggingBehavior.cs b/src/Services/Ordering/Ordering.API/Application/Behaviors/LoggingBehavior.cs
index 2708db8a9..35023b297 100644
--- a/src/Services/Ordering/Ordering.API/Application/Behaviors/LoggingBehavior.cs
+++ b/src/Services/Ordering/Ordering.API/Application/Behaviors/LoggingBehavior.cs
@@ -1,9 +1,11 @@
using MediatR;
using Microsoft.Extensions.Logging;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions;
-namespace Ordering.API.Infrastructure.Behaviors
+namespace Ordering.API.Application.Behaviors
{
public class LoggingBehavior : IPipelineBehavior
{
@@ -12,9 +14,10 @@ namespace Ordering.API.Infrastructure.Behaviors
public async Task Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate next)
{
- _logger.LogInformation($"Handling {typeof(TRequest).Name}");
+ _logger.LogInformation("----- Handling command {CommandName} ({@Command})", request.GetGenericTypeName(), request);
var response = await next();
- _logger.LogInformation($"Handled {typeof(TResponse).Name}");
+ _logger.LogInformation("----- Command {CommandName} handled - response: {@Response}", request.GetGenericTypeName(), response);
+
return response;
}
}
diff --git a/src/Services/Ordering/Ordering.API/Application/Behaviors/TransactionBehaviour.cs b/src/Services/Ordering/Ordering.API/Application/Behaviors/TransactionBehaviour.cs
index 6f9aed9e5..d9d3e0b0a 100644
--- a/src/Services/Ordering/Ordering.API/Application/Behaviors/TransactionBehaviour.cs
+++ b/src/Services/Ordering/Ordering.API/Application/Behaviors/TransactionBehaviour.cs
@@ -1,11 +1,11 @@
using MediatR;
using Microsoft.EntityFrameworkCore;
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
using Microsoft.Extensions.Logging;
using Ordering.API.Application.IntegrationEvents;
+using Serilog.Context;
using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -28,33 +28,41 @@ namespace Ordering.API.Application.Behaviors
public async Task Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate next)
{
- TResponse response = default(TResponse);
+ var response = default(TResponse);
+ var typeName = request.GetGenericTypeName();
try
{
- var strategy = _dbContext.Database.CreateExecutionStrategy();
- await strategy.ExecuteAsync(async () =>
+ if (_dbContext.HasActiveTransaction)
{
- _logger.LogInformation($"Begin transaction {typeof(TRequest).Name}");
+ return await next();
+ }
+
+ var strategy = _dbContext.Database.CreateExecutionStrategy();
- await _dbContext.BeginTransactionAsync();
+ await strategy.ExecuteAsync(async () =>
+ {
+ using (var transaction = await _dbContext.BeginTransactionAsync())
+ using (LogContext.PushProperty("TransactionContext", transaction.TransactionId))
+ {
+ _logger.LogInformation("----- Begin transaction {TransactionId} for {CommandName} ({@Command})", transaction.TransactionId, typeName, request);
- response = await next();
+ response = await next();
- await _dbContext.CommitTransactionAsync();
+ _logger.LogInformation("----- Commit transaction {TransactionId} for {CommandName}", transaction.TransactionId, typeName);
- _logger.LogInformation($"Committed transaction {typeof(TRequest).Name}");
+ await _dbContext.CommitTransactionAsync(transaction);
+ }
await _orderingIntegrationEventService.PublishEventsThroughEventBusAsync();
});
return response;
}
- catch (Exception)
+ catch (Exception ex)
{
- _logger.LogInformation($"Rollback transaction executed {typeof(TRequest).Name}");
+ _logger.LogError(ex, "ERROR Handling transaction for {CommandName} ({@Command})", typeName, request);
- _dbContext.RollbackTransaction();
throw;
}
}
diff --git a/src/Services/Ordering/Ordering.API/Application/Behaviors/ValidatorBehavior.cs b/src/Services/Ordering/Ordering.API/Application/Behaviors/ValidatorBehavior.cs
index de0a2ba4b..6fc12258b 100644
--- a/src/Services/Ordering/Ordering.API/Application/Behaviors/ValidatorBehavior.cs
+++ b/src/Services/Ordering/Ordering.API/Application/Behaviors/ValidatorBehavior.cs
@@ -1,20 +1,31 @@
using FluentValidation;
using MediatR;
+using Microsoft.Extensions.Logging;
using Ordering.Domain.Exceptions;
-using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions;
-namespace Ordering.API.Infrastructure.Behaviors
+namespace Ordering.API.Application.Behaviors
{
public class ValidatorBehavior : IPipelineBehavior
{
+ private readonly ILogger> _logger;
private readonly IValidator[] _validators;
- public ValidatorBehavior(IValidator[] validators) => _validators = validators;
+
+ public ValidatorBehavior(IValidator[] validators, ILogger> logger)
+ {
+ _validators = validators;
+ _logger = logger;
+ }
public async Task Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate next)
{
+ var typeName = request.GetGenericTypeName();
+
+ _logger.LogInformation("----- Validating command {CommandType}", typeName);
+
var failures = _validators
.Select(v => v.Validate(request))
.SelectMany(result => result.Errors)
@@ -23,12 +34,13 @@ namespace Ordering.API.Infrastructure.Behaviors
if (failures.Any())
{
+ _logger.LogWarning("Validation errors - {CommandType} - Command: {@Command} - Errors: {@ValidationErrors}", typeName, request, failures);
+
throw new OrderingDomainException(
$"Command Validation Errors for type {typeof(TRequest).Name}", new ValidationException("Validation exception", failures));
}
- var response = await next();
- return response;
+ return await next();
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Services/Ordering/Ordering.API/Application/Commands/CancelOrderCommandHandler.cs b/src/Services/Ordering/Ordering.API/Application/Commands/CancelOrderCommandHandler.cs
index a4c4facb8..85858486c 100644
--- a/src/Services/Ordering/Ordering.API/Application/Commands/CancelOrderCommandHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/Commands/CancelOrderCommandHandler.cs
@@ -2,6 +2,7 @@
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
+using Microsoft.Extensions.Logging;
using System.Threading;
using System.Threading.Tasks;
@@ -40,7 +41,11 @@ namespace Ordering.API.Application.Commands
// Use for Idempotency in Command process
public class CancelOrderIdentifiedCommandHandler : IdentifiedCommandHandler
{
- public CancelOrderIdentifiedCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager)
+ public CancelOrderIdentifiedCommandHandler(
+ IMediator mediator,
+ IRequestManager requestManager,
+ ILogger> logger)
+ : base(mediator, requestManager, logger)
{
}
diff --git a/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs b/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs
index 9a3035d5c..00a088c09 100644
--- a/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs
@@ -6,6 +6,7 @@
using MediatR;
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
+ using Microsoft.Extensions.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;
@@ -18,17 +19,20 @@
private readonly IIdentityService _identityService;
private readonly IMediator _mediator;
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
+ private readonly ILogger _logger;
// Using DI to inject infrastructure persistence Repositories
public CreateOrderCommandHandler(IMediator mediator,
IOrderingIntegrationEventService orderingIntegrationEventService,
- IOrderRepository orderRepository,
- IIdentityService identityService)
+ IOrderRepository orderRepository,
+ IIdentityService identityService,
+ ILogger logger)
{
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
_identityService = identityService ?? throw new ArgumentNullException(nameof(identityService));
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
_orderingIntegrationEventService = orderingIntegrationEventService ?? throw new ArgumentNullException(nameof(orderingIntegrationEventService));
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task Handle(CreateOrderCommand message, CancellationToken cancellationToken)
@@ -36,20 +40,22 @@
// Add Integration event to clean the basket
var orderStartedIntegrationEvent = new OrderStartedIntegrationEvent(message.UserId);
await _orderingIntegrationEventService.AddAndSaveEventAsync(orderStartedIntegrationEvent);
-
+
// Add/Update the Buyer AggregateRoot
// DDD patterns comment: Add child entities and value-objects through the Order Aggregate-Root
// 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, message.UserName, address, message.CardTypeId, message.CardNumber, message.CardSecurityNumber, message.CardHolderName, message.CardExpiration);
-
+
foreach (var item in message.OrderItems)
{
order.AddOrderItem(item.ProductId, item.ProductName, item.UnitPrice, item.Discount, item.PictureUrl, item.Units);
}
- _orderRepository.Add(order);
+ _logger.LogInformation("----- Creating Order - Order: {@Order}", order);
+
+ _orderRepository.Add(order);
return await _orderRepository.UnitOfWork
.SaveEntitiesAsync();
@@ -60,7 +66,11 @@
// Use for Idempotency in Command process
public class CreateOrderIdentifiedCommandHandler : IdentifiedCommandHandler
{
- public CreateOrderIdentifiedCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager)
+ public CreateOrderIdentifiedCommandHandler(
+ IMediator mediator,
+ IRequestManager requestManager,
+ ILogger> logger)
+ : base(mediator, requestManager, logger)
{
}
diff --git a/src/Services/Ordering/Ordering.API/Application/Commands/IdentifiedCommandHandler.cs b/src/Services/Ordering/Ordering.API/Application/Commands/IdentifiedCommandHandler.cs
index f00ea44c8..e389e3975 100644
--- a/src/Services/Ordering/Ordering.API/Application/Commands/IdentifiedCommandHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/Commands/IdentifiedCommandHandler.cs
@@ -1,5 +1,10 @@
using MediatR;
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
+using Microsoft.Extensions.Logging;
+using Ordering.API.Application.Behaviors;
+using Ordering.API.Application.Commands;
+using System;
using System.Threading;
using System.Threading.Tasks;
@@ -16,11 +21,16 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
{
private readonly IMediator _mediator;
private readonly IRequestManager _requestManager;
+ private readonly ILogger> _logger;
- public IdentifiedCommandHandler(IMediator mediator, IRequestManager requestManager)
+ public IdentifiedCommandHandler(
+ IMediator mediator,
+ IRequestManager requestManager,
+ ILogger> logger)
{
_mediator = mediator;
_requestManager = requestManager;
+ _logger = logger ?? throw new System.ArgumentNullException(nameof(logger));
}
///
@@ -48,16 +58,60 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
else
{
await _requestManager.CreateRequestForCommandAsync(message.Id);
- try
- {
- // Send the embeded business command to mediator so it runs its related CommandHandler
- var result = await _mediator.Send(message.Command);
- return result;
- }
- catch
- {
- return default(R);
- }
+ try
+ {
+ var command = message.Command;
+ var commandName = command.GetGenericTypeName();
+ var idProperty = string.Empty;
+ var commandId = string.Empty;
+
+ switch (command)
+ {
+ case CreateOrderCommand createOrderCommand:
+ idProperty = nameof(createOrderCommand.UserId);
+ commandId = createOrderCommand.UserId;
+ break;
+
+ case CancelOrderCommand cancelOrderCommand:
+ idProperty = nameof(cancelOrderCommand.OrderNumber);
+ commandId = $"{cancelOrderCommand.OrderNumber}";
+ break;
+
+ case ShipOrderCommand shipOrderCommand:
+ idProperty = nameof(shipOrderCommand.OrderNumber);
+ commandId = $"{shipOrderCommand.OrderNumber}";
+ break;
+
+ default:
+ idProperty = "Id?";
+ commandId = "n/a";
+ break;
+ }
+
+ _logger.LogInformation(
+ "----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
+ commandName,
+ idProperty,
+ commandId,
+ command);
+
+ // Send the embeded business command to mediator so it runs its related CommandHandler
+ var result = await _mediator.Send(command);
+
+ _logger.LogInformation(
+ "----- Command result: {@Result} - {CommandName} - {IdProperty}: {CommandId} ({@Command})",
+ result,
+ commandName,
+ idProperty,
+ commandId,
+ command);
+
+ return result;
+ }
+ catch
+ {
+ return default(R);
+ }
}
}
}
diff --git a/src/Services/Ordering/Ordering.API/Application/Commands/SetAwaitingValidationOrderStatusCommandHandler.cs b/src/Services/Ordering/Ordering.API/Application/Commands/SetAwaitingValidationOrderStatusCommandHandler.cs
index cee307ca2..c40ddb37f 100644
--- a/src/Services/Ordering/Ordering.API/Application/Commands/SetAwaitingValidationOrderStatusCommandHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/Commands/SetAwaitingValidationOrderStatusCommandHandler.cs
@@ -2,6 +2,7 @@
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
+using Microsoft.Extensions.Logging;
using System.Threading;
using System.Threading.Tasks;
@@ -40,7 +41,11 @@ namespace Ordering.API.Application.Commands
// Use for Idempotency in Command process
public class SetAwaitingValidationIdentifiedOrderStatusCommandHandler : IdentifiedCommandHandler
{
- public SetAwaitingValidationIdentifiedOrderStatusCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager)
+ public SetAwaitingValidationIdentifiedOrderStatusCommandHandler(
+ IMediator mediator,
+ IRequestManager requestManager,
+ ILogger> logger)
+ : base(mediator, requestManager, logger)
{
}
diff --git a/src/Services/Ordering/Ordering.API/Application/Commands/SetPaidOrderStatusCommandHandler.cs b/src/Services/Ordering/Ordering.API/Application/Commands/SetPaidOrderStatusCommandHandler.cs
index 211e568cb..8282bf6ab 100644
--- a/src/Services/Ordering/Ordering.API/Application/Commands/SetPaidOrderStatusCommandHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/Commands/SetPaidOrderStatusCommandHandler.cs
@@ -2,6 +2,7 @@
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
+using Microsoft.Extensions.Logging;
using System.Threading;
using System.Threading.Tasks;
@@ -43,7 +44,11 @@ namespace Ordering.API.Application.Commands
// Use for Idempotency in Command process
public class SetPaidIdentifiedOrderStatusCommandHandler : IdentifiedCommandHandler
{
- public SetPaidIdentifiedOrderStatusCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager)
+ public SetPaidIdentifiedOrderStatusCommandHandler(
+ IMediator mediator,
+ IRequestManager requestManager,
+ ILogger> logger)
+ : base(mediator, requestManager, logger)
{
}
diff --git a/src/Services/Ordering/Ordering.API/Application/Commands/SetStockConfirmedOrderStatusCommandHandler.cs b/src/Services/Ordering/Ordering.API/Application/Commands/SetStockConfirmedOrderStatusCommandHandler.cs
index 4e1bc6185..e9c3eb75c 100644
--- a/src/Services/Ordering/Ordering.API/Application/Commands/SetStockConfirmedOrderStatusCommandHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/Commands/SetStockConfirmedOrderStatusCommandHandler.cs
@@ -2,6 +2,7 @@
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
+using Microsoft.Extensions.Logging;
using System.Threading;
using System.Threading.Tasks;
@@ -43,7 +44,11 @@ namespace Ordering.API.Application.Commands
// Use for Idempotency in Command process
public class SetStockConfirmedOrderStatusIdenfifiedCommandHandler : IdentifiedCommandHandler
{
- public SetStockConfirmedOrderStatusIdenfifiedCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager)
+ public SetStockConfirmedOrderStatusIdenfifiedCommandHandler(
+ IMediator mediator,
+ IRequestManager requestManager,
+ ILogger> logger)
+ : base(mediator, requestManager, logger)
{
}
diff --git a/src/Services/Ordering/Ordering.API/Application/Commands/SetStockRejectedOrderStatusCommandHandler.cs b/src/Services/Ordering/Ordering.API/Application/Commands/SetStockRejectedOrderStatusCommandHandler.cs
index 2b7a72526..2e6c794d2 100644
--- a/src/Services/Ordering/Ordering.API/Application/Commands/SetStockRejectedOrderStatusCommandHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/Commands/SetStockRejectedOrderStatusCommandHandler.cs
@@ -2,6 +2,7 @@
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
+using Microsoft.Extensions.Logging;
using System.Threading;
using System.Threading.Tasks;
@@ -44,7 +45,11 @@ namespace Ordering.API.Application.Commands
// Use for Idempotency in Command process
public class SetStockRejectedOrderStatusIdenfifiedCommandHandler : IdentifiedCommandHandler
{
- public SetStockRejectedOrderStatusIdenfifiedCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager)
+ public SetStockRejectedOrderStatusIdenfifiedCommandHandler(
+ IMediator mediator,
+ IRequestManager requestManager,
+ ILogger> logger)
+ : base(mediator, requestManager, logger)
{
}
diff --git a/src/Services/Ordering/Ordering.API/Application/Commands/ShipOrderCommandHandler.cs b/src/Services/Ordering/Ordering.API/Application/Commands/ShipOrderCommandHandler.cs
index b4a6ac26d..fcac86ef9 100644
--- a/src/Services/Ordering/Ordering.API/Application/Commands/ShipOrderCommandHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/Commands/ShipOrderCommandHandler.cs
@@ -2,6 +2,7 @@
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
+using Microsoft.Extensions.Logging;
using System.Threading;
using System.Threading.Tasks;
@@ -9,7 +10,7 @@ namespace Ordering.API.Application.Commands
{
// Regular CommandHandler
public class ShipOrderCommandHandler : IRequestHandler
- {
+ {
private readonly IOrderRepository _orderRepository;
public ShipOrderCommandHandler(IOrderRepository orderRepository)
@@ -26,7 +27,7 @@ namespace Ordering.API.Application.Commands
public async Task Handle(ShipOrderCommand command, CancellationToken cancellationToken)
{
var orderToUpdate = await _orderRepository.GetAsync(command.OrderNumber);
- if(orderToUpdate == null)
+ if (orderToUpdate == null)
{
return false;
}
@@ -40,7 +41,11 @@ namespace Ordering.API.Application.Commands
// Use for Idempotency in Command process
public class ShipOrderIdentifiedCommandHandler : IdentifiedCommandHandler
{
- public ShipOrderIdentifiedCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager)
+ public ShipOrderIdentifiedCommandHandler(
+ IMediator mediator,
+ IRequestManager requestManager,
+ ILogger> logger)
+ : base(mediator, requestManager, logger)
{
}
diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/BuyerAndPaymentMethodVerified/UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/BuyerAndPaymentMethodVerified/UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler.cs
index d738c07ee..bea8eaac5 100644
--- a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/BuyerAndPaymentMethodVerified/UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/BuyerAndPaymentMethodVerified/UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler.cs
@@ -8,16 +8,16 @@ using System.Threading.Tasks;
namespace Ordering.API.Application.DomainEventHandlers.BuyerAndPaymentMethodVerified
{
- public class UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler
+ public class UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler
: INotificationHandler
{
- private readonly IOrderRepository _orderRepository;
- private readonly ILoggerFactory _logger;
+ private readonly IOrderRepository _orderRepository;
+ private readonly ILoggerFactory _logger;
public UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler(
- IOrderRepository orderRepository, ILoggerFactory logger)
+ IOrderRepository orderRepository, ILoggerFactory logger)
{
- _orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
+ _orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
@@ -28,10 +28,11 @@ namespace Ordering.API.Application.DomainEventHandlers.BuyerAndPaymentMethodVeri
{
var orderToUpdate = await _orderRepository.GetAsync(buyerPaymentMethodVerifiedEvent.OrderId);
orderToUpdate.SetBuyerId(buyerPaymentMethodVerifiedEvent.Buyer.Id);
- orderToUpdate.SetPaymentId(buyerPaymentMethodVerifiedEvent.Payment.Id);
+ orderToUpdate.SetPaymentId(buyerPaymentMethodVerifiedEvent.Payment.Id);
- _logger.CreateLogger(nameof(UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler))
- .LogTrace($"Order with Id: {buyerPaymentMethodVerifiedEvent.OrderId} has been successfully updated with a payment method id: { buyerPaymentMethodVerifiedEvent.Payment.Id }");
+ _logger.CreateLogger()
+ .LogTrace("Order with Id: {OrderId} has been successfully updated with a payment method {PaymentMethod} ({Id})",
+ buyerPaymentMethodVerifiedEvent.OrderId, nameof(buyerPaymentMethodVerifiedEvent.Payment), buyerPaymentMethodVerifiedEvent.Payment.Id);
}
- }
+ }
}
diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderCancelled/OrderCancelledDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderCancelled/OrderCancelledDomainEventHandler.cs
index 32967f6a7..f8fddf3a8 100644
--- a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderCancelled/OrderCancelledDomainEventHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderCancelled/OrderCancelledDomainEventHandler.cs
@@ -33,9 +33,9 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderCancelled
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}");
+ _logger.CreateLogger()
+ .LogTrace("Order with Id: {OrderId} has been successfully updated to status {Status} ({Id})",
+ orderCancelledDomainEvent.Order.Id, nameof(OrderStatus.Cancelled), OrderStatus.Cancelled.Id);
var order = await _orderRepository.GetAsync(orderCancelledDomainEvent.Order.Id);
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderGracePeriodConfirmed/OrderStatusChangedToAwaitingValidationDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderGracePeriodConfirmed/OrderStatusChangedToAwaitingValidationDomainEventHandler.cs
index e1c54af4f..edea66895 100644
--- a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderGracePeriodConfirmed/OrderStatusChangedToAwaitingValidationDomainEventHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderGracePeriodConfirmed/OrderStatusChangedToAwaitingValidationDomainEventHandler.cs
@@ -33,9 +33,9 @@
public async Task Handle(OrderStatusChangedToAwaitingValidationDomainEvent orderStatusChangedToAwaitingValidationDomainEvent, CancellationToken cancellationToken)
{
- _logger.CreateLogger(nameof(OrderStatusChangedToAwaitingValidationDomainEvent))
- .LogTrace($"Order with Id: {orderStatusChangedToAwaitingValidationDomainEvent.OrderId} has been successfully updated with " +
- $"a status order id: {OrderStatus.AwaitingValidation.Id}");
+ _logger.CreateLogger()
+ .LogTrace("Order with Id: {OrderId} has been successfully updated to status {Status} ({Id})",
+ orderStatusChangedToAwaitingValidationDomainEvent.OrderId, nameof(OrderStatus.AwaitingValidation), OrderStatus.AwaitingValidation.Id);
var order = await _orderRepository.GetAsync(orderStatusChangedToAwaitingValidationDomainEvent.OrderId);
diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderPaid/OrderStatusChangedToPaidDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderPaid/OrderStatusChangedToPaidDomainEventHandler.cs
index d3dca202f..a934a621d 100644
--- a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderPaid/OrderStatusChangedToPaidDomainEventHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderPaid/OrderStatusChangedToPaidDomainEventHandler.cs
@@ -35,9 +35,9 @@
public async Task Handle(OrderStatusChangedToPaidDomainEvent orderStatusChangedToPaidDomainEvent, CancellationToken cancellationToken)
{
- _logger.CreateLogger(nameof(OrderStatusChangedToPaidDomainEventHandler))
- .LogTrace($"Order with Id: {orderStatusChangedToPaidDomainEvent.OrderId} has been successfully updated with " +
- $"a status order id: {OrderStatus.Paid.Id}");
+ _logger.CreateLogger()
+ .LogTrace("Order with Id: {OrderId} has been successfully updated to status {Status} ({Id})",
+ orderStatusChangedToPaidDomainEvent.OrderId, nameof(OrderStatus.Paid), OrderStatus.Paid.Id);
var order = await _orderRepository.GetAsync(orderStatusChangedToPaidDomainEvent.OrderId);
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderShipped/OrderShippedDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderShipped/OrderShippedDomainEventHandler.cs
index 3be83a2ae..7f4754865 100644
--- a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderShipped/OrderShippedDomainEventHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderShipped/OrderShippedDomainEventHandler.cs
@@ -33,9 +33,9 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderShipped
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}");
+ _logger.CreateLogger()
+ .LogTrace("Order with Id: {OrderId} has been successfully updated to status {Status} ({Id})",
+ orderShippedDomainEvent.Order.Id, nameof(OrderStatus.Shipped), OrderStatus.Shipped.Id);
var order = await _orderRepository.GetAsync(orderShippedDomainEvent.Order.Id);
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStartedEvent/ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStartedEvent/ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler.cs
index 99b2a21a0..e47192dcd 100644
--- a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStartedEvent/ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStartedEvent/ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler.cs
@@ -61,7 +61,9 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent
var orderStatusChangedTosubmittedIntegrationEvent = new OrderStatusChangedToSubmittedIntegrationEvent(orderStartedEvent.Order.Id, orderStartedEvent.Order.OrderStatus.Name, buyer.Name);
await _orderingIntegrationEventService.AddAndSaveEventAsync(orderStatusChangedTosubmittedIntegrationEvent);
- _logger.CreateLogger(nameof(ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler)).LogTrace($"Buyer {buyerUpdated.Id} and related payment method were validated or updated for orderId: {orderStartedEvent.Order.Id}.");
+ _logger.CreateLogger()
+ .LogTrace("Buyer {BuyerId} and related payment method were validated or updated for orderId: {OrderId}.",
+ buyerUpdated.Id, orderStartedEvent.Order.Id);
}
}
}
diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmed/OrderStatusChangedToStockConfirmedDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmed/OrderStatusChangedToStockConfirmedDomainEventHandler.cs
index e910964e8..0e9ca4f08 100644
--- a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmed/OrderStatusChangedToStockConfirmedDomainEventHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmed/OrderStatusChangedToStockConfirmedDomainEventHandler.cs
@@ -33,9 +33,9 @@
public async Task Handle(OrderStatusChangedToStockConfirmedDomainEvent orderStatusChangedToStockConfirmedDomainEvent, CancellationToken cancellationToken)
{
- _logger.CreateLogger(nameof(OrderStatusChangedToStockConfirmedDomainEventHandler))
- .LogTrace($"Order with Id: {orderStatusChangedToStockConfirmedDomainEvent.OrderId} has been successfully updated with " +
- $"a status order id: {OrderStatus.StockConfirmed.Id}");
+ _logger.CreateLogger()
+ .LogTrace("Order with Id: {OrderId} has been successfully updated to status {Status} ({Id})",
+ orderStatusChangedToStockConfirmedDomainEvent.OrderId, nameof(OrderStatus.StockConfirmed), OrderStatus.StockConfirmed.Id);
var order = await _orderRepository.GetAsync(orderStatusChangedToStockConfirmedDomainEvent.OrderId);
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/GracePeriodConfirmedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/GracePeriodConfirmedIntegrationEventHandler.cs
index f8dcc6edb..2e003b322 100644
--- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/GracePeriodConfirmedIntegrationEventHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/GracePeriodConfirmedIntegrationEventHandler.cs
@@ -1,8 +1,13 @@
using MediatR;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions;
+using Microsoft.eShopOnContainers.Services.Ordering.API;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
+using Microsoft.Extensions.Logging;
+using Ordering.API.Application.Behaviors;
using Ordering.API.Application.Commands;
using Ordering.API.Application.IntegrationEvents.Events;
+using Serilog.Context;
using System.Threading.Tasks;
namespace Ordering.API.Application.IntegrationEvents.EventHandling
@@ -10,10 +15,14 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling
public class GracePeriodConfirmedIntegrationEventHandler : IIntegrationEventHandler
{
private readonly IMediator _mediator;
+ private readonly ILogger _logger;
- public GracePeriodConfirmedIntegrationEventHandler(IMediator mediator)
+ public GracePeriodConfirmedIntegrationEventHandler(
+ IMediator mediator,
+ ILogger logger)
{
_mediator = mediator;
+ _logger = logger ?? throw new System.ArgumentNullException(nameof(logger));
}
///
@@ -26,8 +35,21 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling
///
public async Task Handle(GracePeriodConfirmedIntegrationEvent @event)
{
- var command = new SetAwaitingValidationOrderStatusCommand(@event.OrderId);
- await _mediator.Send(command);
+ using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
+ {
+ _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
+
+ var command = new SetAwaitingValidationOrderStatusCommand(@event.OrderId);
+
+ _logger.LogInformation(
+ "----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
+ command.GetGenericTypeName(),
+ nameof(command.OrderNumber),
+ command.OrderNumber,
+ command);
+
+ await _mediator.Send(command);
+ }
}
}
}
diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentFailedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentFailedIntegrationEventHandler.cs
index 5f4fc28e1..a123dd891 100644
--- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentFailedIntegrationEventHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentFailedIntegrationEventHandler.cs
@@ -2,26 +2,48 @@
{
using MediatR;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
+ using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions;
+ using Microsoft.eShopOnContainers.Services.Ordering.API;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
+ using Microsoft.Extensions.Logging;
+ using Ordering.API.Application.Behaviors;
using Ordering.API.Application.Commands;
using Ordering.API.Application.IntegrationEvents.Events;
- using System;
+ using Serilog.Context;
using System.Threading.Tasks;
+ using System;
public class OrderPaymentFailedIntegrationEventHandler :
IIntegrationEventHandler
{
private readonly IMediator _mediator;
+ private readonly ILogger _logger;
- public OrderPaymentFailedIntegrationEventHandler(IMediator mediator)
+ public OrderPaymentFailedIntegrationEventHandler(
+ IMediator mediator,
+ ILogger logger)
{
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task Handle(OrderPaymentFailedIntegrationEvent @event)
{
- var command = new CancelOrderCommand(@event.OrderId);
- await _mediator.Send(command);
+ using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
+ {
+ _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
+
+ var command = new CancelOrderCommand(@event.OrderId);
+
+ _logger.LogInformation(
+ "----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
+ command.GetGenericTypeName(),
+ nameof(command.OrderNumber),
+ command.OrderNumber,
+ command);
+
+ await _mediator.Send(command);
+ }
}
}
}
diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSuccededIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSuccededIntegrationEventHandler.cs
index 6c201d77e..9cc69e5e8 100644
--- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSuccededIntegrationEventHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSuccededIntegrationEventHandler.cs
@@ -2,9 +2,14 @@
{
using MediatR;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
+ using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions;
+ using Microsoft.eShopOnContainers.Services.Ordering.API;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
+ using Microsoft.Extensions.Logging;
+ using Ordering.API.Application.Behaviors;
using Ordering.API.Application.Commands;
using Ordering.API.Application.IntegrationEvents.Events;
+ using Serilog.Context;
using System;
using System.Threading.Tasks;
@@ -12,16 +17,33 @@
IIntegrationEventHandler
{
private readonly IMediator _mediator;
+ private readonly ILogger _logger;
- public OrderPaymentSuccededIntegrationEventHandler(IMediator mediator)
+ public OrderPaymentSuccededIntegrationEventHandler(
+ IMediator mediator,
+ ILogger logger)
{
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task Handle(OrderPaymentSuccededIntegrationEvent @event)
{
- var command = new SetPaidOrderStatusCommand(@event.OrderId);
- await _mediator.Send(command);
+ using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
+ {
+ _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
+
+ var command = new SetPaidOrderStatusCommand(@event.OrderId);
+
+ _logger.LogInformation(
+ "----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
+ command.GetGenericTypeName(),
+ nameof(command.OrderNumber),
+ command.OrderNumber,
+ command);
+
+ await _mediator.Send(command);
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs
index c5561508b..6438b01d0 100644
--- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs
@@ -1,27 +1,49 @@
namespace Ordering.API.Application.IntegrationEvents.EventHandling
{
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
+ using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions;
using System.Threading.Tasks;
using Events;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using MediatR;
using System;
using Ordering.API.Application.Commands;
+ using Microsoft.Extensions.Logging;
+ using Serilog.Context;
+ using Microsoft.eShopOnContainers.Services.Ordering.API;
+ using Ordering.API.Application.Behaviors;
- public class OrderStockConfirmedIntegrationEventHandler :
+ public class OrderStockConfirmedIntegrationEventHandler :
IIntegrationEventHandler
{
private readonly IMediator _mediator;
+ private readonly ILogger _logger;
- public OrderStockConfirmedIntegrationEventHandler(IMediator mediator)
+ public OrderStockConfirmedIntegrationEventHandler(
+ IMediator mediator,
+ ILogger logger)
{
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task Handle(OrderStockConfirmedIntegrationEvent @event)
{
- var command = new SetStockConfirmedOrderStatusCommand(@event.OrderId);
- await _mediator.Send(command);
+ using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
+ {
+ _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
+
+ var command = new SetStockConfirmedOrderStatusCommand(@event.OrderId);
+
+ _logger.LogInformation(
+ "----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
+ command.GetGenericTypeName(),
+ nameof(command.OrderNumber),
+ command.OrderNumber,
+ command);
+
+ await _mediator.Send(command);
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockRejectedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockRejectedIntegrationEventHandler.cs
index af7d98f74..b457211ed 100644
--- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockRejectedIntegrationEventHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockRejectedIntegrationEventHandler.cs
@@ -1,31 +1,53 @@
namespace Ordering.API.Application.IntegrationEvents.EventHandling
{
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
+ using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions;
using System.Threading.Tasks;
using Events;
using System.Linq;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using MediatR;
using Ordering.API.Application.Commands;
+ using Microsoft.Extensions.Logging;
+ using Serilog.Context;
+ using Microsoft.eShopOnContainers.Services.Ordering.API;
+ using Ordering.API.Application.Behaviors;
public class OrderStockRejectedIntegrationEventHandler : IIntegrationEventHandler
{
private readonly IMediator _mediator;
+ private readonly ILogger _logger;
- public OrderStockRejectedIntegrationEventHandler(IMediator mediator)
+ public OrderStockRejectedIntegrationEventHandler(
+ IMediator mediator,
+ ILogger logger)
{
_mediator = mediator;
+ _logger = logger ?? throw new System.ArgumentNullException(nameof(logger));
}
public async Task Handle(OrderStockRejectedIntegrationEvent @event)
{
- var orderStockRejectedItems = @event.OrderStockItems
- .FindAll(c => !c.HasStock)
- .Select(c => c.ProductId)
- .ToList();
+ using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
+ {
+ _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
- var command = new SetStockRejectedOrderStatusCommand(@event.OrderId, orderStockRejectedItems);
- await _mediator.Send(command);
+ var orderStockRejectedItems = @event.OrderStockItems
+ .FindAll(c => !c.HasStock)
+ .Select(c => c.ProductId)
+ .ToList();
+
+ var command = new SetStockRejectedOrderStatusCommand(@event.OrderId, orderStockRejectedItems);
+
+ _logger.LogInformation(
+ "----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
+ command.GetGenericTypeName(),
+ nameof(command.OrderNumber),
+ command.OrderNumber,
+ command);
+
+ await _mediator.Send(command);
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs
index 33f327c6b..a1452b23c 100644
--- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs
+++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs
@@ -1,52 +1,82 @@
-using System;
-using MediatR;
+using MediatR;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
-using System.Threading.Tasks;
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions;
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
+using Microsoft.eShopOnContainers.Services.Ordering.API;
using Microsoft.Extensions.Logging;
+using Ordering.API.Application.Behaviors;
using Ordering.API.Application.IntegrationEvents.Events;
+using Serilog.Context;
+using System.Threading.Tasks;
+using System;
namespace Ordering.API.Application.IntegrationEvents.EventHandling
{
public class UserCheckoutAcceptedIntegrationEventHandler : IIntegrationEventHandler
{
private readonly IMediator _mediator;
- private readonly ILoggerFactory _logger;
+ private readonly ILogger _logger;
- public UserCheckoutAcceptedIntegrationEventHandler(IMediator mediator,
- ILoggerFactory logger)
+ public UserCheckoutAcceptedIntegrationEventHandler(
+ IMediator mediator,
+ ILogger logger)
{
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
- _logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
///
/// Integration event handler which starts the create order process
///
- ///
+ ///
/// Integration event message which is sent by the
/// basket.api once it has successfully process the
/// order items.
///
///
- public async Task Handle(UserCheckoutAcceptedIntegrationEvent eventMsg)
+ public async Task Handle(UserCheckoutAcceptedIntegrationEvent @event)
{
- var result = false;
-
- if (eventMsg.RequestId != Guid.Empty)
+ using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
{
- 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);
-
- var requestCreateOrder = new IdentifiedCommand(createOrderCommand, eventMsg.RequestId);
- result = await _mediator.Send(requestCreateOrder);
- }
-
- _logger.CreateLogger(nameof(UserCheckoutAcceptedIntegrationEventHandler))
- .LogTrace(result ? $"UserCheckoutAccepted integration event has been received and a create new order process is started with requestId: {eventMsg.RequestId}" :
- $"UserCheckoutAccepted integration event has been received but a new order process has failed with requestId: {eventMsg.RequestId}");
+ _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
+
+ var result = false;
+
+ if (@event.RequestId != Guid.Empty)
+ {
+ using (LogContext.PushProperty("IdentifiedCommandId", @event.RequestId))
+ {
+ var createOrderCommand = new CreateOrderCommand(@event.Basket.Items, @event.UserId, @event.UserName, @event.City, @event.Street,
+ @event.State, @event.Country, @event.ZipCode,
+ @event.CardNumber, @event.CardHolderName, @event.CardExpiration,
+ @event.CardSecurityNumber, @event.CardTypeId);
+
+ var requestCreateOrder = new IdentifiedCommand(createOrderCommand, @event.RequestId);
+
+ _logger.LogInformation(
+ "----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
+ requestCreateOrder.GetGenericTypeName(),
+ nameof(requestCreateOrder.Id),
+ requestCreateOrder.Id,
+ requestCreateOrder);
+
+ result = await _mediator.Send(requestCreateOrder);
+
+ if (result)
+ {
+ _logger.LogInformation("----- CreateOrderCommand suceeded - RequestId: {RequestId}", @event.RequestId);
+ }
+ else
+ {
+ _logger.LogWarning("CreateOrderCommand failed - RequestId: {RequestId}", @event.RequestId);
+ }
+ }
+ }
+ else
+ {
+ _logger.LogWarning("Invalid IntegrationEvent - RequestId is missing - {@IntegrationEvent}", @event);
+ }
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/OrderingIntegrationEventService.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/OrderingIntegrationEventService.cs
index 9c1bd4e1b..c6360d194 100644
--- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/OrderingIntegrationEventService.cs
+++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/OrderingIntegrationEventService.cs
@@ -5,7 +5,9 @@ using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services;
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Utilities;
+using Microsoft.eShopOnContainers.Services.Ordering.API;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
+using Microsoft.Extensions.Logging;
using System;
using System.Data.Common;
using System.Diagnostics;
@@ -21,39 +23,49 @@ namespace Ordering.API.Application.IntegrationEvents
private readonly OrderingContext _orderingContext;
private readonly IntegrationEventLogContext _eventLogContext;
private readonly IIntegrationEventLogService _eventLogService;
+ private readonly ILogger _logger;
- public OrderingIntegrationEventService(IEventBus eventBus,
+ public OrderingIntegrationEventService(IEventBus eventBus,
OrderingContext orderingContext,
IntegrationEventLogContext eventLogContext,
- Func integrationEventLogServiceFactory)
+ Func integrationEventLogServiceFactory,
+ ILogger logger)
{
_orderingContext = orderingContext ?? throw new ArgumentNullException(nameof(orderingContext));
_eventLogContext = eventLogContext ?? throw new ArgumentNullException(nameof(eventLogContext));
_integrationEventLogServiceFactory = integrationEventLogServiceFactory ?? throw new ArgumentNullException(nameof(integrationEventLogServiceFactory));
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
_eventLogService = _integrationEventLogServiceFactory(_orderingContext.Database.GetDbConnection());
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task PublishEventsThroughEventBusAsync()
{
- var pendindLogEvents = await _eventLogService.RetrieveEventLogsPendingToPublishAsync();
- foreach (var logEvt in pendindLogEvents)
+ var pendingLogEvents = await _eventLogService.RetrieveEventLogsPendingToPublishAsync();
+
+ foreach (var logEvt in pendingLogEvents)
{
+ _logger.LogInformation("----- Publishing integration event: {IntegrationEventId} from {AppName} - ({@IntegrationEvent})", logEvt.EventId, Program.AppName, logEvt.IntegrationEvent);
+
try
{
await _eventLogService.MarkEventAsInProgressAsync(logEvt.EventId);
_eventBus.Publish(logEvt.IntegrationEvent);
await _eventLogService.MarkEventAsPublishedAsync(logEvt.EventId);
}
- catch (Exception)
+ catch (Exception ex)
{
+ _logger.LogError(ex, "ERROR publishing integration event: {IntegrationEventId} from {AppName}", logEvt.EventId, Program.AppName);
+
await _eventLogService.MarkEventAsFailedAsync(logEvt.EventId);
- }
+ }
}
}
public async Task AddAndSaveEventAsync(IntegrationEvent evt)
{
+ _logger.LogInformation("----- Enqueuing integration event {IntegrationEventId} to repository ({@IntegrationEvent})", evt.Id, evt);
+
await _eventLogService.SaveEventAsync(evt, _orderingContext.GetCurrentTransaction.GetDbTransaction());
}
}
diff --git a/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs b/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs
index e2c711b69..7a592bfb8 100644
--- a/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs
+++ b/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs
@@ -1,9 +1,12 @@
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions;
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries;
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
+using Microsoft.Extensions.Logging;
+using Ordering.API.Application.Behaviors;
using Ordering.API.Application.Commands;
using System;
using System.Collections.Generic;
@@ -20,12 +23,18 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
private readonly IMediator _mediator;
private readonly IOrderQueries _orderQueries;
private readonly IIdentityService _identityService;
+ private readonly ILogger _logger;
- public OrdersController(IMediator mediator, IOrderQueries orderQueries, IIdentityService identityService)
+ public OrdersController(
+ IMediator mediator,
+ IOrderQueries orderQueries,
+ IIdentityService identityService,
+ ILogger logger)
{
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
_orderQueries = orderQueries ?? throw new ArgumentNullException(nameof(orderQueries));
_identityService = identityService ?? throw new ArgumentNullException(nameof(identityService));
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
[Route("cancel")]
@@ -39,6 +48,14 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
if (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty)
{
var requestCancelOrder = new IdentifiedCommand(command, guid);
+
+ _logger.LogInformation(
+ "----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
+ requestCancelOrder.GetGenericTypeName(),
+ nameof(requestCancelOrder.Command.OrderNumber),
+ requestCancelOrder.Command.OrderNumber,
+ requestCancelOrder);
+
commandResult = await _mediator.Send(requestCancelOrder);
}
@@ -61,6 +78,14 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
if (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty)
{
var requestShipOrder = new IdentifiedCommand(command, guid);
+
+ _logger.LogInformation(
+ "----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
+ requestShipOrder.GetGenericTypeName(),
+ nameof(requestShipOrder.Command.OrderNumber),
+ requestShipOrder.Command.OrderNumber,
+ requestShipOrder);
+
commandResult = await _mediator.Send(requestShipOrder);
}
@@ -80,6 +105,8 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
{
try
{
+ //Todo: It's good idea to take advantage of GetOrderByIdQuery and handle by GetCustomerByIdQueryHandler
+ //var order customer = await _mediator.Send(new GetOrderByIdQuery(orderId));
var order = await _orderQueries.GetOrderAsync(orderId);
return Ok(order);
@@ -114,7 +141,14 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
[HttpPost]
public async Task> CreateOrderDraftFromBasketDataAsync([FromBody] CreateOrderDraftCommand createOrderDraftCommand)
{
+ _logger.LogInformation(
+ "----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
+ createOrderDraftCommand.GetGenericTypeName(),
+ nameof(createOrderDraftCommand.BuyerId),
+ createOrderDraftCommand.BuyerId,
+ createOrderDraftCommand);
+
return await _mediator.Send(createOrderDraftCommand);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Services/Ordering/Ordering.API/Dockerfile b/src/Services/Ordering/Ordering.API/Dockerfile
index e836d2728..aa1f0e9c6 100644
--- a/src/Services/Ordering/Ordering.API/Dockerfile
+++ b/src/Services/Ordering/Ordering.API/Dockerfile
@@ -1,22 +1,32 @@
-FROM microsoft/dotnet:2.2.0-aspnetcore-runtime AS base
+FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80
-FROM microsoft/dotnet:2.2.100-sdk AS build
+FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
WORKDIR /src
+
+COPY scripts scripts/
+
+COPY src/ApiGateways/*/*.csproj /src/csproj-files/
+COPY src/ApiGateways/*/*/*.csproj /src/csproj-files/
+COPY src/BuildingBlocks/*/*/*.csproj /src/csproj-files/
+COPY src/Services/*/*/*.csproj /src/csproj-files/
+COPY src/Web/*/*.csproj /src/csproj-files/
+
+ARG RUN=pwd
+RUN ${RUN}
+
COPY . .
WORKDIR /src/src/Services/Ordering/Ordering.API
-RUN dotnet restore -nowarn:msb3202,nu1503
-RUN dotnet build --no-restore -c Release -o /app
-
-FROM build as functionaltest
-WORKDIR /src/src/Services/Ordering/Ordering.FunctionalTests
+RUN dotnet publish -c Release -o /app
FROM build as unittest
WORKDIR /src/src/Services/Ordering/Ordering.UnitTests
+FROM build as functionaltest
+WORKDIR /src/src/Services/Ordering/Ordering.FunctionalTests
+
FROM build AS publish
-RUN dotnet publish --no-restore -c Release -o /app
FROM base AS final
WORKDIR /app
diff --git a/src/Services/Ordering/Ordering.API/Dockerfile.develop b/src/Services/Ordering/Ordering.API/Dockerfile.develop
new file mode 100644
index 000000000..f91a71bd8
--- /dev/null
+++ b/src/Services/Ordering/Ordering.API/Dockerfile.develop
@@ -0,0 +1,22 @@
+FROM microsoft/dotnet:2.2-sdk
+ARG BUILD_CONFIGURATION=Debug
+ENV ASPNETCORE_ENVIRONMENT=Development
+ENV DOTNET_USE_POLLING_FILE_WATCHER=true
+EXPOSE 80
+
+WORKDIR /src
+COPY ["src/BuildingBlocks/EventBus/EventBus/EventBus.csproj", "src/BuildingBlocks/EventBus/EventBus/"]
+COPY ["src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "src/BuildingBlocks/EventBus/EventBusRabbitMQ/"]
+COPY ["src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "src/BuildingBlocks/EventBus/EventBusServiceBus/"]
+COPY ["src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj", "src/BuildingBlocks/EventBus/IntegrationEventLogEF/"]
+COPY ["src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj", "src/BuildingBlocks/WebHostCustomization/WebHost.Customization/"]
+COPY ["src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj", "src/Services/Ordering/Ordering.Domain/"]
+COPY ["src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj", "src/Services/Ordering/Ordering.Infrastructure/"]
+COPY ["src/Services/Ordering/Ordering.API/Ordering.API.csproj", "src/Services/Ordering/Ordering.API/"]
+
+RUN dotnet restore src/Services/Ordering/Ordering.API/Ordering.API.csproj
+COPY . .
+WORKDIR /src/src/Services/Ordering/Ordering.API
+RUN dotnet build --no-restore -c $BUILD_CONFIGURATION
+
+ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"]
\ No newline at end of file
diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/AutofacModules/MediatorModule.cs b/src/Services/Ordering/Ordering.API/Infrastructure/AutofacModules/MediatorModule.cs
index 99a413f9f..67275a587 100644
--- a/src/Services/Ordering/Ordering.API/Infrastructure/AutofacModules/MediatorModule.cs
+++ b/src/Services/Ordering/Ordering.API/Infrastructure/AutofacModules/MediatorModule.cs
@@ -7,7 +7,6 @@ using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
using Ordering.API.Application.Behaviors;
using Ordering.API.Application.DomainEventHandlers.OrderStartedEvent;
using Ordering.API.Application.Validations;
-using Ordering.API.Infrastructure.Behaviors;
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.AutofacModules
{
diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/OrderingContextSeed.cs b/src/Services/Ordering/Ordering.API/Infrastructure/OrderingContextSeed.cs
index 5c82b3952..1e95df7dc 100644
--- a/src/Services/Ordering/Ordering.API/Infrastructure/OrderingContextSeed.cs
+++ b/src/Services/Ordering/Ordering.API/Infrastructure/OrderingContextSeed.cs
@@ -74,7 +74,7 @@
}
catch (Exception ex)
{
- log.LogError(ex.Message);
+ log.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message);
return GetPredefinedCardTypes();
}
@@ -82,7 +82,7 @@
return File.ReadAllLines(csvFileCardTypes)
.Skip(1) // skip header column
.SelectTry(x => CreateCardType(x, ref id))
- .OnCaughtException(ex => { log.LogError(ex.Message); return null; })
+ .OnCaughtException(ex => { log.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); return null; })
.Where(x => x != null);
}
@@ -118,7 +118,7 @@
}
catch (Exception ex)
{
- log.LogError(ex.Message);
+ log.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message);
return GetPredefinedOrderStatus();
}
@@ -126,7 +126,7 @@
return File.ReadAllLines(csvFileOrderStatus)
.Skip(1) // skip header row
.SelectTry(x => CreateOrderStatus(x, ref id))
- .OnCaughtException(ex => { log.LogError(ex.Message); return null; })
+ .OnCaughtException(ex => { log.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); return null; })
.Where(x => x != null);
}
@@ -182,7 +182,7 @@
sleepDurationProvider: retry => TimeSpan.FromSeconds(5),
onRetry: (exception, timeSpan, retry, ctx) =>
{
- logger.LogTrace($"[{prefix}] Exception {exception.GetType().Name} with message ${exception.Message} detected on attempt {retry} of {retries}");
+ logger.LogWarning(exception, "[{prefix}] Exception {ExceptionType} with message {Message} detected on attempt {retry} of {retries}", prefix, exception.GetType().Name, exception.Message, retry, retries);
}
);
}
diff --git a/src/Services/Ordering/Ordering.API/Ordering.API.csproj b/src/Services/Ordering/Ordering.API/Ordering.API.csproj
index abd68e9a6..e2b25c2a7 100644
--- a/src/Services/Ordering/Ordering.API/Ordering.API.csproj
+++ b/src/Services/Ordering/Ordering.API/Ordering.API.csproj
@@ -5,6 +5,7 @@
aspnet-Ordering.API-20161122013547
$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;
..\..\..\..\docker-compose.dcproj
+ latest
@@ -27,30 +28,34 @@
-
-
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
+
+
+
-
-
diff --git a/src/Services/Ordering/Ordering.API/Program.cs b/src/Services/Ordering/Ordering.API/Program.cs
index b97ced4d4..a0b7dc40e 100644
--- a/src/Services/Ordering/Ordering.API/Program.cs
+++ b/src/Services/Ordering/Ordering.API/Program.cs
@@ -15,10 +15,22 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API
{
public class Program
{
- public static void Main(string[] args)
+ public static readonly string Namespace = typeof(Program).Namespace;
+ public static readonly string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1);
+
+ public static int Main(string[] args)
{
- BuildWebHost(args)
- .MigrateDbContext((context, services) =>
+ var configuration = GetConfiguration();
+
+ Log.Logger = CreateSerilogLogger(configuration);
+
+ try
+ {
+ Log.Information("Configuring web host ({ApplicationContext})...", AppName);
+ var host = BuildWebHost(configuration, args);
+
+ Log.Information("Applying migrations ({ApplicationContext})...", AppName);
+ host.MigrateDbContext((context, services) =>
{
var env = services.GetService();
var settings = services.GetService>();
@@ -28,46 +40,67 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API
.SeedAsync(context, env, settings, logger)
.Wait();
})
- .MigrateDbContext((_,__)=>{})
- .Run();
+ .MigrateDbContext((_, __) => { });
+
+ Log.Information("Starting web host ({ApplicationContext})...", AppName);
+ host.Run();
+
+ return 0;
+ }
+ catch (Exception ex)
+ {
+ Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
+ return 1;
+ }
+ finally
+ {
+ Log.CloseAndFlush();
+ }
}
- public static IWebHost BuildWebHost(string[] args) =>
- WebHost.CreateDefaultBuilder(args)
+ private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
+ WebHost.CreateDefaultBuilder(args)
+ .CaptureStartupErrors(false)
.UseStartup()
+ .UseApplicationInsights()
.UseContentRoot(Directory.GetCurrentDirectory())
- .ConfigureAppConfiguration((builderContext, config) =>
- {
- var builtConfig = config.Build();
+ .UseConfiguration(configuration)
+ .UseSerilog()
+ .Build();
+
+ private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
+ {
+ var seqServerUrl = configuration["Serilog:SeqServerUrl"];
+ var logstashUrl = configuration["Serilog:LogstashgUrl"];
+ return new LoggerConfiguration()
+ .MinimumLevel.Verbose()
+ .Enrich.WithProperty("ApplicationContext", AppName)
+ .Enrich.FromLogContext()
+ .WriteTo.Console()
+ .WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
+ .WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://logstash:8080" : logstashUrl)
+ .ReadFrom.Configuration(configuration)
+ .CreateLogger();
+ }
- var configurationBuilder = new ConfigurationBuilder();
-
- if (Convert.ToBoolean(builtConfig["UseVault"]))
- {
- configurationBuilder.AddAzureKeyVault(
- $"https://{builtConfig["Vault:Name"]}.vault.azure.net/",
- builtConfig["Vault:ClientId"],
- builtConfig["Vault:ClientSecret"]);
- }
+ private static IConfiguration GetConfiguration()
+ {
+ var builder = new ConfigurationBuilder()
+ .SetBasePath(Directory.GetCurrentDirectory())
+ .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
+ .AddEnvironmentVariables();
- configurationBuilder.AddEnvironmentVariables();
+ var config = builder.Build();
- config.AddConfiguration(configurationBuilder.Build());
- })
- .ConfigureLogging((hostingContext, builder) =>
- {
- builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
- builder.AddConsole();
- builder.AddDebug();
- })
- .UseApplicationInsights()
- .UseSerilog((builderContext, config) =>
- {
- config
- .MinimumLevel.Information()
- .Enrich.FromLogContext()
- .WriteTo.Console();
- })
- .Build();
+ if (config.GetValue("UseVault", false))
+ {
+ builder.AddAzureKeyVault(
+ $"https://{config["Vault:Name"]}.vault.azure.net/",
+ config["Vault:ClientId"],
+ config["Vault:ClientSecret"]);
+ }
+
+ return builder.Build();
+ }
}
-}
+}
\ No newline at end of file
diff --git a/src/Services/Ordering/Ordering.API/Startup.cs b/src/Services/Ordering/Ordering.API/Startup.cs
index b517dfaa9..b77354052 100644
--- a/src/Services/Ordering/Ordering.API/Startup.cs
+++ b/src/Services/Ordering/Ordering.API/Startup.cs
@@ -74,15 +74,15 @@
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
- loggerFactory.AddAzureWebAppDiagnostics();
- loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
+ //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}'");
+ loggerFactory.CreateLogger().LogDebug("Using PATH BASE '{pathBase}'", pathBase);
app.UsePathBase(pathBase);
- }
+ }
app.UseCors("CorsPolicy");
@@ -122,10 +122,9 @@
eventBus.Subscribe>();
eventBus.Subscribe>();
eventBus.Subscribe>();
- eventBus.Subscribe>();
+ eventBus.Subscribe>();
}
-
protected virtual void ConfigureAuth(IApplicationBuilder app)
{
if (Configuration.GetValue("UseLoadTest"))
@@ -147,7 +146,7 @@
if (orchestratorType?.ToUpper() == "K8S")
{
// Enable K8s telemetry initializer
- services.EnableKubernetes();
+ services.AddApplicationInsightsKubernetesEnricher();
}
if (orchestratorType?.ToUpper() == "SF")
{
@@ -168,7 +167,7 @@
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddControllersAsServices(); //Injecting Controllers themselves thru DI
- //For further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services
+ //For further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services
services.AddCors(options =>
{
@@ -306,7 +305,8 @@
var factory = new ConnectionFactory()
{
- HostName = configuration["EventBusConnection"]
+ HostName = configuration["EventBusConnection"],
+ DispatchConsumersAsync = true
};
if (!string.IsNullOrEmpty(configuration["EventBusUserName"]))
diff --git a/src/Services/Ordering/Ordering.API/appsettings.json b/src/Services/Ordering/Ordering.API/appsettings.json
index 96dd74630..f74c312b1 100644
--- a/src/Services/Ordering/Ordering.API/appsettings.json
+++ b/src/Services/Ordering/Ordering.API/appsettings.json
@@ -2,12 +2,16 @@
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;",
"IdentityUrl": "http://localhost:5105",
"UseCustomizationData": false,
- "Logging": {
- "IncludeScopes": false,
- "LogLevel": {
- "Default": "Trace",
- "System": "Information",
- "Microsoft": "Information"
+ "Serilog": {
+ "SeqServerUrl": null,
+ "LogstashgUrl": null,
+ "MinimumLevel": {
+ "Default": "Information",
+ "Override": {
+ "Microsoft": "Warning",
+ "Microsoft.eShopOnContainers": "Information",
+ "System": "Warning"
+ }
}
},
"AzureServiceBusEnabled": false,
diff --git a/src/Services/Ordering/Ordering.API/azds.yaml b/src/Services/Ordering/Ordering.API/azds.yaml
new file mode 100644
index 000000000..77398a0a8
--- /dev/null
+++ b/src/Services/Ordering/Ordering.API/azds.yaml
@@ -0,0 +1,56 @@
+kind: helm-release
+apiVersion: 1.1
+build:
+ context: ..\..\..\..
+ dockerfile: Dockerfile
+install:
+ chart: ../../../../k8s/helm/ordering-api
+ set:
+ replicaCount: 1
+ image:
+ tag: $(tag)
+ pullPolicy: Never
+ ingress:
+ annotations:
+ kubernetes.io/ingress.class: traefik-azds
+ hosts:
+ - $(spacePrefix)eshop$(hostSuffix)
+ inf:
+ k8s:
+ dns: $(spacePrefix)eshop$(hostSuffix)
+ values:
+ - values.dev.yaml?
+ - secrets.dev.yaml?
+ - inf.yaml
+ - app.yaml
+configurations:
+ develop:
+ build:
+ useGitIgnore: true
+ dockerfile: Dockerfile.develop
+ args:
+ BUILD_CONFIGURATION: ${BUILD_CONFIGURATION:-Debug}
+ container:
+ sync:
+ - '**/Pages/**'
+ - '**/Views/**'
+ - '**/wwwroot/**'
+ - '!**/*.{sln,csproj}'
+ command:
+ - dotnet
+ - run
+ - --no-restore
+ - --no-build
+ - --no-launch-profile
+ - -c
+ - ${BUILD_CONFIGURATION:-Debug}
+ iterate:
+ processesToKill:
+ - dotnet
+ - vsdbg
+ buildCommands:
+ - - dotnet
+ - build
+ - --no-restore
+ - -c
+ - ${BUILD_CONFIGURATION:-Debug}
diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile b/src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile
index 7b66be834..0c121f4a8 100644
--- a/src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile
+++ b/src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile
@@ -1,16 +1,26 @@
-FROM microsoft/dotnet:2.2.0-aspnetcore-runtime AS base
+FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80
-FROM microsoft/dotnet:2.2.100-sdk AS build
+FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
WORKDIR /src
+
+COPY scripts scripts/
+
+COPY src/ApiGateways/*/*.csproj /src/csproj-files/
+COPY src/ApiGateways/*/*/*.csproj /src/csproj-files/
+COPY src/BuildingBlocks/*/*/*.csproj /src/csproj-files/
+COPY src/Services/*/*/*.csproj /src/csproj-files/
+COPY src/Web/*/*.csproj /src/csproj-files/
+
+ARG RUN=pwd
+RUN ${RUN}
+
COPY . .
WORKDIR /src/src/Services/Ordering/Ordering.BackgroundTasks
-RUN dotnet restore -nowarn:msb3202,nu1503
-RUN dotnet build --no-restore -c Release -o /app
+RUN dotnet publish -c Release -o /app
FROM build AS publish
-RUN dotnet publish --no-restore -c Release -o /app
FROM base AS final
WORKDIR /app
diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile.develop b/src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile.develop
new file mode 100644
index 000000000..5f5d002db
--- /dev/null
+++ b/src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile.develop
@@ -0,0 +1,18 @@
+FROM microsoft/dotnet:2.2-sdk
+ARG BUILD_CONFIGURATION=Debug
+ENV ASPNETCORE_ENVIRONMENT=Development
+ENV DOTNET_USE_POLLING_FILE_WATCHER=true
+EXPOSE 80
+
+WORKDIR /src
+COPY ["src/BuildingBlocks/EventBus/EventBus/EventBus.csproj", "src/BuildingBlocks/EventBus/EventBus/"]
+COPY ["src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "src/BuildingBlocks/EventBus/EventBusRabbitMQ/"]
+COPY ["src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "src/BuildingBlocks/EventBus/EventBusServiceBus/"]
+COPY ["src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj", "src/Services/Ordering/Ordering.BackgroundTasks/"]
+
+RUN dotnet restore src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj
+COPY . .
+WORKDIR /src/src/Services/Ordering/Ordering.BackgroundTasks
+RUN dotnet build --no-restore -c $BUILD_CONFIGURATION
+
+ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"]
\ No newline at end of file
diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj b/src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj
index b757cada9..63df5da80 100644
--- a/src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj
+++ b/src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj
@@ -14,17 +14,21 @@
-
+
-
+
+
+
+
+
diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/Program.cs b/src/Services/Ordering/Ordering.BackgroundTasks/Program.cs
index 3c78efa10..7a429742e 100644
--- a/src/Services/Ordering/Ordering.BackgroundTasks/Program.cs
+++ b/src/Services/Ordering/Ordering.BackgroundTasks/Program.cs
@@ -1,33 +1,76 @@
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Serilog;
+using System;
+using System.IO;
namespace Ordering.BackgroundTasks
{
public class Program
{
- public static void Main(string[] args)
+ public static readonly string Namespace = typeof(Program).Namespace;
+ public static readonly string AppName = Namespace;
+
+ public static int Main(string[] args)
{
- BuildWebHost(args).Run();
+ var configuration = GetConfiguration();
+
+ Log.Logger = CreateSerilogLogger(configuration);
+
+ try
+ {
+ Log.Information("Configuring web host ({ApplicationContext})...", AppName);
+ var host = BuildWebHost(configuration, args);
+
+ Log.Information("Starting web host ({ApplicationContext})...", AppName);
+ host.Run();
+
+ return 0;
+ }
+ catch (Exception ex)
+ {
+ Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
+ return 1;
+ }
+ finally
+ {
+ Log.CloseAndFlush();
+ }
}
- public static IWebHost BuildWebHost(string[] args) =>
+ private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
WebHost.CreateDefaultBuilder(args)
- .UseStartup()
- .ConfigureLogging((hostingContext, builder) =>
- {
- builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
- builder.AddDebug();
- builder.AddConsole();
- })
- .UseSerilog((builderContext, config) =>
- {
- config
- .MinimumLevel.Information()
- .Enrich.FromLogContext()
- .WriteTo.Console();
- })
+ .CaptureStartupErrors(false)
+ .UseStartup()
+ .UseConfiguration(configuration)
+ .UseSerilog()
.Build();
+
+ private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
+ {
+ var seqServerUrl = configuration["Serilog:SeqServerUrl"];
+ var logstashUrl = configuration["Serilog:LogstashgUrl"];
+ return new LoggerConfiguration()
+ .MinimumLevel.Verbose()
+ .Enrich.WithProperty("ApplicationContext", AppName)
+ .Enrich.FromLogContext()
+ .WriteTo.Console()
+ .WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
+ .WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://logstash:8080" : logstashUrl)
+ .ReadFrom.Configuration(configuration)
+ .CreateLogger();
+ }
+
+ private static IConfiguration GetConfiguration()
+ {
+ var builder = new ConfigurationBuilder()
+ .SetBasePath(Directory.GetCurrentDirectory())
+ .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
+ .AddEnvironmentVariables();
+
+ return builder.Build();
+ }
}
}
diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/Startup.cs b/src/Services/Ordering/Ordering.BackgroundTasks/Startup.cs
index 5844a3964..9d6a78e38 100644
--- a/src/Services/Ordering/Ordering.BackgroundTasks/Startup.cs
+++ b/src/Services/Ordering/Ordering.BackgroundTasks/Startup.cs
@@ -68,7 +68,8 @@ namespace Ordering.BackgroundTasks
var factory = new ConnectionFactory()
{
- HostName = Configuration["EventBusConnection"]
+ HostName = Configuration["EventBusConnection"],
+ DispatchConsumersAsync = true
};
if (!string.IsNullOrEmpty(Configuration["EventBusUserName"]))
@@ -103,7 +104,7 @@ namespace Ordering.BackgroundTasks
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
- public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IHostingEnvironment env)
+ public void Configure(IApplicationBuilder app)
{
app.UseHealthChecks("/hc", new HealthCheckOptions()
{
diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/Tasks/GracePeriodManagerTask.cs b/src/Services/Ordering/Ordering.BackgroundTasks/Tasks/GracePeriodManagerTask.cs
index fbf92f978..328fb95c4 100644
--- a/src/Services/Ordering/Ordering.BackgroundTasks/Tasks/GracePeriodManagerTask.cs
+++ b/src/Services/Ordering/Ordering.BackgroundTasks/Tasks/GracePeriodManagerTask.cs
@@ -20,9 +20,10 @@ namespace Ordering.BackgroundTasks.Tasks
private readonly BackgroundTaskSettings _settings;
private readonly IEventBus _eventBus;
- public GracePeriodManagerService(IOptions settings,
- IEventBus eventBus,
- ILogger logger)
+ public GracePeriodManagerService(
+ IOptions settings,
+ IEventBus eventBus,
+ ILogger logger)
{
_settings = settings?.Value ?? throw new ArgumentNullException(nameof(settings));
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
@@ -32,27 +33,27 @@ namespace Ordering.BackgroundTasks.Tasks
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
- _logger.LogDebug($"GracePeriodManagerService is starting.");
+ _logger.LogDebug("GracePeriodManagerService is starting.");
- stoppingToken.Register(() => _logger.LogDebug($"#1 GracePeriodManagerService background task is stopping."));
+ stoppingToken.Register(() => _logger.LogDebug("#1 GracePeriodManagerService background task is stopping."));
while (!stoppingToken.IsCancellationRequested)
{
- _logger.LogDebug($"GracePeriodManagerService background task is doing background work.");
+ _logger.LogDebug("GracePeriodManagerService background task is doing background work.");
CheckConfirmedGracePeriodOrders();
await Task.Delay(_settings.CheckUpdateTime, stoppingToken);
}
- _logger.LogDebug($"GracePeriodManagerService background task is stopping.");
+ _logger.LogDebug("GracePeriodManagerService background task is stopping.");
await Task.CompletedTask;
}
private void CheckConfirmedGracePeriodOrders()
{
- _logger.LogDebug($"Checking confirmed grace period orders");
+ _logger.LogDebug("Checking confirmed grace period orders");
var orderIds = GetConfirmedGracePeriodOrders();
@@ -60,6 +61,8 @@ namespace Ordering.BackgroundTasks.Tasks
{
var confirmGracePeriodEvent = new GracePeriodConfirmedIntegrationEvent(orderId);
+ _logger.LogInformation("----- Publishing integration event: {IntegrationEventId} from {AppName} - ({@IntegrationEvent})", confirmGracePeriodEvent.Id, Program.AppName, confirmGracePeriodEvent);
+
_eventBus.Publish(confirmGracePeriodEvent);
}
}
@@ -81,7 +84,7 @@ namespace Ordering.BackgroundTasks.Tasks
}
catch (SqlException exception)
{
- _logger.LogCritical($"FATAL ERROR: Database connections could not be opened: {exception.Message}");
+ _logger.LogCritical(exception, "FATAL ERROR: Database connections could not be opened: {Message}", exception.Message);
}
}
diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/appsettings.json b/src/Services/Ordering/Ordering.BackgroundTasks/appsettings.json
index fd26645ab..51250be9d 100644
--- a/src/Services/Ordering/Ordering.BackgroundTasks/appsettings.json
+++ b/src/Services/Ordering/Ordering.BackgroundTasks/appsettings.json
@@ -1,15 +1,14 @@
{
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;",
- "Logging": {
- "IncludeScopes": false,
- "Debug": {
- "LogLevel": {
- "Default": "Debug"
- }
- },
- "Console": {
- "LogLevel": {
- "Default": "Debug"
+ "Serilog": {
+ "SeqServerUrl": null,
+ "LogstashgUrl": null,
+ "MinimumLevel": {
+ "Default": "Information",
+ "Override": {
+ "Microsoft": "Warning",
+ "Microsoft.eShopOnContainers": "Information",
+ "System": "Warning"
}
}
},
diff --git a/src/Services/Ordering/Ordering.BackgroundTasks/azds.yaml b/src/Services/Ordering/Ordering.BackgroundTasks/azds.yaml
new file mode 100644
index 000000000..e92eca09f
--- /dev/null
+++ b/src/Services/Ordering/Ordering.BackgroundTasks/azds.yaml
@@ -0,0 +1,56 @@
+kind: helm-release
+apiVersion: 1.1
+build:
+ context: ..\..\..\..
+ dockerfile: Dockerfile
+install:
+ chart: ../../../../k8s/helm/ordering-backgroundtasks
+ set:
+ replicaCount: 1
+ image:
+ tag: $(tag)
+ pullPolicy: Never
+ ingress:
+ annotations:
+ kubernetes.io/ingress.class: traefik-azds
+ hosts:
+ - $(spacePrefix)eshop$(hostSuffix)
+ inf:
+ k8s:
+ dns: $(spacePrefix)eshop$(hostSuffix)
+ values:
+ - values.dev.yaml?
+ - secrets.dev.yaml?
+ - inf.yaml
+ - app.yaml
+configurations:
+ develop:
+ build:
+ useGitIgnore: true
+ dockerfile: Dockerfile.develop
+ args:
+ BUILD_CONFIGURATION: ${BUILD_CONFIGURATION:-Debug}
+ container:
+ sync:
+ - '**/Pages/**'
+ - '**/Views/**'
+ - '**/wwwroot/**'
+ - '!**/*.{sln,csproj}'
+ command:
+ - dotnet
+ - run
+ - --no-restore
+ - --no-build
+ - --no-launch-profile
+ - -c
+ - ${BUILD_CONFIGURATION:-Debug}
+ iterate:
+ processesToKill:
+ - dotnet
+ - vsdbg
+ buildCommands:
+ - - dotnet
+ - build
+ - --no-restore
+ - -c
+ - ${BUILD_CONFIGURATION:-Debug}
diff --git a/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/Buyer.cs b/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/Buyer.cs
index 2fd52917e..1269fd259 100644
--- a/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/Buyer.cs
+++ b/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/Buyer.cs
@@ -32,8 +32,8 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.B
int cardTypeId, string alias, string cardNumber,
string securityNumber, string cardHolderName, DateTime expiration, int orderId)
{
- var existingPayment = _paymentMethods.Where(p => p.IsEqualTo(cardTypeId, cardNumber, expiration))
- .SingleOrDefault();
+ var existingPayment = _paymentMethods
+ .SingleOrDefault(p => p.IsEqualTo(cardTypeId, cardNumber, expiration));
if (existingPayment != null)
{
@@ -41,16 +41,14 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.B
return existingPayment;
}
- else
- {
- var payment = new PaymentMethod(cardTypeId, alias, cardNumber, securityNumber, cardHolderName, expiration);
- _paymentMethods.Add(payment);
+ var payment = new PaymentMethod(cardTypeId, alias, cardNumber, securityNumber, cardHolderName, expiration);
- AddDomainEvent(new BuyerAndPaymentMethodVerifiedDomainEvent(this, payment, orderId));
+ _paymentMethods.Add(payment);
- return payment;
- }
+ AddDomainEvent(new BuyerAndPaymentMethodVerifiedDomainEvent(this, payment, orderId));
+
+ return payment;
}
}
}
diff --git a/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/CardType.cs b/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/CardType.cs
index d6a92892c..3053cb678 100644
--- a/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/CardType.cs
+++ b/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/CardType.cs
@@ -9,31 +9,13 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.B
public class CardType
: Enumeration
{
- public static CardType Amex = new AmexCardType();
- public static CardType Visa = new VisaCardType();
- public static CardType MasterCard = new MasterCardType();
+ public static CardType Amex = new CardType(1, "Amex");
+ public static CardType Visa = new CardType(2, "Visa");
+ public static CardType MasterCard = new CardType(3, "MasterCard");
public CardType(int id, string name)
: base(id, name)
{
}
-
- private class AmexCardType : CardType
- {
- public AmexCardType() : base(1, "Amex")
- { }
- }
-
- private class VisaCardType : CardType
- {
- public VisaCardType() : base(2, "Visa")
- { }
- }
-
- private class MasterCardType : CardType
- {
- public MasterCardType() : base(3, "MasterCard")
- { }
- }
}
}
diff --git a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs
index 99b3154d8..7da025d3a 100644
--- a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs
+++ b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs
@@ -132,7 +132,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
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\"";
+ _description = "The payment was performed at a simulated \"American Bank checking bank account ending on XX35071\"";
}
}
diff --git a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/OrderStatus.cs b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/OrderStatus.cs
index 1716cc32d..19e62311a 100644
--- a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/OrderStatus.cs
+++ b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/OrderStatus.cs
@@ -16,10 +16,6 @@
public static OrderStatus Shipped = new OrderStatus(5, nameof(Shipped).ToLowerInvariant());
public static OrderStatus Cancelled = new OrderStatus(6, nameof(Cancelled).ToLowerInvariant());
- protected OrderStatus()
- {
- }
-
public OrderStatus(int id, string name)
: base(id, name)
{
diff --git a/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj b/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj
index 0baae56b1..f79d76c60 100644
--- a/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj
+++ b/src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj
@@ -7,7 +7,7 @@
-
+
diff --git a/src/Services/Ordering/Ordering.Domain/SeedWork/Enumeration.cs b/src/Services/Ordering/Ordering.Domain/SeedWork/Enumeration.cs
index a1e4c4c7e..d3e415df2 100644
--- a/src/Services/Ordering/Ordering.Domain/SeedWork/Enumeration.cs
+++ b/src/Services/Ordering/Ordering.Domain/SeedWork/Enumeration.cs
@@ -11,9 +11,6 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.SeedWork
public int Id { get; private set; }
- protected Enumeration()
- { }
-
protected Enumeration(int id, string name)
{
Id = id;
diff --git a/src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj b/src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj
index 1568886f0..851a64895 100644
--- a/src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj
+++ b/src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj
@@ -17,10 +17,15 @@
-
+
+
+
-
-
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
diff --git a/src/Services/Ordering/Ordering.FunctionalTests/OrderingScenarios.cs b/src/Services/Ordering/Ordering.FunctionalTests/OrderingScenarios.cs
index b544ea221..9b46e1841 100644
--- a/src/Services/Ordering/Ordering.FunctionalTests/OrderingScenarios.cs
+++ b/src/Services/Ordering/Ordering.FunctionalTests/OrderingScenarios.cs
@@ -3,7 +3,7 @@ using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
-using WebMVC.Models;
+using WebMVC.Services.ModelDTOs;
using Xunit;
namespace Ordering.FunctionalTests
diff --git a/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/BuyerEntityTYpeConfiguration.cs b/src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/BuyerEntityTypeConfiguration.cs
similarity index 100%
rename from src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/BuyerEntityTYpeConfiguration.cs
rename to src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/BuyerEntityTypeConfiguration.cs
diff --git a/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj b/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj
index d57c30031..4f1a74889 100644
--- a/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj
+++ b/src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj
@@ -9,8 +9,8 @@
-
-
+
+
diff --git a/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs b/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs
index ac9ec608f..18e72fe29 100644
--- a/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs
+++ b/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs
@@ -27,10 +27,12 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure
private readonly IMediator _mediator;
private IDbContextTransaction _currentTransaction;
- private OrderingContext(DbContextOptions options) : base (options) { }
+ private OrderingContext(DbContextOptions options) : base(options) { }
public IDbContextTransaction GetCurrentTransaction => _currentTransaction;
+ public bool HasActiveTransaction => _currentTransaction != null;
+
public OrderingContext(DbContextOptions options, IMediator mediator) : base(options)
{
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
@@ -47,7 +49,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure
modelBuilder.ApplyConfiguration(new OrderItemEntityTypeConfiguration());
modelBuilder.ApplyConfiguration(new CardTypeEntityTypeConfiguration());
modelBuilder.ApplyConfiguration(new OrderStatusEntityTypeConfiguration());
- modelBuilder.ApplyConfiguration(new BuyerEntityTypeConfiguration());
+ modelBuilder.ApplyConfiguration(new BuyerEntityTypeConfiguration());
}
public async Task SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken))
@@ -67,17 +69,24 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure
return true;
}
- public async Task BeginTransactionAsync()
+ public async Task BeginTransactionAsync()
{
- _currentTransaction = _currentTransaction ?? await Database.BeginTransactionAsync(IsolationLevel.ReadCommitted);
+ if (_currentTransaction != null) return null;
+
+ _currentTransaction = await Database.BeginTransactionAsync(IsolationLevel.ReadCommitted);
+
+ return _currentTransaction;
}
- public async Task CommitTransactionAsync()
+ public async Task CommitTransactionAsync(IDbContextTransaction transaction)
{
+ if (transaction == null) throw new ArgumentNullException(nameof(transaction));
+ if (transaction != _currentTransaction) throw new InvalidOperationException($"Transaction {transaction.TransactionId} is not current");
+
try
{
await SaveChangesAsync();
- _currentTransaction?.Commit();
+ transaction.Commit();
}
catch
{
@@ -118,7 +127,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure
var optionsBuilder = new DbContextOptionsBuilder()
.UseSqlServer("Server=.;Initial Catalog=Microsoft.eShopOnContainers.Services.OrderingDb;Integrated Security=true");
- return new OrderingContext(optionsBuilder.Options,new NoMediator());
+ return new OrderingContext(optionsBuilder.Options, new NoMediator());
}
class NoMediator : IMediator
diff --git a/src/Services/Ordering/Ordering.SignalrHub/Dockerfile b/src/Services/Ordering/Ordering.SignalrHub/Dockerfile
index 181e3ea0a..a40dc797f 100644
--- a/src/Services/Ordering/Ordering.SignalrHub/Dockerfile
+++ b/src/Services/Ordering/Ordering.SignalrHub/Dockerfile
@@ -1,16 +1,26 @@
-FROM microsoft/dotnet:2.2.0-aspnetcore-runtime AS base
+FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80
-FROM microsoft/dotnet:2.2.100-sdk AS build
+FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
WORKDIR /src
+
+COPY scripts scripts/
+
+COPY src/ApiGateways/*/*.csproj /src/csproj-files/
+COPY src/ApiGateways/*/*/*.csproj /src/csproj-files/
+COPY src/BuildingBlocks/*/*/*.csproj /src/csproj-files/
+COPY src/Services/*/*/*.csproj /src/csproj-files/
+COPY src/Web/*/*.csproj /src/csproj-files/
+
+ARG RUN=pwd
+RUN ${RUN}
+
COPY . .
WORKDIR /src/src/Services/Ordering/Ordering.SignalrHub
-RUN dotnet restore -nowarn:msb3202,nu1503
-RUN dotnet build --no-restore Ordering.SignalrHub.csproj -c Release -o /app
+RUN dotnet publish -c Release -o /app
FROM build AS publish
-RUN dotnet publish --no-restore Ordering.SignalrHub.csproj -c Release -o /app
FROM base AS final
WORKDIR /app
diff --git a/src/Services/Ordering/Ordering.SignalrHub/Dockerfile.develop b/src/Services/Ordering/Ordering.SignalrHub/Dockerfile.develop
new file mode 100644
index 000000000..d96223149
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/Dockerfile.develop
@@ -0,0 +1,18 @@
+FROM microsoft/dotnet:2.2-sdk
+ARG BUILD_CONFIGURATION=Debug
+ENV ASPNETCORE_ENVIRONMENT=Development
+ENV DOTNET_USE_POLLING_FILE_WATCHER=true
+EXPOSE 80
+
+WORKDIR /src
+COPY ["src/BuildingBlocks/EventBus/EventBus/EventBus.csproj", "src/BuildingBlocks/EventBus/EventBus/"]
+COPY ["src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "src/BuildingBlocks/EventBus/EventBusRabbitMQ/"]
+COPY ["src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "src/BuildingBlocks/EventBus/EventBusServiceBus/"]
+COPY ["src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj", "src/Services/Ordering/Ordering.SignalrHub/"]
+
+RUN dotnet restore src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj
+COPY . .
+WORKDIR /src/src/Services/Ordering/Ordering.SignalrHub
+RUN dotnet build --no-restore -c $BUILD_CONFIGURATION
+
+ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"]
\ No newline at end of file
diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToAwaitingValidationIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToAwaitingValidationIntegrationEventHandler.cs
new file mode 100644
index 000000000..0e2665232
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToAwaitingValidationIntegrationEventHandler.cs
@@ -0,0 +1,38 @@
+using Microsoft.AspNetCore.SignalR;
+using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
+using Microsoft.Extensions.Logging;
+using Serilog.Context;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Ordering.SignalrHub.IntegrationEvents
+{
+ public class OrderStatusChangedToAwaitingValidationIntegrationEventHandler : IIntegrationEventHandler
+ {
+ private readonly IHubContext _hubContext;
+ private readonly ILogger _logger;
+
+ public OrderStatusChangedToAwaitingValidationIntegrationEventHandler(
+ IHubContext hubContext,
+ ILogger logger)
+ {
+ _hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ }
+
+
+ public async Task Handle(OrderStatusChangedToAwaitingValidationIntegrationEvent @event)
+ {
+ using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
+ {
+ _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
+
+ await _hubContext.Clients
+ .Group(@event.BuyerName)
+ .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
+ }
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToCancelledIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToCancelledIntegrationEventHandler.cs
index 171eb81f7..6257bb237 100644
--- a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToCancelledIntegrationEventHandler.cs
+++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToCancelledIntegrationEventHandler.cs
@@ -1,6 +1,8 @@
using Microsoft.AspNetCore.SignalR;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
+using Microsoft.Extensions.Logging;
using Ordering.SignalrHub.IntegrationEvents.Events;
+using Serilog.Context;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -11,18 +13,27 @@ namespace Ordering.SignalrHub.IntegrationEvents.EventHandling
public class OrderStatusChangedToCancelledIntegrationEventHandler : IIntegrationEventHandler
{
private readonly IHubContext _hubContext;
+ private readonly ILogger _logger;
- public OrderStatusChangedToCancelledIntegrationEventHandler(IHubContext hubContext)
+ public OrderStatusChangedToCancelledIntegrationEventHandler(
+ IHubContext hubContext,
+ ILogger logger)
{
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task Handle(OrderStatusChangedToCancelledIntegrationEvent @event)
{
- await _hubContext.Clients
- .Group(@event.BuyerName)
- .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
+ using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
+ {
+ _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
+
+ await _hubContext.Clients
+ .Group(@event.BuyerName)
+ .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs
index 4b0eb780c..836e02d3c 100644
--- a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs
+++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs
@@ -1,6 +1,8 @@
using Microsoft.AspNetCore.SignalR;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
+using Microsoft.Extensions.Logging;
using Ordering.SignalrHub.IntegrationEvents.Events;
+using Serilog.Context;
using System;
using System.Threading.Tasks;
@@ -9,18 +11,27 @@ namespace Ordering.SignalrHub.IntegrationEvents.EventHandling
public class OrderStatusChangedToPaidIntegrationEventHandler : IIntegrationEventHandler
{
private readonly IHubContext _hubContext;
+ private readonly ILogger _logger;
- public OrderStatusChangedToPaidIntegrationEventHandler(IHubContext hubContext)
+ public OrderStatusChangedToPaidIntegrationEventHandler(
+ IHubContext hubContext,
+ ILogger logger)
{
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task Handle(OrderStatusChangedToPaidIntegrationEvent @event)
{
- await _hubContext.Clients
- .Group(@event.BuyerName)
- .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
+ using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
+ {
+ _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
+
+ await _hubContext.Clients
+ .Group(@event.BuyerName)
+ .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
+ }
}
}
}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToShippedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToShippedIntegrationEventHandler.cs
index 7a19a0659..5b08d08b4 100644
--- a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToShippedIntegrationEventHandler.cs
+++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToShippedIntegrationEventHandler.cs
@@ -1,6 +1,8 @@
using Microsoft.AspNetCore.SignalR;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
+using Microsoft.Extensions.Logging;
using Ordering.SignalrHub.IntegrationEvents.Events;
+using Serilog.Context;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -11,18 +13,27 @@ namespace Ordering.SignalrHub.IntegrationEvents.EventHandling
public class OrderStatusChangedToShippedIntegrationEventHandler : IIntegrationEventHandler
{
private readonly IHubContext _hubContext;
+ private readonly ILogger _logger;
- public OrderStatusChangedToShippedIntegrationEventHandler(IHubContext hubContext)
+ public OrderStatusChangedToShippedIntegrationEventHandler(
+ IHubContext hubContext,
+ ILogger logger)
{
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task Handle(OrderStatusChangedToShippedIntegrationEvent @event)
{
- await _hubContext.Clients
- .Group(@event.BuyerName)
- .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
+ using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
+ {
+ _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
+
+ await _hubContext.Clients
+ .Group(@event.BuyerName)
+ .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
+ }
}
}
}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs
index 324ea6259..348627716 100644
--- a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs
+++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs
@@ -1,6 +1,8 @@
using Microsoft.AspNetCore.SignalR;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
+using Microsoft.Extensions.Logging;
using Ordering.SignalrHub.IntegrationEvents.Events;
+using Serilog.Context;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -12,18 +14,27 @@ namespace Ordering.SignalrHub.IntegrationEvents.EventHandling
IIntegrationEventHandler
{
private readonly IHubContext _hubContext;
+ private readonly ILogger _logger;
- public OrderStatusChangedToStockConfirmedIntegrationEventHandler(IHubContext hubContext)
+ public OrderStatusChangedToStockConfirmedIntegrationEventHandler(
+ IHubContext hubContext,
+ ILogger logger)
{
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task Handle(OrderStatusChangedToStockConfirmedIntegrationEvent @event)
{
- await _hubContext.Clients
- .Group(@event.BuyerName)
- .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
+ using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
+ {
+ _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
+
+ await _hubContext.Clients
+ .Group(@event.BuyerName)
+ .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
+ }
}
}
}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToSubmittedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToSubmittedIntegrationEventHandler.cs
index 5fac4c1da..422bc4a7a 100644
--- a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToSubmittedIntegrationEventHandler.cs
+++ b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToSubmittedIntegrationEventHandler.cs
@@ -1,6 +1,8 @@
using Microsoft.AspNetCore.SignalR;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
+using Microsoft.Extensions.Logging;
using Ordering.SignalrHub.IntegrationEvents.Events;
+using Serilog.Context;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -12,18 +14,27 @@ namespace Ordering.SignalrHub.IntegrationEvents.EventHandling
IIntegrationEventHandler
{
private readonly IHubContext _hubContext;
+ private readonly ILogger _logger;
- public OrderStatusChangedToSubmittedIntegrationEventHandler(IHubContext hubContext)
+ public OrderStatusChangedToSubmittedIntegrationEventHandler(
+ IHubContext hubContext,
+ ILogger logger)
{
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task Handle(OrderStatusChangedToSubmittedIntegrationEvent @event)
{
- await _hubContext.Clients
- .Group(@event.BuyerName)
- .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
+ using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
+ {
+ _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
+
+ await _hubContext.Clients
+ .Group(@event.BuyerName)
+ .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/orderStatusChangedToAwaitingValidationIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/orderStatusChangedToAwaitingValidationIntegrationEventHandler.cs
deleted file mode 100644
index 6c2733b77..000000000
--- a/src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/orderStatusChangedToAwaitingValidationIntegrationEventHandler.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using Microsoft.AspNetCore.SignalR;
-using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-
-namespace Ordering.SignalrHub.IntegrationEvents
-{
- public class OrderStatusChangedToAwaitingValidationIntegrationEventHandler : IIntegrationEventHandler
- {
- private readonly IHubContext _hubContext;
-
- public OrderStatusChangedToAwaitingValidationIntegrationEventHandler(IHubContext hubContext)
- {
- _hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
- }
-
-
- public async Task Handle(OrderStatusChangedToAwaitingValidationIntegrationEvent @event)
- {
- await _hubContext.Clients
- .Group(@event.BuyerName)
- .SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
- }
- }
-}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/NotificationHub.cs b/src/Services/Ordering/Ordering.SignalrHub/NotificationHub.cs
index 5fd6f3eb9..943198980 100644
--- a/src/Services/Ordering/Ordering.SignalrHub/NotificationHub.cs
+++ b/src/Services/Ordering/Ordering.SignalrHub/NotificationHub.cs
@@ -19,7 +19,7 @@ namespace Ordering.SignalrHub
public override async Task OnDisconnectedAsync(Exception ex)
{
- await Groups.AddToGroupAsync(Context.ConnectionId, Context.User.Identity.Name);
+ await Groups.RemoveFromGroupAsync(Context.ConnectionId, Context.User.Identity.Name);
await base.OnDisconnectedAsync(ex);
}
}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj b/src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj
index dfc6a45c3..00d70cbe6 100644
--- a/src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj
+++ b/src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj
@@ -11,23 +11,26 @@
-
+
-
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
diff --git a/src/Services/Ordering/Ordering.SignalrHub/Program.cs b/src/Services/Ordering/Ordering.SignalrHub/Program.cs
index e8550dcc8..76f131caa 100644
--- a/src/Services/Ordering/Ordering.SignalrHub/Program.cs
+++ b/src/Services/Ordering/Ordering.SignalrHub/Program.cs
@@ -13,21 +13,68 @@ namespace Ordering.SignalrHub
{
public class Program
{
- public static void Main(string[] args)
+ public static readonly string Namespace = typeof(Program).Namespace;
+ public static readonly string AppName = Namespace;
+
+ public static int Main(string[] args)
{
- BuildWebHost(args).Run();
+ var configuration = GetConfiguration();
+
+ Log.Logger = CreateSerilogLogger(configuration);
+
+ try
+ {
+ Log.Information("Configuring web host ({ApplicationContext})...", AppName);
+ var host = BuildWebHost(configuration, args);
+
+ Log.Information("Starting web host ({ApplicationContext})...", AppName);
+ host.Run();
+
+ return 0;
+ }
+ catch (Exception ex)
+ {
+ Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
+ return 1;
+ }
+ finally
+ {
+ Log.CloseAndFlush();
+ }
}
- public static IWebHost BuildWebHost(string[] args) =>
+ private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
WebHost.CreateDefaultBuilder(args)
+ .CaptureStartupErrors(false)
.UseStartup()
- .UseSerilog((builderContext, config) =>
- {
- config
- .MinimumLevel.Information()
- .Enrich.FromLogContext()
- .WriteTo.Console();
- })
+ .UseConfiguration(configuration)
+ .UseSerilog()
.Build();
+
+ private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
+ {
+ var seqServerUrl = configuration["Serilog:SeqServerUrl"];
+ var logstashUrl = configuration["Serilog:LogstashgUrl"];
+ return new LoggerConfiguration()
+ .MinimumLevel.Verbose()
+ .Enrich.WithProperty("ApplicationContext", AppName)
+ .Enrich.FromLogContext()
+ .WriteTo.Console()
+ .WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
+ .WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://logstash:8080" : logstashUrl)
+ .ReadFrom.Configuration(configuration)
+ .CreateLogger();
+ }
+
+ private static IConfiguration GetConfiguration()
+ {
+ var builder = new ConfigurationBuilder()
+ .SetBasePath(Directory.GetCurrentDirectory())
+ .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
+ .AddEnvironmentVariables();
+
+ return builder.Build();
+ }
+
}
}
diff --git a/src/Services/Ordering/Ordering.SignalrHub/Startup.cs b/src/Services/Ordering/Ordering.SignalrHub/Startup.cs
index 555606a67..edcc80521 100644
--- a/src/Services/Ordering/Ordering.SignalrHub/Startup.cs
+++ b/src/Services/Ordering/Ordering.SignalrHub/Startup.cs
@@ -30,6 +30,8 @@ namespace Ordering.SignalrHub
Configuration = configuration;
}
+ public IConfiguration Configuration { get; }
+
// 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)
@@ -78,7 +80,8 @@ namespace Ordering.SignalrHub
var factory = new ConnectionFactory()
{
- HostName = Configuration["EventBusConnection"]
+ HostName = Configuration["EventBusConnection"],
+ DispatchConsumersAsync = true
};
if (!string.IsNullOrEmpty(Configuration["EventBusUserName"]))
@@ -115,20 +118,18 @@ namespace Ordering.SignalrHub
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);
+ //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}'");
+ loggerFactory.CreateLogger().LogDebug("Using PATH BASE '{pathBase}'", pathBase);
app.UsePathBase(pathBase);
}
@@ -159,13 +160,13 @@ namespace Ordering.SignalrHub
private void ConfigureEventBus(IApplicationBuilder app)
{
var eventBus = app.ApplicationServices.GetRequiredService();
-
+
eventBus.Subscribe();
eventBus.Subscribe();
eventBus.Subscribe();
eventBus.Subscribe();
eventBus.Subscribe();
- eventBus.Subscribe();
+ eventBus.Subscribe();
}
private void ConfigureAuthService(IServiceCollection services)
diff --git a/src/Services/Ordering/Ordering.SignalrHub/appsettings.json b/src/Services/Ordering/Ordering.SignalrHub/appsettings.json
index ab02fda0f..e43c354a3 100644
--- a/src/Services/Ordering/Ordering.SignalrHub/appsettings.json
+++ b/src/Services/Ordering/Ordering.SignalrHub/appsettings.json
@@ -1,11 +1,15 @@
{
"IdentityUrl": "http://localhost:5105",
- "Logging": {
- "IncludeScopes": false,
- "LogLevel": {
- "Default": "Trace",
- "System": "Information",
- "Microsoft": "Information"
+ "Serilog": {
+ "SeqServerUrl": null,
+ "LogstashgUrl": null,
+ "MinimumLevel": {
+ "Default": "Information",
+ "Override": {
+ "Microsoft": "Warning",
+ "Microsoft.eShopOnContainers": "Information",
+ "System": "Warning"
+ }
}
},
"AzureServiceBusEnabled": false,
diff --git a/src/Services/Ordering/Ordering.SignalrHub/azds.yaml b/src/Services/Ordering/Ordering.SignalrHub/azds.yaml
new file mode 100644
index 000000000..a98526394
--- /dev/null
+++ b/src/Services/Ordering/Ordering.SignalrHub/azds.yaml
@@ -0,0 +1,56 @@
+kind: helm-release
+apiVersion: 1.1
+build:
+ context: ..\..\..\..
+ dockerfile: Dockerfile
+install:
+ chart: ../../../../k8s/helm/ordering-signalrhub
+ set:
+ replicaCount: 1
+ image:
+ tag: $(tag)
+ pullPolicy: Never
+ ingress:
+ annotations:
+ kubernetes.io/ingress.class: traefik-azds
+ hosts:
+ - $(spacePrefix)eshop$(hostSuffix)
+ inf:
+ k8s:
+ dns: $(spacePrefix)eshop$(hostSuffix)
+ values:
+ - values.dev.yaml?
+ - secrets.dev.yaml?
+ - inf.yaml
+ - app.yaml
+configurations:
+ develop:
+ build:
+ useGitIgnore: true
+ dockerfile: Dockerfile.develop
+ args:
+ BUILD_CONFIGURATION: ${BUILD_CONFIGURATION:-Debug}
+ container:
+ sync:
+ - '**/Pages/**'
+ - '**/Views/**'
+ - '**/wwwroot/**'
+ - '!**/*.{sln,csproj}'
+ command:
+ - dotnet
+ - run
+ - --no-restore
+ - --no-build
+ - --no-launch-profile
+ - -c
+ - ${BUILD_CONFIGURATION:-Debug}
+ iterate:
+ processesToKill:
+ - dotnet
+ - vsdbg
+ buildCommands:
+ - - dotnet
+ - build
+ - --no-restore
+ - -c
+ - ${BUILD_CONFIGURATION:-Debug}
diff --git a/src/Services/Ordering/Ordering.UnitTests/Application/IdentifiedCommandHandlerTest.cs b/src/Services/Ordering/Ordering.UnitTests/Application/IdentifiedCommandHandlerTest.cs
index e0f861017..95bc4cc81 100644
--- a/src/Services/Ordering/Ordering.UnitTests/Application/IdentifiedCommandHandlerTest.cs
+++ b/src/Services/Ordering/Ordering.UnitTests/Application/IdentifiedCommandHandlerTest.cs
@@ -8,6 +8,7 @@ namespace UnitTest.Ordering.Application
using MediatR;
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
+ using Microsoft.Extensions.Logging;
using Moq;
using System.Collections;
using System.Collections.Generic;
@@ -17,11 +18,13 @@ namespace UnitTest.Ordering.Application
{
private readonly Mock _requestManager;
private readonly Mock _mediator;
+ private readonly Mock>> _loggerMock;
public IdentifiedCommandHandlerTest()
{
_requestManager = new Mock();
_mediator = new Mock();
+ _loggerMock = new Mock>>();
}
[Fact]
@@ -38,7 +41,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(true));
//Act
- var handler = new IdentifiedCommandHandler(_mediator.Object, _requestManager.Object);
+ var handler = new IdentifiedCommandHandler(_mediator.Object, _requestManager.Object, _loggerMock.Object);
var cltToken = new System.Threading.CancellationToken();
var result = await handler.Handle(fakeOrderCmd, cltToken);
@@ -61,7 +64,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(true));
//Act
- var handler = new IdentifiedCommandHandler(_mediator.Object, _requestManager.Object);
+ var handler = new IdentifiedCommandHandler(_mediator.Object, _requestManager.Object, _loggerMock.Object);
var cltToken = new System.Threading.CancellationToken();
var result = await handler.Handle(fakeOrderCmd, cltToken);
diff --git a/src/Services/Ordering/Ordering.UnitTests/Application/NewOrderCommandHandlerTest.cs b/src/Services/Ordering/Ordering.UnitTests/Application/NewOrderCommandHandlerTest.cs
index 80a0deb25..77fede857 100644
--- a/src/Services/Ordering/Ordering.UnitTests/Application/NewOrderCommandHandlerTest.cs
+++ b/src/Services/Ordering/Ordering.UnitTests/Application/NewOrderCommandHandlerTest.cs
@@ -13,6 +13,7 @@ namespace UnitTest.Ordering.Application
using global::Ordering.API.Application.IntegrationEvents;
using global::Ordering.API.Application.Models;
using MediatR;
+ using Microsoft.Extensions.Logging;
using System.Collections;
using System.Collections.Generic;
using Xunit;
@@ -50,8 +51,9 @@ namespace UnitTest.Ordering.Application
_identityServiceMock.Setup(svc => svc.GetUserIdentity()).Returns(buyerId);
+ var LoggerMock = new Mock>();
//Act
- var handler = new CreateOrderCommandHandler(_mediator.Object, _orderingIntegrationEventService.Object, _orderRepositoryMock.Object, _identityServiceMock.Object);
+ var handler = new CreateOrderCommandHandler(_mediator.Object, _orderingIntegrationEventService.Object, _orderRepositoryMock.Object, _identityServiceMock.Object, LoggerMock.Object);
var cltToken = new System.Threading.CancellationToken();
var result = await handler.Handle(fakeOrderCmd, cltToken);
diff --git a/src/Services/Ordering/Ordering.UnitTests/Application/OrderControllerTest.cs b/src/Services/Ordering/Ordering.UnitTests/Application/OrderControllerTest.cs
deleted file mode 100644
index a60ce3bb3..000000000
--- a/src/Services/Ordering/Ordering.UnitTests/Application/OrderControllerTest.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.eShopOnContainers.WebMVC.Controllers;
-using Microsoft.eShopOnContainers.WebMVC.Services;
-using Microsoft.eShopOnContainers.WebMVC.ViewModels;
-using Moq;
-using System;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using Xunit;
-using BasketModel = Microsoft.eShopOnContainers.WebMVC.ViewModels.Basket;
-
-namespace UnitTest.Ordering.Application
-{
- public class OrderControllerTest
- {
- private readonly Mock _orderServiceMock;
- private readonly Mock _basketServiceMock;
- private readonly Mock> _identityParserMock;
- private readonly Mock _contextMock;
-
- public OrderControllerTest()
- {
- _orderServiceMock = new Mock();
- _basketServiceMock = new Mock();
- _identityParserMock = new Mock>();
- _contextMock = new Mock();
- }
-
- [Fact]
- public async Task Get_order_list_success()
- {
- //Arrange
- var expectedTotalResults = 1;
- var fakeOrder = GetFakeOrder();
-
- _orderServiceMock.Setup(x => x.GetMyOrders(It.IsAny()))
- .Returns(Task.FromResult(new List() { fakeOrder }));
-
- //Act
- var orderController = new OrderController(_orderServiceMock.Object, _basketServiceMock.Object, _identityParserMock.Object);
- orderController.ControllerContext.HttpContext = _contextMock.Object;
- var actionResult = await orderController.Index(fakeOrder);
-
- //Assert
- var viewResult = Assert.IsType(actionResult);
- var model = Assert.IsAssignableFrom>(viewResult.ViewData.Model);
- Assert.Equal(model.Count, expectedTotalResults);
- }
-
- [Fact]
- public async Task Get_order_detail_success()
- {
- //Arrange
- var fakeOrderId = "12";
- var fakeOrder = GetFakeOrder();
-
- _orderServiceMock.Setup(x => x.GetOrder(It.IsAny(), It.IsAny()))
- .Returns(Task.FromResult(fakeOrder));
-
- //Act
- var orderController = new OrderController(_orderServiceMock.Object, _basketServiceMock.Object, _identityParserMock.Object);
- orderController.ControllerContext.HttpContext = _contextMock.Object;
- var actionResult = await orderController.Detail(fakeOrderId);
-
- //Assert
- var viewResult = Assert.IsType(actionResult);
- Assert.IsAssignableFrom(viewResult.ViewData.Model);
- }
-
-
-
- private Order GetFakeOrder()
- {
- return new Order()
- {
- OrderNumber = "1",
- CardNumber = "12",
- CardSecurityNumber = "1212",
- Status = "Pending",
- RequestId = Guid.NewGuid(),
- CardExpiration = DateTime.Now.AddYears(1),
- };
- }
- }
-}
diff --git a/src/Services/Ordering/Ordering.UnitTests/Application/OrdersWebApiTest.cs b/src/Services/Ordering/Ordering.UnitTests/Application/OrdersWebApiTest.cs
index c5b8a1764..b19a764e9 100644
--- a/src/Services/Ordering/Ordering.UnitTests/Application/OrdersWebApiTest.cs
+++ b/src/Services/Ordering/Ordering.UnitTests/Application/OrdersWebApiTest.cs
@@ -4,6 +4,7 @@ using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries;
using Microsoft.eShopOnContainers.Services.Ordering.API.Controllers;
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
+using Microsoft.Extensions.Logging;
using Moq;
using Ordering.API.Application.Commands;
using System;
@@ -19,12 +20,14 @@ namespace UnitTest.Ordering.Application
private readonly Mock _mediatorMock;
private readonly Mock _orderQueriesMock;
private readonly Mock _identityServiceMock;
+ private readonly Mock> _loggerMock;
public OrdersWebApiTest()
{
_mediatorMock = new Mock();
_orderQueriesMock = new Mock();
_identityServiceMock = new Mock();
+ _loggerMock = new Mock>();
}
[Fact]
@@ -35,7 +38,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(true));
//Act
- var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
+ var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _loggerMock.Object);
var actionResult = await orderController.CancelOrderAsync(new CancelOrderCommand(1), Guid.NewGuid().ToString()) as OkResult;
//Assert
@@ -51,7 +54,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(true));
//Act
- var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
+ var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _loggerMock.Object);
var actionResult = await orderController.CancelOrderAsync(new CancelOrderCommand(1), String.Empty) as BadRequestResult;
//Assert
@@ -66,7 +69,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(true));
//Act
- var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
+ var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _loggerMock.Object);
var actionResult = await orderController.ShipOrderAsync(new ShipOrderCommand(1), Guid.NewGuid().ToString()) as OkResult;
//Assert
@@ -82,7 +85,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(true));
//Act
- var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
+ var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _loggerMock.Object);
var actionResult = await orderController.ShipOrderAsync(new ShipOrderCommand(1), String.Empty) as BadRequestResult;
//Assert
@@ -102,7 +105,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(fakeDynamicResult));
//Act
- var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
+ var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _loggerMock.Object);
var actionResult = await orderController.GetOrdersAsync();
//Assert
@@ -119,7 +122,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(fakeDynamicResult));
//Act
- var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
+ var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _loggerMock.Object);
var actionResult = await orderController.GetOrderAsync(fakeOrderId) as OkObjectResult;
//Assert
@@ -135,7 +138,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(fakeDynamicResult));
//Act
- var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
+ var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _loggerMock.Object);
var actionResult = await orderController.GetCardTypesAsync();
//Assert
diff --git a/src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj b/src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj
index 04b155b65..e94aae4f1 100644
--- a/src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj
+++ b/src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj
@@ -7,16 +7,18 @@
-
-
-
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
-
+
-
diff --git a/src/Services/Payment/Payment.API/Dockerfile b/src/Services/Payment/Payment.API/Dockerfile
index cfa9a02de..dcaf9b5e8 100644
--- a/src/Services/Payment/Payment.API/Dockerfile
+++ b/src/Services/Payment/Payment.API/Dockerfile
@@ -1,16 +1,26 @@
-FROM microsoft/dotnet:2.2.0-aspnetcore-runtime AS base
+FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80
-FROM microsoft/dotnet:2.2.100-sdk AS build
+FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
WORKDIR /src
+
+COPY scripts scripts/
+
+COPY src/ApiGateways/*/*.csproj /src/csproj-files/
+COPY src/ApiGateways/*/*/*.csproj /src/csproj-files/
+COPY src/BuildingBlocks/*/*/*.csproj /src/csproj-files/
+COPY src/Services/*/*/*.csproj /src/csproj-files/
+COPY src/Web/*/*.csproj /src/csproj-files/
+
+ARG RUN=pwd
+RUN ${RUN}
+
COPY . .
WORKDIR /src/src/Services/Payment/Payment.API
-RUN dotnet restore -nowarn:msb3202,nu1503
-RUN dotnet build --no-restore -c Release -o /app
+RUN dotnet publish -c Release -o /app
FROM build AS publish
-RUN dotnet publish --no-restore -c Release -o /app
FROM base AS final
WORKDIR /app
diff --git a/src/Services/Payment/Payment.API/Dockerfile.develop b/src/Services/Payment/Payment.API/Dockerfile.develop
new file mode 100644
index 000000000..4b959f4b3
--- /dev/null
+++ b/src/Services/Payment/Payment.API/Dockerfile.develop
@@ -0,0 +1,19 @@
+FROM microsoft/dotnet:2.2-sdk
+ARG BUILD_CONFIGURATION=Debug
+ENV ASPNETCORE_ENVIRONMENT=Development
+ENV DOTNET_USE_POLLING_FILE_WATCHER=true
+EXPOSE 80
+
+WORKDIR /src
+COPY ["src/BuildingBlocks/EventBus/EventBus/EventBus.csproj", "src/BuildingBlocks/EventBus/EventBus/"]
+COPY ["src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "src/BuildingBlocks/EventBus/EventBusRabbitMQ/"]
+COPY ["src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "src/BuildingBlocks/EventBus/EventBusServiceBus/"]
+COPY ["src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj", "src/BuildingBlocks/EventBus/IntegrationEventLogEF/"]
+COPY ["src/Services/Payment/Payment.API/Payment.API.csproj", "src/Services/Payment/Payment.API/"]
+
+RUN dotnet restore src/Services/Payment/Payment.API/Payment.API.csproj
+COPY . .
+WORKDIR /src/src/Services/Payment/Payment.API
+RUN dotnet build --no-restore -c $BUILD_CONFIGURATION
+
+ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"]
\ No newline at end of file
diff --git a/src/Services/Payment/Payment.API/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs b/src/Services/Payment/Payment.API/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs
index c70a32093..b26d64d40 100644
--- a/src/Services/Payment/Payment.API/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs
+++ b/src/Services/Payment/Payment.API/IntegrationEvents/EventHandling/OrderStatusChangedToStockConfirmedIntegrationEventHandler.cs
@@ -2,45 +2,58 @@
{
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
+ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Payment.API.IntegrationEvents.Events;
+ using Serilog.Context;
using System.Threading.Tasks;
- public class OrderStatusChangedToStockConfirmedIntegrationEventHandler :
+ public class OrderStatusChangedToStockConfirmedIntegrationEventHandler :
IIntegrationEventHandler
{
private readonly IEventBus _eventBus;
private readonly PaymentSettings _settings;
+ private readonly ILogger _logger;
- public OrderStatusChangedToStockConfirmedIntegrationEventHandler(IEventBus eventBus,
- IOptionsSnapshot settings)
+ public OrderStatusChangedToStockConfirmedIntegrationEventHandler(
+ IEventBus eventBus,
+ IOptionsSnapshot settings,
+ ILogger logger)
{
_eventBus = eventBus;
_settings = settings.Value;
- }
+ _logger = logger ?? throw new System.ArgumentNullException(nameof(logger));
+ }
public async Task Handle(OrderStatusChangedToStockConfirmedIntegrationEvent @event)
{
- IntegrationEvent orderPaymentIntegrationEvent;
+ using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
+ {
+ _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
- //Business feature comment:
- // When OrderStatusChangedToStockConfirmed Integration Event is handled.
- // Here we're simulating that we'd be performing the payment against any payment gateway
- // Instead of a real payment we just take the env. var to simulate the payment
- // The payment can be successful or it can fail
+ IntegrationEvent orderPaymentIntegrationEvent;
- if (_settings.PaymentSucceded)
- {
- orderPaymentIntegrationEvent = new OrderPaymentSuccededIntegrationEvent(@event.OrderId);
- }
- else
- {
- orderPaymentIntegrationEvent = new OrderPaymentFailedIntegrationEvent(@event.OrderId);
- }
+ //Business feature comment:
+ // When OrderStatusChangedToStockConfirmed Integration Event is handled.
+ // Here we're simulating that we'd be performing the payment against any payment gateway
+ // Instead of a real payment we just take the env. var to simulate the payment
+ // The payment can be successful or it can fail
+
+ if (_settings.PaymentSucceded)
+ {
+ orderPaymentIntegrationEvent = new OrderPaymentSuccededIntegrationEvent(@event.OrderId);
+ }
+ else
+ {
+ orderPaymentIntegrationEvent = new OrderPaymentFailedIntegrationEvent(@event.OrderId);
+ }
- _eventBus.Publish(orderPaymentIntegrationEvent);
+ _logger.LogInformation("----- Publishing integration event: {IntegrationEventId} from {AppName} - ({@IntegrationEvent})", orderPaymentIntegrationEvent.Id, Program.AppName, orderPaymentIntegrationEvent);
- await Task.CompletedTask;
+ _eventBus.Publish(orderPaymentIntegrationEvent);
+
+ await Task.CompletedTask;
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Services/Payment/Payment.API/Payment.API.csproj b/src/Services/Payment/Payment.API/Payment.API.csproj
index 73aa4363e..efce8b8ab 100644
--- a/src/Services/Payment/Payment.API/Payment.API.csproj
+++ b/src/Services/Payment/Payment.API/Payment.API.csproj
@@ -7,20 +7,24 @@
-
+
-
-
+
+
+
-
-
-
+
+
+
+
+
+
diff --git a/src/Services/Payment/Payment.API/Program.cs b/src/Services/Payment/Payment.API/Program.cs
index 0b8c5e025..b03bee3da 100644
--- a/src/Services/Payment/Payment.API/Program.cs
+++ b/src/Services/Payment/Payment.API/Program.cs
@@ -4,39 +4,86 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Serilog;
+using System;
using System.IO;
namespace Payment.API
{
public class Program
{
- public static void Main(string[] args)
+ public static readonly string Namespace = typeof(Program).Namespace;
+ public static readonly string AppName = Namespace;
+
+ public static int Main(string[] args)
{
- BuildWebHost(args).Run();
+ var configuration = GetConfiguration();
+
+ Log.Logger = CreateSerilogLogger(configuration);
+
+ try
+ {
+ Log.Information("Configuring web host ({ApplicationContext})...", AppName);
+ var host = BuildWebHost(configuration, args);
+
+ Log.Information("Starting web host ({ApplicationContext})...", AppName);
+ host.Run();
+
+ return 0;
+ }
+ catch (Exception ex)
+ {
+ Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
+ return 1;
+ }
+ finally
+ {
+ Log.CloseAndFlush();
+ }
}
- public static IWebHost BuildWebHost(string[] args) =>
+ private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
WebHost.CreateDefaultBuilder(args)
- .UseContentRoot(Directory.GetCurrentDirectory())
+ .CaptureStartupErrors(false)
.UseStartup()
- .ConfigureAppConfiguration((builderContext, config) =>
- {
- config.AddEnvironmentVariables();
- })
- .ConfigureLogging((hostingContext, builder) =>
- {
- builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
- builder.AddConsole();
- builder.AddDebug();
- })
.UseApplicationInsights()
- .UseSerilog((builderContext, config) =>
- {
- config
- .MinimumLevel.Information()
- .Enrich.FromLogContext()
- .WriteTo.Console();
- })
+ .UseContentRoot(Directory.GetCurrentDirectory())
+ .UseConfiguration(configuration)
+ .UseSerilog()
.Build();
+
+ private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
+ {
+ var seqServerUrl = configuration["Serilog:SeqServerUrl"];
+ var logstashUrl = configuration["Serilog:LogstashgUrl"];
+ return new LoggerConfiguration()
+ .MinimumLevel.Verbose()
+ .Enrich.WithProperty("ApplicationContext", AppName)
+ .Enrich.FromLogContext()
+ .WriteTo.Console()
+ .WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
+ .WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://logstash:8080" : logstashUrl)
+ .ReadFrom.Configuration(configuration)
+ .CreateLogger();
+ }
+
+ private static IConfiguration GetConfiguration()
+ {
+ var builder = new ConfigurationBuilder()
+ .SetBasePath(Directory.GetCurrentDirectory())
+ .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
+ .AddEnvironmentVariables();
+
+ var config = builder.Build();
+
+ if (config.GetValue("UseVault", false))
+ {
+ builder.AddAzureKeyVault(
+ $"https://{config["Vault:Name"]}.vault.azure.net/",
+ config["Vault:ClientId"],
+ config["Vault:ClientSecret"]);
+ }
+
+ return builder.Build();
+ }
}
-}
+}
\ No newline at end of file
diff --git a/src/Services/Payment/Payment.API/Startup.cs b/src/Services/Payment/Payment.API/Startup.cs
index 5241fc1c7..39bb78f91 100644
--- a/src/Services/Payment/Payment.API/Startup.cs
+++ b/src/Services/Payment/Payment.API/Startup.cs
@@ -58,7 +58,8 @@ namespace Payment.API
var logger = sp.GetRequiredService>();
var factory = new ConnectionFactory()
{
- HostName = Configuration["EventBusConnection"]
+ HostName = Configuration["EventBusConnection"],
+ DispatchConsumersAsync = true
};
if (!string.IsNullOrEmpty(Configuration["EventBusUserName"]))
@@ -91,8 +92,8 @@ namespace Payment.API
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
- loggerFactory.AddAzureWebAppDiagnostics();
- loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
+ //loggerFactory.AddAzureWebAppDiagnostics();
+ //loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
var pathBase = Configuration["PATH_BASE"];
if (!string.IsNullOrEmpty(pathBase))
@@ -123,7 +124,7 @@ namespace Payment.API
if (orchestratorType?.ToUpper() == "K8S")
{
// Enable K8s telemetry initializer
- services.EnableKubernetes();
+ services.AddApplicationInsightsKubernetesEnricher();
}
if (orchestratorType?.ToUpper() == "SF")
{
diff --git a/src/Services/Payment/Payment.API/appsettings.json b/src/Services/Payment/Payment.API/appsettings.json
index acc9a2be0..a73471214 100644
--- a/src/Services/Payment/Payment.API/appsettings.json
+++ b/src/Services/Payment/Payment.API/appsettings.json
@@ -1,8 +1,14 @@
{
- "Logging": {
- "IncludeScopes": false,
- "LogLevel": {
- "Default": "Warning"
+ "Serilog": {
+ "SeqServerUrl": null,
+ "LogstashgUrl": null,
+ "MinimumLevel": {
+ "Default": "Information",
+ "Override": {
+ "Microsoft": "Warning",
+ "Microsoft.eShopOnContainers": "Information",
+ "System": "Warning"
+ }
}
},
"PaymentSucceded": true,
diff --git a/src/Services/Payment/Payment.API/azds.yaml b/src/Services/Payment/Payment.API/azds.yaml
new file mode 100644
index 000000000..2536d4371
--- /dev/null
+++ b/src/Services/Payment/Payment.API/azds.yaml
@@ -0,0 +1,56 @@
+kind: helm-release
+apiVersion: 1.1
+build:
+ context: ..\..\..\..
+ dockerfile: Dockerfile
+install:
+ chart: ../../../../k8s/helm/payment-api
+ set:
+ replicaCount: 1
+ image:
+ tag: $(tag)
+ pullPolicy: Never
+ ingress:
+ annotations:
+ kubernetes.io/ingress.class: traefik-azds
+ hosts:
+ - $(spacePrefix)eshop$(hostSuffix)
+ inf:
+ k8s:
+ dns: $(spacePrefix)eshop$(hostSuffix)
+ values:
+ - values.dev.yaml?
+ - secrets.dev.yaml?
+ - inf.yaml
+ - app.yaml
+configurations:
+ develop:
+ build:
+ useGitIgnore: true
+ dockerfile: Dockerfile.develop
+ args:
+ BUILD_CONFIGURATION: ${BUILD_CONFIGURATION:-Debug}
+ container:
+ sync:
+ - '**/Pages/**'
+ - '**/Views/**'
+ - '**/wwwroot/**'
+ - '!**/*.{sln,csproj}'
+ command:
+ - dotnet
+ - run
+ - --no-restore
+ - --no-build
+ - --no-launch-profile
+ - -c
+ - ${BUILD_CONFIGURATION:-Debug}
+ iterate:
+ processesToKill:
+ - dotnet
+ - vsdbg
+ buildCommands:
+ - - dotnet
+ - build
+ - --no-restore
+ - -c
+ - ${BUILD_CONFIGURATION:-Debug}
diff --git a/src/Services/Webhooks/Webhooks.API/Dockerfile b/src/Services/Webhooks/Webhooks.API/Dockerfile
index 5d8b3953d..0da59affa 100644
--- a/src/Services/Webhooks/Webhooks.API/Dockerfile
+++ b/src/Services/Webhooks/Webhooks.API/Dockerfile
@@ -1,17 +1,26 @@
-FROM microsoft/dotnet:2.2-aspnetcore-runtime AS base
+FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80
-FROM microsoft/dotnet:2.2-sdk AS build
+FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
WORKDIR /src
-COPY ["src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj", "src/Services/Webhooks/Webhooks.API/"]
-RUN dotnet restore "src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj"
+
+COPY scripts scripts/
+
+COPY src/ApiGateways/*/*.csproj /src/csproj-files/
+COPY src/ApiGateways/*/*/*.csproj /src/csproj-files/
+COPY src/BuildingBlocks/*/*/*.csproj /src/csproj-files/
+COPY src/Services/*/*/*.csproj /src/csproj-files/
+COPY src/Web/*/*.csproj /src/csproj-files/
+
+ARG RUN=pwd
+RUN ${RUN}
+
COPY . .
WORKDIR "/src/src/Services/Webhooks/Webhooks.API"
-RUN dotnet build "Webhooks.API.csproj" -c Release -o /app
+RUN dotnet publish -c Release -o /app
FROM build AS publish
-RUN dotnet publish "Webhooks.API.csproj" -c Release -o /app
FROM base AS final
WORKDIR /app
diff --git a/src/Services/Webhooks/Webhooks.API/Dockerfile.develop b/src/Services/Webhooks/Webhooks.API/Dockerfile.develop
new file mode 100644
index 000000000..3cc1084f9
--- /dev/null
+++ b/src/Services/Webhooks/Webhooks.API/Dockerfile.develop
@@ -0,0 +1,22 @@
+FROM microsoft/dotnet:2.2-sdk
+ARG BUILD_CONFIGURATION=Debug
+ENV ASPNETCORE_ENVIRONMENT=Development
+ENV DOTNET_USE_POLLING_FILE_WATCHER=true
+EXPOSE 80
+
+WORKDIR /src
+
+COPY ["src/BuildingBlocks/EventBus/EventBus/EventBus.csproj", "src/BuildingBlocks/EventBus/EventBus/"]
+COPY ["src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj", "src/BuildingBlocks/EventBus/EventBusRabbitMQ/"]
+COPY ["src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj", "src/BuildingBlocks/EventBus/EventBusServiceBus/"]
+COPY ["src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj", "src/BuildingBlocks/EventBus/IntegrationEventLogEF/"]
+COPY ["src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj", "src/BuildingBlocks/WebHostCustomization/WebHost.Customization/"]
+COPY ["src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj", "src/BuildingBlocks/Devspaces.Support/"]
+COPY ["src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj", "src/Services/Webhooks/Webhooks.API/"]
+
+RUN dotnet restore src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj -nowarn:msb3202,nu1503
+COPY . .
+WORKDIR "/src/src/Services/Webhooks/Webhooks.API"
+RUN dotnet build --no-restore -c $BUILD_CONFIGURATION
+
+ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"]
\ No newline at end of file
diff --git a/src/Services/Webhooks/Webhooks.API/Program.cs b/src/Services/Webhooks/Webhooks.API/Program.cs
index 063fe2ac1..b08a1c2da 100644
--- a/src/Services/Webhooks/Webhooks.API/Program.cs
+++ b/src/Services/Webhooks/Webhooks.API/Program.cs
@@ -22,6 +22,17 @@ namespace Webhooks.API
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
- .UseStartup();
+ .UseStartup()
+ .ConfigureAppConfiguration((builderContext, config) =>
+ {
+ config.AddEnvironmentVariables();
+ })
+ .ConfigureLogging((hostingContext, builder) =>
+ {
+ builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
+ builder.AddConsole();
+ builder.AddDebug();
+ builder.AddAzureWebAppDiagnostics();
+ });
}
}
diff --git a/src/Services/Webhooks/Webhooks.API/Startup.cs b/src/Services/Webhooks/Webhooks.API/Startup.cs
index ba3ccfe3d..f1a89d329 100644
--- a/src/Services/Webhooks/Webhooks.API/Startup.cs
+++ b/src/Services/Webhooks/Webhooks.API/Startup.cs
@@ -8,6 +8,7 @@ using System.Threading;
using System.Threading.Tasks;
using Autofac;
using Autofac.Extensions.DependencyInjection;
+using Devspaces.Support;
using HealthChecks.UI.Client;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.ApplicationInsights.ServiceFabric;
@@ -55,6 +56,7 @@ namespace Webhooks.API
.AddCustomDbContext(Configuration)
.AddSwagger(Configuration)
.AddCustomHealthCheck(Configuration)
+ .AddDevspaces()
.AddHttpClientServices(Configuration)
.AddIntegrationServices(Configuration)
.AddEventBus(Configuration)
@@ -70,9 +72,8 @@ namespace Webhooks.API
return new AutofacServiceProvider(container.Build());
}
- public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
+ public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
- loggerFactory.AddAzureWebAppDiagnostics();
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
var pathBase = Configuration["PATH_BASE"];
@@ -142,7 +143,7 @@ namespace Webhooks.API
if (orchestratorType?.ToUpper() == "K8S")
{
// Enable K8s telemetry initializer
- services.EnableKubernetes();
+ services.AddApplicationInsightsKubernetesEnricher();
}
if (orchestratorType?.ToUpper() == "SF")
{
@@ -294,8 +295,8 @@ namespace Webhooks.API
services.AddHttpClient("extendedhandlerlifetime").SetHandlerLifetime(Timeout.InfiniteTimeSpan);
//add http client services
services.AddHttpClient("GrantClient")
- .SetHandlerLifetime(TimeSpan.FromMinutes(5));
- //.AddHttpMessageHandler();
+ .SetHandlerLifetime(TimeSpan.FromMinutes(5))
+ .AddDevspacesSupport();
return services;
}
@@ -321,7 +322,8 @@ namespace Webhooks.API
var factory = new ConnectionFactory()
{
- HostName = configuration["EventBusConnection"]
+ HostName = configuration["EventBusConnection"],
+ DispatchConsumersAsync = true
};
if (!string.IsNullOrEmpty(configuration["EventBusUserName"]))
diff --git a/src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj b/src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj
index c054e75e7..4b7fe7eae 100644
--- a/src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj
+++ b/src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj
@@ -13,15 +13,16 @@
-
-
+
+
-
+
+
diff --git a/src/Services/Webhooks/Webhooks.API/azds.yaml b/src/Services/Webhooks/Webhooks.API/azds.yaml
new file mode 100644
index 000000000..38dfe92a2
--- /dev/null
+++ b/src/Services/Webhooks/Webhooks.API/azds.yaml
@@ -0,0 +1,54 @@
+kind: helm-release
+apiVersion: 1.1
+build:
+ context: ..\..\..\..
+ dockerfile: Dockerfile
+install:
+ chart: ../../../../k8s/helm/webhooks-api
+ set:
+ image:
+ tag: $(tag)
+ pullPolicy: Never
+ ingress:
+ annotations:
+ kubernetes.io/ingress.class: traefik-azds
+ hosts:
+ - $(spacePrefix)eshop$(hostSuffix)
+ inf:
+ k8s:
+ dns: $(spacePrefix)eshop$(hostSuffix)
+ values:
+ - values.dev.yaml?
+ - secrets.dev.yaml?
+ - inf.yaml
+ - app.yaml
+configurations:
+ develop:
+ build:
+ useGitIgnore: true
+ dockerfile: Dockerfile.develop
+ container:
+ syncTarget: /src
+ sync:
+ - '**/Pages/**'
+ - '**/Views/**'
+ - '**/wwwroot/**'
+ - '!**/*.{sln,csproj}'
+ command:
+ - dotnet
+ - run
+ - --no-restore
+ - --no-build
+ - --no-launch-profile
+ - -c
+ - ${Configuration:-Debug}
+ iterate:
+ processesToKill:
+ - dotnet
+ - vsdbg
+ buildCommands:
+ - - dotnet
+ - build
+ - --no-restore
+ - -c
+ - ${Configuration:-Debug}
diff --git a/src/Web/WebMVC/.dockerignore b/src/Web/WebMVC/.dockerignore
new file mode 100644
index 000000000..04f7b133d
--- /dev/null
+++ b/src/Web/WebMVC/.dockerignore
@@ -0,0 +1,14 @@
+.dockerignore
+.git
+.gitignore
+.vs
+.vscode
+**/*.*proj.user
+**/azds.yaml
+**/bin
+**/charts
+**/Dockerfile
+**/Dockerfile.develop
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
\ No newline at end of file
diff --git a/src/Web/WebMVC/Controllers/AccountController.cs b/src/Web/WebMVC/Controllers/AccountController.cs
index cf22de133..0f214b8ea 100644
--- a/src/Web/WebMVC/Controllers/AccountController.cs
+++ b/src/Web/WebMVC/Controllers/AccountController.cs
@@ -16,7 +16,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
public async Task SignIn(string returnUrl)
{
var user = User as ClaimsPrincipal;
-
+
var token = await HttpContext.GetTokenAsync("access_token");
if (token != null)
@@ -33,11 +33,11 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
-
+
// "Catalog" because UrlHelper doesn't support nameof() for controllers
// https://github.com/aspnet/Mvc/issues/5853
var homeUrl = Url.Action(nameof(CatalogController.Index), "Catalog");
- return new SignOutResult(OpenIdConnectDefaults.AuthenticationScheme,
+ return new SignOutResult(OpenIdConnectDefaults.AuthenticationScheme,
new AspNetCore.Authentication.AuthenticationProperties { RedirectUri = homeUrl });
}
}
diff --git a/src/Web/WebMVC/Controllers/CampaignsController.cs b/src/Web/WebMVC/Controllers/CampaignsController.cs
index 058012d26..d26e60f94 100644
--- a/src/Web/WebMVC/Controllers/CampaignsController.cs
+++ b/src/Web/WebMVC/Controllers/CampaignsController.cs
@@ -2,7 +2,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
{
using AspNetCore.Authorization;
using AspNetCore.Mvc;
- using global::WebMVC.Models;
+ using global::WebMVC.Services.ModelDTOs;
using global::WebMVC.Services;
using global::WebMVC.ViewModels;
using Microsoft.Extensions.Options;
diff --git a/src/Web/WebMVC/Controllers/OrderManagementController.cs b/src/Web/WebMVC/Controllers/OrderManagementController.cs
index abd0b21ab..7d61b0221 100644
--- a/src/Web/WebMVC/Controllers/OrderManagementController.cs
+++ b/src/Web/WebMVC/Controllers/OrderManagementController.cs
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
-using WebMVC.Models;
+using WebMVC.Services.ModelDTOs;
using Microsoft.eShopOnContainers.WebMVC.Services;
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
using Microsoft.AspNetCore.Authorization;
diff --git a/src/Web/WebMVC/Dockerfile b/src/Web/WebMVC/Dockerfile
index 1a77e4e05..4cb62e614 100644
--- a/src/Web/WebMVC/Dockerfile
+++ b/src/Web/WebMVC/Dockerfile
@@ -1,15 +1,26 @@
-FROM microsoft/dotnet:2.2.0-aspnetcore-runtime AS base
+FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80
-FROM microsoft/dotnet:2.2.100-sdk AS build
+FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
WORKDIR /src
+
+COPY scripts scripts/
+
+COPY src/ApiGateways/*/*.csproj /src/csproj-files/
+COPY src/ApiGateways/*/*/*.csproj /src/csproj-files/
+COPY src/BuildingBlocks/*/*/*.csproj /src/csproj-files/
+COPY src/Services/*/*/*.csproj /src/csproj-files/
+COPY src/Web/*/*.csproj /src/csproj-files/
+
+ARG RUN=pwd
+RUN ${RUN}
+
COPY . .
WORKDIR /src/src/Web/WebMVC
-RUN dotnet restore -nowarn:msb3202,nu1503
+RUN dotnet publish -c Release -o /app
FROM build AS publish
-RUN dotnet publish --no-restore -c Release -o /app
FROM base AS final
WORKDIR /app
diff --git a/src/Web/WebMVC/Dockerfile.develop b/src/Web/WebMVC/Dockerfile.develop
new file mode 100644
index 000000000..6ff9cc869
--- /dev/null
+++ b/src/Web/WebMVC/Dockerfile.develop
@@ -0,0 +1,15 @@
+FROM microsoft/dotnet:2.2-sdk
+ARG BUILD_CONFIGURATION=Debug
+ENV ASPNETCORE_ENVIRONMENT=Development
+ENV DOTNET_USE_POLLING_FILE_WATCHER=true
+EXPOSE 80
+
+WORKDIR /src
+COPY ["src/Web/WebMVC/WebMVC.csproj", "src/Web/WebMVC/"]
+COPY ["src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj", "src/BuildingBlocks/Devspaces.Support/"]
+RUN dotnet restore "src/Web/WebMVC/WebMVC.csproj"
+COPY . .
+WORKDIR "/src/src/Web/WebMVC"
+RUN dotnet build --no-restore "WebMVC.csproj" -c $BUILD_CONFIGURATION
+
+ENTRYPOINT ["dotnet", "run", "--no-build", "--no-launch-profile", "-c", "$BUILD_CONFIGURATION", "--"]
\ No newline at end of file
diff --git a/src/Web/WebMVC/Infrastructure/HttpClientRequestIdDelegatingHandler.cs b/src/Web/WebMVC/Infrastructure/HttpClientRequestIdDelegatingHandler.cs
index 17e4591a1..37bea4d30 100644
--- a/src/Web/WebMVC/Infrastructure/HttpClientRequestIdDelegatingHandler.cs
+++ b/src/Web/WebMVC/Infrastructure/HttpClientRequestIdDelegatingHandler.cs
@@ -17,7 +17,10 @@ namespace WebMVC.Infrastructure
{
if (request.Method == HttpMethod.Post || request.Method == HttpMethod.Put)
{
- request.Headers.Add("x-requestid", Guid.NewGuid().ToString());
+ if (!request.Headers.Contains("x-requestid"))
+ {
+ request.Headers.Add("x-requestid", Guid.NewGuid().ToString());
+ }
}
return await base.SendAsync(request, cancellationToken);
diff --git a/src/Web/WebMVC/Infrastructure/WebContextSeed.cs b/src/Web/WebMVC/Infrastructure/WebContextSeed.cs
index 65063e34f..c34730ac1 100644
--- a/src/Web/WebMVC/Infrastructure/WebContextSeed.cs
+++ b/src/Web/WebMVC/Infrastructure/WebContextSeed.cs
@@ -15,7 +15,7 @@ namespace WebMVC.Infrastructure
{
public static void Seed(IApplicationBuilder applicationBuilder, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
- var log = loggerFactory.CreateLogger("WebMVC seed");
+ var log = loggerFactory.CreateLogger();
var settings = (AppSettings)applicationBuilder
.ApplicationServices.GetRequiredService>().Value;
@@ -39,7 +39,7 @@ namespace WebMVC.Infrastructure
string overrideCssFile = Path.Combine(contentRootPath, "Setup", "override.css");
if (!File.Exists(overrideCssFile))
{
- log.LogError($" override css file '{overrideCssFile}' does not exists.");
+ log.LogError("Override css file '{FileName}' does not exists.", overrideCssFile);
return;
}
@@ -48,7 +48,7 @@ namespace WebMVC.Infrastructure
}
catch (Exception ex)
{
- log.LogError($"Exception in method GetPreconfiguredCSS WebMVC. Exception Message={ex.Message}");
+ log.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message);
}
}
@@ -59,7 +59,7 @@ namespace WebMVC.Infrastructure
string imagesZipFile = Path.Combine(contentRootPath, "Setup", "images.zip");
if (!File.Exists(imagesZipFile))
{
- log.LogError($" zip file '{imagesZipFile}' does not exists.");
+ log.LogError("Zip file '{ZipFileName}' does not exists.", imagesZipFile);
return;
}
@@ -81,14 +81,14 @@ namespace WebMVC.Infrastructure
}
else
{
- log.LogWarning($"Skip file '{entry.Name}' in zipfile '{imagesZipFile}'");
+ log.LogWarning("Skipped file '{FileName}' in zipfile '{ZipFileName}'", entry.Name, imagesZipFile);
}
}
}
}
catch ( Exception ex )
{
- log.LogError($"Exception in method GetPreconfiguredImages WebMVC. Exception Message={ex.Message}");
+ log.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message);
}
}
diff --git a/src/Web/WebMVC/Program.cs b/src/Web/WebMVC/Program.cs
index 7f88feeaf..a80d0514b 100644
--- a/src/Web/WebMVC/Program.cs
+++ b/src/Web/WebMVC/Program.cs
@@ -3,39 +3,75 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Serilog;
+using System;
using System.IO;
namespace Microsoft.eShopOnContainers.WebMVC
{
public class Program
{
- public static void Main(string[] args)
+ public static readonly string Namespace = typeof(Program).Namespace;
+ public static readonly string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1);
+
+ public static int Main(string[] args)
{
- BuildWebHost(args).Run();
+ var configuration = GetConfiguration();
+
+ Log.Logger = CreateSerilogLogger(configuration);
+
+ try
+ {
+ Log.Information("Configuring web host ({ApplicationContext})...", AppName);
+ var host = BuildWebHost(configuration, args);
+
+ Log.Information("Starting web host ({ApplicationContext})...", AppName);
+ host.Run();
+
+ return 0;
+ }
+ catch (Exception ex)
+ {
+ Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
+ return 1;
+ }
+ finally
+ {
+ Log.CloseAndFlush();
+ }
}
- public static IWebHost BuildWebHost(string[] args) =>
+ private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
WebHost.CreateDefaultBuilder(args)
- .UseContentRoot(Directory.GetCurrentDirectory())
+ .CaptureStartupErrors(false)
.UseStartup()
- .ConfigureAppConfiguration((builderContext, config) =>
- {
- config.AddEnvironmentVariables();
- })
- .ConfigureLogging((hostingContext, builder) =>
- {
- builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
- builder.AddConsole();
- builder.AddDebug();
- })
.UseApplicationInsights()
- .UseSerilog((builderContext, config) =>
- {
- config
- .MinimumLevel.Information()
- .Enrich.FromLogContext()
- .WriteTo.Console();
- })
+ .UseConfiguration(configuration)
+ .UseSerilog()
.Build();
+
+ private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
+ {
+ var seqServerUrl = configuration["Serilog:SeqServerUrl"];
+ var logstashUrl = configuration["Serilog:LogstashgUrl"];
+ return new LoggerConfiguration()
+ .MinimumLevel.Verbose()
+ .Enrich.WithProperty("ApplicationContext", AppName)
+ .Enrich.FromLogContext()
+ .WriteTo.Console()
+ .WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
+ .WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://logstash:8080" : logstashUrl)
+ .ReadFrom.Configuration(configuration)
+ .CreateLogger();
+ }
+
+ private static IConfiguration GetConfiguration()
+ {
+ var builder = new ConfigurationBuilder()
+ .SetBasePath(Directory.GetCurrentDirectory())
+ .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
+ .AddEnvironmentVariables();
+
+ return builder.Build();
+ }
}
-}
+}
\ No newline at end of file
diff --git a/src/Web/WebMVC/Services/BasketService.cs b/src/Web/WebMVC/Services/BasketService.cs
index 7dffd934b..dd0a50feb 100644
--- a/src/Web/WebMVC/Services/BasketService.cs
+++ b/src/Web/WebMVC/Services/BasketService.cs
@@ -6,7 +6,7 @@ using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using WebMVC.Infrastructure;
-using WebMVC.Models;
+using WebMVC.Services.ModelDTOs;
namespace Microsoft.eShopOnContainers.WebMVC.Services
{
diff --git a/src/Web/WebMVC/Services/IBasketService.cs b/src/Web/WebMVC/Services/IBasketService.cs
index cfbea5ff0..8c096bfaf 100644
--- a/src/Web/WebMVC/Services/IBasketService.cs
+++ b/src/Web/WebMVC/Services/IBasketService.cs
@@ -3,7 +3,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
-using WebMVC.Models;
+using WebMVC.Services.ModelDTOs;
namespace Microsoft.eShopOnContainers.WebMVC.Services
{
diff --git a/src/Web/WebMVC/Services/ILocationService.cs b/src/Web/WebMVC/Services/ILocationService.cs
index ac2295e10..d5f7b7224 100644
--- a/src/Web/WebMVC/Services/ILocationService.cs
+++ b/src/Web/WebMVC/Services/ILocationService.cs
@@ -1,5 +1,5 @@
using System.Threading.Tasks;
-using WebMVC.Models;
+using WebMVC.Services.ModelDTOs;
namespace WebMVC.Services
{
diff --git a/src/Web/WebMVC/Services/IOrderingService.cs b/src/Web/WebMVC/Services/IOrderingService.cs
index 1de2c631c..480ea4119 100644
--- a/src/Web/WebMVC/Services/IOrderingService.cs
+++ b/src/Web/WebMVC/Services/IOrderingService.cs
@@ -3,7 +3,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
-using WebMVC.Models;
+using WebMVC.Services.ModelDTOs;
namespace Microsoft.eShopOnContainers.WebMVC.Services
{
diff --git a/src/Web/WebMVC/Services/LocationService.cs b/src/Web/WebMVC/Services/LocationService.cs
index 3e58ef125..8d81cbd22 100644
--- a/src/Web/WebMVC/Services/LocationService.cs
+++ b/src/Web/WebMVC/Services/LocationService.cs
@@ -6,7 +6,7 @@ using Newtonsoft.Json;
using System.Net.Http;
using System.Threading.Tasks;
using WebMVC.Infrastructure;
-using WebMVC.Models;
+using WebMVC.Services.ModelDTOs;
namespace WebMVC.Services
{
diff --git a/src/Web/WebMVC/Models/BasketDTO.cs b/src/Web/WebMVC/Services/ModelDTOs/BasketDTO.cs
similarity index 95%
rename from src/Web/WebMVC/Models/BasketDTO.cs
rename to src/Web/WebMVC/Services/ModelDTOs/BasketDTO.cs
index 4609c8533..130a729f5 100644
--- a/src/Web/WebMVC/Models/BasketDTO.cs
+++ b/src/Web/WebMVC/Services/ModelDTOs/BasketDTO.cs
@@ -1,7 +1,7 @@
using System;
using System.ComponentModel.DataAnnotations;
-namespace WebMVC.Models
+namespace WebMVC.Services.ModelDTOs
{
public class BasketDTO
{
diff --git a/src/Web/WebMVC/Models/LocationDTO.cs b/src/Web/WebMVC/Services/ModelDTOs/LocationDTO.cs
similarity index 86%
rename from src/Web/WebMVC/Models/LocationDTO.cs
rename to src/Web/WebMVC/Services/ModelDTOs/LocationDTO.cs
index 88169c421..40c9f07a8 100644
--- a/src/Web/WebMVC/Models/LocationDTO.cs
+++ b/src/Web/WebMVC/Services/ModelDTOs/LocationDTO.cs
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
-namespace WebMVC.Models
+namespace WebMVC.Services.ModelDTOs
{
public class LocationDTO
{
diff --git a/src/Web/WebMVC/Models/OrderDTO.cs b/src/Web/WebMVC/Services/ModelDTOs/OrderDTO.cs
similarity index 82%
rename from src/Web/WebMVC/Models/OrderDTO.cs
rename to src/Web/WebMVC/Services/ModelDTOs/OrderDTO.cs
index 13646ea38..5f925a8ee 100644
--- a/src/Web/WebMVC/Models/OrderDTO.cs
+++ b/src/Web/WebMVC/Services/ModelDTOs/OrderDTO.cs
@@ -1,7 +1,7 @@
using System;
using System.ComponentModel.DataAnnotations;
-namespace WebMVC.Models
+namespace WebMVC.Services.ModelDTOs
{
public class OrderDTO
{
diff --git a/src/Web/WebMVC/Models/OrderProcessAction.cs b/src/Web/WebMVC/Services/ModelDTOs/OrderProcessAction.cs
similarity index 93%
rename from src/Web/WebMVC/Models/OrderProcessAction.cs
rename to src/Web/WebMVC/Services/ModelDTOs/OrderProcessAction.cs
index bd746bb36..c1309d59b 100644
--- a/src/Web/WebMVC/Models/OrderProcessAction.cs
+++ b/src/Web/WebMVC/Services/ModelDTOs/OrderProcessAction.cs
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
-namespace WebMVC.Models
+namespace WebMVC.Services.ModelDTOs
{
public class OrderProcessAction
{
diff --git a/src/Web/WebMVC/Services/OrderingService.cs b/src/Web/WebMVC/Services/OrderingService.cs
index e3d24422f..489946db5 100644
--- a/src/Web/WebMVC/Services/OrderingService.cs
+++ b/src/Web/WebMVC/Services/OrderingService.cs
@@ -6,7 +6,7 @@ using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using WebMVC.Infrastructure;
-using WebMVC.Models;
+using WebMVC.Services.ModelDTOs;
namespace Microsoft.eShopOnContainers.WebMVC.Services
{
diff --git a/src/Web/WebMVC/Startup.cs b/src/Web/WebMVC/Startup.cs
index d69b21459..a2d61a5f3 100644
--- a/src/Web/WebMVC/Startup.cs
+++ b/src/Web/WebMVC/Startup.cs
@@ -1,4 +1,5 @@
-using HealthChecks.UI.Client;
+using Devspaces.Support;
+using HealthChecks.UI.Client;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.ApplicationInsights.ServiceFabric;
using Microsoft.AspNetCore.Authentication.Cookies;
@@ -42,6 +43,7 @@ namespace Microsoft.eShopOnContainers.WebMVC
services.AddAppInsight(Configuration)
.AddHealthChecks(Configuration)
.AddCustomMvc(Configuration)
+ .AddDevspaces()
.AddHttpClientServices(Configuration)
//.AddHttpClientLogging(Configuration) //Opt-in HttpClientLogging config
.AddCustomAuthentication(Configuration);
@@ -52,8 +54,8 @@ namespace Microsoft.eShopOnContainers.WebMVC
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
- loggerFactory.AddAzureWebAppDiagnostics();
- loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
+ //loggerFactory.AddAzureWebAppDiagnostics();
+ //loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
app.UseHealthChecks("/hc", new HealthCheckOptions()
{
@@ -74,7 +76,7 @@ namespace Microsoft.eShopOnContainers.WebMVC
var pathBase = Configuration["PATH_BASE"];
if (!string.IsNullOrEmpty(pathBase))
{
- loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
+ loggerFactory.CreateLogger().LogDebug("Using PATH BASE '{PathBase}'", pathBase);
app.UsePathBase(pathBase);
}
@@ -93,8 +95,6 @@ namespace Microsoft.eShopOnContainers.WebMVC
app.UseAuthentication();
- var log = loggerFactory.CreateLogger("identity");
-
WebContextSeed.Seed(app, env, loggerFactory);
app.UseHttpsRedirection();
@@ -122,7 +122,7 @@ namespace Microsoft.eShopOnContainers.WebMVC
if (orchestratorType?.ToUpper() == "K8S")
{
// Enable K8s telemetry initializer
- services.EnableKubernetes();
+ services.AddApplicationInsightsKubernetesEnricher();
}
if (orchestratorType?.ToUpper() == "SF")
@@ -177,34 +177,39 @@ namespace Microsoft.eShopOnContainers.WebMVC
services.AddTransient();
//set 5 min as the lifetime for each HttpMessageHandler int the pool
- services.AddHttpClient("extendedhandlerlifetime").SetHandlerLifetime(TimeSpan.FromMinutes(5));
+ services.AddHttpClient("extendedhandlerlifetime").SetHandlerLifetime(TimeSpan.FromMinutes(5)).AddDevspacesSupport();
//add http client services
services.AddHttpClient()
.SetHandlerLifetime(TimeSpan.FromMinutes(5)) //Sample. Default lifetime is 2 minutes
.AddHttpMessageHandler()
.AddPolicyHandler(GetRetryPolicy())
- .AddPolicyHandler(GetCircuitBreakerPolicy());
+ .AddPolicyHandler(GetCircuitBreakerPolicy())
+ .AddDevspacesSupport();
services.AddHttpClient | | |