Code Re-factorings and formatted in web Aggregator BFF projects

This commit is contained in:
Rafsanul Hasan 2018-09-09 04:41:45 +06:00
parent 0bc2a29b38
commit 80eb943d78
No known key found for this signature in database
GPG Key ID: FC57FD2D87BE60DD
26 changed files with 810 additions and 854 deletions

View File

@ -1,34 +1,33 @@
{ {
"ReRoutes": [ "ReRoutes": [
{ {
"DownstreamPathTemplate": "/api/{version}/{everything}", "DownstreamPathTemplate": "/api/{version}/{everything}",
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHostAndPorts": [ "DownstreamHostAndPorts": [
{ {
"Host": "marketing.api", "Host": "marketing.api",
"Port": 80 "Port": 80
} }
], ],
"UpstreamPathTemplate": "/api/{version}/m/{everything}", "UpstreamPathTemplate": "/api/{version}/m/{everything}",
"UpstreamHttpMethod": [] "UpstreamHttpMethod": []
}, },
{ {
"DownstreamPathTemplate": "/api/{version}/{everything}", "DownstreamPathTemplate": "/api/{version}/{everything}",
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHostAndPorts": [ "DownstreamHostAndPorts": [
{ {
"Host": "locations.api", "Host": "locations.api",
"Port": 80 "Port": 80
} }
], ],
"UpstreamPathTemplate": "/api/{version}/l/{everything}", "UpstreamPathTemplate": "/api/{version}/l/{everything}",
"UpstreamHttpMethod": [] "UpstreamHttpMethod": []
} }
], ],
"GlobalConfiguration": { "GlobalConfiguration": {
"RequestIdKey": "OcRequestId", "RequestIdKey": "OcRequestId",
"AdministrationPath": "/administration" "AdministrationPath": "/administration"
} }
} }

View File

@ -1,34 +1,33 @@
{ {
"ReRoutes": [ "ReRoutes": [
{ {
"DownstreamPathTemplate": "/api/{version}/{everything}", "DownstreamPathTemplate": "/api/{version}/{everything}",
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHostAndPorts": [ "DownstreamHostAndPorts": [
{ {
"Host": "marketing.api", "Host": "marketing.api",
"Port": 80 "Port": 80
} }
], ],
"UpstreamPathTemplate": "/api/{version}/m/{everything}", "UpstreamPathTemplate": "/api/{version}/m/{everything}",
"UpstreamHttpMethod": [] "UpstreamHttpMethod": []
}, },
{ {
"DownstreamPathTemplate": "/api/{version}/{everything}", "DownstreamPathTemplate": "/api/{version}/{everything}",
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHostAndPorts": [ "DownstreamHostAndPorts": [
{ {
"Host": "locations.api", "Host": "locations.api",
"Port": 80 "Port": 80
} }
], ],
"UpstreamPathTemplate": "/api/{version}/l/{everything}", "UpstreamPathTemplate": "/api/{version}/l/{everything}",
"UpstreamHttpMethod": [] "UpstreamHttpMethod": []
} }
], ],
"GlobalConfiguration": { "GlobalConfiguration": {
"RequestIdKey": "OcRequestId", "RequestIdKey": "OcRequestId",
"AdministrationPath": "/administration" "AdministrationPath": "/administration"
} }
} }

View File

@ -1,31 +1,28 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config
{ {
public class UrlsConfig public class UrlsConfig
{ {
public class CatalogOperations public class CatalogOperations
{ {
public static string GetItemById(int id) => $"/api/v1/catalog/items/{id}"; public static string GetItemById(int id) => $"/api/v1/catalog/items/{id}";
public static string GetItemsById(IEnumerable<int> ids) => $"/api/v1/catalog/items?ids={string.Join(',', ids)}"; public static string GetItemsById(IEnumerable<int> ids) => $"/api/v1/catalog/items?ids={string.Join(',', ids)}";
} }
public class BasketOperations public class BasketOperations
{ {
public static string GetItemById(string id) => $"/api/v1/basket/{id}"; public static string GetItemById(string id) => $"/api/v1/basket/{id}";
public static string UpdateBasket() => "/api/v1/basket"; public static string UpdateBasket() => "/api/v1/basket";
} }
public class OrdersOperations public class OrdersOperations
{ {
public static string GetOrderDraft() => "/api/v1/orders/draft"; public static string GetOrderDraft() => "/api/v1/orders/draft";
} }
public string Basket { get; set; } public string Basket { get; set; }
public string Catalog { get; set; } public string Catalog { get; set; }
public string Orders { get; set; } public string Orders { get; set; }
} }
} }

View File

@ -9,125 +9,125 @@ using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers
{ {
[Route("api/v1/[controller]")] [Route("api/v1/[controller]")]
[Authorize] [Authorize]
public class BasketController : Controller public class BasketController : Controller
{ {
private readonly ICatalogService _catalog; private readonly ICatalogService _catalog;
private readonly IBasketService _basket; private readonly IBasketService _basket;
public BasketController(ICatalogService catalogService, IBasketService basketService) public BasketController(ICatalogService catalogService, IBasketService basketService)
{ {
_catalog = catalogService; _catalog = catalogService;
_basket = basketService; _basket = basketService;
} }
[HttpPost] [HttpPost]
[HttpPut] [HttpPut]
public async Task<IActionResult> UpdateAllBasket([FromBody] UpdateBasketRequest data) public async Task<IActionResult> UpdateAllBasket([FromBody] UpdateBasketRequest data)
{ {
if (data.Items == null || !data.Items.Any()) if (data.Items == null || !data.Items.Any())
{ {
return BadRequest("Need to pass at least one basket line"); return BadRequest("Need to pass at least one basket line");
} }
// Retrieve the current basket // Retrieve the current basket
var currentBasket = await _basket.GetById(data.BuyerId); var currentBasket = await _basket.GetById(data.BuyerId);
if (currentBasket == null) if (currentBasket == null)
{ {
currentBasket = new BasketData(data.BuyerId); currentBasket = new BasketData(data.BuyerId);
} }
var catalogItems = await _catalog.GetCatalogItems(data.Items.Select(x => x.ProductId)); var catalogItems = await _catalog.GetCatalogItems(data.Items.Select(x => x.ProductId));
var newBasket = new BasketData(data.BuyerId); var newBasket = new BasketData(data.BuyerId);
foreach (var bitem in data.Items) foreach (var bitem in data.Items)
{ {
var catalogItem = catalogItems.SingleOrDefault(ci => ci.Id == bitem.ProductId); var catalogItem = catalogItems.SingleOrDefault(ci => ci.Id == bitem.ProductId);
if (catalogItem == null) if (catalogItem == null)
{ {
return BadRequest($"Basket refers to a non-existing catalog item ({bitem.ProductId})"); return BadRequest($"Basket refers to a non-existing catalog item ({bitem.ProductId})");
} }
newBasket.Items.Add(new BasketDataItem() newBasket.Items.Add(new BasketDataItem()
{ {
Id = bitem.Id, Id = bitem.Id,
ProductId = catalogItem.Id.ToString(), ProductId = catalogItem.Id.ToString(),
ProductName = catalogItem.Name, ProductName = catalogItem.Name,
PictureUrl = catalogItem.PictureUri, PictureUrl = catalogItem.PictureUri,
UnitPrice = catalogItem.Price, UnitPrice = catalogItem.Price,
Quantity = bitem.Quantity Quantity = bitem.Quantity
}); });
} }
await _basket.Update(newBasket); await _basket.Update(newBasket);
return Ok(newBasket); return Ok(newBasket);
} }
[HttpPut] [HttpPut]
[Route("items")] [Route("items")]
public async Task<IActionResult> UpdateQuantities([FromBody] UpdateBasketItemsRequest data) public async Task<IActionResult> UpdateQuantities([FromBody] UpdateBasketItemsRequest data)
{ {
if (!data.Updates.Any()) if (!data.Updates.Any())
{ {
return BadRequest("No updates sent"); return BadRequest("No updates sent");
} }
// Retrieve the current basket // Retrieve the current basket
var currentBasket = await _basket.GetById(data.BasketId); var currentBasket = await _basket.GetById(data.BasketId);
if (currentBasket == null) if (currentBasket == null)
{ {
return BadRequest($"Basket with id {data.BasketId} not found."); return BadRequest($"Basket with id {data.BasketId} not found.");
} }
// Update with new quantities // Update with new quantities
foreach (var update in data.Updates) foreach (var update in data.Updates)
{ {
var basketItem = currentBasket.Items.SingleOrDefault(bitem => bitem.Id == update.BasketItemId); var basketItem = currentBasket.Items.SingleOrDefault(bitem => bitem.Id == update.BasketItemId);
if (basketItem == null) if (basketItem == null)
{ {
return BadRequest($"Basket item with id {update.BasketItemId} not found"); return BadRequest($"Basket item with id {update.BasketItemId} not found");
} }
basketItem.Quantity = update.NewQty; basketItem.Quantity = update.NewQty;
} }
// Save the updated basket // Save the updated basket
await _basket.Update(currentBasket); await _basket.Update(currentBasket);
return Ok(currentBasket); return Ok(currentBasket);
} }
[HttpPost] [HttpPost]
[Route("items")] [Route("items")]
public async Task<IActionResult> AddBasketItem([FromBody] AddBasketItemRequest data) public async Task<IActionResult> AddBasketItem([FromBody] AddBasketItemRequest data)
{ {
if (data == null || data.Quantity == 0) if (data == null || data.Quantity == 0)
{ {
return BadRequest("Invalid payload"); return BadRequest("Invalid payload");
} }
// Step 1: Get the item from catalog // Step 1: Get the item from catalog
var item = await _catalog.GetCatalogItem(data.CatalogItemId); var item = await _catalog.GetCatalogItem(data.CatalogItemId);
//item.PictureUri = //item.PictureUri =
// Step 2: Get current basket status // Step 2: Get current basket status
var currentBasket = (await _basket.GetById(data.BasketId)) ?? new BasketData(data.BasketId); var currentBasket = (await _basket.GetById(data.BasketId)) ?? new BasketData(data.BasketId);
// Step 3: Merge current status with new product // Step 3: Merge current status with new product
currentBasket.Items.Add(new BasketDataItem() currentBasket.Items.Add(new BasketDataItem()
{ {
UnitPrice = item.Price, UnitPrice = item.Price,
PictureUrl = item.PictureUri, PictureUrl = item.PictureUri,
ProductId = item.Id.ToString(), ProductId = item.Id.ToString(),
ProductName = item.Name, ProductName = item.Name,
Quantity = data.Quantity, Quantity = data.Quantity,
Id = Guid.NewGuid().ToString() Id = Guid.NewGuid().ToString()
}); });
// Step 4: Update basket // Step 4: Update basket
await _basket.Update(currentBasket); await _basket.Update(currentBasket);
return Ok(); return Ok();
} }
} }
} }

View File

@ -1,18 +1,14 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers
{ {
[Route("")] [Route("")]
public class HomeController : Controller public class HomeController : Controller
{ {
[HttpGet()] [HttpGet()]
public IActionResult Index() public IActionResult Index()
{ {
return new RedirectResult("~/swagger"); return new RedirectResult("~/swagger");
} }
} }
} }

View File

@ -1,42 +1,39 @@
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers
{ {
[Route("api/v1/[controller]")] [Route("api/v1/[controller]")]
[Authorize] [Authorize]
public class OrderController : Controller public class OrderController : Controller
{ {
private readonly IBasketService _basketService; private readonly IBasketService _basketService;
private readonly IOrderApiClient _orderClient; private readonly IOrderApiClient _orderClient;
public OrderController(IBasketService basketService, IOrderApiClient orderClient) public OrderController(IBasketService basketService, IOrderApiClient orderClient)
{ {
_basketService = basketService; _basketService = basketService;
_orderClient = orderClient; _orderClient = orderClient;
} }
[Route("draft/{basketId}")] [Route("draft/{basketId}")]
[HttpGet] [HttpGet]
public async Task<IActionResult> GetOrderDraft(string basketId) public async Task<IActionResult> GetOrderDraft(string basketId)
{ {
if (string.IsNullOrEmpty(basketId)) if (string.IsNullOrEmpty(basketId))
{ {
return BadRequest("Need a valid basketid"); return BadRequest("Need a valid basketid");
} }
// Get the basket data and build a order draft based on it // Get the basket data and build a order draft based on it
var basket = await _basketService.GetById(basketId); var basket = await _basketService.GetById(basketId);
if (basket == null) if (basket == null)
{ {
return BadRequest($"No basket found for id {basketId}"); return BadRequest($"No basket found for id {basketId}");
} }
var orderDraft = await _orderClient.GetOrderDraftFromBasket(basket); var orderDraft = await _orderClient.GetOrderDraftFromBasket(basket);
return Ok(orderDraft); return Ok(orderDraft);
} }
} }
} }

View File

@ -1,33 +1,33 @@
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters
{ {
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Swashbuckle.AspNetCore.Swagger; using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen; using Swashbuckle.AspNetCore.SwaggerGen;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace Basket.API.Infrastructure.Filters namespace Basket.API.Infrastructure.Filters
{ {
public class AuthorizeCheckOperationFilter : IOperationFilter public class AuthorizeCheckOperationFilter : IOperationFilter
{ {
public void Apply(Operation operation, OperationFilterContext context) public void Apply(Operation operation, OperationFilterContext context)
{ {
// Check for authorize attribute // Check for authorize attribute
var hasAuthorize = context.ApiDescription.ControllerAttributes().OfType<AuthorizeAttribute>().Any() || var hasAuthorize = context.ApiDescription.ControllerAttributes().OfType<AuthorizeAttribute>().Any() ||
context.ApiDescription.ActionAttributes().OfType<AuthorizeAttribute>().Any(); context.ApiDescription.ActionAttributes().OfType<AuthorizeAttribute>().Any();
if (hasAuthorize) if (hasAuthorize)
{ {
operation.Responses.Add("401", new Response { Description = "Unauthorized" }); operation.Responses.Add("401", new Response { Description = "Unauthorized" });
operation.Responses.Add("403", new Response { Description = "Forbidden" }); operation.Responses.Add("403", new Response { Description = "Forbidden" });
operation.Security = new List<IDictionary<string, IEnumerable<string>>>(); operation.Security = new List<IDictionary<string, IEnumerable<string>>>();
operation.Security.Add(new Dictionary<string, IEnumerable<string>> operation.Security.Add(new Dictionary<string, IEnumerable<string>>
{ {
{ "oauth2", new [] { "Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator" } } { "oauth2", new [] { "Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator" } }
}); });
} }
} }
} }
} }
} }

View File

@ -8,42 +8,42 @@ using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure
{ {
public class HttpClientAuthorizationDelegatingHandler public class HttpClientAuthorizationDelegatingHandler
: DelegatingHandler : DelegatingHandler
{ {
private readonly IHttpContextAccessor _httpContextAccesor; private readonly IHttpContextAccessor _httpContextAccesor;
public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccesor) public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccesor)
{ {
_httpContextAccesor = httpContextAccesor; _httpContextAccesor = httpContextAccesor;
} }
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{ {
var authorizationHeader = _httpContextAccesor.HttpContext var authorizationHeader = _httpContextAccesor.HttpContext
.Request.Headers["Authorization"]; .Request.Headers["Authorization"];
if (!string.IsNullOrEmpty(authorizationHeader)) if (!string.IsNullOrEmpty(authorizationHeader))
{ {
request.Headers.Add("Authorization", new List<string>() { authorizationHeader }); request.Headers.Add("Authorization", new List<string>() { authorizationHeader });
} }
var token = await GetToken(); var token = await GetToken();
if (token != null) if (token != null)
{ {
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
} }
return await base.SendAsync(request, cancellationToken); return await base.SendAsync(request, cancellationToken);
} }
async Task<string> GetToken() async Task<string> GetToken()
{ {
const string ACCESS_TOKEN = "access_token"; const string ACCESS_TOKEN = "access_token";
return await _httpContextAccesor.HttpContext return await _httpContextAccesor.HttpContext
.GetTokenAsync(ACCESS_TOKEN); .GetTokenAsync(ACCESS_TOKEN);
} }
} }
} }

View File

@ -1,20 +1,15 @@
using System; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models
{ {
public class AddBasketItemRequest public class AddBasketItemRequest
{ {
public int CatalogItemId { get; set; } public int CatalogItemId { get; set; }
public string BasketId { get; set; } public string BasketId { get; set; }
public int Quantity { get; set; } public int Quantity { get; set; }
public AddBasketItemRequest() public AddBasketItemRequest()
{ {
Quantity = 1; Quantity = 1;
} }
} }
} }

View File

@ -1,31 +1,28 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models
{ {
public class BasketData public class BasketData
{ {
public string BuyerId { get; set; } public string BuyerId { get; set; }
public List<BasketDataItem> Items { get; set; } public List<BasketDataItem> Items { get; set; }
public BasketData(string buyerId) public BasketData(string buyerId)
{ {
BuyerId = buyerId; BuyerId = buyerId;
Items = new List<BasketDataItem>(); Items = new List<BasketDataItem>();
} }
} }
public class BasketDataItem public class BasketDataItem
{ {
public string Id { get; set; } public string Id { get; set; }
public string ProductId { get; set; } public string ProductId { get; set; }
public string ProductName { get; set; } public string ProductName { get; set; }
public decimal UnitPrice { get; set; } public decimal UnitPrice { get; set; }
public decimal OldUnitPrice { get; set; } public decimal OldUnitPrice { get; set; }
public int Quantity { get; set; } public int Quantity { get; set; }
public string PictureUrl { get; set; } public string PictureUrl { get; set; }
} }
} }

View File

@ -1,20 +1,15 @@
using System; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models
{ {
public class CatalogItem public class CatalogItem
{ {
public int Id { get; set; } public int Id { get; set; }
public string Name { get; set; } public string Name { get; set; }
public decimal Price { get; set; } public decimal Price { get; set; }
public string PictureUri { get; set; } public string PictureUri { get; set; }
} }
} }

View File

@ -1,33 +1,31 @@
using System; using System.Collections.Generic;
using System.Collections.Generic; using DateTime = System.DateTime;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models
{ {
public class OrderData public class OrderData
{ {
public string OrderNumber { get; set; } public string OrderNumber { get; set; }
public DateTime Date { get; set; } public DateTime Date { get; set; }
public string Status { get; set; } public string Status { get; set; }
public decimal Total { get; set; } public decimal Total { get; set; }
public string Description { get; set; } public string Description { get; set; }
public string City { get; set; } public string City { get; set; }
public string Street { get; set; } public string Street { get; set; }
public string State { get; set; } public string State { get; set; }
public string Country { get; set; } public string Country { get; set; }
public string ZipCode { get; set; } public string ZipCode { get; set; }
public string CardNumber { get; set; } public string CardNumber { get; set; }
public string CardHolderName { get; set; } public string CardHolderName { get; set; }
public bool IsDraft { get; set; } public bool IsDraft { get; set; }
public DateTime CardExpiration { get; set; } public DateTime CardExpiration { get; set; }
public string CardExpirationShort { get; set; } public string CardExpirationShort { get; set; }
public string CardSecurityNumber { get; set; } public string CardSecurityNumber { get; set; }
public int CardTypeId { get; set; } public int CardTypeId { get; set; }
public string Buyer { get; set; } public string Buyer { get; set; }
public List<OrderItemData> OrderItems { get; } = new List<OrderItemData>(); public List<OrderItemData> OrderItems { get; } = new List<OrderItemData>();
} }
} }

View File

@ -1,17 +1,12 @@
using System; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models
{ {
public class OrderItemData public class OrderItemData
{ {
public int ProductId { get; set; } public int ProductId { get; set; }
public string ProductName { get; set; } public string ProductName { get; set; }
public decimal UnitPrice { get; set; } public decimal UnitPrice { get; set; }
public decimal Discount { get; set; } public decimal Discount { get; set; }
public int Units { get; set; } public int Units { get; set; }
public string PictureUrl { get; set; } public string PictureUrl { get; set; }
} }
} }

View File

@ -1,31 +1,28 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models
{ {
public class UpdateBasketItemsRequest public class UpdateBasketItemsRequest
{ {
public string BasketId { get; set; }
public ICollection<UpdateBasketItemData> Updates { get; set; } public string BasketId { get; set; }
public UpdateBasketItemsRequest() public ICollection<UpdateBasketItemData> Updates { get; set; }
{
Updates = new List<UpdateBasketItemData>();
}
}
public class UpdateBasketItemData public UpdateBasketItemsRequest()
{ {
public string BasketItemId { get; set; } Updates = new List<UpdateBasketItemData>();
public int NewQty { get; set; } }
}
public UpdateBasketItemData() public class UpdateBasketItemData
{ {
NewQty = 0; public string BasketItemId { get; set; }
} public int NewQty { get; set; }
}
public UpdateBasketItemData()
{
NewQty = 0;
}
}
} }

View File

@ -1,21 +1,18 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models
{ {
public class UpdateBasketRequest public class UpdateBasketRequest
{ {
public string BuyerId { get; set; } public string BuyerId { get; set; }
public IEnumerable<UpdateBasketRequestItemData> Items { get; set; } public IEnumerable<UpdateBasketRequestItemData> Items { get; set; }
} }
public class UpdateBasketRequestItemData public class UpdateBasketRequestItemData
{ {
public string Id { get; set; } // Basket id public string Id { get; set; } // Basket id
public int ProductId { get; set; } // Catalog item id public int ProductId { get; set; } // Catalog item id
public int Quantity { get; set; } // Quantity public int Quantity { get; set; } // Quantity
} }
} }

View File

@ -1,36 +1,29 @@
using System; using static Microsoft.AspNetCore.Hosting.WebHostBuilderExtensions;
using System.Collections.Generic; using static Microsoft.AspNetCore.Hosting.WebHostExtensions;
using System.IO; using IWebHost = Microsoft.AspNetCore.Hosting.IWebHost;
using System.Linq; using WebHost = Microsoft.AspNetCore.WebHost;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
{ {
public class Program public class Program
{ {
public static void Main(string[] args) public static void Main(string[] args)
{ => BuildWebHost(args).Run();
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) => public static IWebHost BuildWebHost(string[] args) =>
WebHost WebHost
.CreateDefaultBuilder(args) .CreateDefaultBuilder(args)
.ConfigureAppConfiguration(cb => .ConfigureAppConfiguration(cb =>
{ {
var sources = cb.Sources; var sources = cb.Sources;
sources.Insert(3, new Microsoft.Extensions.Configuration.Json.JsonConfigurationSource() sources.Insert(3, new Extensions.Configuration.Json.JsonConfigurationSource()
{ {
Optional = true, Optional = true,
Path = "appsettings.localhost.json", Path = "appsettings.localhost.json",
ReloadOnChange = false ReloadOnChange = false
}); });
}) })
.UseStartup<Startup>() .UseStartup<Startup>()
.Build(); .Build();
} }
} }

View File

@ -1,39 +1,42 @@
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config; using Microsoft.Extensions.Logging;
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using HttpClient = System.Net.Http.HttpClient;
using JsonConvert = Newtonsoft.Json.JsonConvert;
using StringContent = System.Net.Http.StringContent;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
{ {
public class BasketService : IBasketService using BasketData = Models.BasketData;
{ using BasketOperations = Config.UrlsConfig.BasketOperations;
using UrlsConfig = Config.UrlsConfig;
private readonly HttpClient _apiClient; public class BasketService : IBasketService
private readonly ILogger<BasketService> _logger; {
private readonly UrlsConfig _urls;
public BasketService(HttpClient httpClient,ILogger<BasketService> logger, IOptions<UrlsConfig> config) private readonly HttpClient _apiClient;
{ private readonly ILogger<BasketService> _logger;
_apiClient = httpClient; private readonly UrlsConfig _urls;
_logger = logger;
_urls = config.Value;
}
public async Task<BasketData> GetById(string id) public BasketService(HttpClient httpClient, ILogger<BasketService> logger, IOptions<UrlsConfig> config)
{ {
var data = await _apiClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id)); _apiClient = httpClient;
var basket = !string.IsNullOrEmpty(data) ? JsonConvert.DeserializeObject<BasketData>(data) : null; _logger = logger;
return basket; _urls = config.Value;
} }
public async Task Update(BasketData currentBasket) public async Task<BasketData> GetById(string id)
{ {
var basketContent = new StringContent(JsonConvert.SerializeObject(currentBasket), System.Text.Encoding.UTF8, "application/json"); var data = await _apiClient.GetStringAsync(_urls.Basket + BasketOperations.GetItemById(id));
var basket = !string.IsNullOrEmpty(data) ? JsonConvert.DeserializeObject<BasketData>(data) : null;
return basket;
}
var data = await _apiClient.PostAsync(_urls.Basket + UrlsConfig.BasketOperations.UpdateBasket(), basketContent); public async Task Update(BasketData currentBasket)
} {
} var basketContent = new StringContent(JsonConvert.SerializeObject(currentBasket), System.Text.Encoding.UTF8, "application/json");
var data = await _apiClient.PostAsync(_urls.Basket + BasketOperations.UpdateBasket(), basketContent);
}
}
} }

View File

@ -1,42 +1,43 @@
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config; using Microsoft.Extensions.Logging;
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using HttpClient = System.Net.Http.HttpClient;
using JsonConvert = Newtonsoft.Json.JsonConvert;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
{ {
public class CatalogService : ICatalogService using CatalogItem = Models.CatalogItem;
{ using UrlsConfig = Config.UrlsConfig;
private readonly HttpClient _httpClient; public class CatalogService : ICatalogService
private readonly ILogger<CatalogService> _logger; {
private readonly UrlsConfig _urls;
public CatalogService(HttpClient httpClient, ILogger<CatalogService> logger, IOptions<UrlsConfig> config) private readonly HttpClient _httpClient;
{ private readonly ILogger<CatalogService> _logger;
_httpClient = httpClient; private readonly UrlsConfig _urls;
_logger = logger;
_urls = config.Value;
}
public async Task<CatalogItem> GetCatalogItem(int id) public CatalogService(HttpClient httpClient, ILogger<CatalogService> logger, IOptions<UrlsConfig> config)
{ {
var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id)); _httpClient = httpClient;
var catalogItem = JsonConvert.DeserializeObject<CatalogItem>(stringContent); _logger = logger;
_urls = config.Value;
}
return catalogItem; public async Task<CatalogItem> GetCatalogItem(int id)
} {
var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id));
var catalogItem = JsonConvert.DeserializeObject<CatalogItem>(stringContent);
public async Task<IEnumerable<CatalogItem>> GetCatalogItems(IEnumerable<int> ids) return catalogItem;
{ }
var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemsById(ids));
var catalogItems = JsonConvert.DeserializeObject<CatalogItem[]>(stringContent);
return catalogItems; public async Task<IEnumerable<CatalogItem>> GetCatalogItems(IEnumerable<int> ids)
} {
} var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemsById(ids));
var catalogItems = JsonConvert.DeserializeObject<CatalogItem[]>(stringContent);
return catalogItems;
}
}
} }

View File

@ -1,15 +1,13 @@
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
{ {
public interface IBasketService using BasketData = Models.BasketData;
{
Task<BasketData> GetById(string id);
Task Update(BasketData currentBasket);
} public interface IBasketService
{
Task<BasketData> GetById(string id);
Task Update(BasketData currentBasket);
}
} }

View File

@ -1,14 +1,13 @@
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
{ {
public interface ICatalogService using CatalogItem = Models.CatalogItem;
{
Task<CatalogItem> GetCatalogItem(int id); public interface ICatalogService
Task<IEnumerable<CatalogItem>> GetCatalogItems(IEnumerable<int> ids); {
} Task<CatalogItem> GetCatalogItem(int id);
Task<IEnumerable<CatalogItem>> GetCatalogItems(IEnumerable<int> ids);
}
} }

View File

@ -1,13 +1,12 @@
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
{ {
public interface IOrderApiClient using BasketData = Models.BasketData;
{ using OrderData = Models.OrderData;
Task<OrderData> GetOrderDraftFromBasket(BasketData basket);
} public interface IOrderApiClient
{
Task<OrderData> GetOrderDraftFromBasket(BasketData basket);
}
} }

View File

@ -1,38 +1,41 @@
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config; using Microsoft.Extensions.Logging;
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using HttpClient = System.Net.Http.HttpClient;
using JsonConvert = Newtonsoft.Json.JsonConvert;
using StringContent = System.Net.Http.StringContent;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
{ {
public class OrderApiClient : IOrderApiClient using BasketData = Models.BasketData;
{ using OrderData = Models.OrderData;
using UrlsConfig = Config.UrlsConfig;
private readonly HttpClient _apiClient; public class OrderApiClient : IOrderApiClient
private readonly ILogger<OrderApiClient> _logger; {
private readonly UrlsConfig _urls;
public OrderApiClient(HttpClient httpClient, ILogger<OrderApiClient> logger, IOptions<UrlsConfig> config) private readonly HttpClient _apiClient;
{ private readonly ILogger<OrderApiClient> _logger;
_apiClient = httpClient; private readonly UrlsConfig _urls;
_logger = logger;
_urls = config.Value;
}
public async Task<OrderData> GetOrderDraftFromBasket(BasketData basket) public OrderApiClient(HttpClient httpClient, ILogger<OrderApiClient> logger, IOptions<UrlsConfig> config)
{ {
var url = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft(); _apiClient = httpClient;
var content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json"); _logger = logger;
var response = await _apiClient.PostAsync(url, content); _urls = config.Value;
}
response.EnsureSuccessStatusCode(); public async Task<OrderData> GetOrderDraftFromBasket(BasketData basket)
{
var url = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft();
var content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json");
var response = await _apiClient.PostAsync(url, content);
var ordersDraftResponse = await response.Content.ReadAsStringAsync(); response.EnsureSuccessStatusCode();
return JsonConvert.DeserializeObject<OrderData>(ordersDraftResponse); var ordersDraftResponse = await response.Content.ReadAsStringAsync();
}
} return JsonConvert.DeserializeObject<OrderData>(ordersDraftResponse);
}
}
} }

View File

@ -11,7 +11,6 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Polly; using Polly;
using Polly.Extensions.Http; using Polly.Extensions.Http;
using Polly.Timeout;
using Swashbuckle.AspNetCore.Swagger; using Swashbuckle.AspNetCore.Swagger;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -20,168 +19,168 @@ using System.Net.Http;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
{ {
public class Startup public class Startup
{ {
public Startup(IConfiguration configuration) public Startup(IConfiguration configuration) =>
{ Configuration = configuration;
Configuration = configuration;
}
public IConfiguration Configuration { get; } public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container. // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddCustomMvc(Configuration) services
.AddCustomAuthentication(Configuration) .AddCustomMvc(Configuration)
.AddApplicationServices(); .AddCustomAuthentication(Configuration)
} .AddApplicationServices();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{ {
var pathBase = Configuration["PATH_BASE"]; var pathBase = Configuration["PATH_BASE"];
if (!string.IsNullOrEmpty(pathBase)) if (!string.IsNullOrEmpty(pathBase))
{ {
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'"); loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
app.UsePathBase(pathBase); app.UsePathBase(pathBase);
} }
app.UseCors("CorsPolicy"); app.UseCors("CorsPolicy");
if (env.IsDevelopment()) if (env.IsDevelopment())
{ {
app.UseDeveloperExceptionPage(); app.UseDeveloperExceptionPage();
} }
app.UseAuthentication(); app.UseAuthentication();
app.UseMvc(); app.UseMvc();
app.UseSwagger().UseSwaggerUI(c => app.UseSwagger().UseSwaggerUI(c =>
{ {
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1"); c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1");
//c.ConfigureOAuth2("Microsoft.eShopOnContainers.Web.Shopping.HttpAggregatorwaggerui", "", "", "Purchase BFF Swagger UI"); //c.ConfigureOAuth2("Microsoft.eShopOnContainers.Web.Shopping.HttpAggregatorwaggerui", "", "", "Purchase BFF Swagger UI");
}); });
} }
} }
public static class ServiceCollectionExtensions public static class ServiceCollectionExtensions
{ {
public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration)
{ {
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
var identityUrl = configuration.GetValue<string>("urls:identity"); var identityUrl = configuration.GetValue<string>("urls:identity");
services.AddAuthentication(options => services.AddAuthentication(options =>
{ {
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options => }).AddJwtBearer(options =>
{ {
options.Authority = identityUrl; options.Authority = identityUrl;
options.RequireHttpsMetadata = false; options.RequireHttpsMetadata = false;
options.Audience = "webshoppingagg"; options.Audience = "webshoppingagg";
options.Events = new JwtBearerEvents() options.Events = new JwtBearerEvents()
{ {
OnAuthenticationFailed = async ctx => #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
{ OnAuthenticationFailed = async ctx =>
int i = 0; #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
}, {
OnTokenValidated = async ctx => },
{ #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
int i = 0; OnTokenValidated = async ctx =>
} #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
}; {
}); }
};
});
return services; return services;
} }
public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration) public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration)
{ {
services.AddOptions(); services.AddOptions();
services.Configure<UrlsConfig>(configuration.GetSection("urls")); services.Configure<UrlsConfig>(configuration.GetSection("urls"));
services.AddMvc(); services.AddMvc();
services.AddSwaggerGen(options => services.AddSwaggerGen(options =>
{ {
options.DescribeAllEnumsAsStrings(); options.DescribeAllEnumsAsStrings();
options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info
{ {
Title = "Shopping Aggregator for Web Clients", Title = "Shopping Aggregator for Web Clients",
Version = "v1", Version = "v1",
Description = "Shopping Aggregator for Web Clients", Description = "Shopping Aggregator for Web Clients",
TermsOfService = "Terms Of Service" TermsOfService = "Terms Of Service"
}); });
options.AddSecurityDefinition("oauth2", new OAuth2Scheme options.AddSecurityDefinition("oauth2", new OAuth2Scheme
{ {
Type = "oauth2", Type = "oauth2",
Flow = "implicit", Flow = "implicit",
AuthorizationUrl = $"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize", AuthorizationUrl = $"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize",
TokenUrl = $"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token", TokenUrl = $"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token",
Scopes = new Dictionary<string, string>() Scopes = new Dictionary<string, string>()
{ {
{ "webshoppingagg", "Shopping Aggregator for Web Clients" } { "webshoppingagg", "Shopping Aggregator for Web Clients" }
} }
}); });
options.OperationFilter<AuthorizeCheckOperationFilter>(); options.OperationFilter<AuthorizeCheckOperationFilter>();
}); });
services.AddCors(options => services.AddCors(options =>
{ {
options.AddPolicy("CorsPolicy", options
builder => builder.AllowAnyOrigin() .AddPolicy(
.AllowAnyMethod() "CorsPolicy",
.AllowAnyHeader() builder =>
.AllowCredentials()); builder
}); .AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
return services; return services;
} }
public static IServiceCollection AddApplicationServices(this IServiceCollection services) public static IServiceCollection AddApplicationServices(this IServiceCollection services)
{ {
//register delegating handlers //register delegating handlers
services.AddTransient<HttpClientAuthorizationDelegatingHandler>(); services.AddTransient<HttpClientAuthorizationDelegatingHandler>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
//register http services //register http services
services.AddHttpClient<IBasketService, BasketService>()
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy());
services.AddHttpClient<ICatalogService, CatalogService>() services.AddHttpClient<IBasketService, BasketService>()
.AddPolicyHandler(GetRetryPolicy()) .AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
.AddPolicyHandler(GetCircuitBreakerPolicy()); .AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy());
services.AddHttpClient<IOrderApiClient, OrderApiClient>() services.AddHttpClient<ICatalogService, CatalogService>()
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>() .AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetRetryPolicy()) .AddPolicyHandler(GetCircuitBreakerPolicy());
.AddPolicyHandler(GetCircuitBreakerPolicy());
services.AddHttpClient<IOrderApiClient, OrderApiClient>()
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy());
return services; return services;
} }
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy() static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy() =>
{ HttpPolicyExtensions
return HttpPolicyExtensions .HandleTransientHttpError()
.HandleTransientHttpError() .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound) .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
=> HttpPolicyExtensions
} .HandleTransientHttpError()
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy() .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
{ }
return HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
}
}
} }

View File

@ -1,15 +1,15 @@
{ {
"Logging": { "Logging": {
"IncludeScopes": false, "IncludeScopes": false,
"Debug": { "Debug": {
"LogLevel": { "LogLevel": {
"Default": "Warning" "Default": "Warning"
} }
}, },
"Console": { "Console": {
"LogLevel": { "LogLevel": {
"Default": "Warning" "Default": "Warning"
} }
} }
} }
} }

View File

@ -1,8 +1,8 @@
{ {
"urls": { "urls": {
"basket": "http://localhost:55105", "basket": "http://localhost:55105",
"catalog": "http://localhost:55101", "catalog": "http://localhost:55101",
"orders": "http://localhost:55102", "orders": "http://localhost:55102",
"identity": "http://localhost:55105" "identity": "http://localhost:55105"
} }
} }

View File

@ -1,130 +1,129 @@
{ {
"ReRoutes": [ "ReRoutes": [
{ {
"DownstreamPathTemplate": "/api/{version}/{everything}", "DownstreamPathTemplate": "/api/{version}/{everything}",
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHostAndPorts": [ "DownstreamHostAndPorts": [
{ {
"Host": "catalog.api", "Host": "catalog.api",
"Port": 80 "Port": 80
} }
], ],
"UpstreamPathTemplate": "/api/{version}/c/{everything}", "UpstreamPathTemplate": "/api/{version}/c/{everything}",
"UpstreamHttpMethod": [ "GET" ] "UpstreamHttpMethod": [ "GET" ]
}, },
{ {
"DownstreamPathTemplate": "/api/{version}/{everything}", "DownstreamPathTemplate": "/api/{version}/{everything}",
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHostAndPorts": [ "DownstreamHostAndPorts": [
{ {
"Host": "basket.api", "Host": "basket.api",
"Port": 80 "Port": 80
} }
], ],
"UpstreamPathTemplate": "/api/{version}/b/{everything}", "UpstreamPathTemplate": "/api/{version}/b/{everything}",
"UpstreamHttpMethod": [], "UpstreamHttpMethod": [],
"AuthenticationOptions": { "AuthenticationOptions": {
"AuthenticationProviderKey": "IdentityApiKey", "AuthenticationProviderKey": "IdentityApiKey",
"AllowedScopes": [] "AllowedScopes": []
} }
}, },
{ {
"DownstreamPathTemplate": "/api/{version}/{everything}", "DownstreamPathTemplate": "/api/{version}/{everything}",
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHostAndPorts": [ "DownstreamHostAndPorts": [
{ {
"Host": "ordering.api", "Host": "ordering.api",
"Port": 80 "Port": 80
} }
], ],
"UpstreamPathTemplate": "/api/{version}/o/{everything}", "UpstreamPathTemplate": "/api/{version}/o/{everything}",
"UpstreamHttpMethod": [], "UpstreamHttpMethod": [],
"AuthenticationOptions": { "AuthenticationOptions": {
"AuthenticationProviderKey": "IdentityApiKey", "AuthenticationProviderKey": "IdentityApiKey",
"AllowedScopes": [] "AllowedScopes": []
} }
}, },
{ {
"DownstreamPathTemplate": "/{everything}", "DownstreamPathTemplate": "/{everything}",
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHostAndPorts": [ "DownstreamHostAndPorts": [
{ {
"Host": "webshoppingagg", "Host": "webshoppingagg",
"Port": 80 "Port": 80
} }
], ],
"UpstreamPathTemplate": "/{everything}", "UpstreamPathTemplate": "/{everything}",
"UpstreamHttpMethod": [ "POST", "PUT", "GET" ], "UpstreamHttpMethod": [ "POST", "PUT", "GET" ],
"AuthenticationOptions": { "AuthenticationOptions": {
"AuthenticationProviderKey": "IdentityApiKey", "AuthenticationProviderKey": "IdentityApiKey",
"AllowedScopes": [] "AllowedScopes": []
} }
}, },
{ {
"DownstreamPathTemplate": "/{everything}", "DownstreamPathTemplate": "/{everything}",
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHostAndPorts": [ "DownstreamHostAndPorts": [
{ {
"Host": "ordering.api", "Host": "ordering.api",
"Port": 80 "Port": 80
} }
], ],
"UpstreamPathTemplate": "/orders-api/{everything}", "UpstreamPathTemplate": "/orders-api/{everything}",
"UpstreamHttpMethod": [] "UpstreamHttpMethod": []
}, },
{ {
"DownstreamPathTemplate": "/{everything}", "DownstreamPathTemplate": "/{everything}",
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHostAndPorts": [ "DownstreamHostAndPorts": [
{ {
"Host": "ordering.signalrhub", "Host": "ordering.signalrhub",
"Port": 80 "Port": 80
} }
], ],
"UpstreamPathTemplate": "/hub/{everything}", "UpstreamPathTemplate": "/hub/{everything}",
"UpstreamHttpMethod": [] "UpstreamHttpMethod": []
}, },
{ {
"DownstreamPathTemplate": "/{everything}", "DownstreamPathTemplate": "/{everything}",
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHostAndPorts": [ "DownstreamHostAndPorts": [
{ {
"Host": "basket.api", "Host": "basket.api",
"Port": 80 "Port": 80
} }
], ],
"UpstreamPathTemplate": "/basket-api/{everything}", "UpstreamPathTemplate": "/basket-api/{everything}",
"UpstreamHttpMethod": [] "UpstreamHttpMethod": []
}, },
{ {
"DownstreamPathTemplate": "/{everything}", "DownstreamPathTemplate": "/{everything}",
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHostAndPorts": [ "DownstreamHostAndPorts": [
{ {
"Host": "catalog.api", "Host": "catalog.api",
"Port": 80 "Port": 80
} }
], ],
"UpstreamPathTemplate": "/catalog-api/{everything}", "UpstreamPathTemplate": "/catalog-api/{everything}",
"UpstreamHttpMethod": [] "UpstreamHttpMethod": []
}, },
{ {
"DownstreamPathTemplate": "/{everything}", "DownstreamPathTemplate": "/{everything}",
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHostAndPorts": [ "DownstreamHostAndPorts": [
{ {
"Host": "payment.api", "Host": "payment.api",
"Port": 80 "Port": 80
} }
], ],
"UpstreamPathTemplate": "/payment-api/{everything}", "UpstreamPathTemplate": "/payment-api/{everything}",
"UpstreamHttpMethod": [] "UpstreamHttpMethod": []
} }
], ],
"GlobalConfiguration": { "GlobalConfiguration": {
"RequestIdKey": "OcRequestId", "RequestIdKey": "OcRequestId",
"AdministrationPath": "/administration" "AdministrationPath": "/administration"
} }
} }