Browse Source

Merge branch 'master' into xamarin

pull/211/head
David Britch 7 years ago
parent
commit
01ede6477f
142 changed files with 64356 additions and 821 deletions
  1. +134
    -0
      KUBERNETES.md
  2. +48
    -0
      README.CICD.k8s.md
  3. +28
    -0
      README.k8s.md
  4. +32
    -12
      README.md
  5. +0
    -29
      _docker/rabbitmq/Dockerfile.nanowin
  6. +0
    -1
      _docker/rabbitmq/enabled_plugins
  7. +0
    -1
      _docker/rabbitmq/rabbitmq.config
  8. +0
    -30
      _docker/redis/Dockerfile.nanowin
  9. +6
    -0
      cli-mac/build-bits.sh
  10. +1
    -2
      cli-windows/build-bits-simple.ps1
  11. +21
    -17
      docker-compose-windows.override.yml
  12. +19
    -15
      docker-compose-windows.prod.yml
  13. +2
    -2
      docker-compose-windows.yml
  14. +3
    -3
      docker-compose.ci.build.yml
  15. +56
    -0
      docker-compose.nobuild.yml
  16. +30
    -26
      docker-compose.override.yml
  17. +31
    -26
      docker-compose.prod.yml
  18. +8
    -7
      docker-compose.yml
  19. BIN
      docs/Enterprise-Application-Patterns-using-XamarinForms.pdf
  20. BIN
      docs/NET-Microservices-Architecture-for-Containerized-NET-Applications-(Microsoft-eBook).pdf
  21. +315
    -0
      eShopOnContainers-Android.sln
  22. +1
    -1
      eShopOnContainers-ServicesAndWebApps.sln
  23. +237
    -0
      eShopOnContainers-iOS.sln
  24. +52
    -52
      eShopOnContainers.sln
  25. BIN
      img/ebook_arch_dev_microservices_containers_cover.png
  26. BIN
      img/k8s/blob_creation.png
  27. BIN
      img/k8s/deploy_script_task.png
  28. BIN
      img/k8s/get_kubectlbin_task.png
  29. BIN
      img/k8s/get_kubectlconfig_task.png
  30. BIN
      img/xamarin-enterprise-patterns-ebook-cover-small.png
  31. +20024
    -0
      k8s/.kube/schema/v1.5.3/api/v1/schema.json
  32. +10768
    -0
      k8s/.kube/schema/v1.5.3/apis/extensions/v1beta1/schema.json
  33. +20024
    -0
      k8s/.kube/schema/v1.5.3/schema095733259
  34. +10768
    -0
      k8s/.kube/schema/v1.5.3/schema392735526
  35. +29
    -0
      k8s/basket-data.yaml
  36. +140
    -0
      k8s/deploy.ps1
  37. +306
    -0
      k8s/deployments.yaml
  38. +47
    -0
      k8s/frontend.yaml
  39. +25
    -0
      k8s/gen-k8s-env.ps1
  40. +80
    -0
      k8s/nginx.conf
  41. +30
    -0
      k8s/rabbitmq.yaml
  42. +97
    -0
      k8s/services.yaml
  43. +33
    -0
      k8s/sql-data.yaml
  44. +1
    -2
      src/BuildingBlocks/EventBus/EventBus/EventBus.csproj
  45. +5
    -6
      src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj
  46. +7
    -8
      src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj
  47. +2
    -2
      src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/Microsoft.AspNetCore.HealthChecks.csproj
  48. +10
    -1
      src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/HealthCheckBuilderSqlServerExtensions.cs
  49. +1
    -1
      src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/Microsoft.Extensions.HealthChecks.SqlServer.csproj
  50. +18
    -4
      src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/NumericChecks.cs
  51. +10
    -0
      src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/SystemChecks.cs
  52. +45
    -8
      src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Checks/UrlChecks.cs
  53. +2
    -2
      src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Microsoft.Extensions.HealthChecks.csproj
  54. +8
    -8
      src/BuildingBlocks/Resilience/Resilience.Http/IHttpClient.cs
  55. +3
    -3
      src/BuildingBlocks/Resilience/Resilience.Http/Resilience.Http.csproj
  56. +0
    -10
      src/BuildingBlocks/Resilience/Resilience.Http/ResiliencePolicy.cs
  57. +121
    -26
      src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs
  58. +77
    -9
      src/BuildingBlocks/Resilience/Resilience.Http/StandardHttpClient.cs
  59. +6
    -6
      src/Mobile/README.md
  60. +4
    -3
      src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Identity/IdentityService.cs
  61. +1
    -1
      src/Mobile/eShopOnContainers/eShopOnContainers.Droid/Properties/AndroidManifest.xml
  62. +6
    -6
      src/Mobile/eShopOnContainers/eShopOnContainers.Droid/Renderers/CustomNavigationPageRenderer.cs
  63. +2
    -1
      src/Mobile/eShopOnContainers/eShopOnContainers.Droid/eShopOnContainers.Droid.csproj
  64. +2
    -1
      src/Mobile/eShopOnContainers/eShopOnContainers.Windows/eShopOnContainers.Windows.csproj
  65. +1
    -0
      src/Mobile/eShopOnContainers/eShopOnContainers.iOS/eShopOnContainers.iOS.csproj
  66. +2
    -4
      src/Services/Basket/Basket.API/Auth/Server/AuthorizationHeaderParameterOperationFilter.cs
  67. +1
    -4
      src/Services/Basket/Basket.API/Auth/Server/IdentitySecurityScheme.cs
  68. +15
    -19
      src/Services/Basket/Basket.API/Basket.API.csproj
  69. +3
    -7
      src/Services/Basket/Basket.API/Controllers/BasketController.cs
  70. +2
    -8
      src/Services/Basket/Basket.API/Controllers/HomeController.cs
  71. +1
    -1
      src/Services/Basket/Basket.API/Dockerfile
  72. +1
    -4
      src/Services/Basket/Basket.API/Model/Basket.cs
  73. +1
    -6
      src/Services/Basket/Basket.API/Model/BasketItem.cs
  74. +0
    -1
      src/Services/Basket/Basket.API/Model/RedisBasketRepository.cs
  75. +2
    -2
      src/Services/Basket/Basket.API/Properties/launchSettings.json
  76. +7
    -8
      src/Services/Basket/Basket.API/Startup.cs
  77. +22
    -25
      src/Services/Catalog/Catalog.API/Catalog.API.csproj
  78. +1
    -1
      src/Services/Catalog/Catalog.API/Controllers/HomeController.cs
  79. +1
    -1
      src/Services/Catalog/Catalog.API/Dockerfile
  80. +1
    -1
      src/Services/Catalog/Catalog.API/Properties/launchSettings.json
  81. +35
    -30
      src/Services/Catalog/Catalog.API/Startup.cs
  82. +19
    -17
      src/Services/Identity/Identity.API/Configuration/Config.cs
  83. +1
    -1
      src/Services/Identity/Identity.API/Dockerfile
  84. +23
    -27
      src/Services/Identity/Identity.API/Identity.API.csproj
  85. +1
    -1
      src/Services/Identity/Identity.API/Services/ProfileService.cs
  86. +6
    -1
      src/Services/Identity/Identity.API/Startup.cs
  87. +1
    -1
      src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommand.cs
  88. +2
    -5
      src/Services/Ordering/Ordering.API/Application/Commands/IdentifiedCommand.cs
  89. +2
    -2
      src/Services/Ordering/Ordering.API/Application/Commands/IdentifierCommandHandler.cs
  90. +1
    -1
      src/Services/Ordering/Ordering.API/Application/Decorators/LogDecorator.cs
  91. +1
    -1
      src/Services/Ordering/Ordering.API/Application/Decorators/ValidatorDecorator.cs
  92. +3
    -2
      src/Services/Ordering/Ordering.API/Application/Queries/IOrderQueries.cs
  93. +2
    -2
      src/Services/Ordering/Ordering.API/Application/Queries/OrderQueries.cs
  94. +2
    -8
      src/Services/Ordering/Ordering.API/Controllers/HomeController.cs
  95. +7
    -10
      src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs
  96. +1
    -1
      src/Services/Ordering/Ordering.API/Dockerfile
  97. +2
    -2
      src/Services/Ordering/Ordering.API/Infrastructure/Auth/AuthorizationHeaderParameterOperationFilter.cs
  98. +2
    -3
      src/Services/Ordering/Ordering.API/Infrastructure/AutofacModules/MediatorModule.cs
  99. +25
    -0
      src/Services/Ordering/Ordering.API/Infrastructure/Middlewares/FailingStartupFilter.cs
  100. +23
    -0
      src/Services/Ordering/Ordering.API/Infrastructure/Middlewares/FailingWebHostBuilderExtensions.cs

+ 134
- 0
KUBERNETES.md View File

@ -0,0 +1,134 @@
# Kubernetes 101
## Docker vs. Kubernetes
Docker helps you package applications into images, and execute them in containers. Kubernetes is a robust platform for containerized applications. It abstracts away the underlying network infrastructure and hardware required to run them, simplifying their deployment, scaling, and management.
## Kubernetes from the container up
### Pods
The basic unit of a Kubernetes deployment is the **Pod**. A Pod encapsulates one or more containers. For example, the `basket` Pod specifies two containers:
>`deployments.yaml`
>
>The first container runs the `eshop/basket.api` image:
>```yaml
>spec:
> containers:
> - name: basket
> image: eshop/basket.api
> env:
> - name: ConnectionString
> value: 127.0.0.1
>```
>Note the `ConnectionString` environment variable: containers within a Pod are networked via `localhost`. The second container runs the `redis` image:
>```yaml
>- name: basket-data
> image: redis:3.2-alpine
> ports:
> - containerPort: 6379
>```
Placing `basket` and `basket-data` in the same Pod is reasonable here because the former requires the latter, and owns all its data. If we wanted to scale the service, however, it would be better to place the containers in separate Pods because the basket API and redis scale at different rates.
If the containers were in separate Pods, they would no longer be able to communicate via `localhost`; a **Service** would be required.
### Services
Services expose Pods to external networks. For example, the `basket` Service exposes Pods with labels `app=eshop` and `component=basket` to the cluster at large:
>`services.yaml`
>```yaml
>kind: Service
>metadata:
> ...
> name: basket
>spec:
> ports:
> - port: 80
> selector:
> app: eshop
> component: basket
>```
Kubernetes's built-in DNS service resolves Service names to cluster-internal IP addresses. This allows the nginx frontend to proxy connections to the app's microservices by name:
>`nginx.conf`
>```
>location /basket-api {
> proxy_pass http://basket;
>```
The frontend Pod is different in that it needs to be exposed outside the cluster. This is accomplished with another Service:
>`frontend.yaml`
>```yaml
>spec:
> ports:
> - port: 80
> targetPort: 8080
> selector:
> app: eshop
> component: frontend
> type: LoadBalancer
>```
`type: LoadBalancer` tells Kubernetes to expose the Service behind a load balancer appropriate for the cluster's platform. For Azure Container Service, this creates an Azure load balancer rule with a public IP.
### Deployments
Kubernetes uses Pods to organize containers, and Services to network them. It uses **Deployments** to organize creating, and modifying, Pods. A Deployment describes a state of one or more Pods. When a Deployment is created or modified, Kubernetes attempts to realize that state.
The Deployments in this project are basic. Still, `deploy.ps1` shows some more advanced Deployment capabilities. For example, Deployments can be paused. Each Deployment of this app is paused at creation:
>`deployments.yaml`
>```yaml
>kind: Deployment
>spec:
> paused: true
>```
This allows the deployment script to change images before Kubernetes creates the Pods:
>`deploy.ps1`
>```powershell
>kubectl set image -f deployments.yaml basket=$registry/basket.api ...
>kubectl rollout resume -f deployments.yaml
>```
### ConfigMaps
A **ConfigMap** is a collection of key/value pairs commonly used to provide configuration information to Pods. The deployment script uses one to store the frontend's configuration:
>`deploy.ps1`
>```
>kubectl create configmap config-files from-file=nginx-conf=nginx.conf
>```
This creates a ConfigMap named `config-files` with key `nginx-conf` whose value is the content of nginx.conf. The frontend Pod mounts that value as `/etc/nginx/nginx.conf`:
>`frontend.yaml`
>```yaml
>spec:
> containers:
> - name: nginx
> ...
> volumeMounts:
> - name: config
> mountPath: /etc/nginx
> volumes:
> - name: config
> configMap:
> name: config-files
> items:
> - key: nginx-conf
> path: nginx.conf
>```
This facilitates rapid iteration better than other techniques, e.g. building an image to bake in configuration.
The script also stores public URLs for the app's components in a ConfigMap:
>`deploy.ps1`
>```powershell
>kubectl create configmap urls --from-literal=BasketUrl=http://$($frontendUrl)/basket-api ...
>```
>Here's how the `webspa` Deployment uses it:
>
>`deployments.yaml`
>```yaml
>spec:
> containers:
> - name: webspa
> ...
> env:
> ...
> - name: BasketUrl
> valueFrom:
> configMapKeyRef:
> name: urls
> key: BasketUrl
>```
### Further reading
* [Kubernetes Concepts](https://kubernetes.io/docs/concepts/)
* [kubectl for Docker Users](https://kubernetes.io/docs/user-guide/docker-cli-to-kubectl/)
* [Kubernetes API reference](https://kubernetes.io/docs/api-reference/v1.5/)

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

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

+ 28
- 0
README.k8s.md View File

@ -0,0 +1,28 @@
# eShopOnContainers on Kubernetes
The k8s directory contains Kubernetes configuration for the eShopOnContainers app and a PowerShell script to deploy it to a cluster. Each eShopOnContainers microservice has a deployment configuration in `deployments.yaml`, and is exposed to the cluster by a service in `services.yaml`. The microservices are exposed externally on individual routes (`/basket-api`, `/webmvc`, etc.) by an nginx reverse proxy specified in `frontend.yaml` and `nginx.conf`.
## Prerequisites
* A Kubernetes cluster. Follow Azure Container Service's [walkthrough](https://docs.microsoft.com/en-us/azure/container-service/container-service-kubernetes-walkthrough) to create one.
* A private Docker registry. Follow Azure Container Registry's [guide](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-get-started-portal) to create one.
* Optionally, previous steps can be skipped if you run gen-k8s-env.ps1 script to automatically create the azure environment needed for kubernetes deployment. Azure cli 2.0 must be previously installed [installation guide](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli). For example:
>```
>./gen-k8s-env -resourceGroupName k8sGroup -location westeurope -registryName k8sregistry -orchestratorName k8s-cluster -dnsName k8s-dns
>```
* A Docker development environment with `docker` and `docker-compose`.
* Visit [docker.com](https://docker.com) to download the tools and set up the environment. Docker's [installation guide](https://docs.docker.com/engine/getstarted/step_one/#step-3-verify-your-installation) covers verifying your Docker installation.
* The Kubernetes command line client, `kubectl`.
* This can be installed with the `az` tool as described in the Azure Container Service [walkthrough](https://docs.microsoft.com/en-us/azure/container-service/container-service-kubernetes-walkthrough). `az` is also helpful for getting the credentials `kubectl` needs to access your cluster. For other installation options, and information about configuring `kubectl` yourself, see the [Kubernetes documentation](https://kubernetes.io/docs/tasks/kubectl/install/).
## Deploy the application with the deployment script
1. Open a PowerShell command line at the `k8s` directory of your local eShopOnContainers repository.
1. Ensure `docker`, `docker-compose`, and `kubectl` are on the path, and configured for your Docker machine and Kubernetes cluster.
1. Run `deploy.ps1` with your registry information. The Docker username and password are provided by Azure Container Registry, and can be retrieved from the Azure portal. Optionally, ACR credentials can be obtained by running the following command:
>```
>az acr credential show -n eshopregistry
>```
Once the user and password are retrieved, run the following script for deployment. For example:
>```
>./deploy.ps1 -registry myregistry.azurecr.io -dockerUser User -dockerPassword SecretPassword
>```
The script will build the code and corresponding Docker images, push the latter to your registry, and deploy the application to your cluster. You can watch the deployment unfold from the Kubernetes web interface: run `kubectl proxy` and open a browser to [http://localhost:8001/ui](http://localhost:8001/ui)

+ 32
- 12
README.md View File

@ -3,20 +3,20 @@ Sample .NET Core reference application, powered by Microsoft, based on a simplif
**Note for Pull Requests**: We accept pull request from the community. When doing it, please do it onto the DEV branch which is the consolidated work-in-progress branch. Do not request it onto Master, if possible.
> ### DISCLAIMER
> **IMPORTANT:** The current state of this sample application is **BETA**, consider it version a 0.1 foundational version, therefore, many areas could be improved and change significantly while refactoring current code and implementing new features. **Feedback with improvements and pull requests from the community will be highly appreciated and accepted.**
> **IMPORTANT:** The current state of this sample application is **BETA**, consider it version a 0.1 foundational version, therefore, many areas could be improved and change significantly while refactoring current code and implementing new features. **Feedback with improvements and pull requests from the community will be highly appreciated and accepted.**
>
> This reference application proposes a simplified microservice oriented architecture implementation to introduce technologies like .NET Core with Docker containers through a comprehensive application. The chosen domain is an eShop/eCommerce but simply because it is a well-know domain by most people/developers.
However, this sample application should not be considered as an "eCommerce reference model", at all. The implemented business domain might not be ideal from an eCommerce business point of view. It is neither trying to solve all the problems in a large, scalable and mission-critical distributed system. It is just a bootstrap for developers to easily get started in the world of Docker containers and microservices with .NET Core.
> <p>For example, the next step (still not covered in eShopOnContainers) after understanding Docker containers and microservices development with .NET Core, is to select a microservice cluster/orchestrator like Docker Swarm, Kubernetes or DC/OS (in Azure Container Service) or Azure Service Fabric which in most of the cases will require additional partial changes to your application's configuration (although the present architecture should work on most orchestrators with small changes).
However, this sample application should not be considered as an "eCommerce reference model", at all. The implemented business domain might not be ideal from an eCommerce business point of view. It is neither trying to solve all the problems in a large, scalable and mission-critical distributed system. It is just a bootstrap for developers to easily get started in the world of Docker containers and microservices with .NET Core.
> <p>For example, the next step (still not covered in eShopOnContainers) after understanding Docker containers and microservices development with .NET Core, is to select a microservice cluster/orchestrator like Docker Swarm, Kubernetes or DC/OS (in Azure Container Service) or Azure Service Fabric which in most of the cases will require additional partial changes to your application's configuration (although the present architecture should work on most orchestrators with small changes).
> Additional steps would be to move your databases to HA cloud services, or to implement your EventBus with Azure Service Bus or any other production ready Service Bus in the market.
> <p> In the future we might fork this project and make multiple versions targeting specific microservice cluster/orchestrators plus using additional cloud infrastructure. <p>
> <img src="img/exploring-to-production-ready.png">
> Read the planned <a href='https://github.com/dotnet/eShopOnContainers/wiki/01.-Roadmap-and-Milestones-for-future-releases'>Roadmap and Milestones for future releases of eShopOnContainers</a> within the Wiki for further info about possible new implementations and provide feedback at the <a href='https://github.com/dotnet/eShopOnContainers/issues'>ISSUES section</a> if you'd like to see any specific scenario implemented or improved. Also, feel free to discuss on any current issue.
**Architecture overview**: This reference application is cross-platform either at the server and client side, thanks to .NET Core services capable of running on Linux or Windows containers depending on your Docker host, and to Xamarin for mobile apps running on Android, iOS or Windows/UWP plus any browser for the client web apps.
The architecture proposes a simplified microservice oriented architecture implementation with multiple autonomous microservices (each one owning its own data/db) and implementing different approaches within each microservice (simple CRUD vs. DDD/CQRS patterns) using Http as the current communication protocol.
**Architecture overview**: This reference application is cross-platform either at the server and client side, thanks to .NET Core services capable of running on Linux or Windows containers depending on your Docker host, and to Xamarin for mobile apps running on Android, iOS or Windows/UWP plus any browser for the client web apps.
The architecture proposes a simplified microservice oriented architecture implementation with multiple autonomous microservices (each one owning its own data/db) and implementing different approaches within each microservice (simple CRUD vs. DDD/CQRS patterns) using Http as the current communication protocol.
<p>
It also supports asynchronous communication for data updates propagation across multiple services based on Integration Events and an Event Bus plus other features defined at the <a href='https://github.com/dotnet/eShopOnContainers/wiki/01.-Roadmap-and-Milestones-for-future-releases'>roadmap</a>.
It also supports asynchronous communication for data updates propagation across multiple services based on Integration Events and an Event Bus plus other features defined at the <a href='https://github.com/dotnet/eShopOnContainers/wiki/01.-Roadmap-and-Milestones-for-future-releases'>roadmap</a>.
<p>
<img src="img/eshop_logo.png">
<img src="img/eShopOnContainers_Architecture_Diagram.png">
@ -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** (Early DRAFT, still work in progress)</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>
@ -66,7 +66,7 @@ Finally, those microservices are consumed by multiple client web and mobile apps
<b>*MVC Application (ASP.NET Core)*</b>: Its an MVC application where you can find interesting scenarios on how to consume HTTP-based microservices from C# running in the server side, as it is a typical ASP.NET Core MVC application. Since it is a server-side application, access to other containers/microservices is done within the internal Docker Host network with its internal name resolution.
<img src="img/eshop-webmvc-app-screenshot.png">
<br>
<b>*SPA (Single Page Application)*</b>: Providing similar "eShop business functionality" but developed with Angular 2, Typescript and slightly using ASP.NET Core MVC. This is another approach for client web applications to be used when you want to have a more modern client behavior which is not behaving with the typical browser round-trip on every action but behaving like a Single-Page-Application which is more similar to a desktop app usage experience. The consumption of the HTTP-based microservices is done from TypeScript/JavaScript in the client browser, so the client calls to the microservices come from out of the Docker Host internal network (Like from your network or even from the Internet).
<b>*SPA (Single Page Application)*</b>: Providing similar "eShop business functionality" but developed with Angular 2, Typescript and slightly using ASP.NET Core MVC. This is another approach for client web applications to be used when you want to have a more modern client behavior which is not behaving with the typical browser round-trip on every action but behaving like a Single-Page-Application which is more similar to a desktop app usage experience. The consumption of the HTTP-based microservices is done from TypeScript/JavaScript in the client browser, so the client calls to the microservices come from out of the Docker Host internal network (Like from your network or even from the Internet).
<img src="img/eshop-webspa-app-screenshot.png">
<br>
<b>*Xamarin Mobile App (For iOS, Android and Windows/UWP)*</b>: It is a client mobile app supporting the most common mobile OS platforms (iOS, Android and Windows/UWP). In this case, the consumption of the microservices is done from C# but running on the client devices, so out of the Docker Host internal network (Like from your network or even the Internet).
@ -79,23 +79,43 @@ 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
### CLI and Windows based
For those who prefer the CLI on Windows, using dotnet CLI, docker CLI and VS Code for Windows:
For those who prefer the CLI on Windows, using dotnet CLI, docker CLI and VS Code for Windows:
https://github.com/dotnet/eShopOnContainers/wiki/03.-Setting-the-eShopOnContainers-solution-up-in-a-Windows-CLI-environment-(dotnet-CLI,-Docker-CLI-and-VS-Code)
### CLI and Mac based
For those who prefer the CLI on a Mac, using dotnet CLI, docker CLI and VS Code for Mac
For those who prefer the CLI on a Mac, using dotnet CLI, docker CLI and VS Code for Mac
(Instructions still TBD, but similar to Windows CLI):
https://github.com/dotnet/eShopOnContainers/wiki/04.-Setting-eShopOnContainer-solution-up-in-a-Mac,-VS-Code-and-CLI-environment--(dotnet-CLI,-Docker-CLI-and-VS-Code)
> ### Note on tested Docker Containers/Images
> Most of the development and testing of this project was (as of early March 2017) done <b> on Docker Linux containers</b> running in development machines with "Docker for Windows" and the default Hyper-V Linux VM (MobiLinuxVM) installed by "Docker for Windows".
> Most of the development and testing of this project was (as of early March 2017) done <b> on Docker Linux containers</b> running in development machines with "Docker for Windows" and the default Hyper-V Linux VM (MobiLinuxVM) installed by "Docker for Windows".
The <b>Windows Containers scenario is currently being implemented/tested yet</b>. The application should be able to run on Windows Nano Containers based on different Docker base images, as well, as the .NET Core services have also been tested running on plain Windows (with no Docker).
The app was also partially tested on "Docker for Mac" using a development MacOS machine with .NET Core and VS Code installed, which is still a scenario using Linux containers running on the VM setup in the Mac by the "Docker for Windows" setup. But further testing and feedback on Mac environments and Windows Containers, from the community, will be appreciated.
## Kubernetes
The k8s directory contains Kubernetes configuration for the eShopOnContainers app and a PowerShell script to deploy it to a cluster. Each eShopOnContainers microservice has a deployment configuration in `deployments.yaml`, and is exposed to the cluster by a service in `services.yaml`. The microservices are exposed externally on individual routes (`/basket-api`, `/webmvc`, etc.) by an nginx reverse proxy specified in `frontend.yaml` and `nginx.conf`.
### Prerequisites
* A Kubernetes cluster. Follow Azure Container Service's [walkthrough](https://docs.microsoft.com/en-us/azure/container-service/container-service-kubernetes-walkthrough) to create one.
* A private Docker registry. Follow Azure Container Registry's [guide](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-get-started-portal) to create one.
* A Docker development environment with `docker` and `docker-compose`.
* Visit [docker.com](https://docker.com) to download the tools and set up the environment. Docker's [installation guide](https://docs.docker.com/engine/getstarted/step_one/#step-3-verify-your-installation) covers verifying your Docker installation.
* The Kubernetes command line client, `kubectl`.
* This can be installed with the `az` tool as described in the Azure Container Service [walkthrough](https://docs.microsoft.com/en-us/azure/container-service/container-service-kubernetes-walkthrough). `az` is also helpful for getting the credentials `kubectl` needs to access your cluster. For other installation options, and information about configuring `kubectl` yourself, see the [Kubernetes documentation](https://kubernetes.io/docs/tasks/kubectl/install/).
### Deploy the application with the deployment script
1. Open a PowerShell command line at the `k8s` directory of your local eShopOnContainers repository.
1. Ensure `docker`, `docker-compose`, and `kubectl` are on the path, and configured for your Docker machine and Kubernetes cluster.
1. Run `deploy.ps1` with your registry information. The Docker username and password are provided by Azure Container Registry, and can be retrieved from the Azure portal. For example:
>```
>./deploy.ps1 -registry myregistry.azurecr.io -dockerUser User -dockerPassword SecretPassword
>```
The script will build the code and corresponding Docker images, push the latter to your registry, and deploy the application to your cluster. You can watch the deployment unfold from the Kubernetes web interface: run `kubectl proxy` and open a browser to [http://localhost:8001/ui](http://localhost:8001/ui)
## Sending feedback and pull requests
As mentioned, we'd appreciate to your feedback, improvements and ideas.
You can create new issues at the issues section, do pull requests and/or send emails to **eshop_feedback@service.microsoft.com**
## Questions
[QUESTION] Answer +1 if the solution is working for you (Through VS2017 or CLI environment):
https://github.com/dotnet/eShopOnContainers/issues/107
https://github.com/dotnet/eShopOnContainers/issues/107

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

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

+ 0
- 1
_docker/rabbitmq/enabled_plugins View File

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

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

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

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

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

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

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


+ 1
- 2
cli-windows/build-bits-simple.ps1 View File

@ -11,8 +11,7 @@ if ([string]::IsNullOrEmpty($rootPath)) {
}
Write-Host "Root path used is $rootPath" -ForegroundColor Yellow
$SolutionFilePath = $rootPath + "eShopOnContainers-ServicesAndWebApps.sln"
$SolutionFilePath = [IO.Path]::Combine($rootPath, "eShopOnContainers-ServicesAndWebApps.sln")
dotnet restore $SolutionFilePath


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

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


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

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


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

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


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

@ -2,9 +2,9 @@ version: '2'
services:
ci-build:
image: microsoft/aspnetcore-build:1.0-1.1
image: microsoft/aspnetcore-build:1.1.2
volumes:
- .:/src
working_dir: /src
command: /bin/bash -c "dotnet restore ./eShopOnContainers-ServicesAndWebApps.sln && dotnet publish ./eShopOnContainers-ServicesAndWebApps.sln -c Release -o ./obj/Docker/publish"
command: /bin/bash -c "pushd ./src/Web/WebSPA && npm rebuild node-sass && popd && dotnet restore ./eShopOnContainers-ServicesAndWebApps.sln && dotnet publish ./eShopOnContainers-ServicesAndWebApps.sln -c Release -o ./obj/Docker/publish"

+ 56
- 0
docker-compose.nobuild.yml View 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

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

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

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

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

+ 8
- 7
docker-compose.yml View File

@ -5,7 +5,7 @@ services:
image: eshop/basket.api
build:
context: ./src/Services/Basket/Basket.API
dockerfile: Dockerfile
dockerfile: Dockerfile
depends_on:
- basket.data
- identity.api
@ -15,7 +15,7 @@ services:
image: eshop/catalog.api
build:
context: ./src/Services/Catalog/Catalog.API
dockerfile: Dockerfile
dockerfile: Dockerfile
depends_on:
- sql.data
- rabbitmq
@ -24,7 +24,7 @@ services:
image: eshop/identity.api
build:
context: ./src/Services/Identity/Identity.API
dockerfile: Dockerfile
dockerfile: Dockerfile
depends_on:
- sql.data
@ -32,7 +32,7 @@ services:
image: eshop/ordering.api
build:
context: ./src/Services/Ordering/Ordering.API
dockerfile: Dockerfile
dockerfile: Dockerfile
depends_on:
- sql.data
@ -40,7 +40,7 @@ services:
image: eshop/webspa
build:
context: ./src/Web/WebSPA
dockerfile: Dockerfile
dockerfile: Dockerfile
depends_on:
- identity.api
- basket.api
@ -49,7 +49,7 @@ services:
image: eshop/webmvc
build:
context: ./src/Web/WebMVC
dockerfile: Dockerfile
dockerfile: Dockerfile
depends_on:
- catalog.api
- ordering.api
@ -73,4 +73,5 @@ services:
image: eshop/webstatus
build:
context: ./src/Web/WebStatus
dockerfile: Dockerfile
dockerfile: Dockerfile

BIN
docs/Enterprise-Application-Patterns-using-XamarinForms.pdf View File


BIN
docs/architecting-and-developing-containerized-and-microservice-based-net-applications-ebook-early-draft.pdf → docs/NET-Microservices-Architecture-for-Containerized-NET-Applications-(Microsoft-eBook).pdf View File


+ 315
- 0
eShopOnContainers-Android.sln View File

@ -0,0 +1,315 @@

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

+ 1
- 1
eShopOnContainers-ServicesAndWebApps.sln View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26403.7
VisualStudioVersion = 15.0.26430.12
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{932D8224-11F6-4D07-B109-DA28AD288A63}"
EndProject


+ 237
- 0
eShopOnContainers-iOS.sln View File

@ -0,0 +1,237 @@

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

+ 52
- 52
eShopOnContainers.sln View File

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

BIN
img/ebook_arch_dev_microservices_containers_cover.png View File

Before After
Width: 260  |  Height: 336  |  Size: 38 KiB Width: 260  |  Height: 336  |  Size: 35 KiB

BIN
img/k8s/blob_creation.png View File

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

BIN
img/k8s/deploy_script_task.png View File

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

BIN
img/k8s/get_kubectlbin_task.png View File

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

BIN
img/k8s/get_kubectlconfig_task.png View File

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

BIN
img/xamarin-enterprise-patterns-ebook-cover-small.png View File

Before After
Width: 260  |  Height: 336  |  Size: 25 KiB Width: 260  |  Height: 336  |  Size: 22 KiB

+ 20024
- 0
k8s/.kube/schema/v1.5.3/api/v1/schema.json
File diff suppressed because it is too large
View File


+ 10768
- 0
k8s/.kube/schema/v1.5.3/apis/extensions/v1beta1/schema.json
File diff suppressed because it is too large
View File


+ 20024
- 0
k8s/.kube/schema/v1.5.3/schema095733259
File diff suppressed because it is too large
View File


+ 10768
- 0
k8s/.kube/schema/v1.5.3/schema392735526
File diff suppressed because it is too large
View File


+ 29
- 0
k8s/basket-data.yaml View 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

+ 140
- 0
k8s/deploy.ps1 View File

@ -0,0 +1,140 @@
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
)
function ExecKube($cmd) {
if($deployCI) {
$kubeconfig = $kubeconfigPath + 'config';
$exp = $execPath + 'kubectl ' + $cmd + ' --kubeconfig=' + $kubeconfig
Invoke-Expression $exp
}
else{
$exp = $execPath + 'kubectl ' + $cmd
Invoke-Expression $exp
}
}
# Not used when deploying through CI VSTS
if(-not $deployCI) {
$requiredCommands = ("docker", "docker-compose", "kubectl")
foreach ($command in $requiredCommands) {
if ((Get-Command $command -ErrorAction SilentlyContinue) -eq $null) {
Write-Host "$command must be on path" -ForegroundColor Red
exit
}
}
}
# Use ACR instead of DockerHub as image repository
if(-not $useDockerHub) {
Write-Host "Logging in to $registry" -ForegroundColor Yellow
docker login -u $dockerUser -p $dockerPassword $registry
if (-not $LastExitCode -eq 0) {
Write-Host "Login failed" -ForegroundColor Red
exit
}
# create registry key secret
ExecKube -cmd 'create secret docker-registry registry-key `
--docker-server=$registry `
--docker-username=$dockerUser `
--docker-password=$dockerPassword `
--docker-email=not@used.com'
}
# Removing previous services & deployments
Write-Host "Removing existing services & deployments.." -ForegroundColor Yellow
ExecKube -cmd 'delete deployments --all'
ExecKube -cmd 'delete services --all'
ExecKube -cmd 'delete configmap config-files'
ExecKube -cmd 'delete configmap urls'
# 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 basket-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
}
}
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
}
ExecKube -cmd 'create configmap urls `
--from-literal=BasketUrl=http://basket `
--from-literal=BasketHealthCheckUrl=http://basket/hc `
--from-literal=CatalogUrl=http://$($frontendUrl)/catalog-api `
--from-literal=CatalogHealthCheckUrl=http://catalog/hc `
--from-literal=IdentityUrl=http://$($frontendUrl)/identity `
--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://$($frontendUrl)/ordering-api `
--from-literal=SpaClientCatalogExternalUrl=http://$($frontendUrl)/catalog-api `
--from-literal=SpaClientBasketExternalUrl=http://$($frontendUrl)/basket-api `
--from-literal=SpaClientIdentityExternalUrl=http://$($frontendUrl)/identity `
--from-literal=SpaClientExternalUrl=http://$($frontendUrl)'
ExecKube -cmd 'label configmap urls 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)
Write-Host "Update Image containers..." -ForegroundColor Yellow
ExecKube -cmd 'set image deployments/basket basket=$registry/eshop/basket.api'
ExecKube -cmd 'set image deployments/catalog catalog=$registry/eshop/catalog.api'
ExecKube -cmd 'set image deployments/identity identity=$registry/eshop/identity.api'
ExecKube -cmd 'set image deployments/ordering ordering=$registry/eshop/ordering.api'
ExecKube -cmd 'set image deployments/webmvc webmvc=$registry/eshop/webmvc'
ExecKube -cmd 'set image deployments/webstatus webstatus=$registry/eshop/webstatus'
ExecKube -cmd 'set image deployments/webspa webspa=$registry/eshop/webspa'
}
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/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

+ 306
- 0
k8s/deployments.yaml View File

@ -0,0 +1,306 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: basket
spec:
paused: true
template:
metadata:
labels:
app: eshop
component: basket
spec:
containers:
- name: basket
image: eshop/basket.api
imagePullPolicy: Always
env:
- name: ASPNETCORE_URLS
value: http://0.0.0.0:80/basket-api
- name: ConnectionString
value: basket-data
- name: EventBusConnection
value: rabbitmq
- name: IdentityUrl
valueFrom:
configMapKeyRef:
name: urls
key: IdentityUrl
ports:
- containerPort: 80
imagePullSecrets:
- name: registry-key
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: catalog
spec:
paused: true
template:
metadata:
labels:
app: eshop
component: catalog
spec:
containers:
- name: catalog
image: eshop/catalog.api
imagePullPolicy: Always
env:
- 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
- name: ExternalCatalogBaseUrl
valueFrom:
configMapKeyRef:
name: urls
key: CatalogUrl
ports:
- containerPort: 80
imagePullSecrets:
- name: registry-key
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: identity
spec:
paused: true
template:
metadata:
labels:
app: eshop
component: identity
spec:
containers:
- name: identity
image: eshop/identity.api
imagePullPolicy: Always
env:
- 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"
- name: MvcClient
valueFrom:
configMapKeyRef:
name: urls
key: MvcClientExternalUrl
- name: SpaClient
valueFrom:
configMapKeyRef:
name: urls
key: SpaClientExternalUrl
ports:
- containerPort: 80
imagePullSecrets:
- name: registry-key
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: ordering
spec:
paused: true
template:
metadata:
labels:
app: eshop
component: ordering
spec:
containers:
- name: ordering
image: eshop/ordering.api
imagePullPolicy: Always
env:
- 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;"
- name: EventBusConnection
value: rabbitmq
- name: IdentityUrl
valueFrom:
configMapKeyRef:
name: urls
key: IdentityUrl
ports:
- containerPort: 80
imagePullSecrets:
- name: registry-key
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: webmvc
spec:
paused: true
template:
metadata:
labels:
app: eshop
component: webmvc
spec:
containers:
- name: webmvc
image: eshop/webmvc
imagePullPolicy: Always
env:
- name: ASPNETCORE_URLS
value: http://0.0.0.0:80/webmvc
- name: BasketUrl
valueFrom:
configMapKeyRef:
name: urls
key: MvcClientBasketUrl
- name: CallBackUrl
valueFrom:
configMapKeyRef:
name: urls
key: MvcClientExternalUrl
- name: CatalogUrl
valueFrom:
configMapKeyRef:
name: urls
key: MvcClientCatalogUrl
- name: IdentityUrl
valueFrom:
configMapKeyRef:
name: urls
key: IdentityUrl
- name: OrderingUrl
valueFrom:
configMapKeyRef:
name: urls
key: MvcClientOrderingUrl
ports:
- containerPort: 80
imagePullSecrets:
- name: registry-key
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: webstatus
spec:
paused: true
template:
metadata:
labels:
app: eshop
component: webstatus
spec:
containers:
- name: webstatus
image: eshop/webstatus
imagePullPolicy: Always
env:
- name: ASPNETCORE_URLS
value: http://0.0.0.0:80/webstatus
- name: BasketUrl
valueFrom:
configMapKeyRef:
name: urls
key: BasketHealthCheckUrl
- name: CatalogUrl
valueFrom:
configMapKeyRef:
name: urls
key: CatalogHealthCheckUrl
- name: IdentityUrl
valueFrom:
configMapKeyRef:
name: urls
key: IdentityHealthCheckUrl
- name: OrderingUrl
valueFrom:
configMapKeyRef:
name: urls
key: OrderingHealthCheckUrl
- name: mvc
valueFrom:
configMapKeyRef:
name: urls
key: WebMvcHealthCheckUrl
- name: spa
valueFrom:
configMapKeyRef:
name: urls
key: WebSpaHealthCheckUrl
ports:
- containerPort: 80
imagePullSecrets:
- name: registry-key
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: webspa
spec:
paused: true
template:
metadata:
labels:
app: eshop
component: webspa
spec:
containers:
- name: webspa
image: eshop/webspa
imagePullPolicy: Always
env:
- name: ASPNETCORE_URLS
value: http://0.0.0.0:80
- name: BasketUrl
valueFrom:
configMapKeyRef:
name: urls
key: SpaClientBasketExternalUrl
- name: CallBackUrl
valueFrom:
configMapKeyRef:
name: urls
key: SpaClientExternalUrl
- name: CatalogUrl
valueFrom:
configMapKeyRef:
name: urls
key: SpaClientCatalogExternalUrl
- name: IdentityUrl
valueFrom:
configMapKeyRef:
name: urls
key: SpaClientIdentityExternalUrl
- name: OrderingUrl
valueFrom:
configMapKeyRef:
name: urls
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:
- name: registry-key

+ 47
- 0
k8s/frontend.yaml View File

@ -0,0 +1,47 @@
apiVersion: v1
kind: Service
metadata:
labels:
app: eshop
component: frontend
name: frontend
spec:
ports:
- port: 80
targetPort: 8080
selector:
app: eshop
component: frontend
type: LoadBalancer
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: frontend
spec:
template:
metadata:
labels:
app: eshop
component: frontend
spec:
containers:
- name: nginx
image: nginx:1.11.10-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
lifecycle:
preStop:
exec:
command: ["/usr/sbin/nginx","-s","quit"]
volumeMounts:
- name: config
mountPath: /etc/nginx
volumes:
- name: config
configMap:
name: config-files
items:
- key: nginx-conf
path: nginx.conf

+ 25
- 0
k8s/gen-k8s-env.ps1 View File

@ -0,0 +1,25 @@
Param(
[parameter(Mandatory=$true)][string]$resourceGroupName,
[parameter(Mandatory=$true)][string]$location,
[parameter(Mandatory=$true)][string]$registryName,
[parameter(Mandatory=$true)][string]$orchestratorName,
[parameter(Mandatory=$true)][string]$dnsName
)
# 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
# Create kubernetes orchestrator
Write-Host "Creating kubernetes orchestrator..." -ForegroundColor Yellow
az acs create --orchestrator-type=kubernetes --resource-group $resourceGroupName --name=$orchestratorName --dns-prefix=$dnsName --generate-ssh-keys
# Retrieve kubernetes cluster configuration and save it under ~/.kube/config
az acs kubernetes get-credentials --resource-group=$resourceGroupName --name=$orchestratorName
# Show ACR credentials
az acr credential show -n $registryName

+ 80
- 0
k8s/nginx.conf View File

@ -0,0 +1,80 @@
pid /tmp/nginx.pid;
worker_processes 1;
events {
worker_connections 1024;
}
http {
server_tokens off;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
client_body_temp_path /tmp/client_body;
fastcgi_temp_path /tmp/fastcgi_temp;
proxy_temp_path /tmp/proxy_temp;
scgi_temp_path /tmp/scgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
gzip on;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_buffers 4 32k;
gzip_types text/plain application/javascript text/css;
gzip_vary on;
keepalive_timeout 65;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
server {
listen 8080;
location /basket-api {
proxy_pass http://basket;
proxy_redirect off;
proxy_set_header Host $host;
}
location /catalog-api {
proxy_pass http://catalog;
proxy_redirect off;
proxy_set_header Host $host;
}
location /identity {
proxy_pass http://identity;
proxy_redirect off;
proxy_set_header Host $host;
}
location /ordering-api {
proxy_pass http://ordering;
proxy_redirect off;
proxy_set_header Host $host;
}
location /webmvc {
proxy_pass http://webmvc;
proxy_redirect off;
proxy_set_header Host $host;
}
location /webstatus {
proxy_pass http://webstatus;
proxy_redirect off;
proxy_set_header Host $host;
}
location / {
proxy_pass http://webspa;
proxy_redirect off;
proxy_set_header Host $host;
}
}
}

+ 30
- 0
k8s/rabbitmq.yaml View File

@ -0,0 +1,30 @@
apiVersion: v1
kind: Service
metadata:
labels:
app: eshop
component: rabbitmq
name: rabbitmq
spec:
ports:
- port: 5672
selector:
app: eshop
component: rabbitmq
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: rabbitmq
spec:
template:
metadata:
labels:
app: eshop
component: rabbitmq
spec:
containers:
- name: rabbitmq
image: rabbitmq:3.6.9-alpine
ports:
- containerPort: 5672

+ 97
- 0
k8s/services.yaml View File

@ -0,0 +1,97 @@
apiVersion: v1
kind: Service
metadata:
labels:
app: eshop
component: basket
name: basket
spec:
ports:
- port: 80
selector:
app: eshop
component: basket
---
apiVersion: v1
kind: Service
metadata:
labels:
app: eshop
component: catalog
name: catalog
spec:
ports:
- port: 80
selector:
app: eshop
component: catalog
---
apiVersion: v1
kind: Service
metadata:
labels:
app: eshop
component: identity
name: identity
spec:
ports:
- port: 80
selector:
app: eshop
component: identity
---
apiVersion: v1
kind: Service
metadata:
labels:
app: eshop
component: ordering
name: ordering
spec:
ports:
- port: 80
selector:
app: eshop
component: ordering
---
apiVersion: v1
kind: Service
metadata:
labels:
app: eshop
component: webmvc
name: webmvc
spec:
ports:
- port: 80
selector:
app: eshop
component: webmvc
---
apiVersion: v1
kind: Service
metadata:
labels:
app: eshop
component: webstatus
name: webstatus
spec:
ports:
- port: 80
selector:
app: eshop
component: webstatus
---
apiVersion: v1
kind: Service
metadata:
labels:
app: eshop
component: webspa
name: webspa
spec:
ports:
- port: 80
selector:
app: eshop
component: webspa

+ 33
- 0
k8s/sql-data.yaml View File

@ -0,0 +1,33 @@
apiVersion: v1
kind: Service
metadata:
labels:
app: eshop
component: sql-data
name: sql-data
spec:
ports:
- port: 1433
selector:
app: eshop
component: sql-data
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: sql-data
spec:
template:
metadata:
labels:
app: eshop
component: sql-data
spec:
containers:
- name: sql-data
image: microsoft/mssql-server-linux:ctp1-3
env:
- name: ACCEPT_EULA
value: "Y"
- name: SA_PASSWORD
value: Pass@word

+ 1
- 2
src/BuildingBlocks/EventBus/EventBus/EventBus.csproj View File

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

+ 5
- 6
src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj View File

@ -2,16 +2,15 @@
<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="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>


+ 7
- 8
src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj View File

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


+ 2
- 2
src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/Microsoft.AspNetCore.HealthChecks.csproj View File

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

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

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


+ 1
- 1
src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.SqlServer/Microsoft.Extensions.HealthChecks.SqlServer.csproj View File

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


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

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


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

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

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

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


+ 2
- 2
src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Microsoft.Extensions.HealthChecks.csproj View File

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


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

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

+ 3
- 3
src/BuildingBlocks/Resilience/Resilience.Http/Resilience.Http.csproj View File

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

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

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

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

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

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

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

+ 6
- 6
src/Mobile/README.md View File

@ -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:
@ -155,4 +155,4 @@ In the configuration window of the machine, go to the Compatibility section and
<img src="Images/set-compatibility-vs-sml.png" alt="Migrate to a physical computer with a different processor version" Width="600" />
## Copyright and license
* Code and documentation copyright 2017 Microsoft Corp. Code released under the [MIT license](https://opensource.org/licenses/MIT).
* Code and documentation copyright 2017 Microsoft Corp. Code released under the [MIT license](https://opensource.org/licenses/MIT).

+ 4
- 3
src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Identity/IdentityService.cs View File

@ -14,8 +14,9 @@ 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_secret", "secret");
dic.Add("response_type", "code id_token token");
dic.Add("scope", "openid profile basket orders offline_access");
dic.Add("redirect_uri", GlobalSetting.Instance.IdentityCallback);
dic.Add("nonce", Guid.NewGuid().ToString("N"));
@ -24,7 +25,7 @@ namespace eShopOnContainers.Core.Services.Identity
var currentCSRFToken = Guid.NewGuid().ToString("N");
dic.Add("state", currentCSRFToken);
var authorizeUri = authorizeRequest.Create(dic);
var authorizeUri = authorizeRequest.Create(dic);
return authorizeUri;
}


+ 1
- 1
src/Mobile/eShopOnContainers/eShopOnContainers.Droid/Properties/AndroidManifest.xml View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto">
<uses-sdk android:minSdkVersion="15" />
<uses-sdk android:minSdkVersion="15" android:targetSdkVersion="23" />
<uses-permission android:name="android.permission.INTERNET" />
<application android:label="eShopOnContainers" android:icon="@drawable/icon" android:largeHeap="true"></application>
</manifest>

+ 6
- 6
src/Mobile/eShopOnContainers/eShopOnContainers.Droid/Renderers/CustomNavigationPageRenderer.cs View File

@ -12,17 +12,17 @@ namespace eShopOnContainers.Droid.Renderers
{
base.OnLayout(changed, l, t, r, b);
if (Element.CurrentPage == null)
{
return;
}
var toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
if (toolbar != null)
{
var image = toolbar.FindViewById<ImageView>(Resource.Id.toolbar_image);
if (Element.CurrentPage == null)
{
return;
}
if (!string.IsNullOrEmpty(Element.CurrentPage.Title))
image.Visibility = Android.Views.ViewStates.Invisible;
else
@ -30,4 +30,4 @@ namespace eShopOnContainers.Droid.Renderers
}
}
}
}
}

+ 2
- 1
src/Mobile/eShopOnContainers/eShopOnContainers.Droid/eShopOnContainers.Droid.csproj View File

@ -27,6 +27,7 @@
</NuGetPackageImportStamp>
<AndroidTlsProvider>
</AndroidTlsProvider>
<SkipValidatePackageReferences>true</SkipValidatePackageReferences>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>True</DebugSymbols>
@ -373,4 +374,4 @@
</Target>
<Import Project="..\..\..\..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
<Import Project="..\..\..\..\packages\Xamarin.Forms.2.3.4.231\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets" Condition="Exists('..\..\..\..\packages\Xamarin.Forms.2.3.4.231\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets')" />
</Project>
</Project>

+ 2
- 1
src/Mobile/eShopOnContainers/eShopOnContainers.Windows/eShopOnContainers.Windows.csproj View File

@ -18,6 +18,7 @@
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PackageCertificateKeyFile>Windows_TemporaryKey.pfx</PackageCertificateKeyFile>
<SkipValidatePackageReferences>true</SkipValidatePackageReferences>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<DebugSymbols>true</DebugSymbols>
@ -183,4 +184,4 @@
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
</Project>
</Project>

+ 1
- 0
src/Mobile/eShopOnContainers/eShopOnContainers.iOS/eShopOnContainers.iOS.csproj View File

@ -13,6 +13,7 @@
<AssemblyName>eShopOnContainersiOS</AssemblyName>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<SkipValidatePackageReferences>true</SkipValidatePackageReferences>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhoneSimulator' ">
<DebugSymbols>true</DebugSymbols>


+ 2
- 4
src/Services/Basket/Basket.API/Auth/Server/AuthorizationHeaderParameterOperationFilter.cs View File

@ -1,10 +1,8 @@
using Microsoft.AspNetCore.Mvc.Authorization;
using Swashbuckle.Swagger.Model;
using Swashbuckle.SwaggerGen.Generator;
using System;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Services.Basket.API.Auth.Server
{


+ 1
- 4
src/Services/Basket/Basket.API/Auth/Server/IdentitySecurityScheme.cs View File

@ -1,8 +1,5 @@
using Swashbuckle.Swagger.Model;
using System;
using Swashbuckle.AspNetCore.Swagger;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Services.Basket.API.Auth.Server
{


+ 15
- 19
src/Services/Basket/Basket.API/Basket.API.csproj View File

@ -2,12 +2,8 @@
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
<DebugType>portable</DebugType>
<PreserveCompilationContext>true</PreserveCompilationContext>
<AssemblyName>Basket.API</AssemblyName>
<RuntimeFrameworkVersion>1.1.2</RuntimeFrameworkVersion>
<OutputType>Exe</OutputType>
<PackageId>Basket.API</PackageId>
<RuntimeFrameworkVersion>1.1.0</RuntimeFrameworkVersion>
<PackageTargetFallback>$(PackageTargetFallback);netstandard1.6.1;dnxcore50;portable-net451+win8</PackageTargetFallback>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
@ -22,21 +18,21 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" />
<PackageReference Include="System.Threading" Version="4.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="1.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.1.1" />
<PackageReference Include="StackExchange.Redis" Version="1.1.608" />
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="1.0.1-rc3" />
<PackageReference Include="Swashbuckle" Version="6.0.0-beta902" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.1.2" />
<PackageReference Include="StackExchange.Redis" Version="1.2.3" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="1.2.0" />
</ItemGroup>
<ItemGroup>


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

@ -8,10 +8,6 @@ using Microsoft.AspNetCore.Authorization;
namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
{
//TODO NOTE: Right now this is a very chunky API, as the app evolves it is possible we would
//want to make the actions more fine grained, add basket item as an action for example.
//If this is the case we should also investigate changing the serialization format used for Redis,
//using a HashSet instead of a simple string.
[Route("/")]
[Authorize]
public class BasketController : Controller
@ -22,7 +18,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
{
_repository = repository;
}
// GET api/values/5
// GET /id
[HttpGet("{id}")]
public async Task<IActionResult> Get(string id)
{
@ -31,7 +27,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
return Ok(basket);
}
// POST api/values
// POST /value
[HttpPost]
public async Task<IActionResult> Post([FromBody]CustomerBasket value)
{
@ -40,7 +36,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
return Ok(basket);
}
// DELETE api/values/5
// DELETE /id
[HttpDelete("{id}")]
public void Delete(string id)
{


+ 2
- 8
src/Services/Basket/Basket.API/Controllers/HomeController.cs View File

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
// For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
using Microsoft.AspNetCore.Mvc;
namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
{
@ -13,7 +7,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
// GET: /<controller>/
public IActionResult Index()
{
return new RedirectResult("~/swagger/ui");
return new RedirectResult("~/swagger");
}
}
}

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

@ -1,4 +1,4 @@
FROM microsoft/aspnetcore:1.1
FROM microsoft/aspnetcore:1.1.2
ARG source
WORKDIR /app
EXPOSE 80


+ 1
- 4
src/Services/Basket/Basket.API/Model/Basket.cs View File

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
{


+ 1
- 6
src/Services/Basket/Basket.API/Model/BasketItem.cs View File

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
{
public class BasketItem
{


+ 0
- 1
src/Services/Basket/Basket.API/Model/RedisBasketRepository.cs View File

@ -111,4 +111,3 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
}
}

+ 2
- 2
src/Services/Basket/Basket.API/Properties/launchSettings.json View File

@ -11,7 +11,7 @@
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "api/values",
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
@ -19,7 +19,7 @@
"Microsoft.eShopOnContainers.Services.Basket.API": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "http://localhost:5000/api/values",
"launchUrl": "http://localhost:5000/swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}


+ 7
- 8
src/Services/Basket/Basket.API/Startup.cs View File

@ -82,13 +82,10 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
return new DefaultRabbitMQPersistentConnection(factory, logger);
});
services.AddSwaggerGen();
services.ConfigureSwaggerGen(options =>
services.AddSwaggerGen(options =>
{
options.OperationFilter<AuthorizationHeaderParameterOperationFilter>();
options.DescribeAllEnumsAsStrings();
options.SingleApiVersion(new Swashbuckle.Swagger.Model.Info()
options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info
{
Title = "Basket HTTP API",
Version = "v1",
@ -97,7 +94,6 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
});
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
@ -137,7 +133,10 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
app.UseMvcWithDefaultRoute();
app.UseSwagger()
.UseSwaggerUi();
.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
ConfigureEventBus(app);
@ -149,7 +148,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
Authority = identityUrl.ToString(),
ScopeName = "basket",
ApiName = "basket",
RequireHttpsMetadata = false
});
}


+ 22
- 25
src/Services/Catalog/Catalog.API/Catalog.API.csproj View File

@ -2,13 +2,9 @@
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
<DebugType>portable</DebugType>
<PreserveCompilationContext>true</PreserveCompilationContext>
<AssemblyName>Catalog.API</AssemblyName>
<RuntimeFrameworkVersion>1.1.2</RuntimeFrameworkVersion>
<OutputType>Exe</OutputType>
<PackageId>Catalog.API</PackageId>
<UserSecretsId>aspnet-Catalog.API-20161122013618</UserSecretsId>
<RuntimeFrameworkVersion>1.1.0</RuntimeFrameworkVersion>
<PackageTargetFallback>$(PackageTargetFallback);dotnet5.6;portable-net45+win8</PackageTargetFallback>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
@ -29,26 +25,27 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="1.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.Abstractions" Version="1.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="1.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" 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.Design" Version="1.1.1" />
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
<PackageReference Include="Swashbuckle" Version="6.0.0-beta902" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.Abstractions" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore" 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.Design" Version="1.1.2" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" />
<PackageReference Include="Polly" Version="5.1.0" />
</ItemGroup>
<ItemGroup>


+ 1
- 1
src/Services/Catalog/Catalog.API/Controllers/HomeController.cs View File

@ -9,7 +9,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
// GET: /<controller>/
public IActionResult Index()
{
return new RedirectResult("~/swagger/ui");
return new RedirectResult("~/swagger");
}
}
}

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

@ -1,4 +1,4 @@
FROM microsoft/aspnetcore:1.1
FROM microsoft/aspnetcore:1.1.2
ARG source
WORKDIR /app
EXPOSE 80


+ 1
- 1
src/Services/Catalog/Catalog.API/Properties/launchSettings.json View File

@ -11,7 +11,7 @@
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "/swagger/ui",
"launchUrl": "/swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}


+ 35
- 30
src/Services/Catalog/Catalog.API/Startup.cs View File

@ -17,11 +17,13 @@
using Microsoft.Extensions.HealthChecks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Polly;
using RabbitMQ.Client;
using System;
using System.Data.Common;
using System.Data.SqlClient;
using System.Reflection;
using System.Threading.Tasks;
public class Startup
{
@ -50,7 +52,12 @@
services.AddHealthChecks(checks =>
{
checks.AddSqlCheck("CatalogDb", Configuration["ConnectionString"]);
var minutes = 1;
if (int.TryParse(Configuration["HealthCheck:Timeout"], out var minutesParsed))
{
minutes = minutesParsed;
}
checks.AddSqlCheck("CatalogDb", Configuration["ConnectionString"], TimeSpan.FromMinutes(minutes));
});
services.AddMvc(options =>
@ -77,11 +84,10 @@
services.Configure<CatalogSettings>(Configuration);
// Add framework services.
services.AddSwaggerGen();
services.ConfigureSwaggerGen(options =>
services.AddSwaggerGen(options =>
{
options.DescribeAllEnumsAsStrings();
options.SingleApiVersion(new Swashbuckle.Swagger.Model.Info()
options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info
{
Title = "eShopOnContainers - Catalog HTTP API",
Version = "v1",
@ -132,16 +138,15 @@
app.UseMvcWithDefaultRoute();
app.UseSwagger()
.UseSwaggerUi();
.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
var context = (CatalogContext)app
.ApplicationServices.GetService(typeof(CatalogContext));
WaitForSqlAvailability(context, loggerFactory);
//Seed Data
CatalogContextSeed.SeedAsync(app, loggerFactory)
.Wait();
WaitForSqlAvailabilityAsync(context, loggerFactory, app).Wait();
var integrationEventLogContext = new IntegrationEventLogContext(
new DbContextOptionsBuilder<IntegrationEventLogContext>()
@ -151,28 +156,28 @@
integrationEventLogContext.Database.Migrate();
}
private void WaitForSqlAvailability(CatalogContext ctx, ILoggerFactory loggerFactory, int? retry = 0)
private async Task WaitForSqlAvailabilityAsync(CatalogContext ctx, ILoggerFactory loggerFactory, IApplicationBuilder app, int retries = 0)
{
int retryForAvailability = retry.Value;
try
{
ctx.Database.OpenConnection();
}
catch (SqlException ex)
{
if (retryForAvailability < 10)
{
retryForAvailability++;
var log = loggerFactory.CreateLogger(nameof(Startup));
log.LogError(ex.Message);
WaitForSqlAvailability(ctx, loggerFactory, retryForAvailability);
}
}
finally
var logger = loggerFactory.CreateLogger(nameof(Startup));
var policy = CreatePolicy(retries, logger, nameof (WaitForSqlAvailabilityAsync));
await policy.ExecuteAsync(async () =>
{
ctx.Database.CloseConnection();
}
await CatalogContextSeed.SeedAsync(app, loggerFactory);
});
}
private Policy CreatePolicy(int retries, ILogger logger, string prefix)
{
return Policy.Handle<SqlException>().
WaitAndRetryAsync(
retryCount: retries,
sleepDurationProvider: retry => TimeSpan.FromSeconds(5),
onRetry: (exception, timeSpan, retry, ctx) =>
{
logger.LogTrace($"[{prefix}] Exception {exception.GetType().Name} with message ${exception.Message} detected on attempt {retry} of {retries}");
}
);
}
}
}

+ 19
- 17
src/Services/Identity/Identity.API/Configuration/Config.cs View File

@ -1,7 +1,6 @@
using IdentityServer4.Models;
using Microsoft.Extensions.Options;
using IdentityServer4;
using IdentityServer4.Models;
using System.Collections.Generic;
using IdentityServer4;
namespace Identity.API.Configuration
{
@ -56,19 +55,26 @@ namespace Identity.API.Configuration
{
ClientId = "xamarin",
ClientName = "eShop Xamarin OpenId Client",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = { clientsUrl["Xamarin"] },
AllowedGrantTypes = GrantTypes.Hybrid,
//Used to retrieve the access token on the back channel.
ClientSecrets =
{
new Secret("secret".Sha256())
},
RedirectUris = { clientsUrl["Xamarin"] },
RequireConsent = false,
PostLogoutRedirectUris = { "http://13.88.8.119:5105/Account/Redirecting", "http://10.6.1.234:5105/Account/Redirecting" },
AllowedCorsOrigins = { "http://eshopxamarin" },
AllowedScopes =
PostLogoutRedirectUris = { $"{clientsUrl["Xamarin"]}/Account/Redirecting" },
AllowedCorsOrigins = { "http://eshopxamarin" },
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.OfflineAccess,
"orders",
"basket"
}
},
//Allow requesting refresh tokens for long lived API access
AllowOfflineAccess = true
},
new Client
{
@ -84,15 +90,11 @@ namespace Identity.API.Configuration
AllowOfflineAccess = true,
RedirectUris = new List<string>
{
$"{clientsUrl["Mvc"]}/signin-oidc",
"http://104.40.62.65:5100/signin-oidc",
"http://localhost:5100/signin-oidc",
"http://13.88.8.119:5100/signin-oidc"
$"{clientsUrl["Mvc"]}/signin-oidc"
},
PostLogoutRedirectUris = new List<string>
{
$"{clientsUrl["Mvc"]}/signout-callback-oidc",
"http://localhost:5100/signout-callback-oidc"
$"{clientsUrl["Mvc"]}/signout-callback-oidc"
},
AllowedScopes = new List<string>
{
@ -100,7 +102,7 @@ namespace Identity.API.Configuration
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.OfflineAccess,
"orders",
"basket",
"basket"
},
}
};


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

@ -1,4 +1,4 @@
FROM microsoft/aspnetcore:1.1
FROM microsoft/aspnetcore:1.1.2
ARG source
WORKDIR /app
EXPOSE 80


+ 23
- 27
src/Services/Identity/Identity.API/Identity.API.csproj View File

@ -2,47 +2,43 @@
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
<DebugType>portable</DebugType>
<PreserveCompilationContext>true</PreserveCompilationContext>
<AssemblyName>Identity.API</AssemblyName>
<RuntimeFrameworkVersion>1.1.2</RuntimeFrameworkVersion>
<OutputType>Exe</OutputType>
<PackageId>Identity.API</PackageId>
<UserSecretsId>aspnet-eShopOnContainers.Identity-90487118-103c-4ff0-b9da-e5e26f7ab0c5</UserSecretsId>
<RuntimeFrameworkVersion>1.1.0</RuntimeFrameworkVersion>
<PackageTargetFallback>$(PackageTargetFallback);dotnet5.6;portable-net45+win8</PackageTargetFallback>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Routing" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.Design" Version="1.1.0">
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Routing" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.Design" Version="1.1.2">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="1.0.0-msbuild3-final">
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="1.1.1">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.1.2" />
<PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink.Loader" Version="14.1.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="1.1.0-msbuild3-final">
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="1.1.1">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="1.0.0" />
<PackageReference Include="IdentityServer4.EntityFramework" Version="1.0.0" />
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="1.0.1" />
<PackageReference Include="IdentityServer4.EntityFramework" Version="1.0.1" />
</ItemGroup>
<Target Name="PrepublishScript" BeforeTargets="PrepareForPublish">


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

@ -74,7 +74,7 @@ namespace Identity.API.Services
if (!string.IsNullOrWhiteSpace(user.Name))
claims.Add(new Claim("name", user.Name));
if (!string.IsNullOrWhiteSpace(user.Name))
if (!string.IsNullOrWhiteSpace(user.LastName))
claims.Add(new Claim("last_name", user.LastName));
if (!string.IsNullOrWhiteSpace(user.CardNumber))


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

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


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

@ -17,7 +17,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
[DataContract]
public class CreateOrderCommand
:IAsyncRequest<bool>
: IRequest<bool>
{
[DataMember]
private readonly List<OrderItemDTO> _orderItems;


+ 2
- 5
src/Services/Ordering/Ordering.API/Application/Commands/IdentifiedCommand.cs View File

@ -1,13 +1,10 @@
using MediatR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
{
public class IdentifiedCommand<T, R> : IAsyncRequest<R>
where T : IAsyncRequest<R>
public class IdentifiedCommand<T, R> : IRequest<R>
where T : IRequest<R>
{
public T Command { get; }
public Guid Id { get; }


+ 2
- 2
src/Services/Ordering/Ordering.API/Application/Commands/IdentifierCommandHandler.cs View File

@ -11,7 +11,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
/// <typeparam name="T">Type of the command handler that performs the operation if request is not duplicated</typeparam>
/// <typeparam name="R">Return value of the inner command handler</typeparam>
public class IdentifierCommandHandler<T, R> : IAsyncRequestHandler<IdentifiedCommand<T, R>, R>
where T : IAsyncRequest<R>
where T : IRequest<R>
{
private readonly IMediator _mediator;
private readonly IRequestManager _requestManager;
@ -48,7 +48,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
{
await _requestManager.CreateRequestForCommandAsync<T>(message.Id);
var result = await _mediator.SendAsync(message.Command);
var result = await _mediator.Send(message.Command);
return result;
}


+ 1
- 1
src/Services/Ordering/Ordering.API/Application/Decorators/LogDecorator.cs View File

@ -6,7 +6,7 @@
public class LogDecorator<TRequest, TResponse>
: IAsyncRequestHandler<TRequest, TResponse>
where TRequest : IAsyncRequest<TResponse>
where TRequest : IRequest<TResponse>
{
private readonly IAsyncRequestHandler<TRequest, TResponse> _inner;
private readonly ILogger<LogDecorator<TRequest, TResponse>> _logger;


+ 1
- 1
src/Services/Ordering/Ordering.API/Application/Decorators/ValidatorDecorator.cs View File

@ -10,7 +10,7 @@ namespace Ordering.API.Application.Decorators
{
public class ValidatorDecorator<TRequest, TResponse>
: IAsyncRequestHandler<TRequest, TResponse>
where TRequest : IAsyncRequest<TResponse>
where TRequest : IRequest<TResponse>
{
private readonly IAsyncRequestHandler<TRequest, TResponse> _inner;
private readonly IValidator<TRequest>[] _validators;


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

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

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

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


+ 2
- 8
src/Services/Ordering/Ordering.API/Controllers/HomeController.cs View File

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
// For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
using Microsoft.AspNetCore.Mvc;
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
{
@ -13,7 +7,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
// GET: /<controller>/
public IActionResult Index()
{
return new RedirectResult("~/swagger/ui");
return new RedirectResult("~/swagger");
}
}
}

+ 7
- 10
src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs View File

@ -30,25 +30,21 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
[HttpPost]
public async Task<IActionResult> CreateOrder([FromBody]CreateOrderCommand command, [FromHeader(Name = "x-requestid")] string requestId)
{
bool result = false;
bool commandResult = false;
if (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty)
{
var requestCreateOrder = new IdentifiedCommand<CreateOrderCommand, bool>(command, guid);
result = await _mediator.SendAsync(requestCreateOrder);
commandResult = await _mediator.Send(requestCreateOrder);
}
else
{
// If no x-requestid header is found we process the order anyway. This is just temporary to not break existing clients
// that aren't still updated. When all clients were updated this could be removed.
result = await _mediator.SendAsync(command);
commandResult = await _mediator.Send(command);
}
if (result)
{
return Ok();
}
return commandResult ? (IActionResult)Ok() : (IActionResult)BadRequest();
return BadRequest();
}
[Route("{orderId:int}")]
@ -72,8 +68,9 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
[HttpGet]
public async Task<IActionResult> GetOrders()
{
var orders = await _orderQueries
.GetOrdersAsync();
var orderTask = _orderQueries.GetOrdersAsync();
var orders = await orderTask;
return Ok(orders);
}


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

@ -1,4 +1,4 @@
FROM microsoft/aspnetcore:1.1
FROM microsoft/aspnetcore:1.1.2
ARG source
WORKDIR /app
EXPOSE 80


+ 2
- 2
src/Services/Ordering/Ordering.API/Infrastructure/Auth/AuthorizationHeaderParameterOperationFilter.cs View File

@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Mvc.Authorization;
using Swashbuckle.Swagger.Model;
using Swashbuckle.SwaggerGen.Generator;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Collections.Generic;
using System.Linq;


+ 2
- 3
src/Services/Ordering/Ordering.API/Infrastructure/AutofacModules/MediatorModule.cs View File

@ -44,9 +44,8 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Autof
builder.Register<SingleInstanceFactory>(context =>
{
var componentContext = context.Resolve<IComponentContext>();
return t => componentContext.Resolve(t);
});
return t => { object o; return componentContext.TryResolve(t, out o) ? o : null; };
});
builder.Register<MultiInstanceFactory>(context =>
{


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

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

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

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

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

Loading…
Cancel
Save