diff --git a/README.CICD.k8s.md b/README.CICD.k8s.md
new file mode 100644
index 000000000..182880fc5
--- /dev/null
+++ b/README.CICD.k8s.md
@@ -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:
+
+
+
+* 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\\.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
+>```
+
+
+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
+>```
+
+
+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)/'
+>```
+
+
diff --git a/_docker/rabbitmq/Dockerfile.nanowin b/_docker/rabbitmq/Dockerfile.nanowin
deleted file mode 100644
index 26474c235..000000000
--- a/_docker/rabbitmq/Dockerfile.nanowin
+++ /dev/null
@@ -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
\ No newline at end of file
diff --git a/_docker/rabbitmq/enabled_plugins b/_docker/rabbitmq/enabled_plugins
deleted file mode 100644
index 9eafc419b..000000000
--- a/_docker/rabbitmq/enabled_plugins
+++ /dev/null
@@ -1 +0,0 @@
-[rabbitmq_amqp1_0,rabbitmq_management].
diff --git a/_docker/rabbitmq/rabbitmq.config b/_docker/rabbitmq/rabbitmq.config
deleted file mode 100644
index f7837f213..000000000
--- a/_docker/rabbitmq/rabbitmq.config
+++ /dev/null
@@ -1 +0,0 @@
-[{rabbit, [{loopback_users, []}]}].
\ No newline at end of file
diff --git a/_docker/redis/Dockerfile.nanowin b/_docker/redis/Dockerfile.nanowin
deleted file mode 100644
index a08bcb0b6..000000000
--- a/_docker/redis/Dockerfile.nanowin
+++ /dev/null
@@ -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 }
diff --git a/cli-mac/build-bits.sh b/cli-mac/build-bits.sh
old mode 100644
new mode 100755
index f8ad2e2f9..681c3605d
--- a/cli-mac/build-bits.sh
+++ b/cli-mac/build-bits.sh
@@ -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"
diff --git a/docker-compose-windows.override.yml b/docker-compose-windows.override.yml
index c85864d72..c3733c164 100644
--- a/docker-compose-windows.override.yml
+++ b/docker-compose-windows.override.yml
@@ -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:
diff --git a/docker-compose-windows.prod.yml b/docker-compose-windows.prod.yml
index 8d00df4ca..7b9c9ab22 100644
--- a/docker-compose-windows.prod.yml
+++ b/docker-compose-windows.prod.yml
@@ -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:
diff --git a/docker-compose-windows.yml b/docker-compose-windows.yml
index 5a08a9302..48f7ef7b4 100644
--- a/docker-compose-windows.yml
+++ b/docker-compose-windows.yml
@@ -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
diff --git a/docker-compose.ci.build.yml b/docker-compose.ci.build.yml
index 546b7690f..1b3f3bea3 100644
--- a/docker-compose.ci.build.yml
+++ b/docker-compose.ci.build.yml
@@ -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"
+
\ No newline at end of file
diff --git a/docker-compose.override.yml b/docker-compose.override.yml
index f96a8d177..04d1c4d9c 100644
--- a/docker-compose.override.yml
+++ b/docker-compose.override.yml
@@ -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"
diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml
index 58bfe5f82..c5d8839ea 100644
--- a/docker-compose.prod.yml
+++ b/docker-compose.prod.yml
@@ -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"
\ No newline at end of file
+ - "5107:80"
\ No newline at end of file
diff --git a/eShopOnContainers-iOS.sln b/eShopOnContainers-iOS.sln
new file mode 100644
index 000000000..a6e889786
--- /dev/null
+++ b/eShopOnContainers-iOS.sln
@@ -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
diff --git a/img/k8s/blob_creation.png b/img/k8s/blob_creation.png
new file mode 100644
index 000000000..a9e386ead
Binary files /dev/null and b/img/k8s/blob_creation.png differ
diff --git a/img/k8s/deploy_script_task.png b/img/k8s/deploy_script_task.png
new file mode 100644
index 000000000..917625f3e
Binary files /dev/null and b/img/k8s/deploy_script_task.png differ
diff --git a/img/k8s/get_kubectlbin_task.png b/img/k8s/get_kubectlbin_task.png
new file mode 100644
index 000000000..423aceca8
Binary files /dev/null and b/img/k8s/get_kubectlbin_task.png differ
diff --git a/img/k8s/get_kubectlconfig_task.png b/img/k8s/get_kubectlconfig_task.png
new file mode 100644
index 000000000..594e68ba7
Binary files /dev/null and b/img/k8s/get_kubectlconfig_task.png differ
diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/HealthCheckBuilderSqlServerExtensions.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/HealthCheckBuilderSqlServerExtensions.cs
index 4998c91ed..1837d9638 100644
--- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/HealthCheckBuilderSqlServerExtensions.cs
+++ b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/HealthCheckBuilderSqlServerExtensions.cs
@@ -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;
}
diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/NumericChecks.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/NumericChecks.cs
index f3c795629..4c958234e 100644
--- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/NumericChecks.cs
+++ b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/NumericChecks.cs
@@ -10,7 +10,14 @@ namespace Microsoft.Extensions.HealthChecks
{
// Numeric checks
- public static HealthCheckBuilder AddMinValueCheck(this HealthCheckBuilder builder, string name, T minValue, Func currentValueFunc)
+ public static HealthCheckBuilder AddMinValueCheck(this HealthCheckBuilder builder, string name, T minValue, Func currentValueFunc) where T : IComparable
+ {
+ Guard.ArgumentNotNull(nameof(builder), builder);
+
+ return AddMinValueCheck(builder, name, minValue, currentValueFunc, builder.DefaultCacheDuration);
+ }
+
+ public static HealthCheckBuilder AddMinValueCheck(this HealthCheckBuilder builder, string name, T minValue, Func currentValueFunc, TimeSpan cacheDuration)
where T : IComparable
{
Guard.ArgumentNotNull(nameof(builder), builder);
@@ -26,12 +33,19 @@ namespace Microsoft.Extensions.HealthChecks
$"min={minValue}, current={currentValue}",
new Dictionary { { "min", minValue }, { "current", currentValue } }
);
- });
+ }, cacheDuration);
return builder;
}
- public static HealthCheckBuilder AddMaxValueCheck(this HealthCheckBuilder builder, string name, T maxValue, Func currentValueFunc)
+ public static HealthCheckBuilder AddMaxValueCheck(this HealthCheckBuilder builder, string name, T maxValue, Func currentValueFunc) where T : IComparable
+ {
+ Guard.ArgumentNotNull(nameof(builder), builder);
+
+ return AddMaxValueCheck(builder, name, maxValue, currentValueFunc, builder.DefaultCacheDuration);
+ }
+
+ public static HealthCheckBuilder AddMaxValueCheck(this HealthCheckBuilder builder, string name, T maxValue, Func currentValueFunc, TimeSpan cacheDuration)
where T : IComparable
{
Guard.ArgumentNotNull(nameof(builder), builder);
@@ -47,7 +61,7 @@ namespace Microsoft.Extensions.HealthChecks
$"max={maxValue}, current={currentValue}",
new Dictionary { { "max", maxValue }, { "current", currentValue } }
);
- });
+ }, cacheDuration);
return builder;
}
diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/SystemChecks.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/SystemChecks.cs
index d4491fda4..dbd9feff2 100644
--- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/SystemChecks.cs
+++ b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/SystemChecks.cs
@@ -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);
}
}
diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/UrlChecks.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/UrlChecks.cs
index d7df58def..2a6cfe908 100644
--- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/UrlChecks.cs
+++ b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/UrlChecks.cs
@@ -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 checkFunc)
+ {
+ Guard.ArgumentNotNull(nameof(builder), builder);
+
+ return AddUrlCheck(builder, url, checkFunc, builder.DefaultCacheDuration);
+ }
public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url,
- Func checkFunc)
+ Func checkFunc,
+ TimeSpan cacheDuration)
{
Guard.ArgumentNotNull(nameof(checkFunc), checkFunc);
- return AddUrlCheck(builder, url, response => new ValueTask(checkFunc(response)));
+ return AddUrlCheck(builder, url, response => new ValueTask(checkFunc(response)), cacheDuration);
+ }
+
+ // Func returning Task
+
+ public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url, Func> checkFunc)
+ {
+ Guard.ArgumentNotNull(nameof(builder), builder);
+
+ return AddUrlCheck(builder, url, checkFunc, builder.DefaultCacheDuration);
}
public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url,
- Func> checkFunc)
+ Func> checkFunc,
+ TimeSpan cacheDuration)
{
Guard.ArgumentNotNull(nameof(checkFunc), checkFunc);
- return AddUrlCheck(builder, url, response => new ValueTask(checkFunc(response)));
+ return AddUrlCheck(builder, url, response => new ValueTask(checkFunc(response)), cacheDuration);
+ }
+
+ // Func returning ValueTask
+
+ public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url, Func> checkFunc)
+ {
+ Guard.ArgumentNotNull(nameof(builder), builder);
+
+ return AddUrlCheck(builder, url, checkFunc, builder.DefaultCacheDuration);
}
public static HealthCheckBuilder AddUrlCheck(this HealthCheckBuilder builder, string url,
- Func> checkFunc)
+ Func> 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;
}
}
diff --git a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckBuilder.cs b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckBuilder.cs
index 4e1c6e4c9..006e4a6ef 100644
--- a/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckBuilder.cs
+++ b/src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/HealthCheckBuilder.cs
@@ -21,7 +21,7 @@ namespace Microsoft.Extensions.HealthChecks
[string.Empty] = _currentGroup
};
- DefaultCacheDuration = TimeSpan.FromMinutes(1);
+ DefaultCacheDuration = TimeSpan.FromMinutes(5);
}
///
diff --git a/src/BuildingBlocks/Resilience/Resilience.Http/IHttpClient.cs b/src/BuildingBlocks/Resilience/Resilience.Http/IHttpClient.cs
index 0e56a66da..5ea3003ed 100644
--- a/src/BuildingBlocks/Resilience/Resilience.Http/IHttpClient.cs
+++ b/src/BuildingBlocks/Resilience/Resilience.Http/IHttpClient.cs
@@ -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 GetStringAsync(string uri);
- Task PostAsync(string uri, T item);
- Task DeleteAsync(string uri);
+ Task GetStringAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer");
+
+ Task PostAsync(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer");
+
+ Task DeleteAsync(string uri, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer");
+
+ Task PutAsync(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer");
}
}
diff --git a/src/BuildingBlocks/Resilience/Resilience.Http/ResiliencePolicy.cs b/src/BuildingBlocks/Resilience/Resilience.Http/ResiliencePolicy.cs
deleted file mode 100644
index 63eadc857..000000000
--- a/src/BuildingBlocks/Resilience/Resilience.Http/ResiliencePolicy.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http
-{
- public class ResiliencePolicy
- {
- }
-}
diff --git a/src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs b/src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs
index 2ccc84aaa..d80352862 100644
--- a/src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs
+++ b/src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs
@@ -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
///
public class ResilientHttpClient : IHttpClient
{
- private HttpClient _client;
- private PolicyWrap _policyWrapper;
- private ILogger _logger;
- public HttpClient Inst => _client;
+ private readonly HttpClient _client;
+ private readonly ILogger _logger;
+ private readonly Func> _policyCreator;
+ private ConcurrentDictionary _policyWrappers;
- public ResilientHttpClient(Policy[] policies, ILogger logger)
+ public ResilientHttpClient(Func> policyCreator, ILogger logger)
{
_client = new HttpClient();
_logger = logger;
+ _policyCreator = policyCreator;
+ _policyWrappers = new ConcurrentDictionary();
+ }
- // Add Policies to be applied
- _policyWrapper = Policy.WrapAsync(policies);
- }
- public Task GetStringAsync(string uri) =>
- HttpInvoker(() =>
- _client.GetStringAsync(uri));
+ public Task PostAsync(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
+ {
+ return DoPostPutAsync(HttpMethod.Post, uri, item, authorizationToken, requestId, authorizationMethod);
+ }
- public Task PostAsync(string uri, T item) =>
- // a new StringContent must be created for each retry
- // as it is disposed after each call
- HttpInvoker(() =>
+ public Task PutAsync(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
+ {
+ return DoPostPutAsync(HttpMethod.Put, uri, item, authorizationToken, requestId, authorizationMethod);
+ }
+
+ public Task 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 DeleteAsync(string uri) =>
- HttpInvoker(() => _client.DeleteAsync(uri));
+ public Task 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 DoPostPutAsync(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 HttpInvoker(string origin, Func> action)
+ {
+ var normalizedOrigin = NormalizeOrigin(origin);
+
+ if (!_policyWrappers.TryGetValue(normalizedOrigin, out PolicyWrap policyWrap))
+ {
+ policyWrap = Policy.Wrap(_policyCreator(normalizedOrigin).ToArray());
+ _policyWrappers.TryAdd(normalizedOrigin, policyWrap);
+ }
- private Task HttpInvoker(Func> 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;
+ }
+ }
}
diff --git a/src/BuildingBlocks/Resilience/Resilience.Http/StandardHttpClient.cs b/src/BuildingBlocks/Resilience/Resilience.Http/StandardHttpClient.cs
index 4f400caf5..3d5217064 100644
--- a/src/BuildingBlocks/Resilience/Resilience.Http/StandardHttpClient.cs
+++ b/src/BuildingBlocks/Resilience/Resilience.Http/StandardHttpClient.cs
@@ -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 _logger;
- public HttpClient Inst => _client;
+
public StandardHttpClient(ILogger logger)
{
_client = new HttpClient();
_logger = logger;
}
-
- public Task GetStringAsync(string uri) =>
- _client.GetStringAsync(uri);
- public Task PostAsync(string uri, T item)
+ public async Task 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 DeleteAsync(string uri) =>
- _client.DeleteAsync(uri);
+ private async Task DoPostPutAsync(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 PostAsync(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 PutAsync(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 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);
+ }
}
}
diff --git a/src/Services/Catalog/Catalog.API/Startup.cs b/src/Services/Catalog/Catalog.API/Startup.cs
index 9eb195674..65fb26515 100644
--- a/src/Services/Catalog/Catalog.API/Startup.cs
+++ b/src/Services/Catalog/Catalog.API/Startup.cs
@@ -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 =>
diff --git a/src/Services/Identity/Identity.API/Configuration/Config.cs b/src/Services/Identity/Identity.API/Configuration/Config.cs
index c26674591..744d0a0ce 100644
--- a/src/Services/Identity/Identity.API/Configuration/Config.cs
+++ b/src/Services/Identity/Identity.API/Configuration/Config.cs
@@ -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
{
- $"{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
{
- $"{clientsUrl["Mvc"]}/signout-callback-oidc",
- "http://localhost:5100/signout-callback-oidc"
+ $"{clientsUrl["Mvc"]}/signout-callback-oidc"
},
AllowedScopes = new List
{
diff --git a/src/Services/Identity/Identity.API/Startup.cs b/src/Services/Identity/Identity.API/Startup.cs
index b47f0535d..981e305c8 100644
--- a/src/Services/Identity/Identity.API/Startup.cs
+++ b/src/Services/Identity/Identity.API/Startup.cs
@@ -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();
diff --git a/src/Services/Ordering/Ordering.API/Application/Queries/IOrderQueries.cs b/src/Services/Ordering/Ordering.API/Application/Queries/IOrderQueries.cs
index 8d78524ea..253b01e9c 100644
--- a/src/Services/Ordering/Ordering.API/Application/Queries/IOrderQueries.cs
+++ b/src/Services/Ordering/Ordering.API/Application/Queries/IOrderQueries.cs
@@ -1,13 +1,14 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries
{
+ using System.Collections.Generic;
using System.Threading.Tasks;
public interface IOrderQueries
{
Task GetOrderAsync(int id);
- Task GetOrdersAsync();
+ Task> GetOrdersAsync();
- Task GetCardTypesAsync();
+ Task> GetCardTypesAsync();
}
}
diff --git a/src/Services/Ordering/Ordering.API/Application/Queries/OrderQueries.cs b/src/Services/Ordering/Ordering.API/Application/Queries/OrderQueries.cs
index 9d909e254..e51cf04ce 100644
--- a/src/Services/Ordering/Ordering.API/Application/Queries/OrderQueries.cs
+++ b/src/Services/Ordering/Ordering.API/Application/Queries/OrderQueries.cs
@@ -44,7 +44,7 @@
}
}
- public async Task GetOrdersAsync()
+ public async Task> GetOrdersAsync()
{
using (var connection = new SqlConnection(_connectionString))
{
@@ -58,7 +58,7 @@
}
}
- public async Task GetCardTypesAsync()
+ public async Task> GetCardTypesAsync()
{
using (var connection = new SqlConnection(_connectionString))
{
diff --git a/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs b/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs
index c5b21aeef..902eb007b 100644
--- a/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs
+++ b/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs
@@ -68,8 +68,9 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
[HttpGet]
public async Task GetOrders()
{
- var orders = await _orderQueries
- .GetOrdersAsync();
+ var orderTask = _orderQueries.GetOrdersAsync();
+
+ var orders = await orderTask;
return Ok(orders);
}
diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/Middlewares/FailingStartupFilter.cs b/src/Services/Ordering/Ordering.API/Infrastructure/Middlewares/FailingStartupFilter.cs
new file mode 100644
index 000000000..028239f2d
--- /dev/null
+++ b/src/Services/Ordering/Ordering.API/Infrastructure/Middlewares/FailingStartupFilter.cs
@@ -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 Configure(Action next)
+ {
+ return app =>
+ {
+ app.UseFailingMiddleware();
+ next(app);
+ };
+ }
+ }
+}
diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/Middlewares/FailingWebHostBuilderExtensions.cs b/src/Services/Ordering/Ordering.API/Infrastructure/Middlewares/FailingWebHostBuilderExtensions.cs
new file mode 100644
index 000000000..1c4979fae
--- /dev/null
+++ b/src/Services/Ordering/Ordering.API/Infrastructure/Middlewares/FailingWebHostBuilderExtensions.cs
@@ -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(new FailingStartupFilter());
+ });
+ return builder;
+ }
+
+ }
+}
diff --git a/src/Services/Ordering/Ordering.API/Program.cs b/src/Services/Ordering/Ordering.API/Program.cs
index ba92a2da9..752c15e80 100644
--- a/src/Services/Ordering/Ordering.API/Program.cs
+++ b/src/Services/Ordering/Ordering.API/Program.cs
@@ -10,6 +10,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API
{
var host = new WebHostBuilder()
.UseKestrel()
+ .UseFailing("/Failing")
.UseHealthChecks("/hc")
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
diff --git a/src/Services/Ordering/Ordering.API/Startup.cs b/src/Services/Ordering/Ordering.API/Startup.cs
index 58d8f1cbe..0cc8dbc0a 100644
--- a/src/Services/Ordering/Ordering.API/Startup.cs
+++ b/src/Services/Ordering/Ordering.API/Startup.cs
@@ -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();
diff --git a/src/Web/WebMVC/Controllers/OrderController.cs b/src/Web/WebMVC/Controllers/OrderController.cs
index 90be194dc..83152d697 100644
--- a/src/Web/WebMVC/Controllers/OrderController.cs
+++ b/src/Web/WebMVC/Controllers/OrderController.cs
@@ -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);
}
diff --git a/src/Web/WebMVC/Infrastructure/API.cs b/src/Web/WebMVC/Infrastructure/API.cs
new file mode 100644
index 000000000..c837b8067
--- /dev/null
+++ b/src/Web/WebMVC/Infrastructure/API.cs
@@ -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";
+ }
+ }
+ }
+}
diff --git a/src/Web/WebMVC/Infrastructure/ResilientHttpClientFactory.cs b/src/Web/WebMVC/Infrastructure/ResilientHttpClientFactory.cs
index 8efadf366..6322869ff 100644
--- a/src/Web/WebMVC/Infrastructure/ResilientHttpClientFactory.cs
+++ b/src/Web/WebMVC/Infrastructure/ResilientHttpClientFactory.cs
@@ -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()
- .WaitAndRetryAsync(
+ Policy.Handle()
+ .WaitAndRetry(
// number of retries
6,
// exponential backofff
@@ -40,7 +36,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
_logger.LogDebug(msg);
}),
Policy.Handle()
- .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");
- })};
+ })
+ };
}
}
diff --git a/src/Web/WebMVC/Services/BasketService.cs b/src/Web/WebMVC/Services/BasketService.cs
index 7d82a0fc6..bd418ea26 100644
--- a/src/Web/WebMVC/Services/BasketService.cs
+++ b/src/Web/WebMVC/Services/BasketService.cs
@@ -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 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(dataString) ??
+ var response = JsonConvert.DeserializeObject(dataString) ??
new Basket()
{
BuyerId = user.Id
@@ -47,14 +44,10 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
public async Task 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 GetUserTokenAsync()
+ {
+ var context = _httpContextAccesor.HttpContext;
+ return await context.Authentication.GetTokenAsync("access_token");
+ }
}
}
diff --git a/src/Web/WebMVC/Services/CatalogService.cs b/src/Web/WebMVC/Services/CatalogService.cs
index f7225ff0b..2af428e2e 100644
--- a/src/Web/WebMVC/Services/CatalogService.cs
+++ b/src/Web/WebMVC/Services/CatalogService.cs
@@ -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 _settings;
- private IHttpClient _apiClient;
+ private readonly IHttpClient _apiClient;
+ private readonly ILogger _logger;
+
private readonly string _remoteServiceBaseUrl;
-
- public CatalogService(IOptionsSnapshot settings, ILoggerFactory loggerFactory, IHttpClient httpClient) {
+
+ public CatalogService(IOptionsSnapshot settings, IHttpClient httpClient, ILogger 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 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 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(dataString);
@@ -52,14 +41,16 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
public async Task> 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();
items.Add(new SelectListItem() { Value = null, Text = "All", Selected = true });
- JArray brands = JArray.Parse(dataString);
- foreach (JObject brand in brands.Children())
+ var brands = JArray.Parse(dataString);
+
+ foreach (var brand in brands.Children())
{
items.Add(new SelectListItem()
{
@@ -73,14 +64,15 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
public async Task> 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();
items.Add(new SelectListItem() { Value = null, Text = "All", Selected = true });
- JArray brands = JArray.Parse(dataString);
- foreach (JObject brand in brands.Children())
+ var brands = JArray.Parse(dataString);
+ foreach (var brand in brands.Children())
{
items.Add(new SelectListItem()
{
diff --git a/src/Web/WebMVC/Services/OrderingService.cs b/src/Web/WebMVC/Services/OrderingService.cs
index 570a48361..8f198fbed 100644
--- a/src/Web/WebMVC/Services/OrderingService.cs
+++ b/src/Web/WebMVC/Services/OrderingService.cs
@@ -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 GetOrder(ApplicationUser user, string Id)
+ async public Task 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(dataString);
return response;
@@ -43,16 +40,13 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
async public Task> 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>(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 GetUserTokenAsync()
+ {
+ var context = _httpContextAccesor.HttpContext;
+
+ return await context.Authentication.GetTokenAsync("access_token");
+ }
}
}
diff --git a/src/Web/WebMVC/Startup.cs b/src/Web/WebMVC/Startup.cs
index e86c88c04..ba0b1244f 100644
--- a/src/Web/WebMVC/Startup.cs
+++ b/src/Web/WebMVC/Startup.cs
@@ -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();
- services.AddTransient();
- services.AddTransient();
+ services.AddSingleton();
+ services.AddTransient();
+ services.AddTransient();
services.AddTransient();
services.AddTransient, IdentityParser>();
if (Configuration.GetValue("UseResilientHttp") == bool.TrueString)
{
- services.AddTransient();
- services.AddTransient(sp => sp.GetService().CreateResilientHttpClient());
+ services.AddSingleton();
+ services.AddSingleton(sp => sp.GetService().CreateResilientHttpClient());
}
else
{
- services.AddTransient();
+ services.AddSingleton();
}
- }
+ }
// 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,
diff --git a/src/Web/WebMVC/Views/Shared/_Layout.cshtml b/src/Web/WebMVC/Views/Shared/_Layout.cshtml
index 456248b94..990018b09 100644
--- a/src/Web/WebMVC/Views/Shared/_Layout.cshtml
+++ b/src/Web/WebMVC/Views/Shared/_Layout.cshtml
@@ -55,7 +55,7 @@
diff --git a/src/Web/WebMVC/WebMVC.csproj b/src/Web/WebMVC/WebMVC.csproj
index 3f0f6b84b..f109548e6 100644
--- a/src/Web/WebMVC/WebMVC.csproj
+++ b/src/Web/WebMVC/WebMVC.csproj
@@ -13,12 +13,12 @@
..\..\..\docker-compose.dcproj
-
+
diff --git a/src/Web/WebMVC/wwwroot/css/site.min.css b/src/Web/WebMVC/wwwroot/css/site.min.css
index f5fc90999..2a4a53b47 100644
--- a/src/Web/WebMVC/wwwroot/css/site.min.css
+++ b/src/Web/WebMVC/wwwroot/css/site.min.css
@@ -1 +1 @@
-.esh-app-footer{background-color:#000;border-top:1px solid #eee;margin-top:2.5rem;padding-bottom:2.5rem;padding-top:2.5rem;width:100%}.esh-app-footer-brand{height:50px;width:230px}.esh-app-footer-text{color:#83d01b;line-height:50px;text-align:right;width:100%}@font-face{font-family:Montserrat;font-weight:400;src:url("../fonts/Montserrat-Regular.eot?") format("eot"),url("../fonts/Montserrat-Regular.woff") format("woff"),url("../fonts/Montserrat-Regular.ttf") format("truetype"),url("../fonts/Montserrat-Regular.svg#Montserrat") format("svg")}@font-face{font-family:Montserrat;font-weight:700;src:url("../fonts/Montserrat-Bold.eot?") format("eot"),url("../fonts/Montserrat-Bold.woff") format("woff"),url("../fonts/Montserrat-Bold.ttf") format("truetype"),url("../fonts/Montserrat-Bold.svg#Montserrat") format("svg")}html,body{font-family:Montserrat,sans-serif;font-size:16px;font-weight:400;z-index:10}*,*::after,*::before{box-sizing:border-box}.preloading{color:#00a69c;display:block;font-size:1.5rem;left:50%;position:fixed;top:50%;transform:translate(-50%,-50%)}select::-ms-expand{display:none}@media screen and (min-width:992px){.form-input{max-width:360px;width:360px}}.form-input{border-radius:0;height:45px;padding:10px}.form-input-small{max-width:100px !important}.form-input-medium{width:150px !important}.alert{padding-left:0}.alert-danger{background-color:transparent;border:0;color:#fb0d0d;font-size:12px}a,a:active,a:hover,a:visited{color:#000;text-decoration:none;transition:color .35s}a:hover,a:active{color:#75b918;transition:color .35s}.esh-basket{min-height:80vh}.esh-basket-titles{padding-bottom:1rem;padding-top:2rem}.esh-basket-titles--clean{padding-bottom:0;padding-top:0}.esh-basket-title{text-transform:uppercase}.esh-basket-items--border{border-bottom:1px solid #eee;padding:.5rem 0}.esh-basket-items--border:last-of-type{border-color:transparent}.esh-basket-item{font-size:1rem;font-weight:300}.esh-basket-item--middle{line-height:8rem}@media screen and (max-width:1024px){.esh-basket-item--middle{line-height:1rem}}.esh-basket-item--mark{color:#00a69c}.esh-basket-image{height:8rem}.esh-basket-input{line-height:1rem;width:100%}.esh-basket-checkout{border:none;border-radius:0;background-color:#83d01b;color:#fff;display:inline-block;font-size:1rem;font-weight:400;margin-top:1rem;padding:1rem 1.5rem;text-align:center;text-transform:uppercase;transition:all .35s}.esh-basket-checkout:hover{background-color:#4a760f;transition:all .35s}.esh-basket-margin12{margin-left:12px}.esh-basketstatus{cursor:pointer;display:inline-block;float:right;position:relative;transition:all .35s}.esh-basketstatus.is-disabled{opacity:.5;pointer-events:none}.esh-basketstatus-image{height:36px;margin-top:.5rem}.esh-basketstatus-badge{background-color:#83d01b;border-radius:50%;color:#fff;display:block;height:1.5rem;left:50%;position:absolute;text-align:center;top:0;transform:translateX(-38%);transition:all .35s;width:1.5rem}.esh-basketstatus:hover .esh-basketstatus-badge{background-color:transparent;color:#75b918;transition:all .35s}.esh-catalog-hero{background-image:url("../images/main_banner.png");background-size:cover;height:260px;width:100%}.esh-catalog-title{position:relative;top:74.28571px}.esh-catalog-filters{background-color:#00a69c;height:65px}.esh-catalog-filter{background-color:transparent;border-color:#00d9cc;color:#fff;cursor:pointer;margin-right:1rem;margin-top:.5rem;outline-color:#83d01b;padding-bottom:0;padding-left:.5rem;padding-right:.5rem;padding-top:1.5rem;min-width:140px;-webkit-appearance:none}.esh-catalog-filter option{background-color:#00a69c}.esh-catalog-label{display:inline-block;position:relative;z-index:0}.esh-catalog-label::before{color:rgba(255,255,255,.5);content:attr(data-title);font-size:.65rem;margin-top:.65rem;margin-left:.5rem;position:absolute;text-transform:uppercase;z-index:1}.esh-catalog-label::after{background-image:url("../images/arrow-down.png");height:7px;content:'';position:absolute;right:1.5rem;top:2.5rem;width:10px;z-index:1}.esh-catalog-send{background-color:#83d01b;color:#fff;cursor:pointer;font-size:1rem;transform:translateY(.5rem);padding:.5rem;transition:all .35s}.esh-catalog-send:hover{background-color:#4a760f;transition:all .35s}.esh-catalog-items{margin-top:1rem}.esh-catalog-item{text-align:center;margin-bottom:1.5rem;width:33%;display:inline-block;float:none !important}@media screen and (max-width:1024px){.esh-catalog-item{width:50%}}@media screen and (max-width:768px){.esh-catalog-item{width:100%}}.esh-catalog-thumbnail{max-width:370px;width:100%}.esh-catalog-button{background-color:#83d01b;border:none;color:#fff;cursor:pointer;font-size:1rem;height:3rem;margin-top:1rem;transition:all .35s;width:80%}.esh-catalog-button.is-disabled{opacity:.5;pointer-events:none}.esh-catalog-button:hover{background-color:#4a760f;transition:all .35s}.esh-catalog-name{font-size:1rem;font-weight:300;margin-top:.5rem;text-align:center;text-transform:uppercase}.esh-catalog-price{text-align:center;font-weight:900;font-size:28px}.esh-catalog-price::before{content:'$'}.esh-orders{min-height:80vh;overflow-x:hidden}.esh-orders-header{background-color:#00a69c;height:4rem}.esh-orders-back{color:rgba(255,255,255,.4);line-height:4rem;text-transform:uppercase;text-decoration:none;transition:color .35s}.esh-orders-back:hover{color:#fff;transition:color .35s}.esh-orders-titles{padding-bottom:1rem;padding-top:2rem}.esh-orders-title{text-transform:uppercase}.esh-orders-items{height:2rem;line-height:2rem;position:relative}.esh-orders-items:nth-of-type(2n+1):before{background-color:#eef;content:'';height:100%;left:0;margin-left:-100vw;position:absolute;top:0;width:200vw;z-index:-1}.esh-orders-item{font-weight:300}.esh-orders-item--hover{opacity:0;pointer-events:none}.esh-orders-items:hover .esh-orders-item--hover{opacity:1;pointer-events:all}.esh-orders-link{color:#83d01b;text-decoration:none;transition:color .35s}.esh-orders-link:hover{color:#75b918;transition:color .35s}.esh-orders_new{min-height:80vh}.esh-orders_new-header{background-color:#00a69c;height:4rem}.esh-orders_new-back{color:rgba(255,255,255,.4);line-height:4rem;text-decoration:none;text-transform:uppercase;transition:color .35s}.esh-orders_new-back:hover{color:#fff;transition:color .35s}.esh-orders_new-section{padding:1rem 0}.esh-orders_new-section--right{text-align:right}.esh-orders_new-placeOrder{background-color:#83d01b;border:0;border-radius:0;color:#fff;display:inline-block;font-size:1rem;font-weight:400;margin-top:1rem;padding:1rem 1.5rem;text-align:center;text-transform:uppercase;transition:all .35s}.esh-orders_new-placeOrder:hover{background-color:#4a760f;transition:all .35s}.esh-orders_new-titles{padding-bottom:1rem;padding-top:2rem}.esh-orders_new-title{font-size:1.25rem;text-transform:uppercase}.esh-orders_new-items--border{border-bottom:1px solid #eee;padding:.5rem 0}.esh-orders_new-items--border:last-of-type{border-color:transparent}.esh-orders_new-item{font-size:1rem;font-weight:300}.esh-orders_new-item--middle{line-height:8rem}@media screen and (max-width:768px){.esh-orders_new-item--middle{line-height:1rem}}.esh-orders_new-item--mark{color:#83d01b}.esh-orders_new-image{height:8rem}.esh-orders_detail{min-height:80vh}.esh-orders_detail-section{padding:1rem 0}.esh-orders_detail-section--right{text-align:right}.esh-orders_detail-titles{padding-bottom:1rem;padding-top:2rem}.esh-orders_detail-title{text-transform:uppercase}.esh-orders_detail-items--border{border-bottom:1px solid #eee;padding:.5rem 0}.esh-orders_detail-items--border:last-of-type{border-color:transparent}.esh-orders_detail-item{font-size:1rem;font-weight:300}.esh-orders_detail-item--middle{line-height:8rem}@media screen and (max-width:768px){.esh-orders_detail-item--middle{line-height:1rem}}.esh-orders_detail-item--mark{color:#83d01b}.esh-orders_detail-image{height:8rem}.esh-identity{line-height:3rem;position:relative;text-align:right}.esh-identity-section{display:inline-block;width:100%}.esh-identity-name{display:inline-block}.esh-identity-name--upper{text-transform:uppercase}@media screen and (max-width:768px){.esh-identity-name{font-size:.85rem}}.esh-identity-image{display:inline-block}.esh-identity-drop{background:#fff;height:0;min-width:14rem;right:0;overflow:hidden;padding:.5rem;position:absolute;top:2.5rem;transition:height .35s}.esh-identity:hover .esh-identity-drop{border:1px solid #eee;height:7rem;transition:height .35s}.esh-identity-item{cursor:pointer;display:block;transition:color .35s}.esh-identity-item:hover{color:#75b918;transition:color .35s}.esh-header{background-color:#00a69c;height:4rem}.esh-header-back{color:rgba(255,255,255,.5) !important;line-height:4rem;text-transform:uppercase;text-decoration:none;transition:color .35s}.esh-header-back:hover{color:#fff !important;transition:color .35s}.esh-pager-wrapper{padding-top:1rem;text-align:center}.esh-pager-item{margin:0 5vw}.esh-pager-item--navigable{display:inline-block;cursor:pointer}.esh-pager-item--navigable.is-disabled{opacity:0;pointer-events:none}.esh-pager-item--navigable:hover{color:#83d01b}@media screen and (max-width:1280px){.esh-pager-item{font-size:.85rem}}@media screen and (max-width:1024px){.esh-pager-item{margin:0 4vw}}
\ No newline at end of file
+.esh-app-footer{background-color:#000;border-top:1px solid #eee;margin-top:2.5rem;padding-bottom:2.5rem;padding-top:2.5rem;width:100%}.esh-app-footer-brand{height:50px;width:230px}.esh-app-footer-text{color:#83d01b;line-height:50px;text-align:right;width:100%}@font-face{font-family:Montserrat;font-weight:400;src:url("../fonts/Montserrat-Regular.eot?") format("eot"),url("../fonts/Montserrat-Regular.woff") format("woff"),url("../fonts/Montserrat-Regular.ttf") format("truetype"),url("../fonts/Montserrat-Regular.svg#Montserrat") format("svg")}@font-face{font-family:Montserrat;font-weight:700;src:url("../fonts/Montserrat-Bold.eot?") format("eot"),url("../fonts/Montserrat-Bold.woff") format("woff"),url("../fonts/Montserrat-Bold.ttf") format("truetype"),url("../fonts/Montserrat-Bold.svg#Montserrat") format("svg")}html,body{font-family:Montserrat,sans-serif;font-size:16px;font-weight:400;z-index:10}*,*::after,*::before{box-sizing:border-box}.preloading{color:#00a69c;display:block;font-size:1.5rem;left:50%;position:fixed;top:50%;transform:translate(-50%,-50%)}select::-ms-expand{display:none}@media screen and (min-width:992px){.form-input{max-width:360px;width:360px}}.form-input{border-radius:0;height:45px;padding:10px}.form-input-small{max-width:100px !important}.form-input-medium{width:150px !important}.alert{padding-left:0}.alert-danger{background-color:transparent;border:0;color:#fb0d0d;font-size:12px}a,a:active,a:hover,a:visited{color:#000;text-decoration:none;transition:color .35s}a:hover,a:active{color:#75b918;transition:color .35s}.esh-pager-wrapper{padding-top:1rem;text-align:center}.esh-pager-item{margin:0 5vw}.esh-pager-item--navigable{display:inline-block;cursor:pointer}.esh-pager-item--navigable.is-disabled{opacity:0;pointer-events:none}.esh-pager-item--navigable:hover{color:#83d01b}@media screen and (max-width:1280px){.esh-pager-item{font-size:.85rem}}@media screen and (max-width:1024px){.esh-pager-item{margin:0 4vw}}.esh-identity{line-height:3rem;position:relative;text-align:right}.esh-identity-section{display:inline-block;width:100%}.esh-identity-name{display:inline-block}.esh-identity-name--upper{text-transform:uppercase}@media screen and (max-width:768px){.esh-identity-name{font-size:.85rem}}.esh-identity-image{display:inline-block}.esh-identity-drop{background:#fff;height:0;min-width:14rem;right:0;overflow:hidden;padding:.5rem;position:absolute;top:2.5rem;transition:height .35s}.esh-identity:hover .esh-identity-drop{border:1px solid #eee;height:7rem;transition:height .35s}.esh-identity-item{cursor:pointer;display:block;transition:color .35s}.esh-identity-item:hover{color:#75b918;transition:color .35s}.esh-header{background-color:#00a69c;height:4rem}.esh-header-back{color:rgba(255,255,255,.5) !important;line-height:4rem;text-transform:uppercase;text-decoration:none;transition:color .35s}.esh-header-back:hover{color:#fff !important;transition:color .35s}.esh-orders{min-height:80vh;overflow-x:hidden}.esh-orders-header{background-color:#00a69c;height:4rem}.esh-orders-back{color:rgba(255,255,255,.4);line-height:4rem;text-transform:uppercase;text-decoration:none;transition:color .35s}.esh-orders-back:hover{color:#fff;transition:color .35s}.esh-orders-titles{padding-bottom:1rem;padding-top:2rem}.esh-orders-title{text-transform:uppercase}.esh-orders-items{height:2rem;line-height:2rem;position:relative}.esh-orders-items:nth-of-type(2n+1):before{background-color:#eef;content:'';height:100%;left:0;margin-left:-100vw;position:absolute;top:0;width:200vw;z-index:-1}.esh-orders-item{font-weight:300}.esh-orders-item--hover{opacity:0;pointer-events:none}.esh-orders-items:hover .esh-orders-item--hover{opacity:1;pointer-events:all}.esh-orders-link{color:#83d01b;text-decoration:none;transition:color .35s}.esh-orders-link:hover{color:#75b918;transition:color .35s}.esh-orders_new{min-height:80vh}.esh-orders_new-header{background-color:#00a69c;height:4rem}.esh-orders_new-back{color:rgba(255,255,255,.4);line-height:4rem;text-decoration:none;text-transform:uppercase;transition:color .35s}.esh-orders_new-back:hover{color:#fff;transition:color .35s}.esh-orders_new-section{padding:1rem 0}.esh-orders_new-section--right{text-align:right}.esh-orders_new-placeOrder{background-color:#83d01b;border:0;border-radius:0;color:#fff;display:inline-block;font-size:1rem;font-weight:400;margin-top:1rem;padding:1rem 1.5rem;text-align:center;text-transform:uppercase;transition:all .35s}.esh-orders_new-placeOrder:hover{background-color:#4a760f;transition:all .35s}.esh-orders_new-titles{padding-bottom:1rem;padding-top:2rem}.esh-orders_new-title{font-size:1.25rem;text-transform:uppercase}.esh-orders_new-items--border{border-bottom:1px solid #eee;padding:.5rem 0}.esh-orders_new-items--border:last-of-type{border-color:transparent}.esh-orders_new-item{font-size:1rem;font-weight:300}.esh-orders_new-item--middle{line-height:8rem}@media screen and (max-width:768px){.esh-orders_new-item--middle{line-height:1rem}}.esh-orders_new-item--mark{color:#83d01b}.esh-orders_new-image{height:8rem}.esh-orders_detail{min-height:80vh}.esh-orders_detail-section{padding:1rem 0}.esh-orders_detail-section--right{text-align:right}.esh-orders_detail-titles{padding-bottom:1rem;padding-top:2rem}.esh-orders_detail-title{text-transform:uppercase}.esh-orders_detail-items--border{border-bottom:1px solid #eee;padding:.5rem 0}.esh-orders_detail-items--border:last-of-type{border-color:transparent}.esh-orders_detail-item{font-size:1rem;font-weight:300}.esh-orders_detail-item--middle{line-height:8rem}@media screen and (max-width:768px){.esh-orders_detail-item--middle{line-height:1rem}}.esh-orders_detail-item--mark{color:#83d01b}.esh-orders_detail-image{height:8rem}.esh-catalog-hero{background-image:url("../images/main_banner.png");background-size:cover;height:260px;width:100%}.esh-catalog-title{position:relative;top:74.28571px}.esh-catalog-filters{background-color:#00a69c;height:65px}.esh-catalog-filter{background-color:transparent;border-color:#00d9cc;color:#fff;cursor:pointer;margin-right:1rem;margin-top:.5rem;outline-color:#83d01b;padding-bottom:0;padding-left:.5rem;padding-right:.5rem;padding-top:1.5rem;min-width:140px;-webkit-appearance:none}.esh-catalog-filter option{background-color:#00a69c}.esh-catalog-label{display:inline-block;position:relative;z-index:0}.esh-catalog-label::before{color:rgba(255,255,255,.5);content:attr(data-title);font-size:.65rem;margin-top:.65rem;margin-left:.5rem;position:absolute;text-transform:uppercase;z-index:1}.esh-catalog-label::after{background-image:url("../images/arrow-down.png");height:7px;content:'';position:absolute;right:1.5rem;top:2.5rem;width:10px;z-index:1}.esh-catalog-send{background-color:#83d01b;color:#fff;cursor:pointer;font-size:1rem;transform:translateY(.5rem);padding:.5rem;transition:all .35s}.esh-catalog-send:hover{background-color:#4a760f;transition:all .35s}.esh-catalog-items{margin-top:1rem}.esh-catalog-item{text-align:center;margin-bottom:1.5rem;width:33%;display:inline-block;float:none !important}@media screen and (max-width:1024px){.esh-catalog-item{width:50%}}@media screen and (max-width:768px){.esh-catalog-item{width:100%}}.esh-catalog-thumbnail{max-width:370px;width:100%}.esh-catalog-button{background-color:#83d01b;border:none;color:#fff;cursor:pointer;font-size:1rem;height:3rem;margin-top:1rem;transition:all .35s;width:80%}.esh-catalog-button.is-disabled{opacity:.5;pointer-events:none}.esh-catalog-button:hover{background-color:#4a760f;transition:all .35s}.esh-catalog-name{font-size:1rem;font-weight:300;margin-top:.5rem;text-align:center;text-transform:uppercase}.esh-catalog-price{text-align:center;font-weight:900;font-size:28px}.esh-catalog-price::before{content:'$'}.esh-basket{min-height:80vh}.esh-basket-titles{padding-bottom:1rem;padding-top:2rem}.esh-basket-titles--clean{padding-bottom:0;padding-top:0}.esh-basket-title{text-transform:uppercase}.esh-basket-items--border{border-bottom:1px solid #eee;padding:.5rem 0}.esh-basket-items--border:last-of-type{border-color:transparent}.esh-basket-item{font-size:1rem;font-weight:300}.esh-basket-item--middle{line-height:8rem}@media screen and (max-width:1024px){.esh-basket-item--middle{line-height:1rem}}.esh-basket-item--mark{color:#00a69c}.esh-basket-image{height:8rem}.esh-basket-input{line-height:1rem;width:100%}.esh-basket-checkout{border:none;border-radius:0;background-color:#83d01b;color:#fff;display:inline-block;font-size:1rem;font-weight:400;margin-top:1rem;padding:1rem 1.5rem;text-align:center;text-transform:uppercase;transition:all .35s}.esh-basket-checkout:hover{background-color:#4a760f;transition:all .35s}.esh-basket-margin12{margin-left:12px}.esh-basketstatus{cursor:pointer;display:inline-block;float:right;position:relative;transition:all .35s}.esh-basketstatus.is-disabled{opacity:.5;pointer-events:none}.esh-basketstatus-image{height:36px;margin-top:.5rem}.esh-basketstatus-badge{background-color:#83d01b;border-radius:50%;color:#fff;display:block;height:1.5rem;left:50%;position:absolute;text-align:center;top:0;transform:translateX(-38%);transition:all .35s;width:1.5rem}.esh-basketstatus:hover .esh-basketstatus-badge{background-color:transparent;color:#75b918;transition:all .35s}
\ No newline at end of file
diff --git a/src/Web/WebSPA/Startup.cs b/src/Web/WebSPA/Startup.cs
index ee932f476..53476266a 100644
--- a/src/Web/WebSPA/Startup.cs
+++ b/src/Web/WebSPA/Startup.cs
@@ -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(Configuration);
diff --git a/src/Web/WebSPA/WebSPA.csproj b/src/Web/WebSPA/WebSPA.csproj
index 03c3cd442..bf126f271 100644
--- a/src/Web/WebSPA/WebSPA.csproj
+++ b/src/Web/WebSPA/WebSPA.csproj
@@ -73,12 +73,14 @@
+
+
diff --git a/src/Web/WebStatus/Controllers/HomeController.cs b/src/Web/WebStatus/Controllers/HomeController.cs
index 34a31f1f5..cd59c44d2 100644
--- a/src/Web/WebStatus/Controllers/HomeController.cs
+++ b/src/Web/WebStatus/Controllers/HomeController.cs
@@ -28,6 +28,7 @@ namespace WebStatus.Controllers
data.AddResult(checkResult.Key, checkResult.Value);
}
+ ViewBag.RefreshSeconds = 60;
return View(data);
}
diff --git a/src/Web/WebStatus/Extensions/HealthCheckBuilderExtensions.cs b/src/Web/WebStatus/Extensions/HealthCheckBuilderExtensions.cs
index 369f59722..c0655b753 100644
--- a/src/Web/WebStatus/Extensions/HealthCheckBuilderExtensions.cs
+++ b/src/Web/WebStatus/Extensions/HealthCheckBuilderExtensions.cs
@@ -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;
diff --git a/src/Web/WebStatus/Startup.cs b/src/Web/WebStatus/Startup.cs
index 06416940c..0b9ecb937 100644
--- a/src/Web/WebStatus/Startup.cs
+++ b/src/Web/WebStatus/Startup.cs
@@ -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();
}
diff --git a/src/Web/WebStatus/Views/Shared/_Layout.cshtml b/src/Web/WebStatus/Views/Shared/_Layout.cshtml
index a7eb2e3b6..7429afcaf 100644
--- a/src/Web/WebStatus/Views/Shared/_Layout.cshtml
+++ b/src/Web/WebStatus/Views/Shared/_Layout.cshtml
@@ -16,6 +16,12 @@
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
+
+ @if (ViewBag.RefreshSeconds != null && ViewBag.RefreshSeconds > 0)
+ {
+
+ }
+
@Html.Raw(JavaScriptSnippet.FullScript)
@@ -42,9 +48,10 @@
@RenderBody()
-
+
+
diff --git a/test/Services/FunctionalTests/Services/Catalog/CatalogScenariosBase.cs b/test/Services/FunctionalTests/Services/Catalog/CatalogScenariosBase.cs
index 2c8c1280b..afc43c2eb 100644
--- a/test/Services/FunctionalTests/Services/Catalog/CatalogScenariosBase.cs
+++ b/test/Services/FunctionalTests/Services/Catalog/CatalogScenariosBase.cs
@@ -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";
}
}
}
diff --git a/test/Services/FunctionalTests/Services/IntegrationEventsScenarios.cs b/test/Services/FunctionalTests/Services/IntegrationEventsScenarios.cs
index 8ed11be3a..fd270d159 100644
--- a/test/Services/FunctionalTests/Services/IntegrationEventsScenarios.cs
+++ b/test/Services/FunctionalTests/Services/IntegrationEventsScenarios.cs
@@ -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);
diff --git a/test/Services/IntegrationTests/Services/Ordering/OrderingScenarios.cs b/test/Services/IntegrationTests/Services/Ordering/OrderingScenarios.cs
index 49f04fa3b..52119997d 100644
--- a/test/Services/IntegrationTests/Services/Ordering/OrderingScenarios.cs
+++ b/test/Services/IntegrationTests/Services/Ordering/OrderingScenarios.cs
@@ -93,7 +93,7 @@
string BuildOrderWithInvalidExperationTime()
{
var order = new CreateOrderCommand(
- null,
+ new List(),
cardExpiration: DateTime.UtcNow.AddYears(-1),
cardNumber: "5145-555-5555",
cardHolderName: "Jhon Senna",
diff --git a/test/Services/UnitTest/Ordering/Application/NewOrderCommandHandlerTest.cs b/test/Services/UnitTest/Ordering/Application/NewOrderCommandHandlerTest.cs
index 9a4a70bf8..1615bcd0b 100644
--- a/test/Services/UnitTest/Ordering/Application/NewOrderCommandHandlerTest.cs
+++ b/test/Services/UnitTest/Ordering/Application/NewOrderCommandHandlerTest.cs
@@ -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 _orderRepositoryMock;
@@ -72,7 +74,7 @@ namespace UnitTest.Ordering.Application
private CreateOrderCommand FakeOrderRequestWithBuyer(Dictionary args = null)
{
return new CreateOrderCommand(
- null,
+ new List(),
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,
diff --git a/test/Services/UnitTest/Ordering/Application/OrdersWebApiTest.cs b/test/Services/UnitTest/Ordering/Application/OrdersWebApiTest.cs
index 8c7659862..c0656f050 100644
--- a/test/Services/UnitTest/Ordering/Application/OrdersWebApiTest.cs
+++ b/test/Services/UnitTest/Ordering/Application/OrdersWebApiTest.cs
@@ -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