Merge from eShopOnContainers Dev
This commit is contained in:
commit
a3e63c11aa
1
.gitignore
vendored
1
.gitignore
vendored
@ -258,3 +258,4 @@ pub/
|
||||
#Ignore marker-file used to know which docker files we have.
|
||||
.eshopdocker_*
|
||||
/src/Web/WebMVC/wwwroot/lib
|
||||
/src/Web/WebMVC/wwwroot/css/site.min.css
|
||||
|
@ -43,7 +43,7 @@ You can download them and start reviewing these Guides/eBooks here:
|
||||
| Architecting & Developing | Containers Lifecycle & CI/CD | App patterns with Xamarin.Forms |
|
||||
| ------------ | ------------| ------------|
|
||||
| <a href='https://aka.ms/microservicesebook'><img src="img/ebook_arch_dev_microservices_containers_cover.png"> </a> | <a href='https://aka.ms/dockerlifecycleebook'> <img src="img/ebook_containers_lifecycle.png"> </a> | <a href='https://aka.ms/xamarinpatternsebook'> <img src="img/xamarin-enterprise-patterns-ebook-cover-small.png"> </a> |
|
||||
| <sup> <a href='https://aka.ms/microservicesebook'>**Download** (First Edition)</a> </sup> | <sup> <a href='https://aka.ms/dockerlifecycleebook'>**Download** (First Edition from late 2016) </a> </sup> | <sup> <a href='https://aka.ms/xamarinpatternsebook'>**Download** (Preview Edition) </a> </sup> |
|
||||
| <sup> <a href='https://aka.ms/microservicesebook'>**Download** (First Edition)</a> </sup> | <sup> <a href='https://aka.ms/dockerlifecycleebook'>**Download** (First Edition from late 2016) </a> </sup> | <sup> <a href='https://aka.ms/xamarinpatternsebook'>**Download** (First Edition) </a> </sup> |
|
||||
|
||||
Send feedback to [dotnet-architecture-ebooks-feedback@service.microsoft.com](dotnet-architecture-ebooks-feedback@service.microsoft.com)
|
||||
<p>
|
||||
@ -76,7 +76,7 @@ Finally, those microservices are consumed by multiple client web and mobile apps
|
||||
## Setting up your development environment for eShopOnContainers
|
||||
### Visual Studio 2017 and Windows based
|
||||
This is the more straightforward way to get started:
|
||||
https://github.com/dotnet/eShopOnContainers/wiki/02.-Setting-eShopOnContainer-solution-up-in-a-Visual-Studio-2017-environment
|
||||
https://github.com/dotnet-architecture/eShopOnContainers/wiki/02.-Setting-eShopOnContainers-in-a-Visual-Studio-2017-environment
|
||||
|
||||
### CLI and Windows based
|
||||
For those who prefer the CLI on Windows, using dotnet CLI, docker CLI and VS Code for Windows:
|
||||
|
@ -1,12 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
declare -x path=$1
|
||||
|
||||
if [ -z "$path" ]; then
|
||||
$path="$(pwd)/../src";
|
||||
fi
|
||||
|
||||
declare -a projectList=(
|
||||
'../src/Services/Catalog/Catalog.API'
|
||||
'../src/Services/Basket/Basket.API'
|
||||
'../src/Services/Ordering/Ordering.API'
|
||||
'../src/Services/Identity/Identity.API'
|
||||
'../src/Web/WebMVC'
|
||||
'../src/Web/WebSPA'
|
||||
'../src/Web/WebStatus'
|
||||
"$path/Web/WebSPA"
|
||||
"$path/Services/Catalog/Catalog.API"
|
||||
"$path/Services/Basket/Basket.API"
|
||||
"$path/Services/Ordering/Ordering.API"
|
||||
"$path/Services/Identity/Identity.API"
|
||||
"$path/Services/Location/Locations.API"
|
||||
"$path/Services/Marketing/Marketing.API"
|
||||
"$path/Services/Payment/Payment.API"
|
||||
"$path/Services/GracePeriod/GracePeriodManager"
|
||||
"$path/Web/WebMVC"
|
||||
"$path/Web/WebStatus"
|
||||
)
|
||||
|
||||
# Build SPA app
|
||||
@ -15,9 +26,9 @@ declare -a projectList=(
|
||||
|
||||
for project in "${projectList[@]}"
|
||||
do
|
||||
echo -e "\e[33mWorking on $(pwd)/$project"
|
||||
echo -e "\e[33mWorking on $path/$project"
|
||||
echo -e "\e[33m\tRemoving old publish output"
|
||||
pushd $(pwd)/$project
|
||||
pushd $path/$project
|
||||
rm -rf obj/Docker/publish
|
||||
echo -e "\e[33m\tRestoring project"
|
||||
dotnet restore
|
||||
@ -26,14 +37,15 @@ do
|
||||
popd
|
||||
done
|
||||
|
||||
# remove old docker images:
|
||||
images=$(docker images --filter=reference="eshop/*" -q)
|
||||
if [ -n "$images" ]; then
|
||||
docker rm $(docker ps -a -q) -f
|
||||
echo "Deleting eShop images in local Docker repo"
|
||||
echo $images
|
||||
docker rmi $(docker images --filter=reference="eshop/*" -q) -f
|
||||
fi
|
||||
## remove old docker images:
|
||||
#images=$(docker images --filter=reference="eshop/*" -q)
|
||||
#if [ -n "$images" ]; then
|
||||
# docker rm $(docker ps -a -q) -f
|
||||
# echo "Deleting eShop images in local Docker repo"
|
||||
# echo $images
|
||||
# docker rmi $(docker images --filter=reference="eshop/*" -q) -f
|
||||
#fi
|
||||
|
||||
|
||||
# No need to build the images, docker build or docker compose will
|
||||
# do that using the images and containers defined in the docker-compose.yml file.
|
||||
|
@ -21,6 +21,6 @@ try {
|
||||
Write-Host "Rule found"
|
||||
}
|
||||
catch [Exception] {
|
||||
New-NetFirewallRule -DisplayName eShopOnContainers-Inbound -Confirm -Description "eShopOnContainers Inbound Rule for port range 5100-5105" -LocalAddress Any -LocalPort 5100-5105 -Protocol tcp -RemoteAddress Any -RemotePort Any -Direction Inbound
|
||||
New-NetFirewallRule -DisplayName eShopOnContainers-Outbound -Confirm -Description "eShopOnContainers Outbound Rule for port range 5100-5105" -LocalAddress Any -LocalPort 5100-5105 -Protocol tcp -RemoteAddress Any -RemotePort Any -Direction Outbound
|
||||
New-NetFirewallRule -DisplayName eShopOnContainers-Inbound -Confirm -Description "eShopOnContainers Inbound Rule for port range 5100-5105" -LocalAddress Any -LocalPort 5100-5110 -Protocol tcp -RemoteAddress Any -RemotePort Any -Direction Inbound
|
||||
New-NetFirewallRule -DisplayName eShopOnContainers-Outbound -Confirm -Description "eShopOnContainers Outbound Rule for port range 5100-5105" -LocalAddress Any -LocalPort 5100-5110 -Protocol tcp -RemoteAddress Any -RemotePort Any -Direction Outbound
|
||||
}
|
11
cli-windows/build-images.ps1
Normal file
11
cli-windows/build-images.ps1
Normal file
@ -0,0 +1,11 @@
|
||||
Param([string] $imageTag)
|
||||
|
||||
$scriptPath = Split-Path $script:MyInvocation.MyCommand.Path
|
||||
|
||||
if ([string]::IsNullOrEmpty($imageTag)) {
|
||||
$imageTag = $(git rev-parse --abbrev-ref HEAD)
|
||||
}
|
||||
|
||||
Write-Host "Building images with tag $imageTag" -ForegroundColor Yellow
|
||||
$env:TAG=$imageTag
|
||||
docker-compose -f "$scriptPath\..\docker-compose.yml" build
|
@ -81,3 +81,30 @@ services:
|
||||
- ACCEPT_EULA=Y
|
||||
ports:
|
||||
- "5433:1433"
|
||||
|
||||
nosql.data:
|
||||
ports:
|
||||
- "27017:27017"
|
||||
|
||||
locations.api:
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Development
|
||||
- ASPNETCORE_URLS=http://0.0.0.0:80
|
||||
- ConnectionString=mongodb://nosql.data
|
||||
- Database=LocationsDb
|
||||
- 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:
|
||||
- "5109:80"
|
||||
|
||||
marketing.api:
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Development
|
||||
- ASPNETCORE_URLS=http://0.0.0.0:80
|
||||
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word
|
||||
- EventBusConnection=rabbitmq
|
||||
- MongoConnectionString=mongodb://nosql.data
|
||||
- MongoDatabase=MarketingDb
|
||||
- identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
|
||||
ports:
|
||||
- "5110:80"
|
@ -76,6 +76,18 @@ services:
|
||||
ports:
|
||||
- "5100:80"
|
||||
|
||||
marketing.api:
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Production
|
||||
- ASPNETCORE_URLS=http://0.0.0.0:80
|
||||
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word
|
||||
- EventBusConnection=rabbitmq
|
||||
- MongoConnectionString=mongodb://nosql.data
|
||||
- MongoDatabase=MarketingDb
|
||||
- identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
|
||||
ports:
|
||||
- "5110:80"
|
||||
|
||||
sql.data:
|
||||
environment:
|
||||
- SA_PASSWORD=Pass@word
|
||||
|
@ -2,7 +2,7 @@ version: '2.1'
|
||||
|
||||
services:
|
||||
basket.api:
|
||||
image: eshop/basket.api-win
|
||||
image: eshop/basket.api-win:${TAG:-latest}
|
||||
build:
|
||||
context: ./src/Services/Basket/Basket.API
|
||||
dockerfile: Dockerfile.nanowin
|
||||
@ -11,7 +11,7 @@ services:
|
||||
- identity.api
|
||||
|
||||
catalog.api:
|
||||
image: eshop/catalog.api-win
|
||||
image: eshop/catalog.api-win:${TAG:-latest}
|
||||
build:
|
||||
context: ./src/Services/Catalog/Catalog.API
|
||||
dockerfile: Dockerfile.nanowin
|
||||
@ -19,7 +19,7 @@ services:
|
||||
- sql.data
|
||||
|
||||
identity.api:
|
||||
image: eshop/identity.api-win
|
||||
image: eshop/identity.api-win:${TAG:-latest}
|
||||
build:
|
||||
context: ./src/Services/Identity/Identity.API
|
||||
dockerfile: Dockerfile.nanowin
|
||||
@ -27,7 +27,7 @@ services:
|
||||
- sql.data
|
||||
|
||||
ordering.api:
|
||||
image: eshop/ordering.api-win
|
||||
image: eshop/ordering.api-win:${TAG:-latest}
|
||||
build:
|
||||
context: ./src/Services/Ordering/Ordering.API
|
||||
dockerfile: Dockerfile.nanowin
|
||||
@ -35,7 +35,7 @@ services:
|
||||
- sql.data
|
||||
|
||||
webspa:
|
||||
image: eshop/webspa-win
|
||||
image: eshop/webspa-win:${TAG:-latest}
|
||||
build:
|
||||
context: ./src/Web/WebSPA
|
||||
dockerfile: Dockerfile.nanowin
|
||||
@ -44,7 +44,7 @@ services:
|
||||
- basket.api
|
||||
|
||||
webmvc:
|
||||
image: eshop/webmvc-win
|
||||
image: eshop/webmvc-win:${TAG:-latest}
|
||||
build:
|
||||
context: ./src/Web/WebMVC
|
||||
dockerfile: Dockerfile.nanowin
|
||||
@ -54,9 +54,32 @@ services:
|
||||
- identity.api
|
||||
- basket.api
|
||||
|
||||
locations.api:
|
||||
image: eshop/locations.api:${TAG:-latest}
|
||||
build:
|
||||
context: ./src/Services/Location/Locations.API
|
||||
dockerfile: Dockerfile
|
||||
depends_on:
|
||||
- nosql.data
|
||||
- rabbitmq
|
||||
|
||||
marketing.api:
|
||||
image: eshop/marketing.api:${TAG:-latest}
|
||||
build:
|
||||
context: ./src/Services/Marketing/Marketing.API
|
||||
dockerfile: Dockerfile
|
||||
depends_on:
|
||||
- sql.data
|
||||
- nosql.data
|
||||
- identity.api
|
||||
- rabbitmq
|
||||
|
||||
sql.data:
|
||||
image: microsoft/mssql-server-windows
|
||||
|
||||
nosql.data:
|
||||
image: mongo:windowsservercore
|
||||
|
||||
basket.data:
|
||||
image: redis:nanoserver
|
||||
# build:
|
||||
|
@ -1,10 +1,14 @@
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
ci-build:
|
||||
image: microsoft/aspnetcore-build:1.0-1.1
|
||||
image: microsoft/aspnetcore-build:1.1.2
|
||||
volumes:
|
||||
- .:/src
|
||||
- ./cli-linux:/cli-linux
|
||||
working_dir: /src
|
||||
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"
|
||||
# DO NOT USE the sln file to compile because msbuild issue (https://github.com/Microsoft/msbuild/issues/2153)
|
||||
# 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"
|
||||
# NOTE: Using build-bits-linux.sh triggers the same MSBUILD error :( (but at least, less frequently)
|
||||
command: /bin/bash -c "pushd ./src/Web/WebSPA && npm rebuild node-sass && popd && pushd /cli-linux && ./build-bits-linux.sh /src"
|
||||
|
56
docker-compose.nobuild.yml
Normal file
56
docker-compose.nobuild.yml
Normal file
@ -0,0 +1,56 @@
|
||||
version: '2'
|
||||
|
||||
services:
|
||||
basket.api:
|
||||
image: eshop/basket.api
|
||||
depends_on:
|
||||
- basket.data
|
||||
- identity.api
|
||||
- rabbitmq
|
||||
|
||||
catalog.api:
|
||||
image: eshop/catalog.api
|
||||
depends_on:
|
||||
- sql.data
|
||||
- rabbitmq
|
||||
|
||||
identity.api:
|
||||
image: eshop/identity.api
|
||||
depends_on:
|
||||
- sql.data
|
||||
|
||||
ordering.api:
|
||||
image: eshop/ordering.api
|
||||
depends_on:
|
||||
- sql.data
|
||||
|
||||
webspa:
|
||||
image: eshop/webspa
|
||||
depends_on:
|
||||
- identity.api
|
||||
- basket.api
|
||||
|
||||
webmvc:
|
||||
image: eshop/webmvc
|
||||
depends_on:
|
||||
- catalog.api
|
||||
- ordering.api
|
||||
- identity.api
|
||||
- basket.api
|
||||
|
||||
sql.data:
|
||||
image: microsoft/mssql-server-linux
|
||||
|
||||
basket.data:
|
||||
image: redis
|
||||
ports:
|
||||
- "6379:6379"
|
||||
|
||||
rabbitmq:
|
||||
image: rabbitmq
|
||||
ports:
|
||||
- "5672:5672"
|
||||
|
||||
webstatus:
|
||||
image: eshop/webstatus
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: '2.1'
|
||||
version: '3'
|
||||
|
||||
# The default docker-compose.override file can use the "localhost" as the external name for testing web apps within the same dev machine.
|
||||
# The ESHOP_EXTERNAL_DNS_NAME_OR_IP environment variable is taken, by default, from the ".env" file defined like:
|
||||
@ -7,6 +7,10 @@ version: '2.1'
|
||||
# An external IP or DNS name has to be used (instead localhost and the 10.0.75.1 IP) when testing the Web apps and the Xamarin apps from remote machines/devices using the same WiFi, for instance.
|
||||
|
||||
services:
|
||||
graceperiodmanager:
|
||||
environment:
|
||||
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word
|
||||
- EventBusConnection=rabbitmq
|
||||
|
||||
basket.api:
|
||||
environment:
|
||||
@ -49,6 +53,19 @@ services:
|
||||
ports:
|
||||
- "5102:80"
|
||||
|
||||
marketing.api:
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Development
|
||||
- ASPNETCORE_URLS=http://0.0.0.0:80
|
||||
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word
|
||||
- MongoConnectionString=mongodb://nosql.data
|
||||
- MongoDatabase=MarketingDb
|
||||
- EventBusConnection=rabbitmq
|
||||
- ExternalCatalogBaseUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5110 #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.
|
||||
ports:
|
||||
- "5110:80"
|
||||
|
||||
webspa:
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Development
|
||||
@ -57,6 +74,7 @@ services:
|
||||
- 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
|
||||
- MarketingUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5110
|
||||
- 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.
|
||||
@ -71,7 +89,8 @@ services:
|
||||
- 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.
|
||||
- IdentityUrl=http://10.0.75.1:5105
|
||||
- MarketingUrl=http://marketing.api #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:80"
|
||||
@ -83,6 +102,10 @@ services:
|
||||
ports:
|
||||
- "5433:1433"
|
||||
|
||||
nosql.data:
|
||||
ports:
|
||||
- "27017:27017"
|
||||
|
||||
webstatus:
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Development
|
||||
@ -95,3 +118,22 @@ services:
|
||||
- spa=http://webspa/hc
|
||||
ports:
|
||||
- "5107:80"
|
||||
|
||||
payment.api:
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Development
|
||||
- ASPNETCORE_URLS=http://0.0.0.0:5108
|
||||
- EventBusConnection=rabbitmq
|
||||
ports:
|
||||
- "5108:80"
|
||||
|
||||
locations.api:
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Development
|
||||
- ASPNETCORE_URLS=http://0.0.0.0:80
|
||||
- ConnectionString=mongodb://nosql.data
|
||||
- Database=LocationsDb
|
||||
- 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:
|
||||
- "5109:80"
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: '2.1'
|
||||
version: '3'
|
||||
|
||||
# The Production docker-compose file has to have the external/real IPs or DNS names for the services
|
||||
# The ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP environment variable is taken, by default, from the ".env" file defined like:
|
||||
@ -54,6 +54,18 @@ services:
|
||||
ports:
|
||||
- "5102:80"
|
||||
|
||||
marketing.api:
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Production
|
||||
- ASPNETCORE_URLS=http://0.0.0.0:80
|
||||
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word
|
||||
- MongoConnectionString=mongodb://nosql.data
|
||||
- MongoDatabase=MarketingDb
|
||||
- EventBusConnection=rabbitmq
|
||||
- identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
|
||||
ports:
|
||||
- "5110:80"
|
||||
|
||||
webspa:
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Production
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: '2.1'
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
basket.api:
|
||||
@ -61,6 +61,22 @@ services:
|
||||
labels:
|
||||
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
||||
|
||||
marketing.api:
|
||||
image: eshop/marketing.api:dev
|
||||
build:
|
||||
args:
|
||||
source: ${DOCKER_BUILD_SOURCE}
|
||||
environment:
|
||||
- DOTNET_USE_POLLING_FILE_WATCHER=1
|
||||
volumes:
|
||||
- ./src/Services/Marketing/Marketing.API:/app
|
||||
- ~/.nuget/packages:/root/.nuget/packages:ro
|
||||
- ~/clrdbg:/clrdbg:ro
|
||||
entrypoint: tail -f /dev/null
|
||||
labels:
|
||||
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
||||
|
||||
|
||||
webspa:
|
||||
image: eshop/webspa:dev
|
||||
build:
|
||||
@ -105,3 +121,46 @@ services:
|
||||
entrypoint: tail -f /dev/null
|
||||
labels:
|
||||
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
||||
|
||||
payment.api:
|
||||
image: eshop/payment.api:dev
|
||||
build:
|
||||
args:
|
||||
source: ${DOCKER_BUILD_SOURCE}
|
||||
environment:
|
||||
- DOTNET_USE_POLLING_FILE_WATCHER=1
|
||||
volumes:
|
||||
- ./src/Services/Payment/Payment.API:/app
|
||||
- ~/.nuget/packages:/root/.nuget/packages:ro
|
||||
- ~/clrdbg:/clrdbg:ro
|
||||
entrypoint: tail -f /dev/null
|
||||
labels:
|
||||
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
||||
|
||||
graceperiodmanager:
|
||||
image: eshop/graceperiodmanager:dev
|
||||
build:
|
||||
args:
|
||||
source: ${DOCKER_BUILD_SOURCE}
|
||||
volumes:
|
||||
- ./src/Services/GracePeriod/GracePeriodManager:/app
|
||||
- ~/.nuget/packages:/root/.nuget/packages:ro
|
||||
- ~/clrdbg:/clrdbg:ro
|
||||
entrypoint: tail -f /dev/null
|
||||
labels:
|
||||
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
||||
|
||||
locations.api:
|
||||
image: eshop/locations.api:dev
|
||||
build:
|
||||
args:
|
||||
source: ${DOCKER_BUILD_SOURCE}
|
||||
environment:
|
||||
- DOTNET_USE_POLLING_FILE_WATCHER=1
|
||||
volumes:
|
||||
- ./src/Services/Location/Locations.API:/app
|
||||
- ~/.nuget/packages:/root/.nuget/packages:ro
|
||||
- ~/clrdbg:/clrdbg:ro
|
||||
entrypoint: tail -f /dev/null
|
||||
labels:
|
||||
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: '2.1'
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
basket.api:
|
||||
@ -41,6 +41,16 @@ services:
|
||||
labels:
|
||||
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
||||
|
||||
marketing.api:
|
||||
build:
|
||||
args:
|
||||
source: ${DOCKER_BUILD_SOURCE}
|
||||
volumes:
|
||||
- ~/clrdbg:/clrdbg:ro
|
||||
entrypoint: tail -f /dev/null
|
||||
labels:
|
||||
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
||||
|
||||
webspa:
|
||||
build:
|
||||
args:
|
||||
@ -70,3 +80,33 @@ services:
|
||||
entrypoint: tail -f /dev/null
|
||||
labels:
|
||||
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
||||
|
||||
payment.api:
|
||||
build:
|
||||
args:
|
||||
source: ${DOCKER_BUILD_SOURCE}
|
||||
volumes:
|
||||
- ~/clrdbg:/clrdbg:ro
|
||||
entrypoint: tail -f /dev/null
|
||||
labels:
|
||||
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
||||
|
||||
graceperiodmanager:
|
||||
build:
|
||||
args:
|
||||
source: ${DOCKER_BUILD_SOURCE}
|
||||
volumes:
|
||||
- ~/clrdbg:/clrdbg:ro
|
||||
entrypoint: tail -f /dev/null
|
||||
labels:
|
||||
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
||||
|
||||
locations.api:
|
||||
build:
|
||||
args:
|
||||
source: ${DOCKER_BUILD_SOURCE}
|
||||
volumes:
|
||||
- ~/clrdbg:/clrdbg:ro
|
||||
entrypoint: tail -f /dev/null
|
||||
labels:
|
||||
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
||||
|
@ -1,18 +1,26 @@
|
||||
version: '2.1'
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
graceperiodmanager:
|
||||
image: eshop/graceperiodmanager:${TAG:-latest}
|
||||
build:
|
||||
context: ./src/Services/GracePeriod/GracePeriodManager
|
||||
dockerfile: Dockerfile
|
||||
depends_on:
|
||||
- sql.data
|
||||
- rabbitmq
|
||||
|
||||
basket.api:
|
||||
image: eshop/basket.api
|
||||
image: eshop/basket.api:${TAG:-latest}
|
||||
build:
|
||||
context: ./src/Services/Basket/Basket.API
|
||||
dockerfile: Dockerfile
|
||||
depends_on:
|
||||
- basket.data
|
||||
- identity.api
|
||||
- rabbitmq
|
||||
|
||||
catalog.api:
|
||||
image: eshop/catalog.api
|
||||
image: eshop/catalog.api:${TAG:-latest}
|
||||
build:
|
||||
context: ./src/Services/Catalog/Catalog.API
|
||||
dockerfile: Dockerfile
|
||||
@ -21,7 +29,7 @@ services:
|
||||
- rabbitmq
|
||||
|
||||
identity.api:
|
||||
image: eshop/identity.api
|
||||
image: eshop/identity.api:${TAG:-latest}
|
||||
build:
|
||||
context: ./src/Services/Identity/Identity.API
|
||||
dockerfile: Dockerfile
|
||||
@ -29,15 +37,27 @@ services:
|
||||
- sql.data
|
||||
|
||||
ordering.api:
|
||||
image: eshop/ordering.api
|
||||
image: eshop/ordering.api:${TAG:-latest}
|
||||
build:
|
||||
context: ./src/Services/Ordering/Ordering.API
|
||||
dockerfile: Dockerfile
|
||||
depends_on:
|
||||
- sql.data
|
||||
- rabbitmq
|
||||
|
||||
marketing.api:
|
||||
image: eshop/marketing.api:${TAG:-latest}
|
||||
build:
|
||||
context: ./src/Services/Marketing/Marketing.API
|
||||
dockerfile: Dockerfile
|
||||
depends_on:
|
||||
- sql.data
|
||||
- nosql.data
|
||||
- identity.api
|
||||
- rabbitmq
|
||||
|
||||
webspa:
|
||||
image: eshop/webspa
|
||||
image: eshop/webspa:${TAG:-latest}
|
||||
build:
|
||||
context: ./src/Web/WebSPA
|
||||
dockerfile: Dockerfile
|
||||
@ -46,7 +66,7 @@ services:
|
||||
- basket.api
|
||||
|
||||
webmvc:
|
||||
image: eshop/webmvc
|
||||
image: eshop/webmvc:${TAG:-latest}
|
||||
build:
|
||||
context: ./src/Web/WebMVC
|
||||
dockerfile: Dockerfile
|
||||
@ -55,10 +75,14 @@ services:
|
||||
- ordering.api
|
||||
- identity.api
|
||||
- basket.api
|
||||
- marketing.api
|
||||
|
||||
sql.data:
|
||||
image: microsoft/mssql-server-linux
|
||||
|
||||
nosql.data:
|
||||
image: mongo
|
||||
|
||||
basket.data:
|
||||
image: redis
|
||||
ports:
|
||||
@ -70,7 +94,24 @@ services:
|
||||
- "5672:5672"
|
||||
|
||||
webstatus:
|
||||
image: eshop/webstatus
|
||||
image: eshop/webstatus:${TAG:-latest}
|
||||
build:
|
||||
context: ./src/Web/WebStatus
|
||||
dockerfile: Dockerfile
|
||||
|
||||
payment.api:
|
||||
image: eshop/payment.api:${TAG:-latest}
|
||||
build:
|
||||
context: ./src/Services/Payment/Payment.API
|
||||
dockerfile: Dockerfile
|
||||
depends_on:
|
||||
- rabbitmq
|
||||
|
||||
locations.api:
|
||||
image: eshop/locations.api:${TAG:-latest}
|
||||
build:
|
||||
context: ./src/Services/Location/Locations.API
|
||||
dockerfile: Dockerfile
|
||||
depends_on:
|
||||
- nosql.data
|
||||
- rabbitmq
|
||||
|
Binary file not shown.
Binary file not shown.
@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26430.6
|
||||
VisualStudioVersion = 15.0.26430.12
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{932D8224-11F6-4D07-B109-DA28AD288A63}"
|
||||
EndProject
|
||||
@ -70,11 +70,31 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Resilience", "Resilience",
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Resilience.Http", "src\BuildingBlocks\Resilience\Resilience.Http\Resilience.Http.csproj", "{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Payment", "Payment", "{022E145D-1593-47EE-9608-8E323D3C63F5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Payment.API", "src\Services\Payment\Payment.API\Payment.API.csproj", "{1A01AF82-6FCB-464C-B39C-F127AEBD315D}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HealthChecks", "src\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj", "{22A0F9C1-2D4A-4107-95B7-8459E6688BC5}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.HealthChecks.SqlServer", "src\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.SqlServer\Microsoft.Extensions.HealthChecks.SqlServer.csproj", "{4BD76717-3102-4969-8C2C-BAAA3F0263B6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventBus.Tests", "src\BuildingBlocks\EventBus\EventBus.Tests\EventBus.Tests.csproj", "{89D80DF1-32E1-4AAF-970F-DA0AA6881F9D}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBus.Tests", "src\BuildingBlocks\EventBus\EventBus.Tests\EventBus.Tests.csproj", "{4A980AC4-7205-46BF-8CCB-09E44D700FD4}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GracePeriod", "GracePeriod", "{F38B4FF0-0B49-405A-B1B4-F7A5E3BC4C4E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GracePeriodManager", "src\Services\GracePeriod\GracePeriodManager\GracePeriodManager.csproj", "{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Location", "Location", "{41139F64-4046-4F16-96B7-D941D96FA9C6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Locations.API", "src\Services\Location\Locations.API\Locations.API.csproj", "{E7581357-FC34-474C-B8F5-307EE3CE05EF}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DataProtection", "DataProtection", "{88B22DBB-AA8F-4290-A454-2C109352C345}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataProtection", "src\BuildingBlocks\DataProtection\DataProtection\DataProtection.csproj", "{23A33F9B-7672-426D-ACF9-FF8436ADC81A}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Marketing", "Marketing", "{A5260DE0-1FDD-467E-9CC1-A028AB081CEE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Marketing.API", "src\Services\Marketing\Marketing.API\Marketing.API.csproj", "{DF395F85-B010-465D-857A-7EBCC512C0C2}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventBusServiceBus", "src\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj", "{69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8}"
|
||||
EndProject
|
||||
@ -860,6 +880,54 @@ Global
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x64.Build.0 = Release|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x86.Build.0 = Release|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|x64.Build.0 = Release|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|x86.Build.0 = Release|Any CPU
|
||||
{22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{22A0F9C1-2D4A-4107-95B7-8459E6688BC5}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
@ -956,6 +1024,246 @@ Global
|
||||
{4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4BD76717-3102-4969-8C2C-BAAA3F0263B6}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4}.Release|x86.Build.0 = Release|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|x64.Build.0 = Release|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Release|x86.Build.0 = Release|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|x64.Build.0 = Release|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|x86.Build.0 = Release|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|x64.Build.0 = Release|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|x86.Build.0 = Release|Any CPU
|
||||
{89D80DF1-32E1-4AAF-970F-DA0AA6881F9D}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{89D80DF1-32E1-4AAF-970F-DA0AA6881F9D}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{89D80DF1-32E1-4AAF-970F-DA0AA6881F9D}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
@ -1085,9 +1393,18 @@ Global
|
||||
{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04}
|
||||
{FBF43D93-F2E7-4FF8-B4AB-186895949B88} = {DB0EFB20-B024-4E5E-A75C-52143C131D25}
|
||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502} = {FBF43D93-F2E7-4FF8-B4AB-186895949B88}
|
||||
{022E145D-1593-47EE-9608-8E323D3C63F5} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8}
|
||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D} = {022E145D-1593-47EE-9608-8E323D3C63F5}
|
||||
{22A0F9C1-2D4A-4107-95B7-8459E6688BC5} = {A81ECBC2-6B00-4DCD-8388-469174033379}
|
||||
{4BD76717-3102-4969-8C2C-BAAA3F0263B6} = {A81ECBC2-6B00-4DCD-8388-469174033379}
|
||||
{89D80DF1-32E1-4AAF-970F-DA0AA6881F9D} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F}
|
||||
{69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F}
|
||||
{4A980AC4-7205-46BF-8CCB-09E44D700FD4} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F}
|
||||
{F38B4FF0-0B49-405A-B1B4-F7A5E3BC4C4E} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8}
|
||||
{F6E0F0DD-1400-43C3-B5E0-7CC325728C47} = {F38B4FF0-0B49-405A-B1B4-F7A5E3BC4C4E}
|
||||
{41139F64-4046-4F16-96B7-D941D96FA9C6} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8}
|
||||
{E7581357-FC34-474C-B8F5-307EE3CE05EF} = {41139F64-4046-4F16-96B7-D941D96FA9C6}
|
||||
{88B22DBB-AA8F-4290-A454-2C109352C345} = {DB0EFB20-B024-4E5E-A75C-52143C131D25}
|
||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A} = {88B22DBB-AA8F-4290-A454-2C109352C345}
|
||||
{A5260DE0-1FDD-467E-9CC1-A028AB081CEE} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8}
|
||||
{DF395F85-B010-465D-857A-7EBCC512C0C2} = {A5260DE0-1FDD-467E-9CC1-A028AB081CEE}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26228.12
|
||||
VisualStudioVersion = 15.0.26430.6
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{932D8224-11F6-4D07-B109-DA28AD288A63}"
|
||||
EndProject
|
||||
@ -97,14 +97,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Health
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.HealthChecks", "src\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj", "{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.HealthChecks.Data", "src\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.Data\Microsoft.Extensions.HealthChecks.Data.csproj", "{0E7AEB45-80F2-42B9-96BB-3414669E58AA}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Resilience", "Resilience", "{D13768ED-5AF1-4E09-96DD-FF6E7A2E5E06}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Resilience.Http", "src\BuildingBlocks\Resilience\Resilience.Http\Resilience.Http.csproj", "{D92EB452-7A72-4B26-A8ED-0204CD376BC4}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebStatus", "src\Web\WebStatus\WebStatus.csproj", "{23FB706A-2701-41E9-8BF9-28936001CA41}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.HealthChecks.SqlServer", "src\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.SqlServer\Microsoft.Extensions.HealthChecks.SqlServer.csproj", "{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
||||
@ -1322,54 +1322,6 @@ Global
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Release|x64.Build.0 = Release|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45}.Release|x86.Build.0 = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA}.Release|x86.Build.0 = Release|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
@ -1466,6 +1418,54 @@ Global
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Release|x64.Build.0 = Release|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41}.Release|x86.Build.0 = Release|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Release|x64.Build.0 = Release|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -1510,9 +1510,9 @@ Global
|
||||
{96CE8CE7-BC97-4A53-899F-5EB63D7BBF7B} = {1EF3AC0F-F27C-46DD-AC53-D762D2C11C45}
|
||||
{FFFD3E09-A803-4F99-BAC5-C93ABA3E02D3} = {96CE8CE7-BC97-4A53-899F-5EB63D7BBF7B}
|
||||
{EE65FA8B-1D87-4050-BC21-F305F2F8AE45} = {96CE8CE7-BC97-4A53-899F-5EB63D7BBF7B}
|
||||
{0E7AEB45-80F2-42B9-96BB-3414669E58AA} = {96CE8CE7-BC97-4A53-899F-5EB63D7BBF7B}
|
||||
{D13768ED-5AF1-4E09-96DD-FF6E7A2E5E06} = {1EF3AC0F-F27C-46DD-AC53-D762D2C11C45}
|
||||
{D92EB452-7A72-4B26-A8ED-0204CD376BC4} = {D13768ED-5AF1-4E09-96DD-FF6E7A2E5E06}
|
||||
{23FB706A-2701-41E9-8BF9-28936001CA41} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04}
|
||||
{6CCC4F1B-602D-4FAD-91A7-002CC86C7612} = {96CE8CE7-BC97-4A53-899F-5EB63D7BBF7B}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
5
global.json
Normal file
5
global.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version":"1.0.4"
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 38 KiB |
29
k8s/basket-data.yaml
Normal file
29
k8s/basket-data.yaml
Normal file
@ -0,0 +1,29 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: eshop
|
||||
component: basket-data
|
||||
name: basket-data
|
||||
spec:
|
||||
ports:
|
||||
- port: 6379
|
||||
selector:
|
||||
app: eshop
|
||||
component: basket-data
|
||||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: basket-data
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: eshop
|
||||
component: basket-data
|
||||
spec:
|
||||
containers:
|
||||
- name: basket-data
|
||||
image: redis:3.2-alpine
|
||||
|
193
k8s/deploy.ps1
193
k8s/deploy.ps1
@ -2,10 +2,14 @@ Param(
|
||||
[parameter(Mandatory=$false)][string]$registry,
|
||||
[parameter(Mandatory=$false)][string]$dockerUser,
|
||||
[parameter(Mandatory=$false)][string]$dockerPassword,
|
||||
[parameter(Mandatory=$false)][bool]$deployCI,
|
||||
[parameter(Mandatory=$false)][bool]$useDockerHub,
|
||||
[parameter(Mandatory=$false)][string]$execPath,
|
||||
[parameter(Mandatory=$false)][string]$kubeconfigPath
|
||||
[parameter(Mandatory=$false)][string]$kubeconfigPath,
|
||||
[parameter(Mandatory=$true)][string]$configFile,
|
||||
[parameter(Mandatory=$false)][string]$imageTag,
|
||||
[parameter(Mandatory=$false)][string]$externalDns,
|
||||
[parameter(Mandatory=$false)][bool]$deployCI=$false,
|
||||
[parameter(Mandatory=$false)][bool]$buildImages=$false,
|
||||
[parameter(Mandatory=$false)][bool]$deployInfrastructure=$true
|
||||
)
|
||||
|
||||
function ExecKube($cmd) {
|
||||
@ -20,7 +24,11 @@ function ExecKube($cmd) {
|
||||
}
|
||||
}
|
||||
|
||||
# Not used when deploying through CI VSTS
|
||||
# Initialization
|
||||
$debugMode = $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent
|
||||
$useDockerHub = [string]::IsNullOrEmpty($registry)
|
||||
|
||||
# Check required commands (only if not in CI environment)
|
||||
if(-not $deployCI) {
|
||||
$requiredCommands = ("docker", "docker-compose", "kubectl")
|
||||
foreach ($command in $requiredCommands) {
|
||||
@ -30,6 +38,45 @@ if(-not $deployCI) {
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$buildImages = false; # Never build images through CI, as they previously built
|
||||
}
|
||||
|
||||
# Get tag to use from current branch if no tag is passed
|
||||
if ([string]::IsNullOrEmpty($imageTag)) {
|
||||
$imageTag = $(git rev-parse --abbrev-ref HEAD)
|
||||
}
|
||||
Write-Host "Docker image Tag: $imageTag" -ForegroundColor Yellow
|
||||
|
||||
# Read config to use
|
||||
$config = Get-Content -Raw -Path $configFile | ConvertFrom-Json
|
||||
if ($debugMode) {
|
||||
Write-Host "[DEBUG]: Using following JSON config: " -ForegroundColor Yellow
|
||||
$json = ConvertTo-Json $config -Depth 5
|
||||
Write-Host $json
|
||||
if (-not $deployCI) {
|
||||
Write-Host "[DEBUG]: Press a key " -ForegroundColor Yellow
|
||||
[System.Console]::Read()
|
||||
}
|
||||
}
|
||||
|
||||
# building and publishing docker images if needed
|
||||
if($buildImages) {
|
||||
Write-Host "Building and publishing eShopOnContainers..." -ForegroundColor Yellow
|
||||
dotnet restore ../eShopOnContainers-ServicesAndWebApps.sln
|
||||
dotnet publish -c Release -o obj/Docker/publish ../eShopOnContainers-ServicesAndWebApps.sln
|
||||
|
||||
Write-Host "Building Docker images tagged with '$imageTag'" -ForegroundColor Yellow
|
||||
$env:TAG=$imageTag
|
||||
docker-compose -p .. -f ../docker-compose.yml build
|
||||
|
||||
Write-Host "Pushing images to $registry..." -ForegroundColor Yellow
|
||||
$services = ("basket.api", "catalog.api", "identity.api", "ordering.api", "marketing.api","payment.api","locations.api", "webmvc", "webspa", "webstatus")
|
||||
foreach ($service in $services) {
|
||||
docker tag eshop/${service}:$imageTag $registry/eshop/${service}:$imageTag
|
||||
docker push $registry/eshop/${service}:$imageTag
|
||||
}
|
||||
}
|
||||
|
||||
# Use ACR instead of DockerHub as image repository
|
||||
if(-not $useDockerHub) {
|
||||
@ -50,77 +97,115 @@ if(-not $useDockerHub) {
|
||||
|
||||
# Removing previous services & deployments
|
||||
Write-Host "Removing existing services & deployments.." -ForegroundColor Yellow
|
||||
ExecKube -cmd 'delete -f sql-data.yaml -f rabbitmq.yaml'
|
||||
ExecKube -cmd 'delete -f services.yaml -f frontend.yaml -f deployments.yaml'
|
||||
ExecKube -cmd 'delete deployments --all'
|
||||
ExecKube -cmd 'delete services --all'
|
||||
ExecKube -cmd 'delete configmap config-files'
|
||||
ExecKube -cmd 'delete configmap urls'
|
||||
ExecKube -cmd 'delete configmap externalcfg'
|
||||
|
||||
# start sql, rabbitmq, frontend deploymentsExecKube -cmd 'delete configmap config-files'
|
||||
ExecKube -cmd 'create configmap config-files --from-file=nginx-conf=nginx.conf'
|
||||
ExecKube -cmd 'label configmap config-files app=eshop'
|
||||
ExecKube -cmd 'create -f sql-data.yaml -f rabbitmq.yaml -f services.yaml -f frontend.yaml'
|
||||
|
||||
# building and publishing docker images not necessary when deploying through CI VSTS
|
||||
if(-not $deployCI) {
|
||||
Write-Host "Building and publishing eShopOnContainers..." -ForegroundColor Yellow
|
||||
dotnet restore ../eShopOnContainers-ServicesAndWebApps.sln
|
||||
dotnet publish -c Release -o obj/Docker/publish ../eShopOnContainers-ServicesAndWebApps.sln
|
||||
|
||||
Write-Host "Building Docker images..." -ForegroundColor Yellow
|
||||
docker-compose -p .. -f ../docker-compose.yml build
|
||||
|
||||
Write-Host "Pushing images to $registry..." -ForegroundColor Yellow
|
||||
$services = ("basket.api", "catalog.api", "identity.api", "ordering.api", "webmvc", "webspa", "webstatus")
|
||||
foreach ($service in $services) {
|
||||
docker tag eshop/$service $registry/eshop/$service
|
||||
docker push $registry/eshop/$service
|
||||
}
|
||||
if ($deployInfrastructure) {
|
||||
Write-Host 'Deploying infrastructure deployments (databases, redis, ...)' -ForegroundColor Yellow
|
||||
ExecKube -cmd 'create -f sql-data.yaml -f basket-data.yaml -f keystore-data.yaml -f rabbitmq.yaml -f nosql-data.yaml'
|
||||
}
|
||||
|
||||
Write-Host "Waiting for frontend's external ip..." -ForegroundColor Yellow
|
||||
while ($true) {
|
||||
$frontendUrl = & ExecKube -cmd 'get svc frontend -o=jsonpath="{.status.loadBalancer.ingress[0].ip}"'
|
||||
if ([bool]($frontendUrl -as [ipaddress])) {
|
||||
break
|
||||
}
|
||||
Start-Sleep -s 15
|
||||
Write-Host 'Deploying code deployments (databases, redis, ...)' -ForegroundColor Yellow
|
||||
ExecKube -cmd 'create -f services.yaml -f frontend.yaml'
|
||||
|
||||
if ([string]::IsNullOrEmpty($externalDns)) {
|
||||
Write-Host "Waiting for frontend's external ip..." -ForegroundColor Yellow
|
||||
while ($true) {
|
||||
$frontendUrl = & ExecKube -cmd 'get svc frontend -o=jsonpath="{.status.loadBalancer.ingress[0].ip}"'
|
||||
if ([bool]($frontendUrl -as [ipaddress])) {
|
||||
break
|
||||
}
|
||||
Start-Sleep -s 15
|
||||
}
|
||||
$externalDns = $frontendUrl
|
||||
}
|
||||
|
||||
Write-Host "Using $externalDns as the external DNS/IP of the k8s cluster"
|
||||
|
||||
ExecKube -cmd 'create configmap urls `
|
||||
--from-literal=BasketUrl=http://$($frontendUrl)/basket-api `
|
||||
--from-literal=BasketHealthCheckUrl=http://$($frontendUrl)/basket-api/hc `
|
||||
--from-literal=BasketUrl=http://basket `
|
||||
--from-literal=BasketHealthCheckUrl=http://basket/hc `
|
||||
--from-literal=CatalogUrl=http://$($frontendUrl)/catalog-api `
|
||||
--from-literal=CatalogHealthCheckUrl=http://$($frontendUrl)/catalog-api/hc `
|
||||
--from-literal=CatalogHealthCheckUrl=http://catalog/hc `
|
||||
--from-literal=IdentityUrl=http://$($frontendUrl)/identity `
|
||||
--from-literal=IdentityHealthCheckUrl=http://$($frontendUrl)/identity/hc `
|
||||
--from-literal=OrderingUrl=http://$($frontendUrl)/ordering-api `
|
||||
--from-literal=OrderingHealthCheckUrl=http://$($frontendUrl)/ordering-api/hc `
|
||||
--from-literal=MvcClient=http://$($frontendUrl)/webmvc `
|
||||
--from-literal=WebMvcHealthCheckUrl=http://$($frontendUrl)/webmvc/hc `
|
||||
--from-literal=WebStatusClient=http://$($frontendUrl)/webstatus `
|
||||
--from-literal=WebSpaHealthCheckUrl=http://$($frontendUrl)/hc `
|
||||
--from-literal=SpaClient=http://$($frontendUrl)'
|
||||
--from-literal=IdentityHealthCheckUrl=http://identity/hc `
|
||||
--from-literal=OrderingUrl=http://ordering `
|
||||
--from-literal=OrderingHealthCheckUrl=http://ordering/hc `
|
||||
--from-literal=MvcClientExternalUrl=http://$($frontendUrl)/webmvc `
|
||||
--from-literal=WebMvcHealthCheckUrl=http://webmvc/hc `
|
||||
--from-literal=MvcClientOrderingUrl=http://ordering `
|
||||
--from-literal=MvcClientCatalogUrl=http://catalog `
|
||||
--from-literal=MvcClientBasketUrl=http://basket `
|
||||
--from-literal=WebSpaHealthCheckUrl=http://webspa/hc `
|
||||
--from-literal=SpaClientOrderingExternalUrl=http://$($externalDns)/ordering-api `
|
||||
--from-literal=SpaClientCatalogExternalUrl=http://$($externalDns)/catalog-api `
|
||||
--from-literal=SpaClientBasketExternalUrl=http://$($externalDns)/basket-api `
|
||||
--from-literal=SpaClientIdentityExternalUrl=http://$($externalDns)/identity `
|
||||
--from-literal=SpaClientExternalUrl=http://$($externalDns)'
|
||||
|
||||
ExecKube -cmd 'label configmap urls app=eshop'
|
||||
|
||||
Write-Host "Creating deployments..."
|
||||
Write-Host "Applying external configuration from json" -ForegroundColor Yellow
|
||||
|
||||
ExecKube -cmd 'create configmap externalcfg `
|
||||
--from-literal=CatalogSqlDb=$($config.sql.catalog) `
|
||||
--from-literal=IdentitySqlDb=$($config.sql.identity) `
|
||||
--from-literal=OrderingSqlDb=$($config.sql.ordering) `
|
||||
--from-literal=MarketingSqlDb=$($config.sql.marketing) `
|
||||
--from-literal=LocationsNoSqlDb=$($config.nosql.locations.constr) `
|
||||
--from-literal=LocationsNoSqlDbName=$($config.nosql.locations.db) `
|
||||
--from-literal=MarketingNoSqlDb=$($config.nosql.marketing.constr) `
|
||||
--from-literal=MarketingNoSqlDbName=$($config.nosql.marketing.db) `
|
||||
--from-literal=BasketRedisConStr=$($config.redis.basket) `
|
||||
--from-literal=LocationsBus=$($config.servicebus.locations) `
|
||||
--from-literal=MarketingBus=$($config.servicebus.marketing) `
|
||||
--from-literal=BasketBus=$($config.servicebus.basket) `
|
||||
--from-literal=OrderingBus=$($config.servicebus.ordering) `
|
||||
--from-literal=CatalogBus=$($config.servicebus.catalog) `
|
||||
--from-literal=PaymentBus=$($config.servicebus.payment) `
|
||||
--from-literal=UseAzureServiceBus=$($config.servicebus.use_azure) `
|
||||
--from-literal=keystore=$($config.redis.keystore) '
|
||||
ExecKube -cmd 'label configmap externalcfg app=eshop'
|
||||
|
||||
Write-Host "Creating deployments..." -ForegroundColor Yellow
|
||||
ExecKube -cmd 'create -f deployments.yaml'
|
||||
|
||||
# not using ACR for pulling images when deploying through CI VSTS
|
||||
if(-not $deployCI) {
|
||||
# update deployments with the private registry before k8s tries to pull images
|
||||
# (deployment templating, or Helm, would obviate this)
|
||||
ExecKube -cmd 'set image -f deployments.yaml `
|
||||
basket=$registry/eshop/basket.api `
|
||||
catalog=$registry/eshop/catalog.api `
|
||||
identity=$registry/eshop/identity.api `
|
||||
ordering=$registry/eshop/ordering.api `
|
||||
webmvc=$registry/eshop/webmvc `
|
||||
webstatus=$registry/eshop/webstatus `
|
||||
webspa=$registry/eshop/webspa'
|
||||
# update deployments with the correct image (with tag and/or registry)
|
||||
Write-Host "Update Image containers to use prefix '$registry' and tag '$imageTag'" -ForegroundColor Yellow
|
||||
$registryPath = ""
|
||||
if (-not [string]::IsNullOrEmpty($registry)) {
|
||||
$registryPath = "$registry/"
|
||||
}
|
||||
|
||||
ExecKube -cmd 'rollout resume -f deployments.yaml'
|
||||
ExecKube -cmd 'set image deployments/basket basket=${registryPath}eshop/basket.api:$imageTag'
|
||||
ExecKube -cmd 'set image deployments/catalog catalog=${registryPath}eshop/catalog.api:$imageTag'
|
||||
ExecKube -cmd 'set image deployments/identity identity=${registryPath}eshop/identity.api:$imageTag'
|
||||
ExecKube -cmd 'set image deployments/ordering ordering=${registryPath}eshop/ordering.api:$imageTag'
|
||||
ExecKube -cmd 'set image deployments/marketing marketing=${registryPath}eshop/marketing.api:$imageTag'
|
||||
ExecKube -cmd 'set image deployments/locations locations=${registryPath}eshop/locations.api:$imageTag'
|
||||
ExecKube -cmd 'set image deployments/payment payment=${registryPath}eshop/payment.api:$imageTag'
|
||||
ExecKube -cmd 'set image deployments/webmvc webmvc=${registryPath}eshop/webmvc:$imageTag'
|
||||
ExecKube -cmd 'set image deployments/webstatus webstatus=${registryPath}eshop/webstatus:$imageTag'
|
||||
ExecKube -cmd 'set image deployments/webspa webspa=${registryPath}eshop/webspa:$imageTag'
|
||||
|
||||
Write-Host "Execute rollout..." -ForegroundColor Yellow
|
||||
ExecKube -cmd 'rollout resume deployments/basket'
|
||||
ExecKube -cmd 'rollout resume deployments/catalog'
|
||||
ExecKube -cmd 'rollout resume deployments/identity'
|
||||
ExecKube -cmd 'rollout resume deployments/ordering'
|
||||
ExecKube -cmd 'rollout resume deployments/marketing'
|
||||
ExecKube -cmd 'rollout resume deployments/locations'
|
||||
ExecKube -cmd 'rollout resume deployments/payment'
|
||||
ExecKube -cmd 'rollout resume deployments/webmvc'
|
||||
ExecKube -cmd 'rollout resume deployments/webstatus'
|
||||
ExecKube -cmd 'rollout resume deployments/webspa'
|
||||
|
||||
Write-Host "WebSPA is exposed at http://$frontendUrl, WebMVC at http://$frontendUrl/webmvc, WebStatus at http://$frontendUrl/webstatus" -ForegroundColor Yellow
|
||||
|
||||
|
@ -18,9 +18,20 @@ spec:
|
||||
- name: ASPNETCORE_URLS
|
||||
value: http://0.0.0.0:80/basket-api
|
||||
- name: ConnectionString
|
||||
value: 127.0.0.1
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: BasketRedisConStr
|
||||
- name: EventBusConnection
|
||||
value: rabbitmq
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: BasketBus
|
||||
- name: AzureServiceBusEnabled
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: UseAzureServiceBus
|
||||
- name: IdentityUrl
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
@ -28,10 +39,6 @@ spec:
|
||||
key: IdentityUrl
|
||||
ports:
|
||||
- containerPort: 80
|
||||
- name: basket-data
|
||||
image: redis:3.2-alpine
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
imagePullSecrets:
|
||||
- name: registry-key
|
||||
---
|
||||
@ -55,14 +62,20 @@ spec:
|
||||
- name: ASPNETCORE_URLS
|
||||
value: http://0.0.0.0:80/catalog-api
|
||||
- name: ConnectionString
|
||||
value: "Server=sql-data;Initial Catalog=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word"
|
||||
- name: EventBusConnection
|
||||
value: rabbitmq
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: CatalogSqlDb
|
||||
- name: ExternalCatalogBaseUrl
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: urls
|
||||
key: CatalogUrl
|
||||
- name: EventBusConnection
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: CatalogBus
|
||||
ports:
|
||||
- containerPort: 80
|
||||
imagePullSecrets:
|
||||
@ -88,17 +101,27 @@ spec:
|
||||
- name: ASPNETCORE_URLS
|
||||
value: http://0.0.0.0:80/identity
|
||||
- name: ConnectionStrings__DefaultConnection
|
||||
value: "Server=sql-data;Initial Catalog=Microsoft.eShopOnContainers.Services.IdentityDb;User Id=sa;Password=Pass@word"
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: IdentitySqlDb
|
||||
- name: DPConnectionString
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: keystore
|
||||
- name: IsClusterEnv
|
||||
value: 'True'
|
||||
- name: MvcClient
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: urls
|
||||
key: MvcClient
|
||||
key: MvcClientExternalUrl
|
||||
- name: SpaClient
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: urls
|
||||
key: SpaClient
|
||||
key: SpaClientExternalUrl
|
||||
ports:
|
||||
- containerPort: 80
|
||||
imagePullSecrets:
|
||||
@ -124,9 +147,20 @@ spec:
|
||||
- name: ASPNETCORE_URLS
|
||||
value: http://0.0.0.0:80/ordering-api
|
||||
- name: ConnectionString
|
||||
value: "Server=sql-data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;"
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: OrderingSqlDb
|
||||
- name: EventBusConnection
|
||||
value: rabbitmq
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: OrderingBus
|
||||
- name: AzureServiceBusEnabled
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: UseAzureServiceBus
|
||||
- name: IdentityUrl
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
@ -139,6 +173,143 @@ spec:
|
||||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: locations
|
||||
spec:
|
||||
paused: true
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: eshop
|
||||
component: locations
|
||||
spec:
|
||||
containers:
|
||||
- name: locations
|
||||
image: eshop/locations.api
|
||||
imagePullPolicy: Always
|
||||
env:
|
||||
- name: ASPNETCORE_URLS
|
||||
value: http://0.0.0.0:80/locations-api
|
||||
- name: ConnectionString
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: LocationsNoSqlDb
|
||||
- name: Database
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: LocationsNoSqlDbName
|
||||
- name: AzureServiceBusEnabled
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: UseAzureServiceBus
|
||||
- name: EventBusConnection
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: LocationsBus
|
||||
- name: IdentityUrl
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: urls
|
||||
key: IdentityUrl
|
||||
ports:
|
||||
- containerPort: 80
|
||||
imagePullSecrets:
|
||||
- name: registry-key
|
||||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: marketing
|
||||
spec:
|
||||
paused: true
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: eshop
|
||||
component: marketing
|
||||
spec:
|
||||
containers:
|
||||
- name: marketing
|
||||
image: eshop/marketing.api
|
||||
imagePullPolicy: Always
|
||||
env:
|
||||
- name: ASPNETCORE_URLS
|
||||
value: http://0.0.0.0:80/marketing-api
|
||||
- name: ConnectionString
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: MarketingSqlDb
|
||||
- name: MongoConnectionString
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: MarketingNoSqlDb
|
||||
- name: MongoDatabase
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: MarketingNoSqlDbName
|
||||
- name: AzureServiceBusEnabled
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: UseAzureServiceBus
|
||||
- name: EventBusConnection
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: MarketingBus
|
||||
- name: IdentityUrl
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: urls
|
||||
key: IdentityUrl
|
||||
ports:
|
||||
- containerPort: 80
|
||||
imagePullSecrets:
|
||||
- name: registry-key
|
||||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: payment
|
||||
spec:
|
||||
paused: true
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: eshop
|
||||
component: payment
|
||||
spec:
|
||||
containers:
|
||||
- name: payment
|
||||
image: eshop/payment.api
|
||||
imagePullPolicy: Always
|
||||
env:
|
||||
- name: ASPNETCORE_URLS
|
||||
value: http://0.0.0.0:80/payment-api
|
||||
- name: AzureServiceBusEnabled
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: UseAzureServiceBus
|
||||
- name: EventBusConnection
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: PaymentBus
|
||||
ports:
|
||||
- containerPort: 80
|
||||
imagePullSecrets:
|
||||
- name: registry-key
|
||||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: webmvc
|
||||
spec:
|
||||
@ -156,21 +327,28 @@ spec:
|
||||
env:
|
||||
- name: ASPNETCORE_URLS
|
||||
value: http://0.0.0.0:80/webmvc
|
||||
- name: DPConnectionString
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: keystore
|
||||
- name: IsClusterEnv
|
||||
value: 'True'
|
||||
- name: BasketUrl
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: urls
|
||||
key: BasketUrl
|
||||
key: MvcClientBasketUrl
|
||||
- name: CallBackUrl
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: urls
|
||||
key: MvcClient
|
||||
key: MvcClientExternalUrl
|
||||
- name: CatalogUrl
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: urls
|
||||
key: CatalogUrl
|
||||
key: MvcClientCatalogUrl
|
||||
- name: IdentityUrl
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
@ -180,13 +358,12 @@ spec:
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: urls
|
||||
key: OrderingUrl
|
||||
key: MvcClientOrderingUrl
|
||||
ports:
|
||||
- containerPort: 80
|
||||
imagePullSecrets:
|
||||
- name: registry-key
|
||||
---
|
||||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@ -260,31 +437,58 @@ spec:
|
||||
env:
|
||||
- name: ASPNETCORE_URLS
|
||||
value: http://0.0.0.0:80
|
||||
- name: DPConnectionString
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: externalcfg
|
||||
key: keystore
|
||||
- name: IsClusterEnv
|
||||
value: 'True'
|
||||
- name: BasketUrl
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: urls
|
||||
key: BasketUrl
|
||||
key: SpaClientBasketExternalUrl
|
||||
- name: CallBackUrl
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: urls
|
||||
key: SpaClient
|
||||
key: SpaClientExternalUrl
|
||||
- name: CatalogUrl
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: urls
|
||||
key: CatalogUrl
|
||||
key: SpaClientCatalogExternalUrl
|
||||
- name: IdentityUrl
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: urls
|
||||
key: IdentityUrl
|
||||
key: SpaClientIdentityExternalUrl
|
||||
- name: OrderingUrl
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: urls
|
||||
key: OrderingUrl
|
||||
key: SpaClientOrderingExternalUrl
|
||||
- name: BasketUrlHC
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: urls
|
||||
key: BasketHealthCheckUrl
|
||||
- name: CatalogUrlHC
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: urls
|
||||
key: CatalogHealthCheckUrl
|
||||
- name: IdentityUrlHC
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: urls
|
||||
key: IdentityHealthCheckUrl
|
||||
- name: OrderingUrlHC
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: urls
|
||||
key: OrderingHealthCheckUrl
|
||||
ports:
|
||||
- containerPort: 80
|
||||
imagePullSecrets:
|
||||
|
@ -3,16 +3,19 @@
|
||||
[parameter(Mandatory=$true)][string]$location,
|
||||
[parameter(Mandatory=$true)][string]$registryName,
|
||||
[parameter(Mandatory=$true)][string]$orchestratorName,
|
||||
[parameter(Mandatory=$true)][string]$dnsName
|
||||
[parameter(Mandatory=$true)][string]$dnsName,
|
||||
[parameter(Mandatory=$true)][string]$createAcr=$true
|
||||
)
|
||||
|
||||
# Create resource group
|
||||
Write-Host "Creating resource group..." -ForegroundColor Yellow
|
||||
az group create --name=$resourceGroupName --location=$location
|
||||
|
||||
# Create Azure Container Registry
|
||||
Write-Host "Creating Azure Container Registry..." -ForegroundColor Yellow
|
||||
az acr create -n $registryName -g $resourceGroupName -l $location --admin-enabled true --sku Basic
|
||||
if ($createAcr) {
|
||||
# Create Azure Container Registry
|
||||
Write-Host "Creating Azure Container Registry..." -ForegroundColor Yellow
|
||||
az acr create -n $registryName -g $resourceGroupName -l $location --admin-enabled true --sku Basic
|
||||
}
|
||||
|
||||
# Create kubernetes orchestrator
|
||||
Write-Host "Creating kubernetes orchestrator..." -ForegroundColor Yellow
|
||||
|
29
k8s/keystore-data.yaml
Normal file
29
k8s/keystore-data.yaml
Normal file
@ -0,0 +1,29 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: eshop
|
||||
component: keystore-data
|
||||
name: keystore-data
|
||||
spec:
|
||||
ports:
|
||||
- port: 6379
|
||||
selector:
|
||||
app: eshop
|
||||
component: keystore-data
|
||||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: keystore-data
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: eshop
|
||||
component: keystore-data
|
||||
spec:
|
||||
containers:
|
||||
- name: keystore-data
|
||||
image: redis:3.2-alpine
|
||||
|
31
k8s/local.json
Normal file
31
k8s/local.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"sql": {
|
||||
"catalog": "Server=sql-data;Initial Catalog=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word;",
|
||||
"identity":"Server=sql-data;Initial Catalog=Microsoft.eShopOnContainers.Services.IdentityDb;User Id=sa;Password=Pass@word;",
|
||||
"ordering":"Server=sql-data;Initial Catalog=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;",
|
||||
"marketing":"Server=sql-data;Initial Catalog=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word;"
|
||||
},
|
||||
"nosql": {
|
||||
"locations": {
|
||||
"constr": "mongodb://nosql-data",
|
||||
"db": "LocationsDb"
|
||||
},
|
||||
"marketing": {
|
||||
"constr": "mongodb://nosql-data",
|
||||
"db": "MarketingDb"
|
||||
}
|
||||
},
|
||||
"redis": {
|
||||
"basket" : "basket-data",
|
||||
"keystore": "keystore-data"
|
||||
},
|
||||
"servicebus": {
|
||||
"use_azure": false,
|
||||
"ordering": "rabbitmq",
|
||||
"marketing": "rabbitmq",
|
||||
"locations": "rabbitmq",
|
||||
"payment": "rabbitmq",
|
||||
"basket": "rabbitmq",
|
||||
"catalog": "rabbitmq"
|
||||
}
|
||||
}
|
@ -71,6 +71,24 @@ http {
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
|
||||
location /marketing-api {
|
||||
proxy_pass http://marketing;
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
|
||||
location /payment-api {
|
||||
proxy_pass http://payment;
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
|
||||
location /locations-api {
|
||||
proxy_pass http://locations;
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://webspa;
|
||||
proxy_redirect off;
|
||||
|
30
k8s/nosql-data.yaml
Normal file
30
k8s/nosql-data.yaml
Normal file
@ -0,0 +1,30 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: eshop
|
||||
component: nosql-data
|
||||
name: nosql-data
|
||||
spec:
|
||||
ports:
|
||||
- port: 27017
|
||||
selector:
|
||||
app: eshop
|
||||
component: nosql-data
|
||||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nosql-data
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: eshop
|
||||
component: nosql-data
|
||||
spec:
|
||||
containers:
|
||||
- name: nosql-data
|
||||
image: mongo
|
||||
ports:
|
||||
- containerPort: 27017
|
@ -56,6 +56,48 @@ spec:
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: eshop
|
||||
component: locations
|
||||
name: locations
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
selector:
|
||||
app: eshop
|
||||
component: locations
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: eshop
|
||||
component: payment
|
||||
name: payment
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
selector:
|
||||
app: eshop
|
||||
component: payment
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: eshop
|
||||
component: marketing
|
||||
name: marketing
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
selector:
|
||||
app: eshop
|
||||
component: marketing
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: eshop
|
||||
|
@ -0,0 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard1.4</TargetFramework>
|
||||
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.CommandBus</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
13
src/BuildingBlocks/CommandBus/CommandBus/ICommandBus.cs
Normal file
13
src/BuildingBlocks/CommandBus/CommandBus/ICommandBus.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.CommandBus
|
||||
{
|
||||
public interface ICommandBus
|
||||
{
|
||||
Task SendAsync<T>(T command) where T : IntegrationCommand;
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.CommandBus
|
||||
{
|
||||
public abstract class IntegrationCommand
|
||||
{
|
||||
public Guid Id { get; private set; }
|
||||
public DateTime Sent { get; private set; }
|
||||
|
||||
protected IntegrationCommand()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
Sent = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard1.4</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp1.1</TargetFramework>
|
||||
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection" Version="1.1.2" />
|
||||
<PackageReference Include="StackExchange.Redis" Version="1.2.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -0,0 +1,95 @@
|
||||
namespace Microsoft.eShopOnContainers.BuildingBlocks
|
||||
{
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.AspNetCore.DataProtection.Repositories;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="IDataProtectionBuilder"/> for configuring
|
||||
/// data protection options.
|
||||
/// </summary>
|
||||
public static class DataProtectionBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets up data protection to persist session keys in Redis.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IDataProtectionBuilder"/> used to set up data protection options.</param>
|
||||
/// <param name="redisConnectionString">The connection string specifying the Redis instance and database for key storage.</param>
|
||||
/// <returns>
|
||||
/// The <paramref name="builder" /> for continued configuration.
|
||||
/// </returns>
|
||||
/// <exception cref="System.ArgumentNullException">
|
||||
/// Thrown if <paramref name="builder" /> or <paramref name="redisConnectionString" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// Thrown if <paramref name="redisConnectionString" /> is empty.
|
||||
/// </exception>
|
||||
public static IDataProtectionBuilder PersistKeysToRedis(this IDataProtectionBuilder builder, string redisConnectionString)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
if (redisConnectionString == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(redisConnectionString));
|
||||
}
|
||||
|
||||
if (redisConnectionString.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("Redis connection string may not be empty.", nameof(redisConnectionString));
|
||||
}
|
||||
|
||||
var ips = Dns.GetHostAddressesAsync(redisConnectionString).Result;
|
||||
|
||||
return builder.Use(ServiceDescriptor.Singleton<IXmlRepository>(services =>
|
||||
new RedisXmlRepository(ips.First().ToString(), services.GetRequiredService<ILogger<RedisXmlRepository>>())));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates an <see cref="IDataProtectionBuilder"/> to use the service of
|
||||
/// a specific type, removing all other services of that type.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IDataProtectionBuilder"/> that should use the specified service.</param>
|
||||
/// <param name="descriptor">The <see cref="ServiceDescriptor"/> with the service the <paramref name="builder" /> should use.</param>
|
||||
/// <returns>
|
||||
/// The <paramref name="builder" /> for continued configuration.
|
||||
/// </returns>
|
||||
/// <exception cref="System.ArgumentNullException">
|
||||
/// Thrown if <paramref name="builder" /> or <paramref name="descriptor" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public static IDataProtectionBuilder Use(this IDataProtectionBuilder builder, ServiceDescriptor descriptor)
|
||||
{
|
||||
// This algorithm of removing all other services of a specific type
|
||||
// before adding the new/replacement service is how the base ASP.NET
|
||||
// DataProtection bits work. Due to some of the differences in how
|
||||
// that base set of bits handles DI, it's better to follow suit
|
||||
// and work in the same way than to try and debug weird issues.
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
if (descriptor == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(descriptor));
|
||||
}
|
||||
|
||||
for (int i = builder.Services.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (builder.Services[i]?.ServiceType == descriptor.ServiceType)
|
||||
{
|
||||
builder.Services.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
builder.Services.Add(descriptor);
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,210 @@
|
||||
namespace Microsoft.eShopOnContainers.BuildingBlocks
|
||||
{
|
||||
using Microsoft.AspNetCore.DataProtection.Repositories;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StackExchange.Redis;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml.Linq;
|
||||
|
||||
/// <summary>
|
||||
/// Key repository that stores XML encrypted keys in a Redis distributed cache.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The values stored in Redis are XML documents that contain encrypted session
|
||||
/// keys used for the protection of things like session state. The document contents
|
||||
/// are double-encrypted - first with a changing session key; then by a master key.
|
||||
/// As such, there's no risk in storing the keys in Redis - even if someone can crack
|
||||
/// the master key, they still need to also crack the session key. (Other solutions
|
||||
/// for sharing keys across a farm environment include writing them to files
|
||||
/// on a file share.)
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// While the repository uses a hash to keep the set of encrypted keys separate, you
|
||||
/// can further separate these items from other items in Redis by specifying a unique
|
||||
/// database in the connection string.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Consumers of the repository are responsible for caching the XML items as needed.
|
||||
/// Typically repositories are consumed by things like <see cref="Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider"/>
|
||||
/// which generates <see cref="Microsoft.AspNetCore.DataProtection.KeyManagement.Internal.CacheableKeyRing"/>
|
||||
/// values that get cached. The mechanism is already optimized for caching so there's
|
||||
/// no need to create a redundant cache.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <seealso cref="Microsoft.AspNetCore.DataProtection.Repositories.IXmlRepository" />
|
||||
/// <seealso cref="System.IDisposable" />
|
||||
public class RedisXmlRepository : IXmlRepository, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The root cache key for XML items stored in Redis
|
||||
/// </summary>
|
||||
public static readonly string RedisHashKey = "DataProtectionXmlRepository";
|
||||
|
||||
/// <summary>
|
||||
/// The connection to the Redis backing store.
|
||||
/// </summary>
|
||||
private IConnectionMultiplexer _connection;
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating whether the object has been disposed.
|
||||
/// </summary>
|
||||
private bool _disposed = false;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RedisXmlRepository"/> class.
|
||||
/// </summary>
|
||||
/// <param name="connectionString">
|
||||
/// The Redis connection string.
|
||||
/// </param>
|
||||
/// <param name="logger">
|
||||
/// The <see cref="ILogger{T}"/> used to log diagnostic messages.
|
||||
/// </param>
|
||||
/// <exception cref="System.ArgumentNullException">
|
||||
/// Thrown if <paramref name="connectionString" /> or <paramref name="logger" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public RedisXmlRepository(string connectionString, ILogger<RedisXmlRepository> logger)
|
||||
: this(ConnectionMultiplexer.Connect(connectionString), logger)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RedisXmlRepository"/> class.
|
||||
/// </summary>
|
||||
/// <param name="connection">
|
||||
/// The Redis database connection.
|
||||
/// </param>
|
||||
/// <param name="logger">
|
||||
/// The <see cref="ILogger{T}"/> used to log diagnostic messages.
|
||||
/// </param>
|
||||
/// <exception cref="System.ArgumentNullException">
|
||||
/// Thrown if <paramref name="connection" /> or <paramref name="logger" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public RedisXmlRepository(IConnectionMultiplexer connection, ILogger<RedisXmlRepository> logger)
|
||||
{
|
||||
if (connection == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(connection));
|
||||
}
|
||||
|
||||
if (logger == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
this._connection = connection;
|
||||
this.Logger = logger;
|
||||
|
||||
// Mask the password so it doesn't get logged.
|
||||
var configuration = Regex.Replace(this._connection.Configuration, @"password\s*=\s*[^,]*", "password=****", RegexOptions.IgnoreCase);
|
||||
this.Logger.LogDebug("Storing data protection keys in Redis: {RedisConfiguration}", configuration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the logger.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The <see cref="ILogger{T}"/> used to log diagnostic messages.
|
||||
/// </value>
|
||||
public ILogger<RedisXmlRepository> Logger { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing,
|
||||
/// or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all top-level XML elements in the repository.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// An <see cref="IReadOnlyCollection{T}"/> with the set of elements
|
||||
/// stored in the repository.
|
||||
/// </returns>
|
||||
public IReadOnlyCollection<XElement> GetAllElements()
|
||||
{
|
||||
var database = this._connection.GetDatabase();
|
||||
var hash = database.HashGetAll(RedisHashKey);
|
||||
var elements = new List<XElement>();
|
||||
|
||||
if (hash == null || hash.Length == 0)
|
||||
{
|
||||
return elements.AsReadOnly();
|
||||
}
|
||||
|
||||
foreach (var item in hash.ToStringDictionary())
|
||||
{
|
||||
elements.Add(XElement.Parse(item.Value));
|
||||
}
|
||||
|
||||
this.Logger.LogDebug("Read {XmlElementCount} XML elements from Redis.", elements.Count);
|
||||
return elements.AsReadOnly();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a top-level XML element to the repository.
|
||||
/// </summary>
|
||||
/// <param name="element">The element to add.</param>
|
||||
/// <param name="friendlyName">
|
||||
/// An optional name to be associated with the XML element.
|
||||
/// For instance, if this repository stores XML files on disk, the friendly name may
|
||||
/// be used as part of the file name. Repository implementations are not required to
|
||||
/// observe this parameter even if it has been provided by the caller.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// The <paramref name="friendlyName" /> parameter must be unique if specified.
|
||||
/// For instance, it could be the ID of the key being stored.
|
||||
/// </remarks>
|
||||
/// <exception cref="System.ArgumentNullException">
|
||||
/// Thrown if <paramref name="element" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public void StoreElement(XElement element, string friendlyName)
|
||||
{
|
||||
if (element == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(element));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(friendlyName))
|
||||
{
|
||||
// The framework always passes in a name, but
|
||||
// the contract indicates this may be null or empty.
|
||||
friendlyName = Guid.NewGuid().ToString();
|
||||
}
|
||||
|
||||
this.Logger.LogDebug("Storing XML element with friendly name {XmlElementFriendlyName}.", friendlyName);
|
||||
|
||||
this._connection.GetDatabase().HashSet(RedisHashKey, friendlyName, element.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged and - optionally - managed resources.
|
||||
/// </summary>
|
||||
/// <param name="disposing">
|
||||
/// <see langword="true" /> to release both managed and unmanaged resources;
|
||||
/// <see langword="false" /> to release only unmanaged resources.
|
||||
/// </param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!this._disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (this._connection != null)
|
||||
{
|
||||
this._connection.Close();
|
||||
this._connection.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
this._connection = null;
|
||||
this._disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
8
src/BuildingBlocks/EventBus/CommandBus/CommandBus.csproj
Normal file
8
src/BuildingBlocks/EventBus/CommandBus/CommandBus.csproj
Normal file
@ -0,0 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard1.0</TargetFramework>
|
||||
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.CommandBus</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
16
src/BuildingBlocks/EventBus/CommandBus/ICommandBus.cs
Normal file
16
src/BuildingBlocks/EventBus/CommandBus/ICommandBus.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.CommandBus
|
||||
{
|
||||
public interface ICommandBus
|
||||
{
|
||||
void Send<T>(string name, T data);
|
||||
void Handle<TC>(string name, IIntegrationCommandHandler<TC> handler);
|
||||
void Handle(string name, IIntegrationCommandHandler handler);
|
||||
void Handle<TI, TC>(TI handler)
|
||||
where TI : IIntegrationCommandHandler<TC>;
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.CommandBus
|
||||
{
|
||||
public interface IIntegrationCommandHandler
|
||||
{
|
||||
void Handle(IntegrationCommand command);
|
||||
}
|
||||
|
||||
public interface IIntegrationCommandHandler<T> : IIntegrationCommandHandler
|
||||
{
|
||||
void Handle(IntegrationCommand<T> command);
|
||||
}
|
||||
}
|
35
src/BuildingBlocks/EventBus/CommandBus/IntegrationCommand.cs
Normal file
35
src/BuildingBlocks/EventBus/CommandBus/IntegrationCommand.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.CommandBus
|
||||
{
|
||||
public abstract class IntegrationCommand
|
||||
{
|
||||
public Guid Id { get; }
|
||||
public DateTime Sent { get; }
|
||||
|
||||
public abstract object GetDataAsObject();
|
||||
|
||||
protected IntegrationCommand()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
Sent = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class IntegrationCommand<T> : IntegrationCommand
|
||||
{
|
||||
public T Data { get; }
|
||||
public string Name { get; }
|
||||
public override object GetDataAsObject() => Data;
|
||||
|
||||
public IntegrationCommand(string name, T data) : base()
|
||||
{
|
||||
Data = data;
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -18,7 +18,7 @@ namespace EventBus.Tests
|
||||
public void After_One_Event_Subscription_Should_Contain_The_Event()
|
||||
{
|
||||
var manager = new InMemoryEventBusSubscriptionsManager();
|
||||
manager.AddSubscription<TestIntegrationEvent,TestIntegrationEventHandler>(() => new TestIntegrationEventHandler());
|
||||
manager.AddSubscription<TestIntegrationEvent,TestIntegrationEventHandler>();
|
||||
Assert.True(manager.HasSubscriptionsForEvent<TestIntegrationEvent>());
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ namespace EventBus.Tests
|
||||
public void After_All_Subscriptions_Are_Deleted_Event_Should_No_Longer_Exists()
|
||||
{
|
||||
var manager = new InMemoryEventBusSubscriptionsManager();
|
||||
manager.AddSubscription<TestIntegrationEvent, TestIntegrationEventHandler>(() => new TestIntegrationEventHandler());
|
||||
manager.AddSubscription<TestIntegrationEvent, TestIntegrationEventHandler>();
|
||||
manager.RemoveSubscription<TestIntegrationEvent, TestIntegrationEventHandler>();
|
||||
Assert.False(manager.HasSubscriptionsForEvent<TestIntegrationEvent>());
|
||||
}
|
||||
@ -37,7 +37,7 @@ namespace EventBus.Tests
|
||||
bool raised = false;
|
||||
var manager = new InMemoryEventBusSubscriptionsManager();
|
||||
manager.OnEventRemoved += (o, e) => raised = true;
|
||||
manager.AddSubscription<TestIntegrationEvent, TestIntegrationEventHandler>(() => new TestIntegrationEventHandler());
|
||||
manager.AddSubscription<TestIntegrationEvent, TestIntegrationEventHandler>();
|
||||
manager.RemoveSubscription<TestIntegrationEvent, TestIntegrationEventHandler>();
|
||||
Assert.True(raised);
|
||||
}
|
||||
@ -46,8 +46,8 @@ namespace EventBus.Tests
|
||||
public void Get_Handlers_For_Event_Should_Return_All_Handlers()
|
||||
{
|
||||
var manager = new InMemoryEventBusSubscriptionsManager();
|
||||
manager.AddSubscription<TestIntegrationEvent, TestIntegrationEventHandler>(() => new TestIntegrationEventHandler());
|
||||
manager.AddSubscription<TestIntegrationEvent, TestIntegrationOtherEventHandler>(() => new TestIntegrationOtherEventHandler());
|
||||
manager.AddSubscription<TestIntegrationEvent, TestIntegrationEventHandler>();
|
||||
manager.AddSubscription<TestIntegrationEvent, TestIntegrationOtherEventHandler>();
|
||||
var handlers = manager.GetHandlersForEvent<TestIntegrationEvent>();
|
||||
Assert.Equal(2, handlers.Count());
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions
|
||||
{
|
||||
public interface IDynamicIntegrationEventHandler
|
||||
{
|
||||
Task Handle(dynamic eventData);
|
||||
}
|
||||
}
|
@ -5,9 +5,15 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions
|
||||
{
|
||||
public interface IEventBus
|
||||
{
|
||||
void Subscribe<T, TH>(Func<TH> handler)
|
||||
void Subscribe<T, TH>()
|
||||
where T : IntegrationEvent
|
||||
where TH : IIntegrationEventHandler<T>;
|
||||
void SubscribeDynamic<TH>(string eventName)
|
||||
where TH : IDynamicIntegrationEventHandler;
|
||||
|
||||
void UnsubscribeDynamic<TH>(string eventName)
|
||||
where TH : IDynamicIntegrationEventHandler;
|
||||
|
||||
void Unsubscribe<T, TH>()
|
||||
where TH : IIntegrationEventHandler<T>
|
||||
where T : IntegrationEvent;
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp1.1</TargetFramework>
|
||||
<RuntimeFrameworkVersion>1.1.0</RuntimeFrameworkVersion>
|
||||
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.EventBus</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
@ -11,7 +10,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -2,6 +2,7 @@
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static Microsoft.eShopOnContainers.BuildingBlocks.EventBus.InMemoryEventBusSubscriptionsManager;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus
|
||||
{
|
||||
@ -9,18 +10,25 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus
|
||||
{
|
||||
bool IsEmpty { get; }
|
||||
event EventHandler<string> OnEventRemoved;
|
||||
void AddSubscription<T, TH>(Func<TH> handler)
|
||||
void AddDynamicSubscription<TH>(string eventName)
|
||||
where TH : IDynamicIntegrationEventHandler;
|
||||
|
||||
void AddSubscription<T, TH>()
|
||||
where T : IntegrationEvent
|
||||
where TH : IIntegrationEventHandler<T>;
|
||||
|
||||
void RemoveSubscription<T, TH>()
|
||||
where TH : IIntegrationEventHandler<T>
|
||||
where T : IntegrationEvent;
|
||||
void RemoveSubscription<T, TH>()
|
||||
where TH : IIntegrationEventHandler<T>
|
||||
where T : IntegrationEvent;
|
||||
void RemoveDynamicSubscription<TH>(string eventName)
|
||||
where TH : IDynamicIntegrationEventHandler;
|
||||
|
||||
bool HasSubscriptionsForEvent<T>() where T : IntegrationEvent;
|
||||
bool HasSubscriptionsForEvent(string eventName);
|
||||
Type GetEventTypeByName(string eventName);
|
||||
void Clear();
|
||||
IEnumerable<Delegate> GetHandlersForEvent<T>() where T : IntegrationEvent;
|
||||
IEnumerable<Delegate> GetHandlersForEvent(string eventName);
|
||||
IEnumerable<SubscriptionInfo> GetHandlersForEvent<T>() where T : IntegrationEvent;
|
||||
IEnumerable<SubscriptionInfo> GetHandlersForEvent(string eventName);
|
||||
string GetEventKey<T>();
|
||||
}
|
||||
}
|
@ -8,64 +8,106 @@ using System.Text;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus
|
||||
{
|
||||
public class InMemoryEventBusSubscriptionsManager : IEventBusSubscriptionsManager
|
||||
public partial class InMemoryEventBusSubscriptionsManager : IEventBusSubscriptionsManager
|
||||
{
|
||||
private readonly Dictionary<string, List<Delegate>> _handlers;
|
||||
|
||||
|
||||
private readonly Dictionary<string, List<SubscriptionInfo>> _handlers;
|
||||
private readonly List<Type> _eventTypes;
|
||||
|
||||
public event EventHandler<string> OnEventRemoved;
|
||||
|
||||
public InMemoryEventBusSubscriptionsManager()
|
||||
{
|
||||
_handlers = new Dictionary<string, List<Delegate>>();
|
||||
_handlers = new Dictionary<string, List<SubscriptionInfo>>();
|
||||
_eventTypes = new List<Type>();
|
||||
}
|
||||
|
||||
public bool IsEmpty => !_handlers.Keys.Any();
|
||||
public void Clear() => _handlers.Clear();
|
||||
|
||||
public void AddSubscription<T, TH>(Func<TH> handler)
|
||||
public void AddDynamicSubscription<TH>(string eventName)
|
||||
where TH : IDynamicIntegrationEventHandler
|
||||
{
|
||||
DoAddSubscription(typeof(TH), eventName, isDynamic: true);
|
||||
}
|
||||
|
||||
public void AddSubscription<T, TH>()
|
||||
where T : IntegrationEvent
|
||||
where TH : IIntegrationEventHandler<T>
|
||||
{
|
||||
var key = GetEventKey<T>();
|
||||
if (!HasSubscriptionsForEvent<T>())
|
||||
{
|
||||
_handlers.Add(key, new List<Delegate>());
|
||||
}
|
||||
_handlers[key].Add(handler);
|
||||
var eventName = GetEventKey<T>();
|
||||
DoAddSubscription(typeof(TH), eventName, isDynamic: false);
|
||||
_eventTypes.Add(typeof(T));
|
||||
}
|
||||
|
||||
private void DoAddSubscription(Type handlerType, string eventName, bool isDynamic)
|
||||
{
|
||||
if (!HasSubscriptionsForEvent(eventName))
|
||||
{
|
||||
_handlers.Add(eventName, new List<SubscriptionInfo>());
|
||||
}
|
||||
|
||||
if (_handlers[eventName].Any(s => s.HandlerType == handlerType))
|
||||
{
|
||||
throw new ArgumentException(
|
||||
$"Handler Type {handlerType.Name} already registered for '{eventName}'", nameof(handlerType));
|
||||
}
|
||||
|
||||
if (isDynamic)
|
||||
{
|
||||
_handlers[eventName].Add(SubscriptionInfo.Dynamic(handlerType));
|
||||
}
|
||||
else
|
||||
{
|
||||
_handlers[eventName].Add(SubscriptionInfo.Typed(handlerType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void RemoveDynamicSubscription<TH>(string eventName)
|
||||
where TH : IDynamicIntegrationEventHandler
|
||||
{
|
||||
var handlerToRemove = FindDynamicSubscriptionToRemove<TH>(eventName);
|
||||
DoRemoveHandler(eventName, handlerToRemove);
|
||||
}
|
||||
|
||||
|
||||
public void RemoveSubscription<T, TH>()
|
||||
where TH : IIntegrationEventHandler<T>
|
||||
where T : IntegrationEvent
|
||||
{
|
||||
var handlerToRemove = FindHandlerToRemove<T, TH>();
|
||||
if (handlerToRemove != null)
|
||||
var handlerToRemove = FindSubscriptionToRemove<T, TH>();
|
||||
var eventName = GetEventKey<T>();
|
||||
DoRemoveHandler(eventName, handlerToRemove);
|
||||
}
|
||||
|
||||
|
||||
private void DoRemoveHandler(string eventName, SubscriptionInfo subsToRemove)
|
||||
{
|
||||
if (subsToRemove != null)
|
||||
{
|
||||
var key = GetEventKey<T>();
|
||||
_handlers[key].Remove(handlerToRemove);
|
||||
if (!_handlers[key].Any())
|
||||
_handlers[eventName].Remove(subsToRemove);
|
||||
if (!_handlers[eventName].Any())
|
||||
{
|
||||
_handlers.Remove(key);
|
||||
var eventType = _eventTypes.SingleOrDefault(e => e.Name == key);
|
||||
_handlers.Remove(eventName);
|
||||
var eventType = _eventTypes.SingleOrDefault(e => e.Name == eventName);
|
||||
if (eventType != null)
|
||||
{
|
||||
_eventTypes.Remove(eventType);
|
||||
RaiseOnEventRemoved(eventType.Name);
|
||||
}
|
||||
RaiseOnEventRemoved(eventName);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<Delegate> GetHandlersForEvent<T>() where T : IntegrationEvent
|
||||
public IEnumerable<SubscriptionInfo> GetHandlersForEvent<T>() where T : IntegrationEvent
|
||||
{
|
||||
var key = GetEventKey<T>();
|
||||
return GetHandlersForEvent(key);
|
||||
}
|
||||
public IEnumerable<Delegate> GetHandlersForEvent(string eventName) => _handlers[eventName];
|
||||
public IEnumerable<SubscriptionInfo> GetHandlersForEvent(string eventName) => _handlers[eventName];
|
||||
|
||||
private void RaiseOnEventRemoved(string eventName)
|
||||
{
|
||||
@ -76,26 +118,31 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus
|
||||
}
|
||||
}
|
||||
|
||||
private Delegate FindHandlerToRemove<T, TH>()
|
||||
where T : IntegrationEvent
|
||||
where TH : IIntegrationEventHandler<T>
|
||||
|
||||
private SubscriptionInfo FindDynamicSubscriptionToRemove<TH>(string eventName)
|
||||
where TH : IDynamicIntegrationEventHandler
|
||||
{
|
||||
if (!HasSubscriptionsForEvent<T>())
|
||||
return DoFindSubscriptionToRemove(eventName, typeof(TH));
|
||||
}
|
||||
|
||||
|
||||
private SubscriptionInfo FindSubscriptionToRemove<T, TH>()
|
||||
where T : IntegrationEvent
|
||||
where TH : IIntegrationEventHandler<T>
|
||||
{
|
||||
var eventName = GetEventKey<T>();
|
||||
return DoFindSubscriptionToRemove(eventName, typeof(TH));
|
||||
}
|
||||
|
||||
private SubscriptionInfo DoFindSubscriptionToRemove(string eventName, Type handlerType)
|
||||
{
|
||||
if (!HasSubscriptionsForEvent(eventName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var key = GetEventKey<T>();
|
||||
foreach (var func in _handlers[key])
|
||||
{
|
||||
var genericArgs = func.GetType().GetGenericArguments();
|
||||
if (genericArgs.SingleOrDefault() == typeof(TH))
|
||||
{
|
||||
return func;
|
||||
}
|
||||
}
|
||||
return _handlers[eventName].SingleOrDefault(s => s.HandlerType == handlerType);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool HasSubscriptionsForEvent<T>() where T : IntegrationEvent
|
||||
@ -105,9 +152,9 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus
|
||||
}
|
||||
public bool HasSubscriptionsForEvent(string eventName) => _handlers.ContainsKey(eventName);
|
||||
|
||||
public Type GetEventTypeByName(string eventName) => _eventTypes.Single(t => t.Name == eventName);
|
||||
public Type GetEventTypeByName(string eventName) => _eventTypes.SingleOrDefault(t => t.Name == eventName);
|
||||
|
||||
private string GetEventKey<T>()
|
||||
public string GetEventKey<T>()
|
||||
{
|
||||
return typeof(T).Name;
|
||||
}
|
||||
|
28
src/BuildingBlocks/EventBus/EventBus/SubscriptionInfo.cs
Normal file
28
src/BuildingBlocks/EventBus/EventBus/SubscriptionInfo.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus
|
||||
{
|
||||
public partial class InMemoryEventBusSubscriptionsManager : IEventBusSubscriptionsManager
|
||||
{
|
||||
public class SubscriptionInfo
|
||||
{
|
||||
public bool IsDynamic { get; }
|
||||
public Type HandlerType{ get; }
|
||||
|
||||
private SubscriptionInfo(bool isDynamic, Type handlerType)
|
||||
{
|
||||
IsDynamic = isDynamic;
|
||||
HandlerType = handlerType;
|
||||
}
|
||||
|
||||
public static SubscriptionInfo Dynamic(Type handlerType)
|
||||
{
|
||||
return new SubscriptionInfo(true, handlerType);
|
||||
}
|
||||
public static SubscriptionInfo Typed(Type handlerType)
|
||||
{
|
||||
return new SubscriptionInfo(false, handlerType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
//using Microsoft.eShopOnContainers.BuildingBlocks.CommandBus;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Polly;
|
||||
using Polly.Retry;
|
||||
using RabbitMQ.Client;
|
||||
using RabbitMQ.Client.Events;
|
||||
using RabbitMQ.Client.Exceptions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
/*
|
||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
||||
{
|
||||
public class CommandBusRabbitMQ : ICommandBus, IDisposable
|
||||
{
|
||||
const string BROKER_NAME = "eshop_command_bus";
|
||||
|
||||
private readonly IRabbitMQPersistentConnection _persistentConnection;
|
||||
private readonly ILogger<CommandBusRabbitMQ> _logger;
|
||||
|
||||
private IModel _consumerChannel;
|
||||
private string _queueName;
|
||||
|
||||
private readonly Dictionary<string, IIntegrationCommandHandler> _handlers;
|
||||
private readonly Dictionary<string, Type> _typeMappings;
|
||||
|
||||
public CommandBusRabbitMQ(IRabbitMQPersistentConnection persistentConnection,
|
||||
ILogger<CommandBusRabbitMQ> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_persistentConnection = persistentConnection;
|
||||
_handlers = new Dictionary<string, IIntegrationCommandHandler>();
|
||||
_typeMappings = new Dictionary<string, Type>();
|
||||
}
|
||||
|
||||
public void Send<T>(string name, T data)
|
||||
{
|
||||
Send(new IntegrationCommand<T>(name, data));
|
||||
}
|
||||
|
||||
public void Handle<TC>(string name, IIntegrationCommandHandler<TC> handler)
|
||||
{
|
||||
_handlers.Add(name, handler);
|
||||
_typeMappings.Add(name, typeof(TC));
|
||||
}
|
||||
|
||||
public void Handle(string name, IIntegrationCommandHandler handler)
|
||||
{
|
||||
_handlers.Add(name, handler);
|
||||
}
|
||||
public void Handle<TI, TC>(TI handler) where TI : IIntegrationCommandHandler<TC>
|
||||
{
|
||||
var name = typeof(TI).Name;
|
||||
_handlers.Add(name, handler);
|
||||
_typeMappings.Add(name, typeof(TC));
|
||||
}
|
||||
|
||||
private void Send<T>(IntegrationCommand<T> command)
|
||||
{
|
||||
if (!_persistentConnection.IsConnected)
|
||||
{
|
||||
_persistentConnection.TryConnect();
|
||||
}
|
||||
|
||||
var policy = RetryPolicy.Handle<BrokerUnreachableException>()
|
||||
.Or<SocketException>()
|
||||
.WaitAndRetry(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) =>
|
||||
{
|
||||
_logger.LogWarning(ex.ToString());
|
||||
});
|
||||
|
||||
using (var channel = _persistentConnection.CreateModel())
|
||||
{
|
||||
var commandName = command.Name;
|
||||
channel.ExchangeDeclare(exchange: BROKER_NAME, type: "direct");
|
||||
var message = JsonConvert.SerializeObject(command);
|
||||
var body = Encoding.UTF8.GetBytes(message);
|
||||
policy.Execute(() =>
|
||||
{
|
||||
channel.BasicPublish(exchange: BROKER_NAME,
|
||||
routingKey: commandName,
|
||||
basicProperties: null,
|
||||
body: body);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private IModel CreateConsumerChannel()
|
||||
{
|
||||
if (!_persistentConnection.IsConnected)
|
||||
{
|
||||
_persistentConnection.TryConnect();
|
||||
}
|
||||
|
||||
var channel = _persistentConnection.CreateModel();
|
||||
|
||||
channel.ExchangeDeclare(exchange: BROKER_NAME, type: "direct");
|
||||
_queueName = channel.QueueDeclare().QueueName;
|
||||
var consumer = new EventingBasicConsumer(channel);
|
||||
consumer.Received += async (model, ea) =>
|
||||
{
|
||||
var commandName = ea.RoutingKey;
|
||||
var message = Encoding.UTF8.GetString(ea.Body);
|
||||
await InvokeHandler(commandName, message);
|
||||
};
|
||||
|
||||
channel.BasicConsume(queue: _queueName,
|
||||
noAck: true,
|
||||
consumer: consumer);
|
||||
|
||||
channel.CallbackException += (sender, ea) =>
|
||||
{
|
||||
_consumerChannel.Dispose();
|
||||
_consumerChannel = CreateConsumerChannel();
|
||||
};
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
private Task InvokeHandler(string commandName, string message)
|
||||
{
|
||||
if (_handlers.ContainsKey(commandName))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_consumerChannel != null)
|
||||
{
|
||||
_consumerChannel.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
@ -1,8 +1,10 @@
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
|
||||
using Autofac;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Polly;
|
||||
using Polly.Retry;
|
||||
using RabbitMQ.Client;
|
||||
@ -25,17 +27,20 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
||||
private readonly IRabbitMQPersistentConnection _persistentConnection;
|
||||
private readonly ILogger<EventBusRabbitMQ> _logger;
|
||||
private readonly IEventBusSubscriptionsManager _subsManager;
|
||||
|
||||
private readonly ILifetimeScope _autofac;
|
||||
private readonly string AUTOFAC_SCOPE_NAME = "eshop_event_bus";
|
||||
|
||||
private IModel _consumerChannel;
|
||||
private string _queueName;
|
||||
|
||||
public EventBusRabbitMQ(IRabbitMQPersistentConnection persistentConnection, ILogger<EventBusRabbitMQ> logger, IEventBusSubscriptionsManager subsManager)
|
||||
public EventBusRabbitMQ(IRabbitMQPersistentConnection persistentConnection, ILogger<EventBusRabbitMQ> logger,
|
||||
ILifetimeScope autofac, IEventBusSubscriptionsManager subsManager)
|
||||
{
|
||||
_persistentConnection = persistentConnection ?? throw new ArgumentNullException(nameof(persistentConnection));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_subsManager = subsManager ?? new InMemoryEventBusSubscriptionsManager();
|
||||
_consumerChannel = CreateConsumerChannel();
|
||||
_autofac = autofac;
|
||||
|
||||
_subsManager.OnEventRemoved += SubsManager_OnEventRemoved;
|
||||
}
|
||||
@ -96,12 +101,25 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
||||
}
|
||||
}
|
||||
|
||||
public void Subscribe<T, TH>(Func<TH> handler)
|
||||
public void SubscribeDynamic<TH>(string eventName)
|
||||
where TH : IDynamicIntegrationEventHandler
|
||||
{
|
||||
DoInternalSubscription(eventName);
|
||||
_subsManager.AddDynamicSubscription<TH>(eventName);
|
||||
}
|
||||
|
||||
public void Subscribe<T, TH>()
|
||||
where T : IntegrationEvent
|
||||
where TH : IIntegrationEventHandler<T>
|
||||
{
|
||||
var eventName = typeof(T).Name;
|
||||
var containsKey = _subsManager.HasSubscriptionsForEvent<T>();
|
||||
var eventName = _subsManager.GetEventKey<T>();
|
||||
DoInternalSubscription(eventName);
|
||||
_subsManager.AddSubscription<T, TH>();
|
||||
}
|
||||
|
||||
private void DoInternalSubscription(string eventName)
|
||||
{
|
||||
var containsKey = _subsManager.HasSubscriptionsForEvent(eventName);
|
||||
if (!containsKey)
|
||||
{
|
||||
if (!_persistentConnection.IsConnected)
|
||||
@ -116,9 +134,6 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
||||
routingKey: eventName);
|
||||
}
|
||||
}
|
||||
|
||||
_subsManager.AddSubscription<T, TH>(handler);
|
||||
|
||||
}
|
||||
|
||||
public void Unsubscribe<T, TH>()
|
||||
@ -128,19 +143,13 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
||||
_subsManager.RemoveSubscription<T, TH>();
|
||||
}
|
||||
|
||||
private static Func<IIntegrationEventHandler> FindHandlerByType(Type handlerType, IEnumerable<Func<IIntegrationEventHandler>> handlers)
|
||||
public void UnsubscribeDynamic<TH>(string eventName)
|
||||
where TH : IDynamicIntegrationEventHandler
|
||||
{
|
||||
foreach (var func in handlers)
|
||||
{
|
||||
if (func.GetMethodInfo().ReturnType == handlerType)
|
||||
{
|
||||
return func;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
_subsManager.RemoveDynamicSubscription<TH>(eventName);
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_consumerChannel != null)
|
||||
@ -190,17 +199,29 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
||||
private async Task ProcessEvent(string eventName, string message)
|
||||
{
|
||||
|
||||
|
||||
if (_subsManager.HasSubscriptionsForEvent(eventName))
|
||||
{
|
||||
var eventType = _subsManager.GetEventTypeByName(eventName);
|
||||
var integrationEvent = JsonConvert.DeserializeObject(message, eventType);
|
||||
var handlers = _subsManager.GetHandlersForEvent(eventName);
|
||||
|
||||
foreach (var handlerfactory in handlers)
|
||||
using (var scope = _autofac.BeginLifetimeScope(AUTOFAC_SCOPE_NAME))
|
||||
{
|
||||
var handler = handlerfactory.DynamicInvoke();
|
||||
var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType);
|
||||
await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent });
|
||||
var subscriptions = _subsManager.GetHandlersForEvent(eventName);
|
||||
foreach (var subscription in subscriptions)
|
||||
{
|
||||
if (subscription.IsDynamic)
|
||||
{
|
||||
var handler = scope.ResolveOptional(subscription.HandlerType) as IDynamicIntegrationEventHandler;
|
||||
dynamic eventData = JObject.Parse(message);
|
||||
await handler.Handle(eventData);
|
||||
}
|
||||
else
|
||||
{
|
||||
var eventType = _subsManager.GetEventTypeByName(eventName);
|
||||
var integrationEvent = JsonConvert.DeserializeObject(message, eventType);
|
||||
var handler = scope.ResolveOptional(subscription.HandlerType);
|
||||
var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType);
|
||||
await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,16 +2,16 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp1.1</TargetFramework>
|
||||
<RuntimeFrameworkVersion>1.1.0</RuntimeFrameworkVersion>
|
||||
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
|
||||
<PackageReference Include="Polly" Version="5.0.6" />
|
||||
<PackageReference Include="RabbitMQ.Client" Version="4.1.1" />
|
||||
<PackageReference Include="System.ValueTuple" Version="4.3.0" />
|
||||
<PackageReference Include="Autofac" Version="4.5.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
|
||||
<PackageReference Include="Polly" Version="5.1.0" />
|
||||
<PackageReference Include="RabbitMQ.Client" Version="4.1.3" />
|
||||
<PackageReference Include="System.ValueTuple" Version="4.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -2,18 +2,17 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp1.1</TargetFramework>
|
||||
<RuntimeFrameworkVersion>1.1.0</RuntimeFrameworkVersion>
|
||||
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.Design" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="1.1.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="1.1.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.1.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="1.1.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.Design" Version="1.1.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="1.1.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp1.0</TargetFramework>
|
||||
<TargetFramework>netstandard1.3</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@ -9,7 +9,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="1.0.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="1.1.2" />
|
||||
<ProjectReference Include="..\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Data.SqlClient" Version="4.3.0" />
|
||||
<PackageReference Include="System.Data.SqlClient" Version="4.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -9,8 +9,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.0.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
|
||||
<PackageReference Include="System.Diagnostics.Process" Version="4.3.0" />
|
||||
<PackageReference Include="System.Threading.Tasks.Parallel" Version="4.3.0" />
|
||||
<PackageReference Include="System.Threading.Thread" Version="4.3.0" />
|
||||
|
@ -6,9 +6,9 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="1.1.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
|
||||
<PackageReference Include="Polly" Version="5.0.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="1.1.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
|
||||
<PackageReference Include="Polly" Version="5.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -96,7 +96,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http
|
||||
// as it is disposed after each call
|
||||
var origin = GetOriginFromUri(uri);
|
||||
|
||||
return HttpInvoker(origin, () =>
|
||||
return HttpInvoker(origin, async () =>
|
||||
{
|
||||
var requestMessage = new HttpRequestMessage(method, uri);
|
||||
|
||||
@ -112,7 +112,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http
|
||||
requestMessage.Headers.Add("x-requestid", requestId);
|
||||
}
|
||||
|
||||
var response = _client.SendAsync(requestMessage).Result;
|
||||
var response = await _client.SendAsync(requestMessage);
|
||||
|
||||
// raise exception if HttpResponseCode 500
|
||||
// needed for circuit breaker to track fails
|
||||
@ -122,7 +122,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http
|
||||
throw new HttpRequestException();
|
||||
}
|
||||
|
||||
return Task.FromResult(response);
|
||||
return response;
|
||||
});
|
||||
}
|
||||
|
||||
@ -132,13 +132,13 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http
|
||||
|
||||
if (!_policyWrappers.TryGetValue(normalizedOrigin, out PolicyWrap policyWrap))
|
||||
{
|
||||
policyWrap = Policy.Wrap(_policyCreator(normalizedOrigin).ToArray());
|
||||
policyWrap = Policy.WrapAsync(_policyCreator(normalizedOrigin).ToArray());
|
||||
_policyWrappers.TryAdd(normalizedOrigin, policyWrap);
|
||||
}
|
||||
|
||||
// Executes the action applying all
|
||||
// the policies defined in the wrapper
|
||||
return await policyWrap.Execute(action, new Context(normalizedOrigin));
|
||||
return await policyWrap.ExecuteAsync(action, new Context(normalizedOrigin));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
#eShopOnContainers
|
||||
# eShopOnContainers
|
||||
|
||||
eShopOnContainers is a reference app whose imagined purpose is to serve the mobile workforce of a fictitious company that sells products. The app allow to manage the catalog, view products, manage the basket and the orders.
|
||||
|
||||
<img src="Images/eShopOnContainers_Architecture_Diagram.png" alt="eShopOnContainers" Width="800" />
|
||||
|
||||
###Supported platforms: iOS, Android and Windows
|
||||
### Supported platforms: iOS, Android and Windows
|
||||
|
||||
###The app architecture consists of two parts:
|
||||
### The app architecture consists of two parts:
|
||||
1. A Xamarin.Forms mobile app for iOS, Android and Windows.
|
||||
2. Several .NET Web API microservices deployed as Docker containers.
|
||||
|
||||
@ -34,7 +34,7 @@ This project exercises the following platforms, frameworks or features:
|
||||
* Entity Framework
|
||||
* Identity Server 4
|
||||
|
||||
##Three platforms
|
||||
## Three platforms
|
||||
The app targets **three** platforms:
|
||||
|
||||
* iOS
|
||||
@ -45,7 +45,7 @@ The app targets **three** platforms:
|
||||
|
||||
As of 07/03/2017, eShopOnContainers features **89.2% code share** (7.2% iOS / 16.7% Android / 8.7% Windows).
|
||||
|
||||
##Licenses
|
||||
## Licenses
|
||||
|
||||
This project uses some third-party assets with a license that requires attribution:
|
||||
|
||||
|
@ -1,7 +1,11 @@
|
||||
using eShopOnContainers.Core.Helpers;
|
||||
using System;
|
||||
using eShopOnContainers.Core.Helpers;
|
||||
using eShopOnContainers.Services;
|
||||
using eShopOnContainers.Core.ViewModels.Base;
|
||||
using System.Threading.Tasks;
|
||||
using eShopOnContainers.Core.Models.Location;
|
||||
using eShopOnContainers.Core.Services.Location;
|
||||
using Plugin.Geolocator;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
@ -36,6 +40,7 @@ namespace eShopOnContainers
|
||||
return navigationService.InitializeAsync();
|
||||
}
|
||||
|
||||
|
||||
protected override async void OnStart()
|
||||
{
|
||||
base.OnStart();
|
||||
@ -44,6 +49,18 @@ namespace eShopOnContainers
|
||||
{
|
||||
await InitNavigation();
|
||||
}
|
||||
|
||||
if (!Settings.UseFakeLocation)
|
||||
{
|
||||
await GetRealLocation();
|
||||
}
|
||||
|
||||
if (!Settings.UseMocks && !string.IsNullOrEmpty(Settings.UserId))
|
||||
{
|
||||
await SendCurrentLocation();
|
||||
}
|
||||
|
||||
base.OnResume();
|
||||
}
|
||||
|
||||
protected override void OnSleep()
|
||||
@ -51,9 +68,29 @@ namespace eShopOnContainers
|
||||
// Handle when your app sleeps
|
||||
}
|
||||
|
||||
protected override void OnResume()
|
||||
private async Task GetRealLocation()
|
||||
{
|
||||
// Handle when your app resumes
|
||||
var locator = CrossGeolocator.Current;
|
||||
locator.AllowsBackgroundUpdates = true;
|
||||
locator.DesiredAccuracy = 50;
|
||||
|
||||
var position = await locator.GetPositionAsync(20000);
|
||||
|
||||
Settings.Latitude = position.Latitude;
|
||||
Settings.Longitude = position.Longitude;
|
||||
}
|
||||
|
||||
private async Task SendCurrentLocation()
|
||||
{
|
||||
var location = new Location
|
||||
{
|
||||
Latitude = Settings.Latitude,
|
||||
Longitude = Settings.Longitude
|
||||
};
|
||||
|
||||
var locationService = ViewModelLocator.Resolve<ILocationService>();
|
||||
await locationService.UpdateUserLocation(location,
|
||||
Settings.AuthAccessToken);
|
||||
}
|
||||
}
|
||||
}
|
@ -6,7 +6,6 @@
|
||||
public const string MockTag = "Mock";
|
||||
public const string DefaultEndpoint = "http://13.88.8.119";
|
||||
|
||||
|
||||
private string _baseEndpoint;
|
||||
private static readonly GlobalSetting _instance = new GlobalSetting();
|
||||
|
||||
@ -31,6 +30,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
public string ClientId { get { return "xamarin"; }}
|
||||
|
||||
public string ClientSecret { get { return "secret"; }}
|
||||
|
||||
public string AuthToken { get; set; }
|
||||
|
||||
public string RegisterWebsite { get; set; }
|
||||
@ -43,8 +46,14 @@
|
||||
|
||||
public string IdentityEndpoint { get; set; }
|
||||
|
||||
public string LocationEndpoint { get; set; }
|
||||
|
||||
public string MarketingEndpoint { get; set; }
|
||||
|
||||
public string UserInfoEndpoint { get; set; }
|
||||
|
||||
public string TokenEndpoint { get; set; }
|
||||
|
||||
public string LogoutEndpoint { get; set; }
|
||||
|
||||
public string IdentityCallback { get; set; }
|
||||
@ -53,15 +62,18 @@
|
||||
|
||||
private void UpdateEndpoint(string baseEndpoint)
|
||||
{
|
||||
RegisterWebsite = string.Format("{0}:5105/Account/Register", baseEndpoint);
|
||||
CatalogEndpoint = string.Format("{0}:5101", baseEndpoint);
|
||||
OrdersEndpoint = string.Format("{0}:5102", baseEndpoint);
|
||||
BasketEndpoint = string.Format("{0}:5103", baseEndpoint);
|
||||
IdentityEndpoint = string.Format("{0}:5105/connect/authorize", baseEndpoint);
|
||||
UserInfoEndpoint = string.Format("{0}:5105/connect/userinfo", baseEndpoint);
|
||||
LogoutEndpoint = string.Format("{0}:5105/connect/endsession", baseEndpoint);
|
||||
IdentityCallback = string.Format("{0}:5105/xamarincallback", baseEndpoint);
|
||||
LogoutCallback = string.Format("{0}:5105/Account/Redirecting", baseEndpoint);
|
||||
RegisterWebsite = $"{baseEndpoint}:5105/Account/Register";
|
||||
CatalogEndpoint = $"{baseEndpoint}:5101";
|
||||
OrdersEndpoint = $"{baseEndpoint}:5102";
|
||||
BasketEndpoint = $"{baseEndpoint}:5103";
|
||||
IdentityEndpoint = $"{baseEndpoint}:5105/connect/authorize";
|
||||
UserInfoEndpoint = $"{baseEndpoint}:5105/connect/userinfo";
|
||||
TokenEndpoint = $"{baseEndpoint}:5105/connect/token";
|
||||
LogoutEndpoint = $"{baseEndpoint}:5105/connect/endsession";
|
||||
IdentityCallback = $"{baseEndpoint}:5105/xamarincallback";
|
||||
LogoutCallback = $"{baseEndpoint}:5105/Account/Redirecting";
|
||||
LocationEndpoint = $"{baseEndpoint}:5109";
|
||||
MarketingEndpoint = $"{baseEndpoint}:5110";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
using eShopOnContainers.Core.Models.Basket;
|
||||
using eShopOnContainers.Core.Models.Catalog;
|
||||
using eShopOnContainers.Core.Models.Marketing;
|
||||
using eShopOnContainers.Core.ViewModels.Base;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -76,5 +77,38 @@ namespace eShopOnContainers.Core.Helpers
|
||||
Debug.WriteLine(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void FixCatalogItemPictureUri(IEnumerable<CampaignItem> campaignItems)
|
||||
{
|
||||
if (campaignItems == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (!ViewModelLocator.UseMockService
|
||||
&& Settings.UrlBase != GlobalSetting.DefaultEndpoint)
|
||||
{
|
||||
foreach (var catalogItem in campaignItems)
|
||||
{
|
||||
MatchCollection serverResult = IpRegex.Matches(catalogItem.PictureUri);
|
||||
MatchCollection localResult = IpRegex.Matches(Settings.UrlBase);
|
||||
|
||||
if (serverResult.Count != -1 && localResult.Count != -1)
|
||||
{
|
||||
var serviceIp = serverResult[0].Value;
|
||||
var localIp = localResult[0].Value;
|
||||
|
||||
catalogItem.PictureUri = catalogItem.PictureUri.Replace(serviceIp, localIp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,63 +20,69 @@ namespace eShopOnContainers.Core.Helpers
|
||||
|
||||
#region Setting Constants
|
||||
|
||||
private const string IdUserId = "user_id";
|
||||
private const string AccessToken = "access_token";
|
||||
private const string IdToken = "id_token";
|
||||
private const string IdUseMocks = "use_mocks";
|
||||
private const string IdUrlBase = "url_base";
|
||||
private const string IdUseFakeLocation = "use_fake_location";
|
||||
private const string IdLatitude = "latitude";
|
||||
private const string IdLongitude = "flongitude";
|
||||
private static readonly string AccessTokenDefault = string.Empty;
|
||||
private static readonly string IdTokenDefault = string.Empty;
|
||||
private static readonly bool UseMocksDefault = true;
|
||||
private static readonly bool UseFakeLocationDefault = false;
|
||||
private static readonly double FakeLatitudeValue = 47.604610d;
|
||||
private static readonly double FakeLongitudeValue = -122.315752d;
|
||||
private static readonly string UrlBaseDefault = GlobalSetting.Instance.BaseEndpoint;
|
||||
|
||||
#endregion
|
||||
|
||||
public static string UserId
|
||||
{
|
||||
get => AppSettings.GetValueOrDefault<string>(IdUserId);
|
||||
set => AppSettings.AddOrUpdateValue<string>(IdUserId, value);
|
||||
}
|
||||
|
||||
public static string AuthAccessToken
|
||||
{
|
||||
get
|
||||
{
|
||||
return AppSettings.GetValueOrDefault<string>(AccessToken, AccessTokenDefault);
|
||||
}
|
||||
set
|
||||
{
|
||||
AppSettings.AddOrUpdateValue<string>(AccessToken, value);
|
||||
}
|
||||
get => AppSettings.GetValueOrDefault<string>(AccessToken, AccessTokenDefault);
|
||||
set => AppSettings.AddOrUpdateValue<string>(AccessToken, value);
|
||||
}
|
||||
|
||||
public static string AuthIdToken
|
||||
{
|
||||
get
|
||||
{
|
||||
return AppSettings.GetValueOrDefault<string>(IdToken, IdTokenDefault);
|
||||
}
|
||||
set
|
||||
{
|
||||
AppSettings.AddOrUpdateValue<string>(IdToken, value);
|
||||
}
|
||||
get => AppSettings.GetValueOrDefault<string>(IdToken, IdTokenDefault);
|
||||
set => AppSettings.AddOrUpdateValue<string>(IdToken, value);
|
||||
}
|
||||
|
||||
public static bool UseMocks
|
||||
{
|
||||
get
|
||||
{
|
||||
return AppSettings.GetValueOrDefault<bool>(IdUseMocks, UseMocksDefault);
|
||||
}
|
||||
set
|
||||
{
|
||||
AppSettings.AddOrUpdateValue<bool>(IdUseMocks, value);
|
||||
}
|
||||
get => AppSettings.GetValueOrDefault<bool>(IdUseMocks, UseMocksDefault);
|
||||
set => AppSettings.AddOrUpdateValue<bool>(IdUseMocks, value);
|
||||
}
|
||||
|
||||
public static string UrlBase
|
||||
{
|
||||
get
|
||||
{
|
||||
return AppSettings.GetValueOrDefault<string>(IdUrlBase, UrlBaseDefault);
|
||||
}
|
||||
set
|
||||
{
|
||||
AppSettings.AddOrUpdateValue<string>(IdUrlBase, value);
|
||||
}
|
||||
get => AppSettings.GetValueOrDefault<string>(IdUrlBase, UrlBaseDefault);
|
||||
set => AppSettings.AddOrUpdateValue<string>(IdUrlBase, value);
|
||||
}
|
||||
|
||||
public static bool UseFakeLocation
|
||||
{
|
||||
get => AppSettings.GetValueOrDefault<bool>(IdUseFakeLocation, UseFakeLocationDefault);
|
||||
set => AppSettings.AddOrUpdateValue<bool>(IdUseFakeLocation, value);
|
||||
}
|
||||
|
||||
public static double Latitude
|
||||
{
|
||||
get => AppSettings.GetValueOrDefault<double>(IdLatitude, FakeLatitudeValue);
|
||||
set => AppSettings.AddOrUpdateValue<double>(IdLatitude, value);
|
||||
}
|
||||
public static double Longitude
|
||||
{
|
||||
get => AppSettings.GetValueOrDefault<double>(IdLongitude, FakeLongitudeValue);
|
||||
set => AppSettings.AddOrUpdateValue<double>(IdLongitude, value);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace eShopOnContainers.Core.Models.Basket
|
||||
{
|
||||
public class BasketCheckout
|
||||
{
|
||||
[Required]
|
||||
public string City { get; set; }
|
||||
[Required]
|
||||
public string Street { get; set; }
|
||||
[Required]
|
||||
public string State { get; set; }
|
||||
[Required]
|
||||
public string Country { get; set; }
|
||||
|
||||
public string ZipCode { get; set; }
|
||||
[Required]
|
||||
public string CardNumber { get; set; }
|
||||
[Required]
|
||||
public string CardHolderName { get; set; }
|
||||
|
||||
[Required]
|
||||
public DateTime CardExpiration { get; set; }
|
||||
|
||||
[Required]
|
||||
public string CardSecurityNumber { get; set; }
|
||||
|
||||
public int CardTypeId { get; set; }
|
||||
|
||||
public string Buyer { get; set; }
|
||||
|
||||
[Required]
|
||||
public Guid RequestId { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
namespace eShopOnContainers.Core.Models.Location
|
||||
{
|
||||
public class Location
|
||||
{
|
||||
public double Longitude { get; set; }
|
||||
public double Latitude { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
namespace eShopOnContainers.Core.Models.Marketing
|
||||
{
|
||||
using System;
|
||||
|
||||
public class Campaign
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
public DateTime From { get; set; }
|
||||
|
||||
public DateTime To { get; set; }
|
||||
|
||||
public string PictureUri { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
namespace eShopOnContainers.Core.Models.Marketing
|
||||
{
|
||||
using System;
|
||||
|
||||
public class CampaignItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
public DateTime From { get; set; }
|
||||
|
||||
public DateTime To { get; set; }
|
||||
|
||||
public string PictureUri { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
namespace eShopOnContainers.Core.Models.Marketing
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class CampaignRoot
|
||||
{
|
||||
public int PageIndex { get; set; }
|
||||
public int PageSize { get; set; }
|
||||
public int Count { get; set; }
|
||||
public List<CampaignItem> Data { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace eShopOnContainers.Core.Models.Token
|
||||
{
|
||||
public class UserToken
|
||||
{
|
||||
[JsonProperty("id_token")]
|
||||
public string IdToken { get; set; }
|
||||
|
||||
[JsonProperty("access_token")]
|
||||
public string AccessToken { get; set; }
|
||||
|
||||
[JsonProperty("expires_in")]
|
||||
public int ExpiresIn { get; set; }
|
||||
|
||||
[JsonProperty("token_type")]
|
||||
public string TokenType { get; set; }
|
||||
|
||||
[JsonProperty("refresh_token")]
|
||||
public string RefreshToken { get; set; }
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Xamarin.Forms;
|
||||
using System;
|
||||
|
||||
namespace eShopOnContainers.Core.Services.Basket
|
||||
{
|
||||
@ -57,5 +58,10 @@ namespace eShopOnContainers.Core.Services.Basket
|
||||
MockCustomBasket.Items.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public Task CheckoutAsync(BasketCheckout basketCheckout, string token)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -42,6 +42,15 @@ namespace eShopOnContainers.Core.Services.Basket
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task CheckoutAsync(BasketCheckout basketCheckout, string token)
|
||||
{
|
||||
UriBuilder builder = new UriBuilder(GlobalSetting.Instance.BasketEndpoint + "/checkout");
|
||||
|
||||
string uri = builder.ToString();
|
||||
|
||||
await _requestProvider.PostAsync(uri, basketCheckout, token);
|
||||
}
|
||||
|
||||
public async Task ClearBasketAsync(string guidUser, string token)
|
||||
{
|
||||
UriBuilder builder = new UriBuilder(GlobalSetting.Instance.BasketEndpoint);
|
||||
|
@ -7,6 +7,7 @@ namespace eShopOnContainers.Core.Services.Basket
|
||||
{
|
||||
Task<CustomerBasket> GetBasketAsync(string guidUser, string token);
|
||||
Task<CustomerBasket> UpdateBasketAsync(CustomerBasket customerBasket, string token);
|
||||
Task CheckoutAsync(BasketCheckout basketCheckout, string token);
|
||||
Task ClearBasketAsync(string guidUser, string token);
|
||||
}
|
||||
}
|
@ -7,5 +7,8 @@
|
||||
public static string MockCatalogItemId03 = "3";
|
||||
public static string MockCatalogItemId04 = "4";
|
||||
public static string MockCatalogItemId05 = "5";
|
||||
|
||||
public static int MockCampaignd01 = 1;
|
||||
public static int MockCampaignd02 = 2;
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,12 @@
|
||||
namespace eShopOnContainers.Core.Services.Identity
|
||||
using eShopOnContainers.Core.Models.Token;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace eShopOnContainers.Core.Services.Identity
|
||||
{
|
||||
public interface IIdentityService
|
||||
{
|
||||
string CreateAuthorizationRequest();
|
||||
string CreateLogoutRequest(string token);
|
||||
Task<UserToken> GetTokenAsync(string code);
|
||||
}
|
||||
}
|
@ -1,11 +1,22 @@
|
||||
using IdentityModel.Client;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using eShopOnContainers.Core.Services.RequestProvider;
|
||||
using eShopOnContainers.Core.Models.Token;
|
||||
|
||||
namespace eShopOnContainers.Core.Services.Identity
|
||||
{
|
||||
public class IdentityService : IIdentityService
|
||||
{
|
||||
private readonly IRequestProvider _requestProvider;
|
||||
|
||||
public IdentityService(IRequestProvider requestProvider)
|
||||
{
|
||||
_requestProvider = requestProvider;
|
||||
}
|
||||
|
||||
public string CreateAuthorizationRequest()
|
||||
{
|
||||
// Create URI to authorization endpoint
|
||||
@ -13,10 +24,10 @@ namespace eShopOnContainers.Core.Services.Identity
|
||||
|
||||
// Dictionary with values for the authorize request
|
||||
var dic = new Dictionary<string, string>();
|
||||
dic.Add("client_id", "xamarin");
|
||||
dic.Add("response_type", "id_token token");
|
||||
dic.Add("scope", "openid profile basket orders");
|
||||
|
||||
dic.Add("client_id", GlobalSetting.Instance.ClientId);
|
||||
dic.Add("client_secret", GlobalSetting.Instance.ClientSecret);
|
||||
dic.Add("response_type", "code id_token");
|
||||
dic.Add("scope", "openid profile basket orders locations marketing offline_access");
|
||||
dic.Add("redirect_uri", GlobalSetting.Instance.IdentityCallback);
|
||||
dic.Add("nonce", Guid.NewGuid().ToString("N"));
|
||||
|
||||
@ -30,7 +41,7 @@ namespace eShopOnContainers.Core.Services.Identity
|
||||
|
||||
public string CreateLogoutRequest(string token)
|
||||
{
|
||||
if(string.IsNullOrEmpty(token))
|
||||
if (string.IsNullOrEmpty(token))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
@ -40,5 +51,12 @@ namespace eShopOnContainers.Core.Services.Identity
|
||||
token,
|
||||
GlobalSetting.Instance.LogoutCallback);
|
||||
}
|
||||
|
||||
public async Task<UserToken> GetTokenAsync(string code)
|
||||
{
|
||||
string data = string.Format("grant_type=authorization_code&code={0}&redirect_uri={1}", code, WebUtility.UrlEncode(GlobalSetting.Instance.IdentityCallback));
|
||||
var token = await _requestProvider.PostAsync<UserToken>(GlobalSetting.Instance.TokenEndpoint, data, GlobalSetting.Instance.ClientId, GlobalSetting.Instance.ClientSecret);
|
||||
return token;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
namespace eShopOnContainers.Core.Services.Location
|
||||
{
|
||||
using System.Threading.Tasks;
|
||||
using eShopOnContainers.Core.Models.Location;
|
||||
|
||||
public interface ILocationService
|
||||
{
|
||||
Task UpdateUserLocation(Location newLocReq, string token);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
namespace eShopOnContainers.Core.Services.Location
|
||||
{
|
||||
using eShopOnContainers.Core.Models.Location;
|
||||
using eShopOnContainers.Core.Services.RequestProvider;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class LocationService : ILocationService
|
||||
{
|
||||
private readonly IRequestProvider _requestProvider;
|
||||
|
||||
public LocationService(IRequestProvider requestProvider)
|
||||
{
|
||||
_requestProvider = requestProvider;
|
||||
}
|
||||
|
||||
public async Task UpdateUserLocation(Location newLocReq, string token)
|
||||
{
|
||||
UriBuilder builder = new UriBuilder(GlobalSetting.Instance.LocationEndpoint);
|
||||
|
||||
builder.Path = "api/v1/locations";
|
||||
|
||||
string uri = builder.ToString();
|
||||
|
||||
await _requestProvider.PostAsync(uri, newLocReq, token);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace eShopOnContainers.Core.Services.Marketing
|
||||
{
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
using Models.Marketing;
|
||||
using Xamarin.Forms;
|
||||
|
||||
public class CampaignMockService : ICampaignService
|
||||
{
|
||||
private readonly ObservableCollection<CampaignItem> _mockCampaign = new ObservableCollection<CampaignItem>
|
||||
{
|
||||
new CampaignItem
|
||||
{
|
||||
Id = Common.Common.MockCampaignd01,
|
||||
PictureUri = Device.RuntimePlatform != Device.Windows
|
||||
? "fake_campaign_01.png"
|
||||
: "Assets/fake_campaign_01.png",
|
||||
Name = ".NET Bot Black Hoodie 50% OFF",
|
||||
Description = "Campaign Description 1",
|
||||
From = DateTime.Now,
|
||||
To = DateTime.Now.AddDays(7)
|
||||
},
|
||||
|
||||
new CampaignItem
|
||||
{
|
||||
Id = Common.Common.MockCampaignd02,
|
||||
PictureUri = Device.RuntimePlatform != Device.Windows
|
||||
? "fake_campaign_02.png"
|
||||
: "Assets/fake_campaign_02.png",
|
||||
Name = "Roslyn Red T-Shirt 3x2",
|
||||
Description = "Campaign Description 2",
|
||||
From = DateTime.Now.AddDays(-7),
|
||||
To = DateTime.Now.AddDays(14)
|
||||
}
|
||||
};
|
||||
|
||||
public async Task<ObservableCollection<CampaignItem>> GetAllCampaignsAsync(string userId, string token)
|
||||
{
|
||||
await Task.Delay(500);
|
||||
|
||||
return _mockCampaign;
|
||||
}
|
||||
|
||||
public async Task<CampaignItem> GetCampaignByIdAsync(int campaignId, string token)
|
||||
{
|
||||
return _mockCampaign.SingleOrDefault(c => c.Id == campaignId);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
using eShopOnContainers.Core.Extensions;
|
||||
using eShopOnContainers.Core.Helpers;
|
||||
|
||||
namespace eShopOnContainers.Core.Services.Marketing
|
||||
{
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
using Models.Marketing;
|
||||
using RequestProvider;
|
||||
|
||||
public class CampaignService : ICampaignService
|
||||
{
|
||||
private readonly IRequestProvider _requestProvider;
|
||||
|
||||
public CampaignService(IRequestProvider requestProvider)
|
||||
{
|
||||
_requestProvider = requestProvider;
|
||||
}
|
||||
|
||||
public async Task<ObservableCollection<CampaignItem>> GetAllCampaignsAsync(string userId, string token)
|
||||
{
|
||||
UriBuilder builder = new UriBuilder(GlobalSetting.Instance.MarketingEndpoint);
|
||||
|
||||
builder.Path = $"api/v1/campaigns/user/{userId}";
|
||||
|
||||
string uri = builder.ToString();
|
||||
|
||||
CampaignRoot campaign =
|
||||
await _requestProvider.GetAsync<CampaignRoot>(uri, token);
|
||||
|
||||
if (campaign?.Data != null)
|
||||
{
|
||||
ServicesHelper.FixCatalogItemPictureUri(campaign?.Data);
|
||||
|
||||
return campaign?.Data.ToObservableCollection();
|
||||
}
|
||||
|
||||
return new ObservableCollection<CampaignItem>();
|
||||
}
|
||||
|
||||
public async Task<CampaignItem> GetCampaignByIdAsync(int campaignId, string token)
|
||||
{
|
||||
UriBuilder builder = new UriBuilder(GlobalSetting.Instance.MarketingEndpoint);
|
||||
|
||||
builder.Path = $"api/v1/campaigns/{campaignId}";
|
||||
|
||||
string uri = builder.ToString();
|
||||
|
||||
return await _requestProvider.GetAsync<CampaignItem>(uri, token);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
|
||||
namespace eShopOnContainers.Core.Services.Marketing
|
||||
{
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
using Models.Marketing;
|
||||
|
||||
public interface ICampaignService
|
||||
{
|
||||
Task<ObservableCollection<CampaignItem>> GetAllCampaignsAsync(string userId, string token);
|
||||
|
||||
Task<CampaignItem> GetCampaignByIdAsync(int id, string token);
|
||||
}
|
||||
}
|
@ -1,13 +1,15 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using eShopOnContainers.Core.Models.Basket;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace eShopOnContainers.Core.Services.Order
|
||||
{
|
||||
public interface IOrderService
|
||||
{
|
||||
Task CreateOrderAsync(Models.Orders.Order newOrder, string token);
|
||||
//Task CreateOrderAsync(Models.Orders.Order newOrder, string token);
|
||||
Task<ObservableCollection<Models.Orders.Order>> GetOrdersAsync(string token);
|
||||
Task<Models.Orders.Order> GetOrderAsync(int orderId, string token);
|
||||
Task<ObservableCollection<Models.Orders.CardType>> GetCardTypesAsync(string token);
|
||||
BasketCheckout MapOrderToBasket(Models.Orders.Order order);
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using eShopOnContainers.Core.Extensions;
|
||||
using eShopOnContainers.Core.Models.Basket;
|
||||
using eShopOnContainers.Core.Models.Orders;
|
||||
using eShopOnContainers.Core.Models.User;
|
||||
using System;
|
||||
@ -64,17 +65,18 @@ namespace eShopOnContainers.Core.Services.Order
|
||||
new CardType { Id = 3, Name = "MasterCard" },
|
||||
};
|
||||
|
||||
public async Task CreateOrderAsync(Models.Orders.Order newOrder, string token)
|
||||
private static BasketCheckout MockBasketCheckout = new BasketCheckout()
|
||||
{
|
||||
await Task.Delay(500);
|
||||
|
||||
if (!string.IsNullOrEmpty(token))
|
||||
{
|
||||
newOrder.OrderNumber = string.Format("{0}", MockOrders.Count + 1);
|
||||
|
||||
MockOrders.Insert(0, newOrder);
|
||||
}
|
||||
}
|
||||
CardExpiration = DateTime.UtcNow,
|
||||
CardHolderName = "FakeCardHolderName",
|
||||
CardNumber = "122333423224",
|
||||
CardSecurityNumber = "1234",
|
||||
CardTypeId = 1,
|
||||
City = "FakeCity",
|
||||
Country = "FakeCountry",
|
||||
ZipCode = "FakeZipCode",
|
||||
Street = "FakeStreet"
|
||||
};
|
||||
|
||||
public async Task<ObservableCollection<Models.Orders.Order>> GetOrdersAsync(string token)
|
||||
{
|
||||
@ -111,5 +113,10 @@ namespace eShopOnContainers.Core.Services.Order
|
||||
else
|
||||
return new ObservableCollection<CardType>();
|
||||
}
|
||||
|
||||
public BasketCheckout MapOrderToBasket(Models.Orders.Order order)
|
||||
{
|
||||
return MockBasketCheckout;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using eShopOnContainers.Core.Services.RequestProvider;
|
||||
using eShopOnContainers.Core.Models.Basket;
|
||||
using eShopOnContainers.Core.Services.RequestProvider;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
@ -14,17 +15,6 @@ namespace eShopOnContainers.Core.Services.Order
|
||||
_requestProvider = requestProvider;
|
||||
}
|
||||
|
||||
public async Task CreateOrderAsync(Models.Orders.Order newOrder, string token)
|
||||
{
|
||||
UriBuilder builder = new UriBuilder(GlobalSetting.Instance.OrdersEndpoint);
|
||||
|
||||
builder.Path = "api/v1/orders/new";
|
||||
|
||||
string uri = builder.ToString();
|
||||
|
||||
await _requestProvider.PostAsync(uri, newOrder, token, "x-requestid");
|
||||
}
|
||||
|
||||
public async Task<ObservableCollection<Models.Orders.Order>> GetOrdersAsync(string token)
|
||||
{
|
||||
|
||||
@ -82,5 +72,21 @@ namespace eShopOnContainers.Core.Services.Order
|
||||
return new ObservableCollection<Models.Orders.CardType>();
|
||||
}
|
||||
}
|
||||
|
||||
public BasketCheckout MapOrderToBasket(Models.Orders.Order order)
|
||||
{
|
||||
return new BasketCheckout()
|
||||
{
|
||||
CardExpiration = order.CardExpiration,
|
||||
CardHolderName = order.CardHolderName,
|
||||
CardNumber = order.CardNumber,
|
||||
CardSecurityNumber = order.CardSecurityNumber,
|
||||
CardTypeId = order.CardTypeId,
|
||||
City = order.ShippingCity,
|
||||
Country = order.ShippingCountry,
|
||||
ZipCode = order.ShippingZipCode,
|
||||
Street = order.ShippingStreet
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -8,6 +8,8 @@ namespace eShopOnContainers.Core.Services.RequestProvider
|
||||
|
||||
Task<TResult> PostAsync<TResult>(string uri, TResult data, string token = "", string header = "");
|
||||
|
||||
Task<TResult> PostAsync<TResult>(string uri, string data, string clientId, string clientSecret);
|
||||
|
||||
Task DeleteAsync(string uri, string token = "");
|
||||
}
|
||||
}
|
@ -61,6 +61,28 @@ namespace eShopOnContainers.Core.Services.RequestProvider
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<TResult> PostAsync<TResult>(string uri, string data, string clientId, string clientSecret)
|
||||
{
|
||||
HttpClient httpClient = CreateHttpClient(string.Empty);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(clientId) && !string.IsNullOrWhiteSpace(clientSecret))
|
||||
{
|
||||
AddBasicAuthenticationHeader(httpClient, clientId, clientSecret);
|
||||
}
|
||||
|
||||
var content = new StringContent(data);
|
||||
content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
|
||||
HttpResponseMessage response = await httpClient.PostAsync(uri, content);
|
||||
|
||||
await HandleResponse(response);
|
||||
string serialized = await response.Content.ReadAsStringAsync();
|
||||
|
||||
TResult result = await Task.Run(() =>
|
||||
JsonConvert.DeserializeObject<TResult>(serialized, _serializerSettings));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(string uri, string token = "")
|
||||
{
|
||||
HttpClient httpClient = CreateHttpClient(token);
|
||||
@ -90,6 +112,17 @@ namespace eShopOnContainers.Core.Services.RequestProvider
|
||||
httpClient.DefaultRequestHeaders.Add(parameter, Guid.NewGuid().ToString());
|
||||
}
|
||||
|
||||
private void AddBasicAuthenticationHeader(HttpClient httpClient, string clientId, string clientSecret)
|
||||
{
|
||||
if (httpClient == null)
|
||||
return;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(clientId) || string.IsNullOrWhiteSpace(clientSecret))
|
||||
return;
|
||||
|
||||
httpClient.DefaultRequestHeaders.Authorization = new BasicAuthenticationHeaderValue(clientId, clientSecret);
|
||||
}
|
||||
|
||||
private async Task HandleResponse(HttpResponseMessage response)
|
||||
{
|
||||
if (!response.IsSuccessStatusCode)
|
||||
|
@ -11,6 +11,8 @@ using eShopOnContainers.Core.Services.Identity;
|
||||
using eShopOnContainers.Core.Services.Order;
|
||||
using eShopOnContainers.Core.Services.User;
|
||||
using Xamarin.Forms;
|
||||
using eShopOnContainers.Core.Services.Location;
|
||||
using eShopOnContainers.Core.Services.Marketing;
|
||||
|
||||
namespace eShopOnContainers.Core.ViewModels.Base
|
||||
{
|
||||
@ -46,22 +48,26 @@ namespace eShopOnContainers.Core.ViewModels.Base
|
||||
builder.RegisterType<OrderDetailViewModel>();
|
||||
builder.RegisterType<ProfileViewModel>();
|
||||
builder.RegisterType<SettingsViewModel>();
|
||||
builder.RegisterType<CampaignViewModel>();
|
||||
builder.RegisterType<CampaignDetailsViewModel>();
|
||||
|
||||
// Services
|
||||
builder.RegisterType<NavigationService>().As<INavigationService>().SingleInstance();
|
||||
// Services
|
||||
builder.RegisterType<NavigationService>().As<INavigationService>().SingleInstance();
|
||||
builder.RegisterType<DialogService>().As<IDialogService>();
|
||||
builder.RegisterType<OpenUrlService>().As<IOpenUrlService>();
|
||||
builder.RegisterType<IdentityService>().As<IIdentityService>();
|
||||
builder.RegisterType<RequestProvider>().As<IRequestProvider>();
|
||||
builder.RegisterType<LocationService>().As<ILocationService>().SingleInstance();
|
||||
|
||||
if (useMockServices)
|
||||
if (useMockServices)
|
||||
{
|
||||
builder.RegisterInstance(new CatalogMockService()).As<ICatalogService>();
|
||||
builder.RegisterInstance(new BasketMockService()).As<IBasketService>();
|
||||
builder.RegisterInstance(new OrderMockService()).As<IOrderService>();
|
||||
builder.RegisterInstance(new UserMockService()).As<IUserService>();
|
||||
builder.RegisterInstance(new CampaignMockService()).As<ICampaignService>();
|
||||
|
||||
UseMockService = true;
|
||||
UseMockService = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -69,8 +75,9 @@ namespace eShopOnContainers.Core.ViewModels.Base
|
||||
builder.RegisterType<BasketService>().As<IBasketService>().SingleInstance();
|
||||
builder.RegisterType<OrderService>().As<IOrderService>().SingleInstance();
|
||||
builder.RegisterType<UserService>().As<IUserService>().SingleInstance();
|
||||
builder.RegisterType<CampaignService>().As<ICampaignService>().SingleInstance();
|
||||
|
||||
UseMockService = false;
|
||||
UseMockService = false;
|
||||
}
|
||||
|
||||
if (_container != null)
|
||||
|
@ -0,0 +1,42 @@
|
||||
namespace eShopOnContainers.Core.ViewModels
|
||||
{
|
||||
using System.Threading.Tasks;
|
||||
using Helpers;
|
||||
using Models.Marketing;
|
||||
using Services.Marketing;
|
||||
using Base;
|
||||
|
||||
public class CampaignDetailsViewModel : ViewModelBase
|
||||
{
|
||||
private CampaignItem _campaign;
|
||||
private readonly ICampaignService _campaignService;
|
||||
|
||||
public CampaignDetailsViewModel(ICampaignService campaignService)
|
||||
{
|
||||
_campaignService = campaignService;
|
||||
}
|
||||
|
||||
public CampaignItem Campaign
|
||||
{
|
||||
get => _campaign;
|
||||
set
|
||||
{
|
||||
_campaign = value;
|
||||
RaisePropertyChanged(() => Campaign);
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task InitializeAsync(object navigationData)
|
||||
{
|
||||
if (navigationData is int)
|
||||
{
|
||||
IsBusy = true;
|
||||
|
||||
// Get campaign by id
|
||||
Campaign = await _campaignService.GetCampaignByIdAsync((int) navigationData, Settings.AuthAccessToken);
|
||||
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
namespace eShopOnContainers.Core.ViewModels
|
||||
{
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using Xamarin.Forms;
|
||||
using System.Collections.ObjectModel;
|
||||
using Models.Marketing;
|
||||
using Services.Marketing;
|
||||
using Base;
|
||||
using Helpers;
|
||||
|
||||
public class CampaignViewModel : ViewModelBase
|
||||
{
|
||||
private ObservableCollection<CampaignItem> _campaigns;
|
||||
private readonly ICampaignService _campaignService;
|
||||
|
||||
public CampaignViewModel(ICampaignService campaignService)
|
||||
{
|
||||
_campaignService = campaignService;
|
||||
}
|
||||
|
||||
public ObservableCollection<CampaignItem> Campaigns
|
||||
{
|
||||
get => _campaigns;
|
||||
set
|
||||
{
|
||||
_campaigns = value;
|
||||
RaisePropertyChanged(() => Campaigns);
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand GetCampaignDetailsCommand => new Command<CampaignItem>(async (item) => await GetCampaignDetails(item));
|
||||
|
||||
public override async Task InitializeAsync(object navigationData)
|
||||
{
|
||||
IsBusy = true;
|
||||
|
||||
// Get campaigns by user
|
||||
Campaigns = await _campaignService.GetAllCampaignsAsync(Settings.UserId, Settings.AuthAccessToken);
|
||||
|
||||
IsBusy = false;
|
||||
}
|
||||
|
||||
private async Task GetCampaignDetails(CampaignItem campaign)
|
||||
{
|
||||
await NavigationService.NavigateToAsync<CampaignDetailsViewModel>(campaign.Id);
|
||||
}
|
||||
}
|
||||
}
|
@ -132,8 +132,10 @@ namespace eShopOnContainers.Core.ViewModels
|
||||
{
|
||||
var authToken = Settings.AuthAccessToken;
|
||||
|
||||
// Create new order
|
||||
await _orderService.CreateOrderAsync(Order, authToken);
|
||||
var basket = _orderService.MapOrderToBasket(Order);
|
||||
|
||||
// Create basket checkout
|
||||
await _basketService.CheckoutAsync(basket, authToken);
|
||||
|
||||
// Clean Basket
|
||||
await _basketService.ClearBasketAsync(_shippingAddress.Id.ToString(), authToken);
|
||||
|
@ -203,20 +203,22 @@ namespace eShopOnContainers.Core.ViewModels
|
||||
private void Logout()
|
||||
{
|
||||
var authIdToken = Settings.AuthIdToken;
|
||||
|
||||
var logoutRequest = _identityService.CreateLogoutRequest(authIdToken);
|
||||
|
||||
if(!string.IsNullOrEmpty(logoutRequest))
|
||||
if (!string.IsNullOrEmpty(logoutRequest))
|
||||
{
|
||||
// Logout
|
||||
LoginUrl = logoutRequest;
|
||||
}
|
||||
|
||||
if(Settings.UseMocks)
|
||||
if (Settings.UseMocks)
|
||||
{
|
||||
Settings.AuthAccessToken = string.Empty;
|
||||
Settings.AuthIdToken = string.Empty;
|
||||
}
|
||||
|
||||
Settings.UserId = string.Empty;
|
||||
Settings.UseFakeLocation = false;
|
||||
}
|
||||
|
||||
private async Task NavigateAsync(string url)
|
||||
@ -233,14 +235,16 @@ namespace eShopOnContainers.Core.ViewModels
|
||||
else if (unescapedUrl.Contains(GlobalSetting.Instance.IdentityCallback))
|
||||
{
|
||||
var authResponse = new AuthorizeResponse(url);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(authResponse.AccessToken))
|
||||
if (!string.IsNullOrWhiteSpace(authResponse.Code))
|
||||
{
|
||||
if (authResponse.AccessToken != null)
|
||||
{
|
||||
Settings.AuthAccessToken = authResponse.AccessToken;
|
||||
Settings.AuthIdToken = authResponse.IdentityToken;
|
||||
var userToken = await _identityService.GetTokenAsync(authResponse.Code);
|
||||
string accessToken = userToken.AccessToken;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(accessToken))
|
||||
{
|
||||
Settings.AuthAccessToken = accessToken;
|
||||
Settings.AuthIdToken = authResponse.IdentityToken;
|
||||
Settings.UserId = authResponse.Values["sub"];
|
||||
await NavigationService.NavigateToAsync<MainViewModel>();
|
||||
await NavigationService.RemoveLastFromBackStackAsync();
|
||||
}
|
||||
|
@ -4,38 +4,51 @@ using Xamarin.Forms;
|
||||
using System.Threading.Tasks;
|
||||
using eShopOnContainers.Core.Helpers;
|
||||
using eShopOnContainers.Core.Models.User;
|
||||
using System;
|
||||
using eShopOnContainers.Core.Models.Location;
|
||||
using eShopOnContainers.Core.Services.Location;
|
||||
|
||||
namespace eShopOnContainers.Core.ViewModels
|
||||
{
|
||||
public class SettingsViewModel : ViewModelBase
|
||||
{
|
||||
private string _title;
|
||||
private string _description;
|
||||
private string _titleUseAzureServices;
|
||||
private string _descriptionUseAzureServices;
|
||||
private bool _useAzureServices;
|
||||
private string _titleUseFakeLocation;
|
||||
private string _descriptionUseFakeLocation;
|
||||
private bool _useFakeLocation;
|
||||
private string _endpoint;
|
||||
private double _latitude;
|
||||
private double _longitude;
|
||||
private ILocationService _locationService;
|
||||
|
||||
public SettingsViewModel()
|
||||
public SettingsViewModel(ILocationService locationService)
|
||||
{
|
||||
UseAzureServices = !Settings.UseMocks;
|
||||
_useFakeLocation = Settings.UseFakeLocation;
|
||||
_latitude = Settings.Latitude;
|
||||
_longitude = Settings.Longitude;
|
||||
_locationService = locationService;
|
||||
}
|
||||
|
||||
public string Title
|
||||
public string TitleUseAzureServices
|
||||
{
|
||||
get { return _title; }
|
||||
get { return _titleUseAzureServices; }
|
||||
set
|
||||
{
|
||||
_title = value;
|
||||
RaisePropertyChanged(() => Title);
|
||||
_titleUseAzureServices = value;
|
||||
RaisePropertyChanged(() => TitleUseAzureServices);
|
||||
}
|
||||
}
|
||||
|
||||
public string Description
|
||||
public string DescriptionUseAzureServices
|
||||
{
|
||||
get { return _description; }
|
||||
get { return _descriptionUseAzureServices; }
|
||||
set
|
||||
{
|
||||
_description = value;
|
||||
RaisePropertyChanged(() => Description);
|
||||
_descriptionUseAzureServices = value;
|
||||
RaisePropertyChanged(() => DescriptionUseAzureServices);
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,6 +65,39 @@ namespace eShopOnContainers.Core.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public string TitleUseFakeLocation
|
||||
{
|
||||
get { return _titleUseFakeLocation; }
|
||||
set
|
||||
{
|
||||
_titleUseFakeLocation = value;
|
||||
RaisePropertyChanged(() => TitleUseFakeLocation);
|
||||
}
|
||||
}
|
||||
|
||||
public string DescriptionUseFakeLocation
|
||||
{
|
||||
get { return _descriptionUseFakeLocation; }
|
||||
set
|
||||
{
|
||||
_descriptionUseFakeLocation = value;
|
||||
RaisePropertyChanged(() => DescriptionUseFakeLocation);
|
||||
}
|
||||
}
|
||||
|
||||
public bool UseFakeLocation
|
||||
{
|
||||
get { return _useFakeLocation; }
|
||||
set
|
||||
{
|
||||
_useFakeLocation = value;
|
||||
|
||||
// Save use fake location services to local storage
|
||||
Settings.UseFakeLocation = _useFakeLocation;
|
||||
RaisePropertyChanged(() => UseFakeLocation);
|
||||
}
|
||||
}
|
||||
|
||||
public string Endpoint
|
||||
{
|
||||
get { return _endpoint; }
|
||||
@ -68,12 +114,49 @@ namespace eShopOnContainers.Core.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public double Latitude
|
||||
{
|
||||
get { return _latitude; }
|
||||
set
|
||||
{
|
||||
_latitude = value;
|
||||
|
||||
UpdateLatitude(_latitude);
|
||||
|
||||
RaisePropertyChanged(() => Latitude);
|
||||
}
|
||||
}
|
||||
|
||||
public double Longitude
|
||||
{
|
||||
get { return _longitude; }
|
||||
set
|
||||
{
|
||||
_longitude = value;
|
||||
|
||||
UpdateLongitude(_longitude);
|
||||
|
||||
RaisePropertyChanged(() => Longitude);
|
||||
}
|
||||
}
|
||||
|
||||
public bool UserIsLogged => !string.IsNullOrEmpty(Settings.AuthAccessToken);
|
||||
|
||||
public ICommand ToggleMockServicesCommand => new Command(async () => await ToggleMockServicesAsync());
|
||||
|
||||
public ICommand ToggleFakeLocationCommand => new Command(() => ToggleFakeLocationAsync());
|
||||
|
||||
public ICommand ToggleSendLocationCommand => new Command(async () => await ToggleSendLocationAsync());
|
||||
|
||||
public override Task InitializeAsync(object navigationData)
|
||||
{
|
||||
UpdateInfo();
|
||||
UpdateInfoFakeLocation();
|
||||
|
||||
Endpoint = Settings.UrlBase;
|
||||
_latitude = Settings.Latitude;
|
||||
_longitude = Settings.Longitude;
|
||||
_useFakeLocation = Settings.UseFakeLocation;
|
||||
return base.InitializeAsync(navigationData);
|
||||
}
|
||||
|
||||
@ -100,17 +183,52 @@ namespace eShopOnContainers.Core.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateInfo()
|
||||
private void ToggleFakeLocationAsync()
|
||||
{
|
||||
ViewModelLocator.RegisterDependencies(!UseAzureServices);
|
||||
UpdateInfoFakeLocation();
|
||||
}
|
||||
|
||||
private async Task ToggleSendLocationAsync()
|
||||
{
|
||||
if (!Settings.UseMocks)
|
||||
{
|
||||
var locationRequest = new Location
|
||||
{
|
||||
Latitude = _latitude,
|
||||
Longitude = _longitude
|
||||
};
|
||||
var authToken = Settings.AuthAccessToken;
|
||||
|
||||
await _locationService.UpdateUserLocation(locationRequest, authToken);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateInfo()
|
||||
{
|
||||
if (!UseAzureServices)
|
||||
{
|
||||
Title = "Use Mock Services";
|
||||
Description = "Mock Services are simulated objects that mimic the behavior of real services using a controlled approach.";
|
||||
TitleUseAzureServices = "Use Mock Services";
|
||||
DescriptionUseAzureServices = "Mock Services are simulated objects that mimic the behavior of real services using a controlled approach.";
|
||||
}
|
||||
else
|
||||
{
|
||||
Title = "Use Microservices/Containers from eShopOnContainers";
|
||||
Description = "When enabling the use of microservices/containers, the app will attempt to use real services deployed as Docker containers at the specified base endpoint, which will must be reachable through the network.";
|
||||
TitleUseAzureServices = "Use Microservices/Containers from eShopOnContainers";
|
||||
DescriptionUseAzureServices = "When enabling the use of microservices/containers, the app will attempt to use real services deployed as Docker containers at the specified base endpoint, which will must be reachable through the network.";
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateInfoFakeLocation()
|
||||
{
|
||||
if (!UseFakeLocation)
|
||||
{
|
||||
TitleUseFakeLocation = "Use Fake Location";
|
||||
DescriptionUseFakeLocation = "Fake Location are added for marketing campaign testing.";
|
||||
}
|
||||
else
|
||||
{
|
||||
TitleUseFakeLocation = "Use Real Location";
|
||||
DescriptionUseFakeLocation = "When enabling the use of real location, the app will attempt to use real location from the device.";
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,5 +237,17 @@ namespace eShopOnContainers.Core.ViewModels
|
||||
// Update remote endpoint (save to local storage)
|
||||
Settings.UrlBase = endpoint;
|
||||
}
|
||||
|
||||
private void UpdateLatitude(double latitude)
|
||||
{
|
||||
// Update fake latitude (save to local storage)
|
||||
Settings.Latitude = latitude;
|
||||
}
|
||||
|
||||
private void UpdateLongitude(double longitude)
|
||||
{
|
||||
// Update fake longitude (save to local storage)
|
||||
Settings.Longitude = longitude;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="eShopOnContainers.Core.Views.CampaignDetailsView"
|
||||
xmlns:viewModelBase="clr-namespace:eShopOnContainers.Core.ViewModels.Base;assembly=eShopOnContainers.Core"
|
||||
viewModelBase:ViewModelLocator.AutoWireViewModel="true"
|
||||
Title="Campaign Details">
|
||||
<ContentPage.Resources>
|
||||
<ResourceDictionary>
|
||||
<Style x:Key="CampaignStyle"
|
||||
TargetType="{x:Type StackLayout}">
|
||||
<Setter Property="VerticalOptions"
|
||||
Value="Center" />
|
||||
<Setter Property="Margin"
|
||||
Value="0" />
|
||||
</Style>
|
||||
<Style x:Key="CampaignTitleStyle"
|
||||
TargetType="{x:Type Label}">
|
||||
<Setter Property="FontFamily"
|
||||
Value="{StaticResource MontserratRegular}" />
|
||||
<Setter Property="FontSize"
|
||||
Value="{StaticResource MediumSize}" />
|
||||
<Setter Property="HorizontalOptions"
|
||||
Value="Start" />
|
||||
<Setter Property="VerticalOptions"
|
||||
Value="Center" />
|
||||
<Setter Property="Margin"
|
||||
Value="12, 0" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="CampaignDescriptionStyle"
|
||||
TargetType="{x:Type Label}"
|
||||
BasedOn="{StaticResource CampaignTitleStyle}">
|
||||
<Setter Property="FontSize"
|
||||
Value="{StaticResource LittleSize}" />
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</ContentPage.Resources>
|
||||
<Grid
|
||||
ColumnSpacing="0"
|
||||
RowSpacing="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<!-- CAMPAIGN DETAILS -->
|
||||
<ScrollView>
|
||||
<StackLayout
|
||||
x:Name="Campaign">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="1" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
BackgroundColor="Gray"/>
|
||||
<StackLayout
|
||||
Style ="{StaticResource CampaignStyle}"
|
||||
Grid.Column="0"
|
||||
Grid.Row="1">
|
||||
<Image
|
||||
Source="{Binding Campaign.PictureUri, Converter={StaticResource ImageConverter}}"
|
||||
Aspect="AspectFit"
|
||||
VerticalOptions="Start"
|
||||
Margin="12,0,0,0" />
|
||||
<Label
|
||||
Text="{Binding Campaign.Name}"
|
||||
TextColor="{StaticResource GreenColor}"
|
||||
Style="{StaticResource CampaignTitleStyle}"/>
|
||||
<Label
|
||||
Text="{Binding Campaign.Description}"
|
||||
Style="{StaticResource CampaignDescriptionStyle}"/>
|
||||
<StackLayout
|
||||
HorizontalOptions="Center"
|
||||
Margin="12,0,0,0" >
|
||||
<Label
|
||||
Text="{Binding Campaign.From, StringFormat='From {0:MMMM dd, yyyy}'}"
|
||||
Style="{StaticResource CampaignDescriptionStyle}"/>
|
||||
<Label
|
||||
Text="{Binding Campaign.To, StringFormat='until {0:MMMM dd, yyyy}'}"
|
||||
Style="{StaticResource CampaignDescriptionStyle}"/>
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
</Grid>
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
<!-- INDICATOR -->
|
||||
<ActivityIndicator
|
||||
Grid.Row="0"
|
||||
Grid.RowSpan="2"
|
||||
Color="{StaticResource LightGreenColor}"
|
||||
IsRunning="{Binding IsBusy}"
|
||||
IsVisible="{Binding IsBusy}"
|
||||
VerticalOptions="Center"
|
||||
HorizontalOptions="Center">
|
||||
<ActivityIndicator.WidthRequest>
|
||||
<OnPlatform
|
||||
x:TypeArguments="x:Double"
|
||||
iOS="100"
|
||||
Android="100"
|
||||
WinPhone="400" />
|
||||
</ActivityIndicator.WidthRequest>
|
||||
</ActivityIndicator>
|
||||
</Grid>
|
||||
</ContentPage>
|
@ -0,0 +1,12 @@
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace eShopOnContainers.Core.Views
|
||||
{
|
||||
public partial class CampaignDetailsView : ContentPage
|
||||
{
|
||||
public CampaignDetailsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="eShopOnContainers.Core.Views.CampaignView"
|
||||
xmlns:templates="clr-namespace:eShopOnContainers.Core.Views.Templates;assembly=eShopOnContainers.Core"
|
||||
xmlns:views="clr-namespace:eShopOnContainers.Core.Views;assembly=eShopOnContainers.Core"
|
||||
xmlns:viewModelBase="clr-namespace:eShopOnContainers.Core.ViewModels.Base;assembly=eShopOnContainers.Core"
|
||||
xmlns:animations="clr-namespace:eShopOnContainers.Core.Animations;assembly=eShopOnContainers.Core"
|
||||
xmlns:triggers="clr-namespace:eShopOnContainers.Core.Triggers;assembly=eShopOnContainers.Core"
|
||||
xmlns:behaviors="clr-namespace:eShopOnContainers.Core.Behaviors;assembly=eShopOnContainers.Core"
|
||||
viewModelBase:ViewModelLocator.AutoWireViewModel="true"
|
||||
Title="Catalog">
|
||||
<ContentPage.Resources>
|
||||
<ResourceDictionary>
|
||||
|
||||
<Style x:Key="CampaignsListStyle"
|
||||
TargetType="{x:Type ListView}">
|
||||
<Setter Property="RowHeight"
|
||||
Value="400" />
|
||||
<Setter Property="VerticalOptions"
|
||||
Value="Center" />
|
||||
<Setter Property="Margin"
|
||||
Value="0" />
|
||||
</Style>
|
||||
<animations:StoryBoard
|
||||
x:Key="CampaignsAnimation"
|
||||
Target="{x:Reference Campaigns}">
|
||||
<animations:FadeInAnimation
|
||||
Direction="Up"
|
||||
Duration="1500"
|
||||
Delay="250"/>
|
||||
</animations:StoryBoard>
|
||||
|
||||
</ResourceDictionary>
|
||||
</ContentPage.Resources>
|
||||
<ContentPage.Triggers>
|
||||
<EventTrigger
|
||||
Event="Appearing">
|
||||
<triggers:BeginAnimation
|
||||
Animation="{StaticResource CampaignsAnimation}" />
|
||||
</EventTrigger>
|
||||
</ContentPage.Triggers>
|
||||
<Grid
|
||||
ColumnSpacing="0"
|
||||
RowSpacing="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<!-- CAMPAIGNS -->
|
||||
<Grid
|
||||
Grid.Row="1">
|
||||
<Grid
|
||||
IsVisible="{Binding IsBusy, Converter={StaticResource InverseBoolConverter}}">
|
||||
<Label
|
||||
Text="NO CAMPAIGNS FOUND"
|
||||
IsVisible="{Binding Campaigns.Count, Converter={StaticResource InverseCountToBoolConverter}}"
|
||||
HorizontalOptions="Center"
|
||||
VerticalOptions="Center"/>
|
||||
</Grid>
|
||||
<ListView
|
||||
x:Name="Campaigns"
|
||||
IsVisible="{Binding Campaigns.Count, Converter={StaticResource CountToBoolConverter}}"
|
||||
ItemsSource="{Binding Campaigns}"
|
||||
HasUnevenRows="True"
|
||||
SeparatorVisibility="None"
|
||||
CachingStrategy="RecycleElement"
|
||||
Style="{StaticResource CampaignsListStyle}">
|
||||
<ListView.Behaviors>
|
||||
<behaviors:EventToCommandBehavior
|
||||
EventName="ItemTapped"
|
||||
Command="{Binding GetCampaignDetailsCommand}"
|
||||
EventArgsConverter="{StaticResource ItemTappedEventArgsConverter}" />
|
||||
</ListView.Behaviors>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ViewCell>
|
||||
<templates:CampaignTemplate />
|
||||
</ViewCell>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</Grid>
|
||||
<!-- INDICATOR -->
|
||||
<ActivityIndicator
|
||||
Grid.Row="0"
|
||||
Grid.RowSpan="2"
|
||||
Color="{StaticResource LightGreenColor}"
|
||||
IsRunning="{Binding IsBusy}"
|
||||
IsVisible="{Binding IsBusy}"
|
||||
VerticalOptions="Center"
|
||||
HorizontalOptions="Center">
|
||||
<ActivityIndicator.WidthRequest>
|
||||
<OnPlatform
|
||||
x:TypeArguments="x:Double"
|
||||
iOS="100"
|
||||
Android="100"
|
||||
WinPhone="400" />
|
||||
</ActivityIndicator.WidthRequest>
|
||||
</ActivityIndicator>
|
||||
</Grid>
|
||||
</ContentPage>
|
@ -0,0 +1,13 @@
|
||||
namespace eShopOnContainers.Core.Views
|
||||
{
|
||||
using Xamarin.Forms;
|
||||
|
||||
public partial class CampaignView: ContentPage
|
||||
{
|
||||
|
||||
public CampaignView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
@ -63,4 +63,15 @@
|
||||
WinPhone="Assets\menu_cart.png"/>
|
||||
</views:BasketView.Icon>
|
||||
</views:BasketView>
|
||||
<!-- CAMPAIGNS -->
|
||||
<views:CampaignView
|
||||
x:Name="CampaignView">
|
||||
<views:CampaignView.Icon>
|
||||
<OnPlatform
|
||||
x:TypeArguments="FileImageSource"
|
||||
Android="menu_filter"
|
||||
iOS="menu_filter"
|
||||
WinPhone="Assets\menu_filter.png"/>
|
||||
</views:CampaignView.Icon>
|
||||
</views:CampaignView>
|
||||
</TabbedPage>
|
@ -28,12 +28,16 @@ namespace eShopOnContainers.Core.Views
|
||||
case 2:
|
||||
CurrentPage = BasketView;
|
||||
break;
|
||||
case 3:
|
||||
CurrentPage = CampaignView;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
await ((CatalogViewModel)HomeView.BindingContext).InitializeAsync(null);
|
||||
await ((BasketViewModel)BasketView.BindingContext).InitializeAsync(null);
|
||||
await ((ProfileViewModel)ProfileView.BindingContext).InitializeAsync(null);
|
||||
await ((CampaignViewModel)CampaignView.BindingContext).InitializeAsync(null);
|
||||
}
|
||||
|
||||
protected override async void OnCurrentPageChanged()
|
||||
@ -44,6 +48,7 @@ namespace eShopOnContainers.Core.Views
|
||||
{
|
||||
// Force basket view refresh every time we access it
|
||||
await (BasketView.BindingContext as ViewModelBase).InitializeAsync(null);
|
||||
await (CampaignView.BindingContext as ViewModelBase).InitializeAsync(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -98,6 +98,8 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="1" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid
|
||||
Grid.Row="0"
|
||||
@ -108,11 +110,11 @@
|
||||
Grid.Column="0"
|
||||
Grid.Row="1">
|
||||
<Label
|
||||
Text="{Binding Title}"
|
||||
Text="{Binding TitleUseAzureServices}"
|
||||
TextColor="{StaticResource GreenColor}"
|
||||
Style="{StaticResource SettingsTitleStyle}"/>
|
||||
<Label
|
||||
Text="{Binding Description}"
|
||||
Text="{Binding DescriptionUseAzureServices}"
|
||||
Style="{StaticResource SettingsDescriptionStyle}"/>
|
||||
</StackLayout>
|
||||
<!-- ON / OFF -->
|
||||
@ -160,8 +162,81 @@
|
||||
<Grid
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"/>
|
||||
<StackLayout
|
||||
Grid.Column="0"
|
||||
Grid.Row="4"
|
||||
IsVisible="{Binding UserIsLogged}">
|
||||
<Label
|
||||
Text="{Binding TitleUseFakeLocation}"
|
||||
TextColor="{StaticResource GreenColor}"
|
||||
Style="{StaticResource SettingsTitleStyle}"/>
|
||||
<Label
|
||||
Text="{Binding DescriptionUseFakeLocation}"
|
||||
Style="{StaticResource SettingsDescriptionStyle}"/>
|
||||
</StackLayout>
|
||||
<!-- ON / OFF -->
|
||||
<controls:ToggleButton
|
||||
Grid.Column="1"
|
||||
Grid.Row="4"
|
||||
Animate="True"
|
||||
Checked="{Binding UseFakeLocation, Mode=TwoWay}"
|
||||
Command="{Binding ToggleFakeLocationCommand}"
|
||||
Style="{StaticResource SettingsToggleButtonStyle}"
|
||||
IsVisible="{Binding UserIsLogged}">
|
||||
<controls:ToggleButton.CheckedImage>
|
||||
<OnPlatform x:TypeArguments="ImageSource"
|
||||
Android="switch_on.png"
|
||||
iOS="switchOn.png"
|
||||
WinPhone="Assets/switchOn.png"/>
|
||||
</controls:ToggleButton.CheckedImage>
|
||||
<controls:ToggleButton.UnCheckedImage>
|
||||
<OnPlatform x:TypeArguments="ImageSource"
|
||||
Android="switch_off.png"
|
||||
iOS="switchOff.png"
|
||||
WinPhone="Assets/switchOff.png"/>
|
||||
</controls:ToggleButton.UnCheckedImage>
|
||||
</controls:ToggleButton>
|
||||
<!-- FAKE LOCATIONS -->
|
||||
<StackLayout
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
BackgroundColor="Gray"/>
|
||||
Margin="12, 0, 12, 12"
|
||||
IsVisible="{Binding UseFakeLocation}">
|
||||
<Label
|
||||
Text="Latitude"
|
||||
Style="{StaticResource HeaderLabelStyle}"/>
|
||||
<Entry
|
||||
Text="{Binding Latitude, Mode=TwoWay}"
|
||||
Keyboard="Text">
|
||||
<Entry.Style>
|
||||
<OnPlatform
|
||||
x:TypeArguments="Style"
|
||||
iOS="{StaticResource EntryStyle}"
|
||||
Android="{StaticResource EntryStyle}"
|
||||
WinPhone="{StaticResource UwpEntryStyle}"/>
|
||||
</Entry.Style>
|
||||
</Entry>
|
||||
<Label
|
||||
Text="Longitude"
|
||||
Style="{StaticResource HeaderLabelStyle}"/>
|
||||
<Entry
|
||||
Text="{Binding Longitude, Mode=TwoWay}"
|
||||
Keyboard="Text">
|
||||
<Entry.Style>
|
||||
<OnPlatform
|
||||
x:TypeArguments="Style"
|
||||
iOS="{StaticResource EntryStyle}"
|
||||
Android="{StaticResource EntryStyle}"
|
||||
WinPhone="{StaticResource UwpEntryStyle}"/>
|
||||
</Entry.Style>
|
||||
</Entry>
|
||||
<Button
|
||||
Command="{Binding ToggleSendLocationCommand}"
|
||||
Text="Send Location"/>
|
||||
</StackLayout>
|
||||
|
||||
</Grid>
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
|
@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ContentView
|
||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"
|
||||
xmlns:controls="clr-namespace:eShopOnContainers.Core.Controls;assembly=eShopOnContainers.Core"
|
||||
x:Class="eShopOnContainers.Core.Views.Templates.CampaignTemplate">
|
||||
<ContentView.Resources>
|
||||
<ResourceDictionary>
|
||||
|
||||
<Style x:Key="CampaignNameStyle"
|
||||
TargetType="{x:Type Label}">
|
||||
<Setter Property="FontFamily"
|
||||
Value="{StaticResource MontserratRegular}" />
|
||||
<Setter Property="FontSize"
|
||||
Value="{StaticResource LargeSize}" />
|
||||
<Setter Property="HorizontalOptions"
|
||||
Value="Center" />
|
||||
<Setter Property="Margin"
|
||||
Value="0, 12, 0, 6" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="MoreDetailsButtonStyle"
|
||||
TargetType="{x:Type Grid}">
|
||||
<Setter Property="HeightRequest"
|
||||
Value="42" />
|
||||
<Setter Property="WidthRequest"
|
||||
Value="42" />
|
||||
<Setter Property="HorizontalOptions"
|
||||
Value="Center" />
|
||||
<Setter Property="VerticalOptions"
|
||||
Value="End" />
|
||||
<Setter Property="Margin"
|
||||
Value="0,0,0,24" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="AddImageStyle"
|
||||
TargetType="{x:Type Image}">
|
||||
<Setter Property="HeightRequest"
|
||||
Value="24" />
|
||||
<Setter Property="WidthRequest"
|
||||
Value="24" />
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
</ContentView.Resources>
|
||||
<ContentView.Content>
|
||||
<Grid
|
||||
BackgroundColor="{StaticResource BackgroundColor}"
|
||||
Padding="0"
|
||||
Margin="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="250" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<!-- IMAGE -->
|
||||
<ffimageloading:CachedImage
|
||||
Grid.Row="0"
|
||||
Source="{Binding PictureUri}"
|
||||
Aspect="AspectFill">
|
||||
<ffimageloading:CachedImage.LoadingPlaceholder>
|
||||
<OnPlatform
|
||||
x:TypeArguments="ImageSource"
|
||||
iOS="default_campaign"
|
||||
Android="default_campaign"
|
||||
WinPhone="Assets/default_campaign.png"/>
|
||||
</ffimageloading:CachedImage.LoadingPlaceholder>
|
||||
<ffimageloading:CachedImage.ErrorPlaceholder>
|
||||
<OnPlatform
|
||||
x:TypeArguments="ImageSource"
|
||||
iOS="noimage"
|
||||
Android="noimage"
|
||||
WinPhone="Assets/noimage.png"/>
|
||||
</ffimageloading:CachedImage.ErrorPlaceholder>
|
||||
</ffimageloading:CachedImage>
|
||||
<!-- NAME -->
|
||||
<Label
|
||||
Grid.Row="1"
|
||||
Text="{Binding Name, Converter={StaticResource ToUpperConverter}}"
|
||||
Style="{StaticResource CampaignNameStyle}"/>
|
||||
</Grid>
|
||||
</ContentView.Content>
|
||||
</ContentView>
|
@ -0,0 +1,12 @@
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace eShopOnContainers.Core.Views.Templates
|
||||
{
|
||||
public partial class CampaignTemplate : ContentView
|
||||
{
|
||||
public CampaignTemplate()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
@ -64,12 +64,16 @@
|
||||
<Compile Include="Helpers\EasingHelper.cs" />
|
||||
<Compile Include="Helpers\ServicesHelper.cs" />
|
||||
<Compile Include="Helpers\Settings.cs" />
|
||||
<Compile Include="Models\Basket\BasketCheckout.cs" />
|
||||
<Compile Include="Models\Basket\BasketItem.cs" />
|
||||
<Compile Include="Models\Basket\CustomerBasket.cs" />
|
||||
<Compile Include="Models\Catalog\CatalogBrand.cs" />
|
||||
<Compile Include="Models\Catalog\CatalogItem.cs" />
|
||||
<Compile Include="Models\Catalog\CatalogRoot.cs" />
|
||||
<Compile Include="Models\Catalog\CatalogType.cs" />
|
||||
<Compile Include="Models\Location\Location.cs" />
|
||||
<Compile Include="Models\Marketing\CampaignItem.cs" />
|
||||
<Compile Include="Models\Marketing\CampaignRoot.cs" />
|
||||
<Compile Include="Models\Navigation\TabParameter.cs" />
|
||||
<Compile Include="Models\Orders\CardType.CS" />
|
||||
<Compile Include="Models\Orders\Order.cs" />
|
||||
@ -91,6 +95,11 @@
|
||||
<Compile Include="Services\Dialog\IDialogService.cs" />
|
||||
<Compile Include="Services\Identity\IdentityService.cs" />
|
||||
<Compile Include="Services\Identity\IIdentityService.cs" />
|
||||
<Compile Include="Services\Location\ILocationService.cs" />
|
||||
<Compile Include="Services\Location\LocationService.cs" />
|
||||
<Compile Include="Services\Marketing\ICampaignService.cs" />
|
||||
<Compile Include="Services\Marketing\CampaignMockService.cs" />
|
||||
<Compile Include="Services\Marketing\CampaignService.cs" />
|
||||
<Compile Include="Services\Navigation\INavigationService.cs" />
|
||||
<Compile Include="Services\Navigation\NavigationService.cs" />
|
||||
<Compile Include="Services\OpenUrl\IOpenUrlService.cs" />
|
||||
@ -113,6 +122,8 @@
|
||||
<Compile Include="ViewModels\Base\ViewModelBase.cs" />
|
||||
<Compile Include="ViewModels\Base\ViewModelLocator.cs" />
|
||||
<Compile Include="ViewModels\BasketViewModel.cs" />
|
||||
<Compile Include="ViewModels\CampaignDetailsViewModel.cs" />
|
||||
<Compile Include="ViewModels\CampaignViewModel.cs" />
|
||||
<Compile Include="ViewModels\CatalogViewModel.cs" />
|
||||
<Compile Include="ViewModels\CheckoutViewModel.cs" />
|
||||
<Compile Include="ViewModels\LoginViewModel.cs" />
|
||||
@ -123,9 +134,15 @@
|
||||
<Compile Include="Views\BasketView.xaml.cs">
|
||||
<DependentUpon>BasketView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\CampaignView.xaml.cs">
|
||||
<DependentUpon>CampaignView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\CatalogView.xaml.cs">
|
||||
<DependentUpon>CatalogView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\CampaignDetailsView.xaml.cs">
|
||||
<DependentUpon>CampaignDetailsView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\CheckoutView.xaml.cs">
|
||||
<DependentUpon>CheckoutView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@ -159,6 +176,9 @@
|
||||
<Compile Include="Views\Templates\OrderTemplate.xaml.cs">
|
||||
<DependentUpon>OrderTemplate.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\Templates\CampaignTemplate.xaml.cs">
|
||||
<DependentUpon>CampaignTemplate.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\Templates\ProductTemplate.xaml.cs">
|
||||
<DependentUpon>ProductTemplate.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@ -166,6 +186,7 @@
|
||||
<Compile Include="Converters\FirstValidationErrorConverter.cs" />
|
||||
<Compile Include="Effects\EntryLineColorEffect.cs" />
|
||||
<Compile Include="Behaviors\LineColorBehavior.cs" />
|
||||
<Compile Include="Models\Token\UserToken.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
@ -259,6 +280,29 @@
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Views\CampaignView.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System.ComponentModel.Annotations">
|
||||
<HintPath>..\..\..\..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.6\Profile\Profile44\System.ComponentModel.Annotations.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Views\CampaignDetailsView.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Views\Templates\CampaignTemplate.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user