diff --git a/.gitignore b/.gitignore index 3e5b59d26..5a5ff6dc0 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,7 @@ bld/ # Visual Studio 2015 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ +**/wwwroot/lib/ **/wwwroot/lib/ @@ -260,3 +260,4 @@ pub/ #Ignore marker-file used to know which docker files we have. .eshopdocker_* + diff --git a/README.md b/README.md index 62f74759a..ad3de086b 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,15 @@ Sample .NET Core reference application, powered by Microsoft, based on a simplif **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.

-The plan is to add asynchronous communication for data updates propagation across multiple services based on integration events and an event bus plus other features defined at the roadmap. +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 roadmap.

+The microservices are different in type, meaning different internal architecture patterns approaches depending on it purpose, as shown in the image below. +

+ +

Additional miroservice styles with other frameworks and No-SQL databases will be added, eventually. This is a great opportunity for pull requests from the community, like a new microservice using Nancy, or even other languages like Node, Go, Python or data containers with MongoDB with Azure DocDB compatibility, PostgreSQL, RavenDB, Event Store, MySql, etc. You name it! :) @@ -88,7 +92,7 @@ The app was also partially tested on "Docker for Mac" using a development MacOS ## 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 +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): diff --git a/cli-linux/build-bits-linux.sh b/cli-linux/build-bits-linux.sh index 27f120214..e99df361b 100644 --- a/cli-linux/build-bits-linux.sh +++ b/cli-linux/build-bits-linux.sh @@ -6,6 +6,7 @@ projectList=( "/src/Services/Identity/Identity.API" "/src/Web/WebMVC" "/src/Web/WebSPA" + "/src/Web/WebStatus ) # Build SPA app @@ -36,4 +37,4 @@ done #fi # No need to build the images, docker build or docker compose will -# do that using the images and containers defined in the docker-compose.yml file. \ No newline at end of file +# do that using the images and containers defined in the docker-compose.yml file. diff --git a/cli-mac/build-bits.sh b/cli-mac/build-bits.sh index caf246e95..f8ad2e2f9 100644 --- a/cli-mac/build-bits.sh +++ b/cli-mac/build-bits.sh @@ -7,6 +7,7 @@ projectList=( "../src/Services/Identity/Identity.API" "../src/Web/WebMVC" "../src/Web/WebSPA" + "../src/Web/WebStatus" ) for project in "${projectList[@]}" diff --git a/cli-windows/build-bits-expanded.ps1 b/cli-windows/build-bits-expanded.ps1 deleted file mode 100644 index 155739d7d..000000000 --- a/cli-windows/build-bits-expanded.ps1 +++ /dev/null @@ -1,160 +0,0 @@ - -######################################################################################################### -# This "expanded Script" can be used when debugging issues when building the .NET Core bits -# as it is easier to follow and debug than when using a loop (like in the optimized build-bits.ps1) -######################################################################################################### - -Param([string] $rootPath) -$scriptPath = Split-Path $script:MyInvocation.MyCommand.Path - -Write-Host "Current script directory is $scriptPath" -ForegroundColor Yellow - -if ([string]::IsNullOrEmpty($rootPath)) { - $rootPath = "$scriptPath\.." -} -Write-Host "Root path used is $rootPath" -ForegroundColor Yellow - -# *** WebMVC paths *** -$webMVCPath = $rootPath + "\src\Web\WebMVC" -$webMVCPathToProject = $webMVCPath + "\WebMVC.csproj" -Write-Host "webMVCPathToProject is $webMVCPathToProject" -ForegroundColor Yellow -$webMVCPathToPub = $webMVCPath + "\obj\Docker\publish" -Write-Host "webMVCPathToPub is $webMVCPathToPub" -ForegroundColor Yellow - - -# *** WebSPA paths *** -$webSPAPath = $rootPath + "\src\Web\WebSPA" -$webSPAPathToProject = $webSPAPath + "\WebSPA.csproj" -Write-Host "webSPAPathToProject is $webSPAPathToProject" -ForegroundColor Yellow -$webSPAPathToPub = $webSPAPath + "\obj\Docker\publish" -Write-Host "webSPAPathToPub is $webSPAPathToPub" -ForegroundColor Yellow - - -# *** IdentitySvc paths *** -$identitySvcPath = $rootPath + "\src\Services\Identity\Identity.API" -$identitySvcToProject = $identitySvcPath + "\Identity.API.csproj" -Write-Host "identitySvcToProject is $identitySvcToProject" -ForegroundColor Yellow -$identitySvcPathToPub = $identitySvcPath + "\obj\Docker\publish" -Write-Host "identitySvcPathToPub is $identitySvcPathToPub" -ForegroundColor Yellow - - -# *** Catalog paths *** -$catalogPath = $rootPath + "\src\Services\Catalog\Catalog.API" -$catalogPathToProject = $catalogPath + "\Catalog.API.csproj" -Write-Host "catalogPathToProject is $catalogPathToProject" -ForegroundColor Yellow -$catalogPathToPub = $catalogPath + "\obj\Docker\publish" -Write-Host "catalogPathToPub is $catalogPathToPub" -ForegroundColor Yellow - - -# *** Ordering paths *** -$orderingPath = $rootPath + "\src\Services\Ordering\Ordering.API" -$orderingPathToProject = $orderingPath + "\Ordering.API.csproj" -Write-Host "orderingPathToProject is $orderingPathToProject" -ForegroundColor Yellow -$orderingPathToPub = $orderingPath + "\obj\Docker\publish" -Write-Host "orderingPathToPub is $orderingPathToPub" -ForegroundColor Yellow - -# *** Basket paths *** -$basketPath = $rootPath + "\src\Services\Basket\Basket.API" -$basketPathToProject = $basketPath + "\Basket.API.csproj" -Write-Host "basketPathToProject is $basketPathToProject" -ForegroundColor Yellow -$basketPathToPub = $basketPath + "\obj\Docker\publish" -Write-Host "basketPathToPub is $basketPathToPub" -ForegroundColor Yellow - - -######################################################################################## -# Delete old eShop dotnet publish bits -######################################################################################## -# Write-Host "Deleting previous dotnet publish bits from all projects" -ForegroundColor Blue - -remove-item -path $WebMVCPathToPub -Force -Recurse -ErrorAction SilentlyContinue -remove-item -path $webSPAPathToPub -Force -Recurse -ErrorAction SilentlyContinue -remove-item -path $identitySvcPathToPub -Force -Recurse -ErrorAction SilentlyContinue -remove-item -path $catalogPathToPub -Force -Recurse -ErrorAction SilentlyContinue -remove-item -path $orderingPathToPub -Force -Recurse -ErrorAction SilentlyContinue -remove-item -path $basketPathToPub -Force -Recurse -ErrorAction SilentlyContinue - - - -######################################################################################## -# Building DotNet bits -######################################################################################## - -# WebMVC: Build dotnet bits -Write-Host "WebMVC: Restore Dependencies, dotnet build and dotnet publish" -ForegroundColor Blue -dotnet restore $WebMVCPathToProject -dotnet build $WebMVCPathToProject -dotnet publish $WebMVCPathToProject -o $WebMVCPathToPub - - -# WebSPA: Build dotnet bits -Write-Host "WebSPA: Installing npm dependencies" -#TEMP COMMENT--- Start-Process -WorkingDirectory $webSPAPath -NoNewWindow -Wait npm i - -Write-Host "WebSPA: Restore Dependencies, dotnet build and dotnet publish" -ForegroundColor Blue -dotnet restore $webSPAPathToProject -dotnet build $webSPAPathToProject -dotnet publish $webSPAPathToProject -o $webSPAPathToPub - - -# Identity Service: Build dotnet bits -Write-Host "Identity Service: Restore Dependencies, dotnet build and dotnet publish" -ForegroundColor Blue -dotnet restore $identitySvcToProject -dotnet build $identitySvcToProject -dotnet publish $identitySvcToProject -o $identitySvcPathToPub - - -# Catalog Service: Build dotnet bits -Write-Host "Catalog Service: Restore Dependencies, dotnet build and dotnet publish" -ForegroundColor Blue -dotnet restore $catalogPathToProject -dotnet build $catalogPathToProject -dotnet publish $catalogPathToProject -o $catalogPathToPub - - -# Ordering Service: Build dotnet bits -Write-Host "Ordering Service: Restore Dependencies, dotnet build and dotnet publish" -ForegroundColor Blue -dotnet restore $orderingPathToProject -dotnet build $orderingPathToProject -dotnet publish $orderingPathToProject -o $orderingPathToPub - - -# Basket Service: Build dotnet bits -Write-Host "Basket Service: Restore Dependencies, dotnet build and dotnet publish" -ForegroundColor Blue -dotnet restore $basketPathToProject -dotnet build $basketPathToProject -dotnet publish $basketPathToProject -o $basketPathToPub - - - -######################################################################################## -# Delete old eShop Docker images -######################################################################################## - -$imagesToDelete = docker images --filter=reference="eshop/*" -q - -If (-Not $imagesToDelete) {Write-Host "Not deleting eShop images as there are no eShop images in the current local Docker repo."} -Else -{ - # Delete all containers - Write-Host "Deleting all containers in local Docker Host" - docker rm $(docker ps -a -q) -f - - # Delete all eshop images - Write-Host "Deleting eShop images in local Docker repo" - Write-Host $imagesToDelete - docker rmi $(docker images --filter=reference="eshop/*" -q) -f -} - - -######################################################################################## -# Build new eShop images -######################################################################################## - -# WE DON'T NEED DOCKER BUILD AS WE CAN RUN "DOCKER-COMPOSE BUILD" OR "DOCKER-COMPOSE UP" AND IT WILL BUILD ALL THE IMAGES IN THE .YML FOR US - -#*** build docker images *** -# docker build -t eshop/web $webPathToPub -# docker build -t eshop/catalog.api $catalogPathToPub -# docker build -t eshop/ordering.api $orderingApiPathToPub -# docker build -t eshop/basket.api $basketPathToPub -# docker build -t eshop/webspa $webSPAPathToPub -# docker build -t eshop/identity $identitySvcPathToPub \ No newline at end of file diff --git a/cli-windows/build-bits.ps1 b/cli-windows/build-bits.ps1 index 21a1b6e34..26651da5b 100644 --- a/cli-windows/build-bits.ps1 +++ b/cli-windows/build-bits.ps1 @@ -15,13 +15,14 @@ $projectPaths = @{Path="$rootPath\src\Services\Catalog\Catalog.API";Prj="Catalog.API.csproj"}, @{Path="$rootPath\src\Services\Ordering\Ordering.API";Prj="Ordering.API.csproj"}, @{Path="$rootPath\src\Services\Basket\Basket.API";Prj="Basket.API.csproj"} + @{Path="$rootPath\src\Web\WebStatus";Prj="WebStatus.csproj"} $projectPaths | foreach { $projectPath = $_.Path $projectFile = $_.Prj $outPath = $_.Path + "\obj\Docker\publish" $projectPathAndFile = "$projectPath\$projectFile" - Write-Host "Deleting $outPath" -ForegroundColor Yellow + Write-Host "Deleting old publish files in $outPath" -ForegroundColor Yellow remove-item -path $outPath -Force -Recurse -ErrorAction SilentlyContinue Write-Host "Publishing $projectPathAndFile to $outPath" -ForegroundColor Yellow dotnet restore $projectPathAndFile diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 68a5521e2..8b0b4602b 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -33,6 +33,7 @@ services: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:5105 - 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: @@ -86,7 +87,7 @@ services: - CatalogUrl=http://catalog.api:5101/hc - OrderingUrl=http://ordering.api:5102/hc - BasketUrl=http://basket.api:5103/hc - - IdentityUrl=http://10.0.75.1:5105/hc + - IdentityUrl=http://identity.api:5105/hc - mvc=http://webmvc:5100/hc - spa=http://webspa:5104/hc ports: diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 4d019d404..5a88f2c6c 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -40,6 +40,7 @@ services: - 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" diff --git a/eShopOnContainers-ServicesAndWebApps.sln b/eShopOnContainers-ServicesAndWebApps.sln index 88fc173e1..d4d39437c 100644 --- a/eShopOnContainers-ServicesAndWebApps.sln +++ b/eShopOnContainers-ServicesAndWebApps.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26228.0 +VisualStudioVersion = 15.0.26228.12 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{932D8224-11F6-4D07-B109-DA28AD288A63}" EndProject @@ -84,6 +84,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Health EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebStatus", "src\Web\WebStatus\WebStatus.csproj", "{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Resilience", "Resilience", "{FBF43D93-F2E7-4FF8-B4AB-186895949B88}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Resilience.Http", "src\BuildingBlocks\Resilience\Resilience.Http\Resilience.Http.csproj", "{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Ad-Hoc|Any CPU = Ad-Hoc|Any CPU @@ -914,6 +918,54 @@ Global {C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Release|x64.Build.0 = Release|Any CPU {C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Release|x86.ActiveCfg = Release|Any CPU {C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Release|x86.Build.0 = Release|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|ARM.Build.0 = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|iPhone.Build.0 = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|x64.ActiveCfg = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|x64.Build.0 = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|x86.ActiveCfg = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|x86.Build.0 = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|ARM.ActiveCfg = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|ARM.Build.0 = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|iPhone.Build.0 = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|x64.ActiveCfg = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|x64.Build.0 = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|x86.ActiveCfg = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|x86.Build.0 = Debug|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|Any CPU.Build.0 = Release|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|ARM.ActiveCfg = Release|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|ARM.Build.0 = Release|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|iPhone.ActiveCfg = Release|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|iPhone.Build.0 = Release|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x64.ActiveCfg = Release|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x64.Build.0 = Release|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x86.ActiveCfg = Release|Any CPU + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -947,5 +999,7 @@ Global {942ED6E8-0050-495F-A0EA-01E97F63760C} = {A81ECBC2-6B00-4DCD-8388-469174033379} {7804FC60-23E6-490C-8E08-F9FEF829F184} = {A81ECBC2-6B00-4DCD-8388-469174033379} {C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04} + {FBF43D93-F2E7-4FF8-B4AB-186895949B88} = {DB0EFB20-B024-4E5E-A75C-52143C131D25} + {D1C47FF1-91F1-4CAF-9ABB-AD642B821502} = {FBF43D93-F2E7-4FF8-B4AB-186895949B88} EndGlobalSection EndGlobal diff --git a/img/eShopOnContainers_Architecture_Diagram.png b/img/eShopOnContainers_Architecture_Diagram.png index 5a45657dc..ca9e986b5 100644 Binary files a/img/eShopOnContainers_Architecture_Diagram.png and b/img/eShopOnContainers_Architecture_Diagram.png differ diff --git a/img/eShopOnContainers_Architecture_Diagram_old.png b/img/eShopOnContainers_Architecture_Diagram_old.png new file mode 100644 index 000000000..5a45657dc Binary files /dev/null and b/img/eShopOnContainers_Architecture_Diagram_old.png differ diff --git a/img/eShopOnContainers_Types_Of_Microservices.png b/img/eShopOnContainers_Types_Of_Microservices.png new file mode 100644 index 000000000..e0621d8a4 Binary files /dev/null and b/img/eShopOnContainers_Types_Of_Microservices.png differ diff --git a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Utilities/ResilientTransaction.cs b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Utilities/ResilientTransaction.cs new file mode 100644 index 000000000..f8227882b --- /dev/null +++ b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Utilities/ResilientTransaction.cs @@ -0,0 +1,37 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; +using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services; +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Utilities +{ + public class ResilientTransaction + { + private DbContext _context; + private ResilientTransaction(DbContext context) => + _context = context ?? throw new ArgumentNullException(nameof(context)); + + public static ResilientTransaction New (DbContext context) => + new ResilientTransaction(context); + + public async Task ExecuteAsync(Func action) + { + //Use of an EF Core resiliency strategy when using multiple DbContexts within an explicit BeginTransaction(): + //See: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency + var strategy = _context.Database.CreateExecutionStrategy(); + await strategy.ExecuteAsync(async () => + { + using (var transaction = _context.Database.BeginTransaction()) + { + await action(); + transaction.Commit(); + } + }); + } + } +} diff --git a/src/Web/WebMVC/Services/Utilities/IHttpClient.cs b/src/BuildingBlocks/Resilience/Resilience.Http/IHttpClient.cs similarity index 84% rename from src/Web/WebMVC/Services/Utilities/IHttpClient.cs rename to src/BuildingBlocks/Resilience/Resilience.Http/IHttpClient.cs index 2a36466bc..0e56a66da 100644 --- a/src/Web/WebMVC/Services/Utilities/IHttpClient.cs +++ b/src/BuildingBlocks/Resilience/Resilience.Http/IHttpClient.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Net.Http; using System.Threading.Tasks; -namespace WebMVC.Services.Utilities +namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http { public interface IHttpClient { diff --git a/src/BuildingBlocks/Resilience/Resilience.Http/Resilience.Http.csproj b/src/BuildingBlocks/Resilience/Resilience.Http/Resilience.Http.csproj new file mode 100644 index 000000000..8f60105fc --- /dev/null +++ b/src/BuildingBlocks/Resilience/Resilience.Http/Resilience.Http.csproj @@ -0,0 +1,14 @@ + + + + netstandard1.4 + Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http + + + + + + + + + \ No newline at end of file diff --git a/src/BuildingBlocks/Resilience/Resilience.Http/ResiliencePolicy.cs b/src/BuildingBlocks/Resilience/Resilience.Http/ResiliencePolicy.cs new file mode 100644 index 000000000..63eadc857 --- /dev/null +++ b/src/BuildingBlocks/Resilience/Resilience.Http/ResiliencePolicy.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http +{ + public class ResiliencePolicy + { + } +} diff --git a/src/Web/WebMVC/Services/Utilities/ResilientHttpClient.cs b/src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs similarity index 52% rename from src/Web/WebMVC/Services/Utilities/ResilientHttpClient.cs rename to src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs index 2e9efe9a6..2ccc84aaa 100644 --- a/src/Web/WebMVC/Services/Utilities/ResilientHttpClient.cs +++ b/src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs @@ -1,14 +1,14 @@ -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Polly; using Polly.Wrap; using System; +using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Threading.Tasks; -namespace WebMVC.Services.Utilities +namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http { ///

/// HttpClient wrapper that integrates Retry and Circuit @@ -21,55 +21,15 @@ namespace WebMVC.Services.Utilities private PolicyWrap _policyWrapper; private ILogger _logger; public HttpClient Inst => _client; - public ResilientHttpClient(ILogger logger) + + public ResilientHttpClient(Policy[] policies, ILogger logger) { _client = new HttpClient(); _logger = logger; // Add Policies to be applied - _policyWrapper = Policy.WrapAsync( - CreateRetryPolicy(), - CreateCircuitBreakerPolicy() - ); - } - - private Policy CreateRetryPolicy() => - Policy.Handle() - .WaitAndRetryAsync( - // number of retries - 6, - // exponential backofff - retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), - // on retry - (exception, timeSpan, retryCount, context) => - { - var msg = $"Retry {retryCount} implemented with Polly's RetryPolicy " + - $"of {context.PolicyKey} " + - $"at {context.ExecutionKey}, " + - $"due to: {exception}."; - _logger.LogWarning(msg); - _logger.LogDebug(msg); - } - ); - - private Policy CreateCircuitBreakerPolicy() => - Policy.Handle() - .CircuitBreakerAsync( - // number of exceptions before breaking circuit - 5, - // time circuit opened before retry - TimeSpan.FromMinutes(1), - (exception, duration) => - { - // on circuit opened - _logger.LogTrace("Circuit breaker opened"); - }, - () => - { - // on circuit closed - _logger.LogTrace("Circuit breaker reset"); - } - ); + _policyWrapper = Policy.WrapAsync(policies); + } public Task GetStringAsync(string uri) => HttpInvoker(() => diff --git a/src/Web/WebMVC/Services/Utilities/StandardHttpClient.cs b/src/BuildingBlocks/Resilience/Resilience.Http/StandardHttpClient.cs similarity index 93% rename from src/Web/WebMVC/Services/Utilities/StandardHttpClient.cs rename to src/BuildingBlocks/Resilience/Resilience.Http/StandardHttpClient.cs index b49240c40..4f400caf5 100644 --- a/src/Web/WebMVC/Services/Utilities/StandardHttpClient.cs +++ b/src/BuildingBlocks/Resilience/Resilience.Http/StandardHttpClient.cs @@ -4,7 +4,7 @@ using System; using System.Net.Http; using System.Threading.Tasks; -namespace WebMVC.Services.Utilities +namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http { public class StandardHttpClient : IHttpClient { diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/App.xaml b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/App.xaml index 2cc30f1d8..a04b35a17 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/App.xaml +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/App.xaml @@ -108,8 +108,9 @@ - - + + +