Browse Source

Merge remote-tracking branch 'eShopOnContainers/dev' into dev

# Conflicts:
#	k8s/deploy.ps1
pull/235/head
Eduard Tomas 7 years ago
parent
commit
9f7a7cda8a
57 changed files with 991 additions and 374 deletions
  1. +48
    -0
      README.CICD.k8s.md
  2. +0
    -29
      _docker/rabbitmq/Dockerfile.nanowin
  3. +0
    -1
      _docker/rabbitmq/enabled_plugins
  4. +0
    -1
      _docker/rabbitmq/rabbitmq.config
  5. +0
    -30
      _docker/redis/Dockerfile.nanowin
  6. +6
    -0
      cli-mac/build-bits.sh
  7. +21
    -17
      docker-compose-windows.override.yml
  8. +19
    -15
      docker-compose-windows.prod.yml
  9. +2
    -2
      docker-compose-windows.yml
  10. +2
    -2
      docker-compose.ci.build.yml
  11. +30
    -26
      docker-compose.override.yml
  12. +31
    -26
      docker-compose.prod.yml
  13. +237
    -0
      eShopOnContainers-iOS.sln
  14. BIN
      img/k8s/blob_creation.png
  15. BIN
      img/k8s/deploy_script_task.png
  16. BIN
      img/k8s/get_kubectlbin_task.png
  17. BIN
      img/k8s/get_kubectlconfig_task.png
  18. +10
    -1
      src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/HealthCheckBuilderSqlServerExtensions.cs
  19. +18
    -4
      src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/NumericChecks.cs
  20. +10
    -0
      src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/SystemChecks.cs
  21. +45
    -8
      src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/UrlChecks.cs
  22. +1
    -1
      src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckBuilder.cs
  23. +8
    -8
      src/BuildingBlocks/Resilience/Resilience.Http/IHttpClient.cs
  24. +0
    -10
      src/BuildingBlocks/Resilience/Resilience.Http/ResiliencePolicy.cs
  25. +121
    -26
      src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs
  26. +77
    -9
      src/BuildingBlocks/Resilience/Resilience.Http/StandardHttpClient.cs
  27. +6
    -1
      src/Services/Catalog/Catalog.API/Startup.cs
  28. +3
    -7
      src/Services/Identity/Identity.API/Configuration/Config.cs
  29. +6
    -1
      src/Services/Identity/Identity.API/Startup.cs
  30. +3
    -2
      src/Services/Ordering/Ordering.API/Application/Queries/IOrderQueries.cs
  31. +2
    -2
      src/Services/Ordering/Ordering.API/Application/Queries/OrderQueries.cs
  32. +3
    -2
      src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs
  33. +25
    -0
      src/Services/Ordering/Ordering.API/Infrastructure/Middlewares/FailingStartupFilter.cs
  34. +23
    -0
      src/Services/Ordering/Ordering.API/Infrastructure/Middlewares/FailingWebHostBuilderExtensions.cs
  35. +1
    -0
      src/Services/Ordering/Ordering.API/Program.cs
  36. +6
    -3
      src/Services/Ordering/Ordering.API/Startup.cs
  37. +1
    -1
      src/Web/WebMVC/Controllers/OrderController.cs
  38. +68
    -0
      src/Web/WebMVC/Infrastructure/API.cs
  39. +7
    -10
      src/Web/WebMVC/Infrastructure/ResilientHttpClientFactory.cs
  40. +22
    -23
      src/Web/WebMVC/Services/BasketService.cs
  41. +25
    -33
      src/Web/WebMVC/Services/CatalogService.cs
  42. +34
    -33
      src/Web/WebMVC/Services/OrderingService.cs
  43. +18
    -13
      src/Web/WebMVC/Startup.cs
  44. +1
    -1
      src/Web/WebMVC/Views/Shared/_Layout.cshtml
  45. +2
    -2
      src/Web/WebMVC/WebMVC.csproj
  46. +1
    -1
      src/Web/WebMVC/wwwroot/css/site.min.css
  47. +10
    -4
      src/Web/WebSPA/Startup.cs
  48. +3
    -1
      src/Web/WebSPA/WebSPA.csproj
  49. +1
    -0
      src/Web/WebStatus/Controllers/HomeController.cs
  50. +2
    -2
      src/Web/WebStatus/Extensions/HealthCheckBuilderExtensions.cs
  51. +12
    -6
      src/Web/WebStatus/Startup.cs
  52. +10
    -3
      src/Web/WebStatus/Views/Shared/_Layout.cshtml
  53. +2
    -2
      test/Services/FunctionalTests/Services/Catalog/CatalogScenariosBase.cs
  54. +1
    -1
      test/Services/FunctionalTests/Services/IntegrationEventsScenarios.cs
  55. +1
    -1
      test/Services/IntegrationTests/Services/Ordering/OrderingScenarios.cs
  56. +3
    -1
      test/Services/UnitTest/Ordering/Application/NewOrderCommandHandlerTest.cs
  57. +3
    -2
      test/Services/UnitTest/Ordering/Application/OrdersWebApiTest.cs

+ 48
- 0
README.CICD.k8s.md View File

@ -0,0 +1,48 @@
# Kubernetes CI/CD VSTS
For k8s CI/CD pipeline delivery a series of tasks must be created in VSTS to deploy k8s in Azure
## Prerequisites
* A Kubernetes cluster. Follow Azure Container Service's [walkthrough](https://docs.microsoft.com/en-us/azure/container-service/container-service-kubernetes-walkthrough) to create one.
* A private Docker registry. Follow Azure Container Registry's [guide](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-get-started-portal) to create one.
* Optionally, previous steps can be skipped if you run gen-k8s-env.ps1 script to automatically create the azure environment needed for kubernetes deployment. Azure cli 2.0 must be previously installed [installation guide](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli). For example:
>```
>./gen-k8s-env -resourceGroupName k8sGroup -location westeurope -registryName k8sregistry -orchestratorName k8s-cluster -dnsName k8s-dns
>```
* An `Azure Blob storage`. It is needed for storing the kubernetes config file used by the hosted agent to access to Kubernetes cluster. Example:
<img src="img/k8s/blob_creation.png">
* Upload the `kubernetes config file` to the blob storage previously created. Execute the following command which will download the config file into the directory `c:\Users\<User>\.kube\` and then, upload it to your blob storage:
>```
>https://eshopk8s.blob.core.windows.net/k8s-config/config
>```
## Create the VSTS tasks
1. Create a `Download File` task to download the kubernetes binary `kubectl` to the hosted agent. For example:
>```
>https://storage.googleapis.com/kubernetes-release/release/v0.0.1.7.0-alpha.0/bin/windows/386/kubectl.exe
>```
<img src="img/k8s/get_kubectlbin_task.png">
2. Create a Download File task to download the kubernetes config file to the hosted agent. For example:
>```
>https://eshopk8s.blob.core.windows.net/k8s-config/config
>```
<img src="img/k8s/get_kubectlconfig_task.png">
3. Create a powershell task to execute the k8s deployment script. For example:
* Deployment script path
>```
>$(System.DefaultWorkingDirectory)/All Microservices/docker-compose/deploy.ps1
>```
* Deployment script path arguments. Where:
- userDockerHub: indicates if Docker Hub is used instead of ACR
- deployCI: indicates that it is a CI/CD deployment
- execPath: path where the k8s binary is stored
- kubeconfigPath: path where the k8s config file is stored
>```
>-deployCI $true -useDockerHub $true -execPath '$(System.DefaultWorkingDirectory)/' -kubeconfigPath '$(System.DefaultWorkingDirectory)/'
>```
<img src="img/k8s/deploy_script_task.png">

+ 0
- 29
_docker/rabbitmq/Dockerfile.nanowin View File

@ -1,29 +0,0 @@
#https://github.com/spring2/dockerfiles/tree/master/rabbitmq
FROM microsoft/windowsservercore
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
ENV chocolateyUseWindowsCompression false
RUN iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')); \
choco install -y curl;
RUN choco install -y erlang
ENV ERLANG_SERVICE_MANAGER_PATH="C:\Program Files\erl8.2\erts-8.2\bin"
RUN choco install -y rabbitmq
ENV RABBITMQ_SERVER="C:\Program Files\RabbitMQ Server\rabbitmq_server-3.6.5"
ENV RABBITMQ_CONFIG_FILE="c:\rabbitmq"
COPY rabbitmq.config C:/
COPY rabbitmq.config C:/Users/ContainerAdministrator/AppData/Roaming/RabbitMQ/
COPY enabled_plugins C:/Users/ContainerAdministrator/AppData/Roaming/RabbitMQ/
EXPOSE 4369
EXPOSE 5672
EXPOSE 5671
EXPOSE 15672
WORKDIR C:/Program\ Files/RabbitMQ\ Server/rabbitmq_server-3.6.5/sbin
CMD .\rabbitmq-server.bat

+ 0
- 1
_docker/rabbitmq/enabled_plugins View File

@ -1 +0,0 @@
[rabbitmq_amqp1_0,rabbitmq_management].

+ 0
- 1
_docker/rabbitmq/rabbitmq.config View File

@ -1 +0,0 @@
[{rabbit, [{loopback_users, []}]}].

+ 0
- 30
_docker/redis/Dockerfile.nanowin View File

@ -1,30 +0,0 @@
# The MSI installs a service which is hard to override, so let's use a zip file.
FROM microsoft/windowsservercore
MAINTAINER alexellis2@gmail.com
SHELL ["powershell"]
RUN $ErrorActionPreference = 'Stop'; \
wget https://github.com/MSOpenTech/redis/releases/download/win-3.2.100/Redis-x64-3.2.100.zip -OutFile Redis-x64-3.2.100.zip ; \
Expand-Archive Redis-x64-3.2.100.zip -dest 'C:\\Program Files\\Redis\\' ; \
Remove-Item Redis-x64-3.2.100.zip -Force
RUN setx PATH '%PATH%;C:\\Program Files\\Redis\\'
WORKDIR 'C:\\Program Files\\Redis\\'
RUN Get-Content redis.windows.conf | Where { $_ -notmatch 'bind 127.0.0.1' } | Set-Content redis.openport.conf ; \
Get-Content redis.openport.conf | Where { $_ -notmatch 'protected-mode yes' } | Set-Content redis.unprotected.conf ; \
Add-Content redis.unprotected.conf 'protected-mode no' ; \
Add-Content redis.unprotected.conf 'bind 0.0.0.0' ; \
Get-Content redis.unprotected.conf
EXPOSE 6379
RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord
# Define our command to be run when launching the container
CMD .\\redis-server.exe .\\redis.unprotected.conf --port 6379 ; \
Write-Host Redis Started... ; \
while ($true) { Start-Sleep -Seconds 3600 }

+ 6
- 0
cli-mac/build-bits.sh View File

@ -10,6 +10,12 @@ projectList=(
"../src/Web/WebStatus"
)
pushd $(pwd)/../src/Web/WebSPA
npm install
npm rebuild node-sass
popd
for project in "${projectList[@]}"
do
echo -e "\e[33mWorking on $(pwd)/$project"


+ 21
- 17
docker-compose-windows.override.yml View File

@ -11,65 +11,69 @@ services:
basket.api:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:5103
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionString=basket.data
- identityUrl=http://identity.api:5105 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
- identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
- EventBusConnection=rabbitmq
ports:
- "5103:5103"
- "5103:80"
catalog.api:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:5101
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word
- ExternalCatalogBaseUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5101 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
- EventBusConnection=rabbitmq
ports:
- "5101:5101"
- "5101:80"
identity.api:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:5105
- ASPNETCORE_URLS=http://0.0.0.0:80
- SpaClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5104
- ConnectionStrings__DefaultConnection=Server=sql.data;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word
- MvcClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5100 #Local: You need to open your local dev-machine firewall at range 5100-5105.
ports:
- "5105:5105"
- "5105:80"
ordering.api:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:5102
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word
- identityUrl=http://identity.api:5105 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
- identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
- EventBusConnection=rabbitmq
ports:
- "5102:5102"
- "5102:80"
webspa:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:5104
- ASPNETCORE_URLS=http://0.0.0.0:80
- CatalogUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5101
- OrderingUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5102
- IdentityUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
- BasketUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5103
- CatalogUrlHC=http://catalog.api/hc
- OrderingUrlHC=http://ordering.api/hc
- IdentityUrlHC=http://identity.api/hc #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser.
- BasketUrlHC=http://basket.api/hc
ports:
- "5104:5104"
- "5104:80"
webmvc:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:5100
- CatalogUrl=http://catalog.api:5101
- OrderingUrl=http://ordering.api:5102
- BasketUrl=http://basket.api:5103
- ASPNETCORE_URLS=http://0.0.0.0:80
- CatalogUrl=http://catalog.api
- OrderingUrl=http://ordering.api
- BasketUrl=http://basket.api
- IdentityUrl=http://10.0.75.1:5105 #Local: Use 10.0.75.1 in a "Docker for Windows" environment, if using "localhost" from browser.
#Remote: Use ${ESHOP_EXTERNAL_DNS_NAME_OR_IP} if using external IP or DNS name from browser.
ports:
- "5100:5100"
- "5100:80"
sql.data:
environment:


+ 19
- 15
docker-compose-windows.prod.yml View File

@ -16,61 +16,65 @@ services:
basket.api:
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://0.0.0.0:5103
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionString=basket.data
- identityUrl=http://identity.api:5105 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
- identityUrl=http://identity.api #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
ports:
- "5103:5103"
catalog.api:
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://0.0.0.0:5101
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word
- ExternalCatalogBaseUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5101 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
ports:
- "5101:5101"
- "5101:80"
identity.api:
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://0.0.0.0:5105
- ASPNETCORE_URLS=http://0.0.0.0:80
- SpaClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5104
- ConnectionStrings__DefaultConnection=Server=sql.data;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word
- MvcClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5100 #Local: You need to open your host's firewall at range 5100-5105.
ports:
- "5105:5105"
- "5105:80"
ordering.api:
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://0.0.0.0:5102
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word
- identityUrl=http://identity.api:5105 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
ports:
- "5102:5102"
- "5102:80"
webspa:
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://0.0.0.0:5104
- ASPNETCORE_URLS=http://0.0.0.0
- CatalogUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5101
- OrderingUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5102
- IdentityUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
- BasketUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5103
- CatalogUrlHC=http://catalog.api/hc
- OrderingUrlHC=http://ordering.api/hc
- IdentityUrlHC=http://identity.api/hc #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser.
- BasketUrlHC=http://basket.api/hc
ports:
- "5104:5104"
- "5104:80"
webmvc:
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://0.0.0.0:5100
- CatalogUrl=http://catalog.api:5101
- OrderingUrl=http://ordering.api:5102
- ASPNETCORE_URLS=http://0.0.0.0:80
- CatalogUrl=http://catalog.api
- OrderingUrl=http://ordering.api
- IdentityUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser.
- BasketUrl=http://basket.api:5103
- BasketUrl=http://basket.api
ports:
- "5100:5100"
- "5100:80"
sql.data:
environment:


+ 2
- 2
docker-compose-windows.yml View File

@ -58,7 +58,7 @@ services:
image: microsoft/mssql-server-windows
basket.data:
image: eshop/redis-win
image: redis:nanoserver
# build:
# context: ./_docker/redis
# dockerfile: Dockerfile.nanowin
@ -66,7 +66,7 @@ services:
- "6379:6379"
rabbitmq:
image: eshop/rabbitmq-win
image: spring2/rabbitmq
# build:
# context: ./_docker/rabbitmq
# dockerfile: Dockerfile.nanowin


+ 2
- 2
docker-compose.ci.build.yml View File

@ -6,5 +6,5 @@ services:
volumes:
- .:/src
working_dir: /src
command: /bin/bash -c "dotnet restore ./eShopOnContainers-ServicesAndWebApps.sln && dotnet publish ./eShopOnContainers-ServicesAndWebApps.sln -c Release -o ./obj/Docker/publish"
command: /bin/bash -c "pushd ./src/Web/WebSPA && npm rebuild node-sass && popd && dotnet restore ./eShopOnContainers-ServicesAndWebApps.sln && dotnet publish ./eShopOnContainers-ServicesAndWebApps.sln -c Release -o ./obj/Docker/publish"

+ 30
- 26
docker-compose.override.yml View File

@ -11,66 +11,70 @@ services:
basket.api:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:5103
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionString=basket.data
- identityUrl=http://identity.api:5105 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
- identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
- EventBusConnection=rabbitmq
ports:
- "5103:5103"
- "5103:80"
catalog.api:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:5101
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word
- ExternalCatalogBaseUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5101 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
- EventBusConnection=rabbitmq
ports:
- "5101:5101"
- "5101:80"
identity.api:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:5105
- ASPNETCORE_URLS=http://0.0.0.0:80
- SpaClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5104
- XamarinCallback=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105/xamarincallback #localhost do not work for UWP login, so we have to use "external" IP always
- ConnectionStrings__DefaultConnection=Server=sql.data;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word
- MvcClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5100 #Local: You need to open your local dev-machine firewall at range 5100-5105.
ports:
- "5105:5105"
- "5105:80"
ordering.api:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:5102
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word
- identityUrl=http://identity.api:5105 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
- identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
- EventBusConnection=rabbitmq
ports:
- "5102:5102"
- "5102:80"
webspa:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:5104
- ASPNETCORE_URLS=http://0.0.0.0:80
- CatalogUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5101
- OrderingUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5102
- IdentityUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
- BasketUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5103
- BasketUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5103
- CatalogUrlHC=http://catalog.api/hc
- OrderingUrlHC=http://ordering.api/hc
- IdentityUrlHC=http://identity.api/hc #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser.
- BasketUrlHC=http://basket.api/hc
ports:
- "5104:5104"
- "5104:80"
webmvc:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:5100
- CatalogUrl=http://catalog.api:5101
- OrderingUrl=http://ordering.api:5102
- BasketUrl=http://basket.api:5103
- ASPNETCORE_URLS=http://0.0.0.0:80
- CatalogUrl=http://catalog.api
- OrderingUrl=http://ordering.api
- BasketUrl=http://basket.api
- IdentityUrl=http://10.0.75.1:5105 #Local: Use 10.0.75.1 in a "Docker for Windows" environment, if using "localhost" from browser.
#Remote: Use ${ESHOP_EXTERNAL_DNS_NAME_OR_IP} if using external IP or DNS name from browser.
ports:
- "5100:5100"
- "5100:80"
sql.data:
environment:
@ -82,12 +86,12 @@ services:
webstatus:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:5107
- CatalogUrl=http://catalog.api:5101/hc
- OrderingUrl=http://ordering.api:5102/hc
- BasketUrl=http://basket.api:5103/hc
- IdentityUrl=http://identity.api:5105/hc
- mvc=http://webmvc:5100/hc
- spa=http://webspa:5104/hc
- ASPNETCORE_URLS=http://0.0.0.0:80
- CatalogUrl=http://catalog.api/hc
- OrderingUrl=http://ordering.api/hc
- BasketUrl=http://basket.api/hc
- IdentityUrl=http://identity.api/hc
- mvc=http://webmvc/hc
- spa=http://webspa/hc
ports:
- "5107:5107"
- "5107:80"

+ 31
- 26
docker-compose.prod.yml View File

@ -16,65 +16,69 @@ services:
basket.api:
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://0.0.0.0:5103
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionString=basket.data
- identityUrl=http://identity.api:5105 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
- identityUrl=http://identity.api #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
- EventBusConnection=rabbitmq
ports:
- "5103:5103"
- "5103:80"
catalog.api:
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://0.0.0.0:5101
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word
- ExternalCatalogBaseUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5101 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
- EventBusConnection=rabbitmq
ports:
- "5101:5101"
- "5101:80"
identity.api:
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://0.0.0.0:5105
- ASPNETCORE_URLS=http://0.0.0.0:80
- SpaClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5104
- ConnectionStrings__DefaultConnection=Server=sql.data;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word
- MvcClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5100 #Local: You need to open your host's firewall at range 5100-5105.
- XamarinCallback=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105/xamarincallback
ports:
- "5105:5105"
- "5105:80"
ordering.api:
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://0.0.0.0:5102
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word
- identityUrl=http://identity.api:5105 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
- identityUrl=http://identity.api #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
- EventBusConnection=rabbitmq
ports:
- "5102:5102"
- "5102:80"
webspa:
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://0.0.0.0:5104
- ASPNETCORE_URLS=http://0.0.0.0:80
- CatalogUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5101
- OrderingUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5102
- IdentityUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
- BasketUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5103
- BasketUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5103
- CatalogUrlHC=http://catalog.api/hc
- OrderingUrlHC=http://ordering.api/hc
- IdentityUrlHC=http://identity.api/hc #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser.
- BasketUrlHC=http://basket.api/hc
ports:
- "5104:5104"
- "5104:80"
webmvc:
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://0.0.0.0:5100
- CatalogUrl=http://catalog.api:5101
- OrderingUrl=http://ordering.api:5102
- ASPNETCORE_URLS=http://0.0.0.0:80
- CatalogUrl=http://catalog.api
- OrderingUrl=http://ordering.api
- IdentityUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser.
- BasketUrl=http://basket.api:5103
- BasketUrl=http://basket.api
ports:
- "5100:5100"
- "5100:80"
sql.data:
environment:
@ -86,12 +90,13 @@ services:
webstatus:
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://0.0.0.0:5107
- CatalogUrl=http://catalog.api:5101/hc
- OrderingUrl=http://ordering.api:5102/hc
- BasketUrl=http://basket.api:5103/hc
- mvc=http://webmvc:5100/hc
- spa=http://webspa:5104/hc
- IdentityUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser.
- ASPNETCORE_URLS=http://0.0.0.0:80
- CatalogUrl=http://catalog.api/hc
- OrderingUrl=http://ordering.api/hc
- BasketUrl=http://basket.api/hc
- IdentityUrl=http://identity.api/hc
- mvc=http://webmvc/hc
- spa=http://webspa/hc
ports:
- "5107:5107"
- "5107:80"

+ 237
- 0
eShopOnContainers-iOS.sln View File

@ -0,0 +1,237 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.6
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{932D8224-11F6-4D07-B109-DA28AD288A63}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3AF739CD-81D8-428D-A08A-0A58372DEBF6}"
ProjectSection(SolutionItems) = preProject
docker-compose.yml = docker-compose.yml
global.json = global.json
NuGet.config = NuGet.config
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mobile Apps", "Mobile Apps", "{F61357CE-1CC2-410E-8776-B16EEBC98EB8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{A857AD10-40FF-4303-BEC2-FF1C58D5735E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eShopOnContainers.Core", "src\Mobile\eShopOnContainers\eShopOnContainers.Core\eShopOnContainers.Core.csproj", "{67F9D3A8-F71E-4428-913F-C37AE82CDB24}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eShopOnContainers.iOS", "src\Mobile\eShopOnContainers\eShopOnContainers.iOS\eShopOnContainers.iOS.csproj", "{6EEB23DC-7063-4444-9AF8-90DF24F549C0}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared Code", "Shared Code", "{778289CA-31F7-4464-8C2A-612EE846F8A7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Targets", "Targets", "{9CC7814B-72A6-465B-A61C-57B512DEE303}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mobile Apps", "Mobile Apps", "{B7B1D395-4E06-4036-BE86-C216756B9367}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eShopOnContainers.UnitTests", "src\Mobile\eShopOnContainers\eShopOnContainers.UnitTests\eShopOnContainers.UnitTests.csproj", "{F7B6A162-BC4D-4924-B16A-713F9B0344E7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eShopOnContainers.TestRunner.iOS", "src\Mobile\eShopOnContainers\eShopOnContainers.TestRunner.iOS\eShopOnContainers.TestRunner.iOS.csproj", "{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
Ad-Hoc|ARM = Ad-Hoc|ARM
Ad-Hoc|iPhone = Ad-Hoc|iPhone
Ad-Hoc|iPhoneSimulator = Ad-Hoc|iPhoneSimulator
Ad-Hoc|x64 = Ad-Hoc|x64
Ad-Hoc|x86 = Ad-Hoc|x86
AppStore|Any CPU = AppStore|Any CPU
AppStore|ARM = AppStore|ARM
AppStore|iPhone = AppStore|iPhone
AppStore|iPhoneSimulator = AppStore|iPhoneSimulator
AppStore|x64 = AppStore|x64
AppStore|x86 = AppStore|x86
Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM
Debug|iPhone = Debug|iPhone
Debug|iPhoneSimulator = Debug|iPhoneSimulator
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|ARM = Release|ARM
Release|iPhone = Release|iPhone
Release|iPhoneSimulator = Release|iPhoneSimulator
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Ad-Hoc|ARM.Build.0 = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Ad-Hoc|x64.Build.0 = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Ad-Hoc|x86.Build.0 = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.AppStore|Any CPU.Build.0 = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.AppStore|ARM.ActiveCfg = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.AppStore|ARM.Build.0 = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.AppStore|iPhone.Build.0 = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.AppStore|x64.ActiveCfg = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.AppStore|x64.Build.0 = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.AppStore|x86.ActiveCfg = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.AppStore|x86.Build.0 = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Debug|Any CPU.Build.0 = Debug|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Debug|ARM.ActiveCfg = Debug|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Debug|ARM.Build.0 = Debug|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Debug|iPhone.Build.0 = Debug|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Debug|x64.ActiveCfg = Debug|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Debug|x64.Build.0 = Debug|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Debug|x86.ActiveCfg = Debug|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Debug|x86.Build.0 = Debug|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Release|Any CPU.ActiveCfg = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Release|Any CPU.Build.0 = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Release|ARM.ActiveCfg = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Release|ARM.Build.0 = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Release|iPhone.ActiveCfg = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Release|iPhone.Build.0 = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Release|x64.ActiveCfg = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Release|x64.Build.0 = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Release|x86.ActiveCfg = Release|Any CPU
{67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Release|x86.Build.0 = Release|Any CPU
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Ad-Hoc|ARM.ActiveCfg = Ad-Hoc|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Ad-Hoc|x64.ActiveCfg = Ad-Hoc|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Ad-Hoc|x86.ActiveCfg = Ad-Hoc|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.AppStore|ARM.ActiveCfg = AppStore|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.AppStore|iPhone.Build.0 = AppStore|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.AppStore|x64.ActiveCfg = AppStore|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.AppStore|x86.ActiveCfg = AppStore|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Debug|Any CPU.ActiveCfg = Debug|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Debug|Any CPU.Build.0 = Debug|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Debug|ARM.ActiveCfg = Debug|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Debug|iPhone.ActiveCfg = Debug|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Debug|iPhone.Build.0 = Debug|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Debug|x64.ActiveCfg = Debug|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Debug|x86.ActiveCfg = Debug|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Release|Any CPU.ActiveCfg = Release|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Release|ARM.ActiveCfg = Release|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Release|iPhone.ActiveCfg = Release|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Release|iPhone.Build.0 = Release|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Release|x64.ActiveCfg = Release|iPhone
{6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Release|x86.ActiveCfg = Release|iPhone
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Ad-Hoc|ARM.Build.0 = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Ad-Hoc|x64.Build.0 = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Ad-Hoc|x86.Build.0 = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.AppStore|Any CPU.Build.0 = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.AppStore|ARM.ActiveCfg = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.AppStore|ARM.Build.0 = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.AppStore|iPhone.Build.0 = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.AppStore|x64.ActiveCfg = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.AppStore|x64.Build.0 = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.AppStore|x86.ActiveCfg = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.AppStore|x86.Build.0 = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Debug|ARM.ActiveCfg = Debug|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Debug|ARM.Build.0 = Debug|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Debug|iPhone.Build.0 = Debug|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Debug|x64.ActiveCfg = Debug|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Debug|x64.Build.0 = Debug|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Debug|x86.ActiveCfg = Debug|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Debug|x86.Build.0 = Debug|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Release|Any CPU.Build.0 = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Release|ARM.ActiveCfg = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Release|ARM.Build.0 = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Release|iPhone.ActiveCfg = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Release|iPhone.Build.0 = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Release|x64.ActiveCfg = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Release|x64.Build.0 = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Release|x86.ActiveCfg = Release|Any CPU
{F7B6A162-BC4D-4924-B16A-713F9B0344E7}.Release|x86.Build.0 = Release|Any CPU
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Ad-Hoc|ARM.ActiveCfg = Ad-Hoc|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Ad-Hoc|x64.ActiveCfg = Ad-Hoc|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Ad-Hoc|x86.ActiveCfg = Ad-Hoc|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.AppStore|ARM.ActiveCfg = AppStore|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.AppStore|iPhone.Build.0 = AppStore|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.AppStore|x64.ActiveCfg = AppStore|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.AppStore|x86.ActiveCfg = AppStore|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Debug|Any CPU.ActiveCfg = Debug|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Debug|Any CPU.Build.0 = Debug|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Debug|ARM.ActiveCfg = Debug|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Debug|iPhone.ActiveCfg = Debug|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Debug|iPhone.Build.0 = Debug|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Debug|x64.ActiveCfg = Debug|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Debug|x86.ActiveCfg = Debug|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Release|Any CPU.ActiveCfg = Release|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Release|ARM.ActiveCfg = Release|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Release|iPhone.ActiveCfg = Release|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Release|iPhone.Build.0 = Release|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Release|x64.ActiveCfg = Release|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Release|x86.ActiveCfg = Release|iPhone
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{F61357CE-1CC2-410E-8776-B16EEBC98EB8} = {932D8224-11F6-4D07-B109-DA28AD288A63}
{67F9D3A8-F71E-4428-913F-C37AE82CDB24} = {778289CA-31F7-4464-8C2A-612EE846F8A7}
{6EEB23DC-7063-4444-9AF8-90DF24F549C0} = {9CC7814B-72A6-465B-A61C-57B512DEE303}
{778289CA-31F7-4464-8C2A-612EE846F8A7} = {F61357CE-1CC2-410E-8776-B16EEBC98EB8}
{9CC7814B-72A6-465B-A61C-57B512DEE303} = {F61357CE-1CC2-410E-8776-B16EEBC98EB8}
{B7B1D395-4E06-4036-BE86-C216756B9367} = {A857AD10-40FF-4303-BEC2-FF1C58D5735E}
{F7B6A162-BC4D-4924-B16A-713F9B0344E7} = {B7B1D395-4E06-4036-BE86-C216756B9367}
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3} = {B7B1D395-4E06-4036-BE86-C216756B9367}
EndGlobalSection
EndGlobal

BIN
img/k8s/blob_creation.png View File

Before After
Width: 1119  |  Height: 319  |  Size: 26 KiB

BIN
img/k8s/deploy_script_task.png View File

Before After
Width: 1408  |  Height: 527  |  Size: 36 KiB

BIN
img/k8s/get_kubectlbin_task.png View File

Before After
Width: 1409  |  Height: 484  |  Size: 31 KiB

BIN
img/k8s/get_kubectlconfig_task.png View File

Before After
Width: 1406  |  Height: 488  |  Size: 30 KiB

+ 10
- 1
src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/HealthCheckBuilderSqlServerExtensions.cs View File

@ -7,9 +7,18 @@ using System.Data.SqlClient;
namespace Microsoft.Extensions.HealthChecks
{
// REVIEW: What are the appropriate guards for these functions?
public static class HealthCheckBuilderSqlServerExtensions
{
public static HealthCheckBuilder AddSqlCheck(this HealthCheckBuilder builder, string name, string connectionString)
{
Guard.ArgumentNotNull(nameof(builder), builder);
return AddSqlCheck(builder, name, connectionString, builder.DefaultCacheDuration);
}
public static HealthCheckBuilder AddSqlCheck(this HealthCheckBuilder builder, string name, string connectionString, TimeSpan cacheDuration)
{
builder.AddCheck($"SqlCheck({name})", async () =>
{
@ -37,7 +46,7 @@ namespace Microsoft.Extensions.HealthChecks
{
return HealthCheckResult.Unhealthy($"SqlCheck({name}): Exception during check: {ex.GetType().FullName}");
}
});
}, cacheDuration);
return builder;
}


+ 18
- 4
src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/NumericChecks.cs View File

@ -10,7 +10,14 @@ namespace Microsoft.Extensions.HealthChecks
{
// Numeric checks
public static HealthCheckBuilder AddMinValueCheck<T>(this HealthCheckBuilder builder, string name, T minValue, Func<T> currentValueFunc)
public static HealthCheckBuilder AddMinValueCheck<T>(this HealthCheckBuilder builder, string name, T minValue, Func<T> currentValueFunc) where T : IComparable<T>
{
Guard.ArgumentNotNull(nameof(builder), builder);
return AddMinValueCheck(builder, name, minValue, currentValueFunc, builder.DefaultCacheDuration);
}
public static HealthCheckBuilder AddMinValueCheck<T>(this HealthCheckBuilder builder, string name, T minValue, Func<T> currentValueFunc, TimeSpan cacheDuration)
where T : IComparable<T>
{
Guard.ArgumentNotNull(nameof(builder), builder);
@ -26,12 +33,19 @@ namespace Microsoft.Extensions.HealthChecks
$"min={minValue}, current={currentValue}",
new Dictionary<string, object> { { "min", minValue }, { "current", currentValue } }
);
});
}, cacheDuration);
return builder;
}
public static HealthCheckBuilder AddMaxValueCheck<T>(this HealthCheckBuilder builder, string name, T maxValue, Func<T> currentValueFunc)
public static HealthCheckBuilder AddMaxValueCheck<T>(this HealthCheckBuilder builder, string name, T maxValue, Func<T> currentValueFunc) where T : IComparable<T>
{
Guard.ArgumentNotNull(nameof(builder), builder);
return AddMaxValueCheck(builder, name, maxValue, currentValueFunc, builder.DefaultCacheDuration);
}
public static HealthCheckBuilder AddMaxValueCheck<T>(this HealthCheckBuilder builder, string name, T maxValue, Func<T> currentValueFunc, TimeSpan cacheDuration)
where T : IComparable<T>
{
Guard.ArgumentNotNull(nameof(builder), builder);
@ -47,7 +61,7 @@ namespace Microsoft.Extensions.HealthChecks
$"max={maxValue}, current={currentValue}",
new Dictionary<string, object> { { "max", maxValue }, { "current", currentValue } }
);
});
}, cacheDuration);
return builder;
}


+ 10
- 0
src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/SystemChecks.cs View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Diagnostics;
namespace Microsoft.Extensions.HealthChecks
@ -12,10 +13,19 @@ namespace Microsoft.Extensions.HealthChecks
public static HealthCheckBuilder AddPrivateMemorySizeCheck(this HealthCheckBuilder builder, long maxSize)
=> AddMaxValueCheck(builder, $"PrivateMemorySize({maxSize})", maxSize, () => Process.GetCurrentProcess().PrivateMemorySize64);
public static HealthCheckBuilder AddPrivateMemorySizeCheck(this HealthCheckBuilder builder, long maxSize, TimeSpan cacheDuration)
=> AddMaxValueCheck(builder, $"PrivateMemorySize({maxSize})", maxSize, () => Process.GetCurrentProcess().PrivateMemorySize64, cacheDuration);
public static HealthCheckBuilder AddVirtualMemorySizeCheck(this HealthCheckBuilder builder, long maxSize)
=> AddMaxValueCheck(builder, $"VirtualMemorySize({maxSize})", maxSize, () => Process.GetCurrentProcess().VirtualMemorySize64);
public static HealthCheckBuilder AddVirtualMemorySizeCheck(this HealthCheckBuilder builder, long maxSize, TimeSpan cacheDuration)
=> AddMaxValueCheck(builder, $"VirtualMemorySize({maxSize})", maxSize, () => Process.GetCurrentProcess().VirtualMemorySize64, cacheDuration);
public static HealthCheckBuilder AddWorkingSetCheck(this HealthCheckBuilder builder, long maxSize)
=> AddMaxValueCheck(builder, $"WorkingSet({maxSize})", maxSize, () => Process.GetCurrentProcess().WorkingSet64);
public static HealthCheckBuilder AddWorkingSetCheck(this HealthCheckBuilder builder, long maxSize, TimeSpan cacheDuration)
=> AddMaxValueCheck(builder, $"WorkingSet({maxSize})", maxSize, () => Process.GetCurrentProcess().WorkingSet64, cacheDuration);
}
}

+ 45
- 8
src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/UrlChecks.cs View File

@ -10,36 +10,73 @@ namespace Microsoft.Extensions.HealthChecks
{
public static partial class HealthCheckBuilderExtensions
{
// URL checks
// Default URL check
public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url)
=> AddUrlCheck(builder, url, response => UrlChecker.DefaultUrlCheck(response));
{
Guard.ArgumentNotNull(nameof(builder), builder);
return AddUrlCheck(builder, url, builder.DefaultCacheDuration);
}
public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url, TimeSpan cacheDuration)
=> AddUrlCheck(builder, url, response => UrlChecker.DefaultUrlCheck(response), cacheDuration);
// Func returning IHealthCheckResult
public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url, Func<HttpResponseMessage, IHealthCheckResult> checkFunc)
{
Guard.ArgumentNotNull(nameof(builder), builder);
return AddUrlCheck(builder, url, checkFunc, builder.DefaultCacheDuration);
}
public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url,
Func<HttpResponseMessage, IHealthCheckResult> checkFunc)
Func<HttpResponseMessage, IHealthCheckResult> checkFunc,
TimeSpan cacheDuration)
{
Guard.ArgumentNotNull(nameof(checkFunc), checkFunc);
return AddUrlCheck(builder, url, response => new ValueTask<IHealthCheckResult>(checkFunc(response)));
return AddUrlCheck(builder, url, response => new ValueTask<IHealthCheckResult>(checkFunc(response)), cacheDuration);
}
// Func returning Task<IHealthCheckResult>
public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url, Func<HttpResponseMessage, Task<IHealthCheckResult>> checkFunc)
{
Guard.ArgumentNotNull(nameof(builder), builder);
return AddUrlCheck(builder, url, checkFunc, builder.DefaultCacheDuration);
}
public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url,
Func<HttpResponseMessage, Task<IHealthCheckResult>> checkFunc)
Func<HttpResponseMessage, Task<IHealthCheckResult>> checkFunc,
TimeSpan cacheDuration)
{
Guard.ArgumentNotNull(nameof(checkFunc), checkFunc);
return AddUrlCheck(builder, url, response => new ValueTask<IHealthCheckResult>(checkFunc(response)));
return AddUrlCheck(builder, url, response => new ValueTask<IHealthCheckResult>(checkFunc(response)), cacheDuration);
}
// Func returning ValueTask<IHealthCheckResult>
public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url, Func<HttpResponseMessage, ValueTask<IHealthCheckResult>> checkFunc)
{
Guard.ArgumentNotNull(nameof(builder), builder);
return AddUrlCheck(builder, url, checkFunc, builder.DefaultCacheDuration);
}
public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url,
Func<HttpResponseMessage, ValueTask<IHealthCheckResult>> checkFunc)
Func<HttpResponseMessage, ValueTask<IHealthCheckResult>> checkFunc,
TimeSpan cacheDuration)
{
Guard.ArgumentNotNull(nameof(builder), builder);
Guard.ArgumentNotNullOrEmpty(nameof(url), url);
Guard.ArgumentNotNull(nameof(checkFunc), checkFunc);
var urlCheck = new UrlChecker(checkFunc, url);
builder.AddCheck($"UrlCheck({url})", () => urlCheck.CheckAsync());
builder.AddCheck($"UrlCheck({url})", () => urlCheck.CheckAsync(), cacheDuration);
return builder;
}
}


+ 1
- 1
src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckBuilder.cs View File

@ -21,7 +21,7 @@ namespace Microsoft.Extensions.HealthChecks
[string.Empty] = _currentGroup
};
DefaultCacheDuration = TimeSpan.FromMinutes(1);
DefaultCacheDuration = TimeSpan.FromMinutes(5);
}
/// <summary>


+ 8
- 8
src/BuildingBlocks/Resilience/Resilience.Http/IHttpClient.cs View File

@ -1,16 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http
{
public interface IHttpClient
{
HttpClient Inst { get; }
Task<string> GetStringAsync(string uri);
Task<HttpResponseMessage> PostAsync<T>(string uri, T item);
Task<HttpResponseMessage> DeleteAsync(string uri);
Task<string> GetStringAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer");
Task<HttpResponseMessage> PostAsync<T>(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer");
Task<HttpResponseMessage> DeleteAsync(string uri, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer");
Task<HttpResponseMessage> PutAsync<T>(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer");
}
}

+ 0
- 10
src/BuildingBlocks/Resilience/Resilience.Http/ResiliencePolicy.cs View File

@ -1,10 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http
{
public class ResiliencePolicy
{
}
}

+ 121
- 26
src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs View File

@ -3,9 +3,12 @@ using Newtonsoft.Json;
using Polly;
using Polly.Wrap;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http
@ -17,48 +20,140 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http
/// </summary>
public class ResilientHttpClient : IHttpClient
{
private HttpClient _client;
private PolicyWrap _policyWrapper;
private ILogger<ResilientHttpClient> _logger;
public HttpClient Inst => _client;
private readonly HttpClient _client;
private readonly ILogger<ResilientHttpClient> _logger;
private readonly Func<string, IEnumerable<Policy>> _policyCreator;
private ConcurrentDictionary<string, PolicyWrap> _policyWrappers;
public ResilientHttpClient(Policy[] policies, ILogger<ResilientHttpClient> logger)
public ResilientHttpClient(Func<string, IEnumerable<Policy>> policyCreator, ILogger<ResilientHttpClient> logger)
{
_client = new HttpClient();
_logger = logger;
_policyCreator = policyCreator;
_policyWrappers = new ConcurrentDictionary<string, PolicyWrap>();
}
// Add Policies to be applied
_policyWrapper = Policy.WrapAsync(policies);
}
public Task<string> GetStringAsync(string uri) =>
HttpInvoker(() =>
_client.GetStringAsync(uri));
public Task<HttpResponseMessage> PostAsync<T>(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
{
return DoPostPutAsync(HttpMethod.Post, uri, item, authorizationToken, requestId, authorizationMethod);
}
public Task<HttpResponseMessage> PostAsync<T>(string uri, T item) =>
// a new StringContent must be created for each retry
// as it is disposed after each call
HttpInvoker(() =>
public Task<HttpResponseMessage> PutAsync<T>(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
{
return DoPostPutAsync(HttpMethod.Put, uri, item, authorizationToken, requestId, authorizationMethod);
}
public Task<HttpResponseMessage> DeleteAsync(string uri, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
{
var origin = GetOriginFromUri(uri);
return HttpInvoker(origin, async () =>
{
var response = _client.PostAsync(uri, new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json"));
// raise exception if HttpResponseCode 500
// needed for circuit breaker to track fails
if (response.Result.StatusCode == HttpStatusCode.InternalServerError)
var requestMessage = new HttpRequestMessage(HttpMethod.Delete, uri);
if (authorizationToken != null)
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
}
if (requestId != null)
{
throw new HttpRequestException();
requestMessage.Headers.Add("x-requestid", requestId);
}
return response;
return await _client.SendAsync(requestMessage);
});
}
public Task<HttpResponseMessage> DeleteAsync(string uri) =>
HttpInvoker(() => _client.DeleteAsync(uri));
public Task<string> GetStringAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer")
{
var origin = GetOriginFromUri(uri);
return HttpInvoker(origin, async () =>
{
var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri);
if (authorizationToken != null)
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
}
var response = await _client.SendAsync(requestMessage);
return await response.Content.ReadAsStringAsync();
});
}
private Task<HttpResponseMessage> DoPostPutAsync<T>(HttpMethod method, string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
{
if (method != HttpMethod.Post && method != HttpMethod.Put)
{
throw new ArgumentException("Value must be either post or put.", nameof(method));
}
// a new StringContent must be created for each retry
// as it is disposed after each call
var origin = GetOriginFromUri(uri);
return HttpInvoker(origin, () =>
{
var requestMessage = new HttpRequestMessage(method, uri);
requestMessage.Content = new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json");
if (authorizationToken != null)
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
}
if (requestId != null)
{
requestMessage.Headers.Add("x-requestid", requestId);
}
var response = _client.SendAsync(requestMessage).Result;
// raise exception if HttpResponseCode 500
// needed for circuit breaker to track fails
if (response.StatusCode == HttpStatusCode.InternalServerError)
{
throw new HttpRequestException();
}
return Task.FromResult(response);
});
}
private async Task<T> HttpInvoker<T>(string origin, Func<Task<T>> action)
{
var normalizedOrigin = NormalizeOrigin(origin);
if (!_policyWrappers.TryGetValue(normalizedOrigin, out PolicyWrap policyWrap))
{
policyWrap = Policy.Wrap(_policyCreator(normalizedOrigin).ToArray());
_policyWrappers.TryAdd(normalizedOrigin, policyWrap);
}
private Task<T> HttpInvoker<T>(Func<Task<T>> action) =>
// Executes the action applying all
// the policies defined in the wrapper
_policyWrapper.ExecuteAsync(() => action());
}
return await policyWrap.Execute(action, new Context(normalizedOrigin));
}
private static string NormalizeOrigin(string origin)
{
return origin?.Trim()?.ToLower();
}
private static string GetOriginFromUri(string uri)
{
var url = new Uri(uri);
var origin = $"{url.Scheme}://{url.DnsSafeHost}:{url.Port}";
return origin;
}
}
}

+ 77
- 9
src/BuildingBlocks/Resilience/Resilience.Http/StandardHttpClient.cs View File

@ -1,7 +1,9 @@
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http
@ -10,24 +12,90 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http
{
private HttpClient _client;
private ILogger<StandardHttpClient> _logger;
public HttpClient Inst => _client;
public StandardHttpClient(ILogger<StandardHttpClient> logger)
{
_client = new HttpClient();
_logger = logger;
}
public Task<string> GetStringAsync(string uri) =>
_client.GetStringAsync(uri);
public Task<HttpResponseMessage> PostAsync<T>(string uri, T item)
public async Task<string> GetStringAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer")
{
var contentString = new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json");
return _client.PostAsync(uri, contentString);
var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri);
if (authorizationToken != null)
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
}
var response = await _client.SendAsync(requestMessage);
return await response.Content.ReadAsStringAsync();
}
public Task<HttpResponseMessage> DeleteAsync(string uri) =>
_client.DeleteAsync(uri);
private async Task<HttpResponseMessage> DoPostPutAsync<T>(HttpMethod method, string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
{
if (method != HttpMethod.Post && method != HttpMethod.Put)
{
throw new ArgumentException("Value must be either post or put.", nameof(method));
}
// a new StringContent must be created for each retry
// as it is disposed after each call
var requestMessage = new HttpRequestMessage(HttpMethod.Post, uri);
requestMessage.Content = new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json");
if (authorizationToken != null)
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
}
if (requestId != null)
{
requestMessage.Headers.Add("x-requestid", requestId);
}
var response = await _client.SendAsync(requestMessage);
// raise exception if HttpResponseCode 500
// needed for circuit breaker to track fails
if (response.StatusCode == HttpStatusCode.InternalServerError)
{
throw new HttpRequestException();
}
return response;
}
public async Task<HttpResponseMessage> PostAsync<T>(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
{
return await DoPostPutAsync(HttpMethod.Post, uri, item, authorizationToken, requestId, authorizationToken);
}
public async Task<HttpResponseMessage> PutAsync<T>(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
{
return await DoPostPutAsync(HttpMethod.Put, uri, item, authorizationToken, requestId, authorizationToken);
}
public async Task<HttpResponseMessage> DeleteAsync(string uri, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
{
var requestMessage = new HttpRequestMessage(HttpMethod.Delete, uri);
if (authorizationToken != null)
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
}
if (requestId != null)
{
requestMessage.Headers.Add("x-requestid", requestId);
}
return await _client.SendAsync(requestMessage);
}
}
}

+ 6
- 1
src/Services/Catalog/Catalog.API/Startup.cs View File

@ -50,7 +50,12 @@
services.AddHealthChecks(checks =>
{
checks.AddSqlCheck("CatalogDb", Configuration["ConnectionString"]);
var minutes = 1;
if (int.TryParse(Configuration["HealthCheck:Timeout"], out var minutesParsed))
{
minutes = minutesParsed;
}
checks.AddSqlCheck("CatalogDb", Configuration["ConnectionString"], TimeSpan.FromMinutes(minutes));
});
services.AddMvc(options =>


+ 3
- 7
src/Services/Identity/Identity.API/Configuration/Config.cs View File

@ -60,7 +60,7 @@ namespace Identity.API.Configuration
AllowAccessTokensViaBrowser = true,
RedirectUris = { clientsUrl["Xamarin"] },
RequireConsent = false,
PostLogoutRedirectUris = { "http://13.88.8.119:5105/Account/Redirecting", "http://10.6.1.234:5105/Account/Redirecting" },
PostLogoutRedirectUris = { $"{clientsUrl["Xamarin"]}/Account/Redirecting" },
AllowedCorsOrigins = { "http://eshopxamarin" },
AllowedScopes =
{
@ -84,15 +84,11 @@ namespace Identity.API.Configuration
AllowOfflineAccess = true,
RedirectUris = new List<string>
{
$"{clientsUrl["Mvc"]}/signin-oidc",
"http://104.40.62.65:5100/signin-oidc",
"http://localhost:5100/signin-oidc",
"http://13.88.8.119:5100/signin-oidc"
$"{clientsUrl["Mvc"]}/signin-oidc"
},
PostLogoutRedirectUris = new List<string>
{
$"{clientsUrl["Mvc"]}/signout-callback-oidc",
"http://localhost:5100/signout-callback-oidc"
$"{clientsUrl["Mvc"]}/signout-callback-oidc"
},
AllowedScopes = new List<string>
{


+ 6
- 1
src/Services/Identity/Identity.API/Startup.cs View File

@ -66,7 +66,12 @@ namespace eShopOnContainers.Identity
services.AddHealthChecks(checks =>
{
checks.AddSqlCheck("Identity_Db", Configuration.GetConnectionString("DefaultConnection"));
var minutes = 1;
if (int.TryParse(Configuration["HealthCheck:Timeout"], out var minutesParsed))
{
minutes = minutesParsed;
}
checks.AddSqlCheck("Identity_Db", Configuration.GetConnectionString("DefaultConnection"), TimeSpan.FromMinutes(minutes));
});
services.AddTransient<IEmailSender, AuthMessageSender>();


+ 3
- 2
src/Services/Ordering/Ordering.API/Application/Queries/IOrderQueries.cs View File

@ -1,13 +1,14 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries
{
using System.Collections.Generic;
using System.Threading.Tasks;
public interface IOrderQueries
{
Task<dynamic> GetOrderAsync(int id);
Task<dynamic> GetOrdersAsync();
Task<IEnumerable<dynamic>> GetOrdersAsync();
Task<dynamic> GetCardTypesAsync();
Task<IEnumerable<dynamic>> GetCardTypesAsync();
}
}

+ 2
- 2
src/Services/Ordering/Ordering.API/Application/Queries/OrderQueries.cs View File

@ -44,7 +44,7 @@
}
}
public async Task<dynamic> GetOrdersAsync()
public async Task<IEnumerable<dynamic>> GetOrdersAsync()
{
using (var connection = new SqlConnection(_connectionString))
{
@ -58,7 +58,7 @@
}
}
public async Task<dynamic> GetCardTypesAsync()
public async Task<IEnumerable<dynamic>> GetCardTypesAsync()
{
using (var connection = new SqlConnection(_connectionString))
{


+ 3
- 2
src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs View File

@ -68,8 +68,9 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
[HttpGet]
public async Task<IActionResult> GetOrders()
{
var orders = await _orderQueries
.GetOrdersAsync();
var orderTask = _orderQueries.GetOrdersAsync();
var orders = await orderTask;
return Ok(orders);
}


+ 25
- 0
src/Services/Ordering/Ordering.API/Infrastructure/Middlewares/FailingStartupFilter.cs View File

@ -0,0 +1,25 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ordering.API.Infrastructure.Middlewares
{
public class FailingStartupFilter : IStartupFilter
{
public FailingStartupFilter()
{
}
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
{
return app =>
{
app.UseFailingMiddleware();
next(app);
};
}
}
}

+ 23
- 0
src/Services/Ordering/Ordering.API/Infrastructure/Middlewares/FailingWebHostBuilderExtensions.cs View File

@ -0,0 +1,23 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Ordering.API.Infrastructure.Middlewares;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Hosting
{
public static class WebHostBuildertExtensions
{
public static IWebHostBuilder UseFailing(this IWebHostBuilder builder, string path)
{
builder.ConfigureServices(services =>
{
services.AddSingleton<IStartupFilter>(new FailingStartupFilter());
});
return builder;
}
}
}

+ 1
- 0
src/Services/Ordering/Ordering.API/Program.cs View File

@ -10,6 +10,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API
{
var host = new WebHostBuilder()
.UseKestrel()
.UseFailing("/Failing")
.UseHealthChecks("/hc")
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()


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

@ -61,7 +61,12 @@
services.AddHealthChecks(checks =>
{
checks.AddSqlCheck("OrderingDb", Configuration["ConnectionString"]);
var minutes = 1;
if (int.TryParse(Configuration["HealthCheck:Timeout"], out var minutesParsed))
{
minutes = minutesParsed;
}
checks.AddSqlCheck("OrderingDb", Configuration["ConnectionString"], TimeSpan.FromMinutes(minutes));
});
services.AddEntityFrameworkSqlServer()
@ -143,8 +148,6 @@
app.UseCors("CorsPolicy");
app.UseFailingMiddleware();
ConfigureAuth(app);
app.UseMvcWithDefaultRoute();


+ 1
- 1
src/Web/WebMVC/Controllers/OrderController.cs View File

@ -51,7 +51,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
}
catch(BrokenCircuitException)
{
ModelState.AddModelError("Error", "It was not possible to create a new order, please try later on");
ModelState.AddModelError("Error", "It was not possible to create a new order, please try later on. (Business Msg Due to Circuit-Breaker)");
}
return View(model);
}


+ 68
- 0
src/Web/WebMVC/Infrastructure/API.cs View File

@ -0,0 +1,68 @@
namespace WebMVC.Infrastructure
{
public static class API
{
public static class Basket
{
public static string GetBasket(string baseUri, string basketId)
{
return $"{baseUri}/{basketId}";
}
public static string UpdateBasket(string baseUri)
{
return baseUri;
}
public static string CleanBasket(string baseUri, string basketId)
{
return $"{baseUri}/{basketId}";
}
}
public static class Order
{
public static string GetOrder(string baseUri, string orderId)
{
return $"{baseUri}/{orderId}";
}
public static string GetAllMyOrders(string baseUri)
{
return baseUri;
}
public static string AddNewOrder(string baseUri)
{
return $"{baseUri}/new";
}
}
public static class Catalog
{
public static string GetAllCatalogItems(string baseUri, int page, int take, int? brand, int? type)
{
var filterQs = "";
if (brand.HasValue || type.HasValue)
{
var brandQs = (brand.HasValue) ? brand.Value.ToString() : "null";
var typeQs = (type.HasValue) ? type.Value.ToString() : "null";
filterQs = $"/type/{typeQs}/brand/{brandQs}";
}
return $"{baseUri}items{filterQs}?pageIndex={page}&pageSize={take}";
}
public static string GetAllBrands(string baseUri)
{
return $"{baseUri}catalogBrands";
}
public static string GetAllTypes(string baseUri)
{
return $"{baseUri}catalogTypes";
}
}
}
}

+ 7
- 10
src/Web/WebMVC/Infrastructure/ResilientHttpClientFactory.cs View File

@ -1,10 +1,7 @@
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Polly;
using System;
using System.Net.Http;
namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
@ -17,14 +14,13 @@ namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
=>_logger = logger;
public ResilientHttpClient CreateResilientHttpClient()
=> new ResilientHttpClient(CreatePolicies(), _logger);
=> new ResilientHttpClient((origin) => CreatePolicies(), _logger);
private Policy[] CreatePolicies()
=> new Policy[]
{
Policy.Handle<HttpRequestException>()
.WaitAndRetryAsync(
Policy.Handle<HttpRequestException>()
.WaitAndRetry(
// number of retries
6,
// exponential backofff
@ -40,7 +36,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
_logger.LogDebug(msg);
}),
Policy.Handle<HttpRequestException>()
.CircuitBreakerAsync(
.CircuitBreaker(
// number of exceptions before breaking circuit
5,
// time circuit opened before retry
@ -54,6 +50,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
{
// on circuit closed
_logger.LogTrace("Circuit breaker reset");
})};
})
};
}
}

+ 22
- 23
src/Web/WebMVC/Services/BasketService.cs View File

@ -5,9 +5,8 @@ using Microsoft.eShopOnContainers.WebMVC.ViewModels;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using WebMVC.Infrastructure;
namespace Microsoft.eShopOnContainers.WebMVC.Services
{
@ -28,15 +27,13 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
public async Task<Basket> GetBasket(ApplicationUser user)
{
var context = _httpContextAccesor.HttpContext;
var token = await context.Authentication.GetTokenAsync("access_token");
var token = await GetUserTokenAsync();
var getBasketUri = API.Basket.GetBasket(_remoteServiceBaseUrl, user.Id);
_apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
var dataString = await _apiClient.GetStringAsync(getBasketUri, token);
var basketUrl = $"{_remoteServiceBaseUrl}/{user.Id}";
var dataString = await _apiClient.GetStringAsync(basketUrl);
// Use the ?? Null conditional operator to simplify the initialization of response
var response = JsonConvert.DeserializeObject<Basket>(dataString) ??
var response = JsonConvert.DeserializeObject<Basket>(dataString) ??
new Basket()
{
BuyerId = user.Id
@ -47,14 +44,10 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
public async Task<Basket> UpdateBasket(Basket basket)
{
var context = _httpContextAccesor.HttpContext;
var token = await context.Authentication.GetTokenAsync("access_token");
_apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
var token = await GetUserTokenAsync();
var updateBasketUri = API.Basket.UpdateBasket(_remoteServiceBaseUrl);
var basketUrl = _remoteServiceBaseUrl;
var response = await _apiClient.PostAsync(basketUrl, basket);
var response = await _apiClient.PostAsync(updateBasketUri, basket, token);
response.EnsureSuccessStatusCode();
@ -88,7 +81,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
order.OrderItems.Add(new OrderItem()
{
ProductId = int.Parse(x.ProductId),
PictureUrl = x.PictureUrl,
ProductName = x.ProductName,
Units = x.Quantity,
@ -102,7 +95,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
public async Task AddItemToBasket(ApplicationUser user, BasketItem product)
{
Basket basket = await GetBasket(user);
var basket = await GetBasket(user);
if (basket == null)
{
basket = new Basket()
@ -113,20 +107,25 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
}
basket.Items.Add(product);
await UpdateBasket(basket);
}
public async Task CleanBasket(ApplicationUser user)
{
var context = _httpContextAccesor.HttpContext;
var token = await context.Authentication.GetTokenAsync("access_token");
var token = await GetUserTokenAsync();
var cleanBasketUri = API.Basket.CleanBasket(_remoteServiceBaseUrl, user.Id);
var response = await _apiClient.DeleteAsync(cleanBasketUri, token);
_apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
var basketUrl = $"{_remoteServiceBaseUrl}/{user.Id}";
var response = await _apiClient.DeleteAsync(basketUrl);
//CCE: response status code...
}
async Task<string> GetUserTokenAsync()
{
var context = _httpContextAccesor.HttpContext;
return await context.Authentication.GetTokenAsync("access_token");
}
}
}

+ 25
- 33
src/Web/WebMVC/Services/CatalogService.cs View File

@ -7,43 +7,32 @@ using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Threading.Tasks;
using WebMVC.Infrastructure;
namespace Microsoft.eShopOnContainers.WebMVC.Services
{
public class CatalogService : ICatalogService
{
private readonly IOptionsSnapshot<AppSettings> _settings;
private IHttpClient _apiClient;
private readonly IHttpClient _apiClient;
private readonly ILogger<CatalogService> _logger;
private readonly string _remoteServiceBaseUrl;
public CatalogService(IOptionsSnapshot<AppSettings> settings, ILoggerFactory loggerFactory, IHttpClient httpClient) {
public CatalogService(IOptionsSnapshot<AppSettings> settings, IHttpClient httpClient, ILogger<CatalogService> logger)
{
_settings = settings;
_remoteServiceBaseUrl = $"{_settings.Value.CatalogUrl}/api/v1/catalog/";
_apiClient = httpClient;
var log = loggerFactory.CreateLogger("catalog service");
log.LogDebug(settings.Value.CatalogUrl);
}
public async Task<Catalog> GetCatalogItems(int page,int take, int? brand, int? type)
{
var itemsQs = $"items?pageIndex={page}&pageSize={take}";
var filterQs = "";
_logger = logger;
if (brand.HasValue || type.HasValue)
{
var brandQs = (brand.HasValue) ? brand.Value.ToString() : "null";
var typeQs = (type.HasValue) ? type.Value.ToString() : "null";
filterQs = $"/type/{typeQs}/brand/{brandQs}";
}
var catalogUrl = $"{_remoteServiceBaseUrl}items{filterQs}?pageIndex={page}&pageSize={take}";
_remoteServiceBaseUrl = $"{_settings.Value.CatalogUrl}/api/v1/catalog/";
}
var dataString = "";
public async Task<Catalog> GetCatalogItems(int page, int take, int? brand, int? type)
{
var allcatalogItemsUri = API.Catalog.GetAllCatalogItems(_remoteServiceBaseUrl, page, take, brand, type);
//
// Using a HttpClient wrapper with Retry and Exponential Backoff
//
dataString = await _apiClient.GetStringAsync(catalogUrl);
var dataString = await _apiClient.GetStringAsync(allcatalogItemsUri);
var response = JsonConvert.DeserializeObject<Catalog>(dataString);
@ -52,14 +41,16 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
public async Task<IEnumerable<SelectListItem>> GetBrands()
{
var url = $"{_remoteServiceBaseUrl}catalogBrands";
var dataString = await _apiClient.GetStringAsync(url);
var getBrandsUri = API.Catalog.GetAllBrands(_remoteServiceBaseUrl);
var dataString = await _apiClient.GetStringAsync(getBrandsUri);
var items = new List<SelectListItem>();
items.Add(new SelectListItem() { Value = null, Text = "All", Selected = true });
JArray brands = JArray.Parse(dataString);
foreach (JObject brand in brands.Children<JObject>())
var brands = JArray.Parse(dataString);
foreach (var brand in brands.Children<JObject>())
{
items.Add(new SelectListItem()
{
@ -73,14 +64,15 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
public async Task<IEnumerable<SelectListItem>> GetTypes()
{
var url = $"{_remoteServiceBaseUrl}catalogTypes";
var dataString = await _apiClient.GetStringAsync(url);
var getTypesUri = API.Catalog.GetAllTypes(_remoteServiceBaseUrl);
var dataString = await _apiClient.GetStringAsync(getTypesUri);
var items = new List<SelectListItem>();
items.Add(new SelectListItem() { Value = null, Text = "All", Selected = true });
JArray brands = JArray.Parse(dataString);
foreach (JObject brand in brands.Children<JObject>())
var brands = JArray.Parse(dataString);
foreach (var brand in brands.Children<JObject>())
{
items.Add(new SelectListItem()
{


+ 34
- 33
src/Web/WebMVC/Services/OrderingService.cs View File

@ -1,14 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
using Microsoft.Extensions.Options;
using System.Net.Http;
using Newtonsoft.Json;
using Microsoft.AspNetCore.Authentication;
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using WebMVC.Infrastructure;
namespace Microsoft.eShopOnContainers.WebMVC.Services
{
@ -27,15 +26,13 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
_apiClient = httpClient;
}
async public Task<Order> GetOrder(ApplicationUser user, string Id)
async public Task<Order> GetOrder(ApplicationUser user, string id)
{
var context = _httpContextAccesor.HttpContext;
var token = await context.Authentication.GetTokenAsync("access_token");
_apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
var token = await GetUserTokenAsync();
var getOrderUri = API.Order.GetOrder(_remoteServiceBaseUrl, id);
var dataString = await _apiClient.GetStringAsync(getOrderUri, token);
var ordersUrl = $"{_remoteServiceBaseUrl}/{Id}";
var dataString = await _apiClient.GetStringAsync(ordersUrl);
var response = JsonConvert.DeserializeObject<Order>(dataString);
return response;
@ -43,16 +40,13 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
async public Task<List<Order>> GetMyOrders(ApplicationUser user)
{
var context = _httpContextAccesor.HttpContext;
var token = await context.Authentication.GetTokenAsync("access_token");
var token = await GetUserTokenAsync();
var allMyOrdersUri = API.Order.GetAllMyOrders(_remoteServiceBaseUrl);
_apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
var ordersUrl = _remoteServiceBaseUrl;
var dataString = await _apiClient.GetStringAsync(ordersUrl);
var dataString = await _apiClient.GetStringAsync(allMyOrdersUri, token);
var response = JsonConvert.DeserializeObject<List<Order>>(dataString);
return response;
return response;
}
public Order MapUserInfoIntoOrder(ApplicationUser user, Order order)
@ -62,10 +56,10 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
order.State = user.State;
order.Country = user.Country;
order.ZipCode = user.ZipCode;
order.CardNumber = user.CardNumber;
order.CardHolderName = user.CardHolderName;
order.CardExpiration = new DateTime(int.Parse("20" + user.Expiration.Split('/')[1]),int.Parse(user.Expiration.Split('/')[0]), 1);
order.CardExpiration = new DateTime(int.Parse("20" + user.Expiration.Split('/')[1]), int.Parse(user.Expiration.Split('/')[0]), 1);
order.CardSecurityNumber = user.SecurityNumber;
return order;
@ -73,21 +67,21 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
async public Task CreateOrder(Order order)
{
var context = _httpContextAccesor.HttpContext;
var token = await context.Authentication.GetTokenAsync("access_token");
_apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
_apiClient.Inst.DefaultRequestHeaders.Add("x-requestid", order.RequestId.ToString());
var token = await GetUserTokenAsync();
var requestId = order.RequestId.ToString();
var addNewOrderUri = API.Order.AddNewOrder(_remoteServiceBaseUrl);
var ordersUrl = $"{_remoteServiceBaseUrl}/new";
order.CardTypeId = 1;
order.CardExpirationApiFormat();
SetFakeIdToProducts(order);
var response = await _apiClient.PostAsync(ordersUrl, order);
var response = await _apiClient.PostAsync(addNewOrderUri, order, token, requestId);
if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
throw new Exception("Error creating order, try later");
{
throw new Exception("Error creating order, try later.");
}
response.EnsureSuccessStatusCode();
}
@ -106,10 +100,17 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
destination.CardSecurityNumber = original.CardSecurityNumber;
}
private void SetFakeIdToProducts(Order order)
void SetFakeIdToProducts(Order order)
{
var id = 1;
order.OrderItems.ForEach(x => { x.ProductId = id; id++; });
}
async Task<string> GetUserTokenAsync()
{
var context = _httpContextAccesor.HttpContext;
return await context.Authentication.GetTokenAsync("access_token");
}
}
}

+ 18
- 13
src/Web/WebMVC/Startup.cs View File

@ -54,29 +54,34 @@ namespace Microsoft.eShopOnContainers.WebMVC
services.AddHealthChecks(checks =>
{
checks.AddUrlCheck(Configuration["CatalogUrl"]);
checks.AddUrlCheck(Configuration["OrderingUrl"]);
checks.AddUrlCheck(Configuration["BasketUrl"]);
checks.AddUrlCheck(Configuration["IdentityUrl"]);
var minutes = 1;
if (int.TryParse(Configuration["HealthCheck:Timeout"], out var minutesParsed))
{
minutes = minutesParsed;
}
checks.AddUrlCheck(Configuration["CatalogUrl"] + "/hc", TimeSpan.FromMinutes(minutes));
checks.AddUrlCheck(Configuration["OrderingUrl"] + "/hc", TimeSpan.FromMinutes(minutes));
checks.AddUrlCheck(Configuration["BasketUrl"] + "/hc", TimeSpan.FromMinutes(minutes));
checks.AddUrlCheck(Configuration["IdentityUrl"] + "/hc", TimeSpan.FromMinutes(minutes));
});
// Add application services.
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddTransient<ICatalogService, CatalogService>();
services.AddTransient<IOrderingService, OrderingService>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddTransient<ICatalogService, CatalogService>();
services.AddTransient<IOrderingService, OrderingService>();
services.AddTransient<IBasketService, BasketService>();
services.AddTransient<IIdentityParser<ApplicationUser>, IdentityParser>();
if (Configuration.GetValue<string>("UseResilientHttp") == bool.TrueString)
{
services.AddTransient<IResilientHttpClientFactory, ResilientHttpClientFactory>();
services.AddTransient<IHttpClient, ResilientHttpClient>(sp => sp.GetService<IResilientHttpClientFactory>().CreateResilientHttpClient());
services.AddSingleton<IResilientHttpClientFactory, ResilientHttpClientFactory>();
services.AddSingleton<IHttpClient, ResilientHttpClient>(sp => sp.GetService<IResilientHttpClientFactory>().CreateResilientHttpClient());
}
else
{
services.AddTransient<IHttpClient, StandardHttpClient>();
services.AddSingleton<IHttpClient, StandardHttpClient>();
}
}
}
// 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)
@ -113,10 +118,10 @@ namespace Microsoft.eShopOnContainers.WebMVC
AuthenticationScheme = "oidc",
SignInScheme = "Cookies",
Authority = identityUrl.ToString(),
PostLogoutRedirectUri = callBackUrl.ToString(),
PostLogoutRedirectUri = callBackUrl.ToString(),
ClientId = "mvc",
ClientSecret = "secret",
ResponseType = "code id_token",
ResponseType = "code id_token",
SaveTokens = true,
GetClaimsFromUserInfoEndpoint = true,
RequireHttpsMetadata = false,


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

@ -55,7 +55,7 @@
</section>
<section class="col-sm-6">
<div class="esh-app-footer-text hidden-xs"> e-ShoponContainers. All right reserved </div>
<div class="esh-app-footer-text hidden-xs"> e-ShoponContainers. By Microsoft Corp. </div>
</section>
</article>


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

@ -13,12 +13,12 @@
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<ItemGroup>
<!--<ItemGroup>
<Compile Remove="wwwroot\lib\bootstrap\**" />
<Content Remove="wwwroot\lib\bootstrap\**" />
<EmbeddedResource Remove="wwwroot\lib\bootstrap\**" />
<None Remove="wwwroot\lib\bootstrap\**" />
</ItemGroup>
</ItemGroup>-->
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="1.1.0" />


+ 1
- 1
src/Web/WebMVC/wwwroot/css/site.min.css
File diff suppressed because it is too large
View File


+ 10
- 4
src/Web/WebSPA/Startup.cs View File

@ -45,10 +45,16 @@ namespace eShopConContainers.WebSPA
{
services.AddHealthChecks(checks =>
{
checks.AddUrlCheck(Configuration["CatalogUrl"]);
checks.AddUrlCheck(Configuration["OrderingUrl"]);
checks.AddUrlCheck(Configuration["BasketUrl"]);
checks.AddUrlCheck(Configuration["IdentityUrl"]);
var minutes = 1;
if (int.TryParse(Configuration["HealthCheck:Timeout"], out var minutesParsed))
{
minutes = minutesParsed;
}
checks.AddUrlCheck(Configuration["CatalogUrlHC"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheck(Configuration["OrderingUrlHC"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheck(Configuration["BasketUrlHC"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheck(Configuration["IdentityUrlHC"], TimeSpan.FromMinutes(minutes));
});
services.Configure<AppSettings>(Configuration);


+ 3
- 1
src/Web/WebSPA/WebSPA.csproj View File

@ -73,12 +73,14 @@
</ItemGroup>
<!-- workaround for https://github.com/aspnet/websdk/issues/114 -->
<!--
<Target Name="AddGeneratedContentItems" BeforeTargets="AssignTargetPaths" DependsOnTargets="PrepareForPublish">
<ItemGroup>
<Content Include="wwwroot/**" CopyToPublishDirectory="PreserveNewest" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder);@(Content)" />
</ItemGroup>
</Target>
-->
<ItemGroup>
<ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
<ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />


+ 1
- 0
src/Web/WebStatus/Controllers/HomeController.cs View File

@ -28,6 +28,7 @@ namespace WebStatus.Controllers
data.AddResult(checkResult.Key, checkResult.Value);
}
ViewBag.RefreshSeconds = 60;
return View(data);
}


+ 2
- 2
src/Web/WebStatus/Extensions/HealthCheckBuilderExtensions.cs View File

@ -8,11 +8,11 @@ namespace WebStatus.Extensions
{
public static class HealthCheckBuilderExtensions
{
public static HealthCheckBuilder AddUrlCheckIfNotNull(this HealthCheckBuilder builder, string url)
public static HealthCheckBuilder AddUrlCheckIfNotNull(this HealthCheckBuilder builder, string url, TimeSpan cacheDuration)
{
if (!string.IsNullOrEmpty(url))
{
builder.AddUrlCheck(url);
builder.AddUrlCheck(url, cacheDuration);
}
return builder;


+ 12
- 6
src/Web/WebStatus/Startup.cs View File

@ -32,12 +32,18 @@ namespace WebStatus
// Add framework services.
services.AddHealthChecks(checks =>
{
checks.AddUrlCheckIfNotNull(Configuration["OrderingUrl"]);
checks.AddUrlCheckIfNotNull(Configuration["BasketUrl"]);
checks.AddUrlCheckIfNotNull(Configuration["CatalogUrl"]);
checks.AddUrlCheckIfNotNull(Configuration["IdentityUrl"]);
checks.AddUrlCheckIfNotNull(Configuration["mvc"]);
checks.AddUrlCheckIfNotNull(Configuration["spa"]);
var minutes = 1;
if (int.TryParse(Configuration["HealthCheck:Timeout"], out var minutesParsed))
{
minutes = minutesParsed;
}
checks.AddUrlCheckIfNotNull(Configuration["OrderingUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["BasketUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["CatalogUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["IdentityUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["mvc"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["spa"], TimeSpan.FromMinutes(minutes));
});
services.AddMvc();
}


+ 10
- 3
src/Web/WebStatus/Views/Shared/_Layout.cshtml View File

@ -16,6 +16,12 @@
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
</environment>
@if (ViewBag.RefreshSeconds != null && ViewBag.RefreshSeconds > 0)
{
<meta http-equiv="refresh" content="@ViewBag.RefreshSeconds">
}
@Html.Raw(JavaScriptSnippet.FullScript)
</head>
<body>
@ -42,9 +48,10 @@
<div class="container body-content">
@RenderBody()
</div>
<footer class="container footer">
<p class="center">&copy; 2017 - WebStatus</p>
</footer>
<br />
<div id="footer">
<p>&nbsp;&copy; 2017 - WebStatus</p>
</div>
<environment names="Development">


+ 2
- 2
test/Services/FunctionalTests/Services/Catalog/CatalogScenariosBase.cs View File

@ -32,9 +32,9 @@ namespace FunctionalTests.Services.Catalog
}
}
public static class Post
public static class Put
{
public static string UpdateCatalogProduct = "api/v1/catalog/update";
public static string UpdateCatalogProduct = "api/v1/catalog/items";
}
}
}

+ 1
- 1
test/Services/FunctionalTests/Services/IntegrationEventsScenarios.cs View File

@ -43,7 +43,7 @@ namespace FunctionalTests.Services
var itemToModify = basket.Items[2];
var oldPrice = itemToModify.UnitPrice;
var newPrice = oldPrice + priceModification;
var pRes = await catalogClient.PostAsync(CatalogScenariosBase.Post.UpdateCatalogProduct, new StringContent(ChangePrice(itemToModify, newPrice, originalCatalogProducts), UTF8Encoding.UTF8, "application/json"));
var pRes = await catalogClient.PutAsync(CatalogScenariosBase.Put.UpdateCatalogProduct, new StringContent(ChangePrice(itemToModify, newPrice, originalCatalogProducts), UTF8Encoding.UTF8, "application/json"));
var modifiedCatalogProducts = await GetCatalogAsync(catalogClient);


+ 1
- 1
test/Services/IntegrationTests/Services/Ordering/OrderingScenarios.cs View File

@ -93,7 +93,7 @@
string BuildOrderWithInvalidExperationTime()
{
var order = new CreateOrderCommand(
null,
new List<OrderItemDTO>(),
cardExpiration: DateTime.UtcNow.AddYears(-1),
cardNumber: "5145-555-5555",
cardHolderName: "Jhon Senna",


+ 3
- 1
test/Services/UnitTest/Ordering/Application/NewOrderCommandHandlerTest.cs View File

@ -14,6 +14,8 @@ namespace UnitTest.Ordering.Application
using System.Collections;
using System.Collections.Generic;
using Xunit;
using static Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands.CreateOrderCommand;
public class NewOrderRequestHandlerTest
{
private readonly Mock<IOrderRepository> _orderRepositoryMock;
@ -72,7 +74,7 @@ namespace UnitTest.Ordering.Application
private CreateOrderCommand FakeOrderRequestWithBuyer(Dictionary<string, object> args = null)
{
return new CreateOrderCommand(
null,
new List<OrderItemDTO>(),
city: args != null && args.ContainsKey("city") ? (string)args["city"] : null,
street: args != null && args.ContainsKey("street") ? (string)args["street"] : null,
state: args != null && args.ContainsKey("state") ? (string)args["state"] : null,


+ 3
- 2
test/Services/UnitTest/Ordering/Application/OrdersWebApiTest.cs View File

@ -6,6 +6,7 @@ using Microsoft.eShopOnContainers.Services.Ordering.API.Controllers;
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
using Moq;
using System;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
@ -59,7 +60,7 @@ namespace UnitTest.Ordering.Application
public async Task Get_orders_success()
{
//Arrange
var fakeDynamicResult = new Object();
var fakeDynamicResult = Enumerable.Empty<object>();
_orderQueriesMock.Setup(x => x.GetOrdersAsync())
.Returns(Task.FromResult(fakeDynamicResult));
@ -92,7 +93,7 @@ namespace UnitTest.Ordering.Application
public async Task Get_cardTypes_success()
{
//Arrange
var fakeDynamicResult = new Object();
var fakeDynamicResult = Enumerable.Empty<object>();
_orderQueriesMock.Setup(x => x.GetCardTypesAsync())
.Returns(Task.FromResult(fakeDynamicResult));


Loading…
Cancel
Save