Added UI alert and circuit-breaker handlers for components that depend on Basket.api

This commit is contained in:
Ramón Tomás 2017-07-14 14:53:17 +02:00
parent f39fdb92ca
commit d42033a83b
11 changed files with 178 additions and 93 deletions

View File

@ -81,6 +81,14 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http
var response = await _client.SendAsync(requestMessage); 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 await response.Content.ReadAsStringAsync(); return await response.Content.ReadAsStringAsync();
}); });
} }

View File

@ -15,8 +15,6 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
.UseFailing(options => .UseFailing(options =>
{ {
options.ConfigPath = "/Failing"; options.ConfigPath = "/Failing";
options.EndpointPaths = new List<string>()
{ "/api/v1/basket/checkout", "/hc" };
}) })
.UseHealthChecks("/hc") .UseHealthChecks("/hc")
.UseContentRoot(Directory.GetCurrentDirectory()) .UseContentRoot(Directory.GetCurrentDirectory())

View File

@ -7,6 +7,7 @@ using Microsoft.eShopOnContainers.WebMVC.Services;
using Microsoft.eShopOnContainers.WebMVC.ViewModels; using Microsoft.eShopOnContainers.WebMVC.ViewModels;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Polly.CircuitBreaker;
namespace Microsoft.eShopOnContainers.WebMVC.Controllers namespace Microsoft.eShopOnContainers.WebMVC.Controllers
{ {
@ -25,17 +26,28 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
} }
public async Task<IActionResult> Index() public async Task<IActionResult> Index()
{
try
{ {
var user = _appUserParser.Parse(HttpContext.User); var user = _appUserParser.Parse(HttpContext.User);
var vm = await _basketSvc.GetBasket(user); var vm = await _basketSvc.GetBasket(user);
return View(vm); return View(vm);
} }
catch (BrokenCircuitException)
{
// Catch error when Basket.api is in circuit-opened mode
HandleBrokenCircuitException();
}
return View();
}
[HttpPost] [HttpPost]
public async Task<IActionResult> Index(Dictionary<string, int> quantities, string action) public async Task<IActionResult> Index(Dictionary<string, int> quantities, string action)
{
try
{ {
var user = _appUserParser.Parse(HttpContext.User); var user = _appUserParser.Parse(HttpContext.User);
var basket = await _basketSvc.SetQuantities(user, quantities); var basket = await _basketSvc.SetQuantities(user, quantities);
@ -46,11 +58,19 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
var order = _basketSvc.MapBasketToOrder(basket); var order = _basketSvc.MapBasketToOrder(basket);
return RedirectToAction("Create", "Order"); return RedirectToAction("Create", "Order");
} }
}
catch (BrokenCircuitException)
{
// Catch error when Basket.api is in circuit-opened mode
HandleBrokenCircuitException();
}
return View(vm); return View();
} }
public async Task<IActionResult> AddToCart(CatalogItem productDetails) public async Task<IActionResult> AddToCart(CatalogItem productDetails)
{
try
{ {
if (productDetails.Id != null) if (productDetails.Id != null)
{ {
@ -68,5 +88,18 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
} }
return RedirectToAction("Index", "Catalog"); return RedirectToAction("Index", "Catalog");
} }
catch (BrokenCircuitException)
{
// Catch error when Basket.api is in circuit-opened mode
HandleBrokenCircuitException();
}
return RedirectToAction("Index", "Catalog");
}
private void HandleBrokenCircuitException()
{
TempData["BasketInoperativeMsg"] = "Basket Service is inoperative, please try later on. (Business Msg Due to Circuit-Breaker)";
}
} }
} }

View File

@ -41,6 +41,7 @@ namespace Microsoft.eShopOnContainers.WebMVC
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddMvc(); services.AddMvc();
services.AddSession();
if (Configuration.GetValue<string>("IsClusterEnv") == bool.TrueString) if (Configuration.GetValue<string>("IsClusterEnv") == bool.TrueString)
{ {
@ -104,6 +105,7 @@ namespace Microsoft.eShopOnContainers.WebMVC
app.UseExceptionHandler("/Catalog/Error"); app.UseExceptionHandler("/Catalog/Error");
} }
app.UseSession();
app.UseStaticFiles(); app.UseStaticFiles();
app.UseCookieAuthentication(new CookieAuthenticationOptions app.UseCookieAuthentication(new CookieAuthenticationOptions

View File

@ -29,7 +29,6 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents
{ {
// Catch error when Basket.api is in circuit-opened mode // Catch error when Basket.api is in circuit-opened mode
ViewBag.IsBasketInoperative = true; ViewBag.IsBasketInoperative = true;
vm.ItemsCount = 0;
} }
return View(vm); return View(vm);

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Polly.CircuitBreaker;
namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents
{ {
@ -16,8 +17,19 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents
public async Task<IViewComponentResult> InvokeAsync(ApplicationUser user) public async Task<IViewComponentResult> InvokeAsync(ApplicationUser user)
{ {
var item = await GetItemsAsync(user); var vm = new Basket();
return View(item); try
{
vm = await GetItemsAsync(user);
return View(vm);
}
catch (BrokenCircuitException)
{
// Catch error when Basket.api is in circuit-opened mode
TempData["BasketInoperativeMsg"] = "Basket Service is inoperative, please try later on. (Business Msg Due to Circuit-Breaker)";
}
return View(vm);
} }
private Task<Basket> GetItemsAsync(ApplicationUser user) => _cartSvc.GetBasket(user); private Task<Basket> GetItemsAsync(ApplicationUser user) => _cartSvc.GetBasket(user);

View File

@ -23,6 +23,15 @@
</section> </section>
<div class="container"> <div class="container">
<div class="row">
<br />
@if(TempData.ContainsKey("BasketInoperativeMsg"))
{
<div class="alert alert-warning" role="alert">
&nbsp;@TempData["BasketInoperativeMsg"]
</div>
}
</div>
@if (Model.CatalogItems.Count() > 0) @if (Model.CatalogItems.Count() > 0)
{ {

View File

@ -8,17 +8,20 @@
asp-area="" asp-area=""
asp-controller="Cart" asp-controller="Cart"
asp-action="Index"> asp-action="Index">
<div class="esh-basketstatus-image">
<img src="~/images/cart.png" />
</div>
@if (ViewBag.IsBasketInoperative == true) @if (ViewBag.IsBasketInoperative == true)
{ {
<div class="esh-basketstatus-image">
<img src="~/images/cart-inoperative.png" />
</div>
<div class="esh-basketstatus-badge-inoperative"> <div class="esh-basketstatus-badge-inoperative">
@Model.ItemsCount X
</div> </div>
} }
else else
{ {
<div class="esh-basketstatus-image">
<img src="~/images/cart.png" />
</div>
<div class="esh-basketstatus-badge"> <div class="esh-basketstatus-badge">
@Model.ItemsCount @Model.ItemsCount
</div> </div>

View File

@ -5,7 +5,24 @@
} }
<div class="container"> <div class="container">
@if (TempData.ContainsKey("BasketInoperativeMsg"))
{
<br />
<div class="alert alert-warning" role="alert">
&nbsp;@TempData["BasketInoperativeMsg"]
</div>
}
else
{
<article class="esh-basket-titles row"> <article class="esh-basket-titles row">
<br />
@if (TempData.ContainsKey("BasketInoperativeMsg"))
{
<div class="alert alert-warning" role="alert">
&nbsp;@TempData["BasketInoperativeMsg"]
</div>
}
<section class="esh-basket-title col-xs-3">Product</section> <section class="esh-basket-title col-xs-3">Product</section>
<section class="esh-basket-title col-xs-3 hidden-lg-down"></section> <section class="esh-basket-title col-xs-3 hidden-lg-down"></section>
<section class="esh-basket-title col-xs-2">Price</section> <section class="esh-basket-title col-xs-2">Price</section>
@ -41,12 +58,10 @@
<div class="alert alert-warning esh-basket-margin12" role="alert">&nbsp;Note that the price of this article changed in our Catalog. The old price when you originally added it to the basket was $ @item.OldUnitPrice </div> <div class="alert alert-warning esh-basket-margin12" role="alert">&nbsp;Note that the price of this article changed in our Catalog. The old price when you originally added it to the basket was $ @item.OldUnitPrice </div>
} }
</div> </div>
<br/> <br />
} }
</div>
<div class="container"> <div class="container">
<article class="esh-basket-titles esh-basket-titles--clean row"> <article class="esh-basket-titles esh-basket-titles--clean row">
<section class="esh-basket-title col-xs-10"></section> <section class="esh-basket-title col-xs-10"></section>
<section class="esh-basket-title col-xs-2">Total</section> <section class="esh-basket-title col-xs-2">Total</section>
@ -68,4 +83,9 @@
value="[ Checkout ]" name="action" /> value="[ Checkout ]" name="action" />
</section> </section>
</article> </article>
</div>
}
</div> </div>

View File

@ -41,6 +41,7 @@
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.3" /> <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" 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.Server.Kestrel" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Session" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.2" /> <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.1.2" /> <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.Json" Version="1.1.2" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 948 B