Moved namespaces to globalusing shopping aggregator
This commit is contained in:
		
							parent
							
								
									7b1764261e
								
							
						
					
					
						commit
						a12fbcaf09
					
				| @ -1,45 +1,41 @@ | ||||
| using System.Collections.Generic; | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config; | ||||
| 
 | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config | ||||
| public class UrlsConfig | ||||
| { | ||||
| 
 | ||||
|     public class UrlsConfig | ||||
|     public class CatalogOperations | ||||
|     { | ||||
|         // grpc call under REST must go trough port 80 | ||||
|         public static string GetItemById(int id) => $"/api/v1/catalog/items/{id}"; | ||||
| 
 | ||||
|         public class CatalogOperations | ||||
|         { | ||||
|             // grpc call under REST must go trough port 80 | ||||
|             public static string GetItemById(int id) => $"/api/v1/catalog/items/{id}"; | ||||
|         public static string GetItemById(string ids) => $"/api/v1/catalog/items/ids/{string.Join(',', ids)}"; | ||||
| 
 | ||||
|             public static string GetItemById(string ids) => $"/api/v1/catalog/items/ids/{string.Join(',', ids)}"; | ||||
| 
 | ||||
|             // REST call standard must go through port 5000 | ||||
|             public static string GetItemsById(IEnumerable<int> ids) => $":5000/api/v1/catalog/items?ids={string.Join(',', ids)}"; | ||||
|         } | ||||
| 
 | ||||
|         public class BasketOperations | ||||
|         { | ||||
|             public static string GetItemById(string id) => $"/api/v1/basket/{id}"; | ||||
| 
 | ||||
|             public static string UpdateBasket() => "/api/v1/basket"; | ||||
|         } | ||||
| 
 | ||||
|         public class OrdersOperations | ||||
|         { | ||||
|             public static string GetOrderDraft() => "/api/v1/orders/draft"; | ||||
|         } | ||||
| 
 | ||||
|         public string Basket { get; set; } | ||||
| 
 | ||||
|         public string Catalog { get; set; } | ||||
| 
 | ||||
|         public string Orders { get; set; } | ||||
| 
 | ||||
|         public string GrpcBasket { get; set; } | ||||
| 
 | ||||
|         public string GrpcCatalog { get; set; } | ||||
| 
 | ||||
|         public string GrpcOrdering { get; set; } | ||||
|         // REST call standard must go through port 5000 | ||||
|         public static string GetItemsById(IEnumerable<int> ids) => $":5000/api/v1/catalog/items?ids={string.Join(',', ids)}"; | ||||
|     } | ||||
| 
 | ||||
|     public class BasketOperations | ||||
|     { | ||||
|         public static string GetItemById(string id) => $"/api/v1/basket/{id}"; | ||||
| 
 | ||||
|         public static string UpdateBasket() => "/api/v1/basket"; | ||||
|     } | ||||
| 
 | ||||
|     public class OrdersOperations | ||||
|     { | ||||
|         public static string GetOrderDraft() => "/api/v1/orders/draft"; | ||||
|     } | ||||
| 
 | ||||
|     public string Basket { get; set; } | ||||
| 
 | ||||
|     public string Catalog { get; set; } | ||||
| 
 | ||||
|     public string Orders { get; set; } | ||||
| 
 | ||||
|     public string GrpcBasket { get; set; } | ||||
| 
 | ||||
|     public string GrpcCatalog { get; set; } | ||||
| 
 | ||||
|     public string GrpcOrdering { get; set; } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,164 +1,154 @@ | ||||
| using Microsoft.AspNetCore.Authorization; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||
| using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; | ||||
| using System; | ||||
| using System.Linq; | ||||
| using System.Net; | ||||
| using System.Threading.Tasks; | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers; | ||||
| 
 | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers | ||||
| [Route("api/v1/[controller]")]
 | ||||
| [Authorize] | ||||
| [ApiController] | ||||
| public class BasketController : ControllerBase | ||||
| { | ||||
|     [Route("api/v1/[controller]")]
 | ||||
|     [Authorize] | ||||
|     [ApiController] | ||||
|     public class BasketController : ControllerBase | ||||
|     private readonly ICatalogService _catalog; | ||||
|     private readonly IBasketService _basket; | ||||
| 
 | ||||
|     public BasketController(ICatalogService catalogService, IBasketService basketService) | ||||
|     { | ||||
|         private readonly ICatalogService _catalog; | ||||
|         private readonly IBasketService _basket; | ||||
|         _catalog = catalogService; | ||||
|         _basket = basketService; | ||||
|     } | ||||
| 
 | ||||
|         public BasketController(ICatalogService catalogService, IBasketService basketService) | ||||
|     [HttpPost] | ||||
|     [HttpPut] | ||||
|     [ProducesResponseType((int)HttpStatusCode.BadRequest)] | ||||
|     [ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)] | ||||
|     public async Task<ActionResult<BasketData>> UpdateAllBasketAsync([FromBody] UpdateBasketRequest data) | ||||
|     { | ||||
|         if (data.Items == null || !data.Items.Any()) | ||||
|         { | ||||
|             _catalog = catalogService; | ||||
|             _basket = basketService; | ||||
|             return BadRequest("Need to pass at least one basket line"); | ||||
|         } | ||||
| 
 | ||||
|         [HttpPost] | ||||
|         [HttpPut] | ||||
|         [ProducesResponseType((int)HttpStatusCode.BadRequest)] | ||||
|         [ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)] | ||||
|         public async Task<ActionResult<BasketData>> UpdateAllBasketAsync([FromBody] UpdateBasketRequest data) | ||||
|         // Retrieve the current basket | ||||
|         var basket = await _basket.GetById(data.BuyerId) ?? new BasketData(data.BuyerId); | ||||
|         var catalogItems = await _catalog.GetCatalogItemsAsync(data.Items.Select(x => x.ProductId)); | ||||
| 
 | ||||
|         // group by product id to avoid duplicates | ||||
|         var itemsCalculated = data | ||||
|                 .Items | ||||
|                 .GroupBy(x => x.ProductId, x => x, (k, i) => new { productId = k, items = i }) | ||||
|                 .Select(groupedItem => | ||||
|                 { | ||||
|                     var item = groupedItem.items.First(); | ||||
|                     item.Quantity = groupedItem.items.Sum(i => i.Quantity); | ||||
|                     return item; | ||||
|                 }); | ||||
| 
 | ||||
|         foreach (var bitem in itemsCalculated) | ||||
|         { | ||||
|             if (data.Items == null || !data.Items.Any()) | ||||
|             var catalogItem = catalogItems.SingleOrDefault(ci => ci.Id == bitem.ProductId); | ||||
|             if (catalogItem == null) | ||||
|             { | ||||
|                 return BadRequest("Need to pass at least one basket line"); | ||||
|                 return BadRequest($"Basket refers to a non-existing catalog item ({bitem.ProductId})"); | ||||
|             } | ||||
| 
 | ||||
|             // Retrieve the current basket | ||||
|             var basket = await _basket.GetById(data.BuyerId) ?? new BasketData(data.BuyerId); | ||||
|             var catalogItems = await _catalog.GetCatalogItemsAsync(data.Items.Select(x => x.ProductId)); | ||||
| 
 | ||||
|             // group by product id to avoid duplicates | ||||
|             var itemsCalculated = data | ||||
|                     .Items | ||||
|                     .GroupBy(x => x.ProductId, x => x, (k, i) => new { productId = k, items = i }) | ||||
|                     .Select(groupedItem => | ||||
|                     { | ||||
|                         var item = groupedItem.items.First(); | ||||
|                         item.Quantity = groupedItem.items.Sum(i => i.Quantity); | ||||
|                         return item; | ||||
|                     }); | ||||
| 
 | ||||
|             foreach (var bitem in itemsCalculated) | ||||
|             var itemInBasket = basket.Items.FirstOrDefault(x => x.ProductId == bitem.ProductId); | ||||
|             if (itemInBasket == null) | ||||
|             { | ||||
|                 var catalogItem = catalogItems.SingleOrDefault(ci => ci.Id == bitem.ProductId); | ||||
|                 if (catalogItem == null) | ||||
|                 basket.Items.Add(new BasketDataItem() | ||||
|                 { | ||||
|                     return BadRequest($"Basket refers to a non-existing catalog item ({bitem.ProductId})"); | ||||
|                 } | ||||
| 
 | ||||
|                 var itemInBasket = basket.Items.FirstOrDefault(x => x.ProductId == bitem.ProductId); | ||||
|                 if (itemInBasket == null) | ||||
|                 { | ||||
|                     basket.Items.Add(new BasketDataItem() | ||||
|                     { | ||||
|                         Id = bitem.Id, | ||||
|                         ProductId = catalogItem.Id, | ||||
|                         ProductName = catalogItem.Name, | ||||
|                         PictureUrl = catalogItem.PictureUri, | ||||
|                         UnitPrice = catalogItem.Price, | ||||
|                         Quantity = bitem.Quantity | ||||
|                     }); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     itemInBasket.Quantity = bitem.Quantity; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             await _basket.UpdateAsync(basket); | ||||
| 
 | ||||
|             return basket; | ||||
|         } | ||||
| 
 | ||||
|         [HttpPut] | ||||
|         [Route("items")] | ||||
|         [ProducesResponseType((int)HttpStatusCode.BadRequest)] | ||||
|         [ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)] | ||||
|         public async Task<ActionResult<BasketData>> UpdateQuantitiesAsync([FromBody] UpdateBasketItemsRequest data) | ||||
|         { | ||||
|             if (!data.Updates.Any()) | ||||
|             { | ||||
|                 return BadRequest("No updates sent"); | ||||
|             } | ||||
| 
 | ||||
|             // Retrieve the current basket | ||||
|             var currentBasket = await _basket.GetById(data.BasketId); | ||||
|             if (currentBasket == null) | ||||
|             { | ||||
|                 return BadRequest($"Basket with id {data.BasketId} not found."); | ||||
|             } | ||||
| 
 | ||||
|             // Update with new quantities | ||||
|             foreach (var update in data.Updates) | ||||
|             { | ||||
|                 var basketItem = currentBasket.Items.SingleOrDefault(bitem => bitem.Id == update.BasketItemId); | ||||
|                 if (basketItem == null) | ||||
|                 { | ||||
|                     return BadRequest($"Basket item with id {update.BasketItemId} not found"); | ||||
|                 } | ||||
|                 basketItem.Quantity = update.NewQty; | ||||
|             } | ||||
| 
 | ||||
|             // Save the updated basket | ||||
|             await _basket.UpdateAsync(currentBasket); | ||||
| 
 | ||||
|             return currentBasket; | ||||
|         } | ||||
| 
 | ||||
|         [HttpPost] | ||||
|         [Route("items")] | ||||
|         [ProducesResponseType((int)HttpStatusCode.BadRequest)] | ||||
|         [ProducesResponseType((int)HttpStatusCode.OK)] | ||||
|         public async Task<ActionResult> AddBasketItemAsync([FromBody] AddBasketItemRequest data) | ||||
|         { | ||||
|             if (data == null || data.Quantity == 0) | ||||
|             { | ||||
|                 return BadRequest("Invalid payload"); | ||||
|             } | ||||
| 
 | ||||
|             // Step 1: Get the item from catalog | ||||
|             var item = await _catalog.GetCatalogItemAsync(data.CatalogItemId); | ||||
| 
 | ||||
|             //item.PictureUri =  | ||||
| 
 | ||||
|             // Step 2: Get current basket status | ||||
|             var currentBasket = (await _basket.GetById(data.BasketId)) ?? new BasketData(data.BasketId); | ||||
|             // Step 3: Search if exist product into basket | ||||
|             var product = currentBasket.Items.SingleOrDefault(i => i.ProductId == item.Id); | ||||
|             if (product != null) | ||||
|             { | ||||
|                 // Step 4: Update quantity for product | ||||
|                 product.Quantity += data.Quantity; | ||||
|                     Id = bitem.Id, | ||||
|                     ProductId = catalogItem.Id, | ||||
|                     ProductName = catalogItem.Name, | ||||
|                     PictureUrl = catalogItem.PictureUri, | ||||
|                     UnitPrice = catalogItem.Price, | ||||
|                     Quantity = bitem.Quantity | ||||
|                 }); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 // Step 4: Merge current status with new product | ||||
|                 currentBasket.Items.Add(new BasketDataItem() | ||||
|                 { | ||||
|                     UnitPrice = item.Price, | ||||
|                     PictureUrl = item.PictureUri, | ||||
|                     ProductId = item.Id, | ||||
|                     ProductName = item.Name, | ||||
|                     Quantity = data.Quantity, | ||||
|                     Id = Guid.NewGuid().ToString() | ||||
|                 }); | ||||
|                 itemInBasket.Quantity = bitem.Quantity; | ||||
|             } | ||||
| 
 | ||||
|             // Step 5: Update basket | ||||
|             await _basket.UpdateAsync(currentBasket); | ||||
| 
 | ||||
|             return Ok(); | ||||
|         } | ||||
| 
 | ||||
|         await _basket.UpdateAsync(basket); | ||||
| 
 | ||||
|         return basket; | ||||
|     } | ||||
| 
 | ||||
|     [HttpPut] | ||||
|     [Route("items")] | ||||
|     [ProducesResponseType((int)HttpStatusCode.BadRequest)] | ||||
|     [ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)] | ||||
|     public async Task<ActionResult<BasketData>> UpdateQuantitiesAsync([FromBody] UpdateBasketItemsRequest data) | ||||
|     { | ||||
|         if (!data.Updates.Any()) | ||||
|         { | ||||
|             return BadRequest("No updates sent"); | ||||
|         } | ||||
| 
 | ||||
|         // Retrieve the current basket | ||||
|         var currentBasket = await _basket.GetById(data.BasketId); | ||||
|         if (currentBasket == null) | ||||
|         { | ||||
|             return BadRequest($"Basket with id {data.BasketId} not found."); | ||||
|         } | ||||
| 
 | ||||
|         // Update with new quantities | ||||
|         foreach (var update in data.Updates) | ||||
|         { | ||||
|             var basketItem = currentBasket.Items.SingleOrDefault(bitem => bitem.Id == update.BasketItemId); | ||||
|             if (basketItem == null) | ||||
|             { | ||||
|                 return BadRequest($"Basket item with id {update.BasketItemId} not found"); | ||||
|             } | ||||
|             basketItem.Quantity = update.NewQty; | ||||
|         } | ||||
| 
 | ||||
|         // Save the updated basket | ||||
|         await _basket.UpdateAsync(currentBasket); | ||||
| 
 | ||||
|         return currentBasket; | ||||
|     } | ||||
| 
 | ||||
|     [HttpPost] | ||||
|     [Route("items")] | ||||
|     [ProducesResponseType((int)HttpStatusCode.BadRequest)] | ||||
|     [ProducesResponseType((int)HttpStatusCode.OK)] | ||||
|     public async Task<ActionResult> AddBasketItemAsync([FromBody] AddBasketItemRequest data) | ||||
|     { | ||||
|         if (data == null || data.Quantity == 0) | ||||
|         { | ||||
|             return BadRequest("Invalid payload"); | ||||
|         } | ||||
| 
 | ||||
|         // Step 1: Get the item from catalog | ||||
|         var item = await _catalog.GetCatalogItemAsync(data.CatalogItemId); | ||||
| 
 | ||||
|         //item.PictureUri =  | ||||
| 
 | ||||
|         // Step 2: Get current basket status | ||||
|         var currentBasket = (await _basket.GetById(data.BasketId)) ?? new BasketData(data.BasketId); | ||||
|         // Step 3: Search if exist product into basket | ||||
|         var product = currentBasket.Items.SingleOrDefault(i => i.ProductId == item.Id); | ||||
|         if (product != null) | ||||
|         { | ||||
|             // Step 4: Update quantity for product | ||||
|             product.Quantity += data.Quantity; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             // Step 4: Merge current status with new product | ||||
|             currentBasket.Items.Add(new BasketDataItem() | ||||
|             { | ||||
|                 UnitPrice = item.Price, | ||||
|                 PictureUrl = item.PictureUri, | ||||
|                 ProductId = item.Id, | ||||
|                 ProductName = item.Name, | ||||
|                 Quantity = data.Quantity, | ||||
|                 Id = Guid.NewGuid().ToString() | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         // Step 5: Update basket | ||||
|         await _basket.UpdateAsync(currentBasket); | ||||
| 
 | ||||
|         return Ok(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,14 +1,11 @@ | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers; | ||||
| 
 | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers | ||||
| [Route("")] | ||||
| public class HomeController : Controller | ||||
| { | ||||
|     [Route("")] | ||||
|     public class HomeController : Controller | ||||
|     [HttpGet()] | ||||
|     public IActionResult Index() | ||||
|     { | ||||
|         [HttpGet()] | ||||
|         public IActionResult Index() | ||||
|         { | ||||
|             return new RedirectResult("~/swagger"); | ||||
|         } | ||||
|         return new RedirectResult("~/swagger"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,44 +1,36 @@ | ||||
| using Microsoft.AspNetCore.Authorization; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||
| using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; | ||||
| using System.Net; | ||||
| using System.Threading.Tasks; | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers; | ||||
| 
 | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers | ||||
| [Route("api/v1/[controller]")]
 | ||||
| [Authorize] | ||||
| [ApiController] | ||||
| public class OrderController : ControllerBase | ||||
| { | ||||
|     [Route("api/v1/[controller]")]
 | ||||
|     [Authorize] | ||||
|     [ApiController] | ||||
|     public class OrderController : ControllerBase | ||||
|     private readonly IBasketService _basketService; | ||||
|     private readonly IOrderingService _orderingService; | ||||
|     public OrderController(IBasketService basketService, IOrderingService orderingService) | ||||
|     { | ||||
|         private readonly IBasketService _basketService; | ||||
|         private readonly IOrderingService _orderingService; | ||||
|         public OrderController(IBasketService basketService, IOrderingService orderingService) | ||||
|         _basketService = basketService; | ||||
|         _orderingService = orderingService; | ||||
|     } | ||||
| 
 | ||||
|     [Route("draft/{basketId}")] | ||||
|     [HttpGet] | ||||
|     [ProducesResponseType((int)HttpStatusCode.BadRequest)] | ||||
|     [ProducesResponseType(typeof(OrderData), (int)HttpStatusCode.OK)] | ||||
|     public async Task<ActionResult<OrderData>> GetOrderDraftAsync(string basketId) | ||||
|     { | ||||
|         if (string.IsNullOrEmpty(basketId)) | ||||
|         { | ||||
|             _basketService = basketService; | ||||
|             _orderingService = orderingService; | ||||
|             return BadRequest("Need a valid basketid"); | ||||
|         } | ||||
|         // Get the basket data and build a order draft based on it | ||||
|         var basket = await _basketService.GetById(basketId); | ||||
| 
 | ||||
|         if (basket == null) | ||||
|         { | ||||
|             return BadRequest($"No basket found for id {basketId}"); | ||||
|         } | ||||
| 
 | ||||
|         [Route("draft/{basketId}")] | ||||
|         [HttpGet] | ||||
|         [ProducesResponseType((int)HttpStatusCode.BadRequest)] | ||||
|         [ProducesResponseType(typeof(OrderData), (int)HttpStatusCode.OK)] | ||||
|         public async Task<ActionResult<OrderData>> GetOrderDraftAsync(string basketId) | ||||
|         { | ||||
|             if (string.IsNullOrEmpty(basketId)) | ||||
|             { | ||||
|                 return BadRequest("Need a valid basketid"); | ||||
|             } | ||||
|             // Get the basket data and build a order draft based on it | ||||
|             var basket = await _basketService.GetById(basketId); | ||||
| 
 | ||||
|             if (basket == null) | ||||
|             { | ||||
|                 return BadRequest($"No basket found for id {basketId}"); | ||||
|             } | ||||
| 
 | ||||
|             return await _orderingService.GetOrderDraftAsync(basket); | ||||
|         } | ||||
|         return await _orderingService.GetOrderDraftAsync(basket); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,10 +1,4 @@ | ||||
| using Microsoft.AspNetCore.Authorization; | ||||
| using Microsoft.OpenApi.Models; | ||||
| using Swashbuckle.AspNetCore.SwaggerGen; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| 
 | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters | ||||
| { | ||||
|     namespace Basket.API.Infrastructure.Filters | ||||
|     { | ||||
| @ -14,7 +8,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters | ||||
|             { | ||||
|                 // Check for authorize attribute | ||||
|                 var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any() || | ||||
|                                    context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any(); | ||||
|                                     context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any(); | ||||
| 
 | ||||
|                 if (!hasAuthorize) return; | ||||
| 
 | ||||
| @ -27,13 +21,14 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters | ||||
|                 }; | ||||
| 
 | ||||
|                 operation.Security = new List<OpenApiSecurityRequirement> | ||||
|             { | ||||
|                 new OpenApiSecurityRequirement | ||||
|                 { | ||||
|                     new OpenApiSecurityRequirement | ||||
|                     { | ||||
|                         [ oAuthScheme ] = new [] { "Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator" } | ||||
|                     } | ||||
|                 }; | ||||
|                     [ oAuthScheme ] = new [] { "Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator" } | ||||
|                 } | ||||
|             }; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| } | ||||
| @ -1,41 +1,35 @@ | ||||
| using Grpc.Core; | ||||
| using Grpc.Core.Interceptors; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using System.Threading.Tasks; | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure; | ||||
| 
 | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure | ||||
| public class GrpcExceptionInterceptor : Interceptor | ||||
| { | ||||
|     public class GrpcExceptionInterceptor : Interceptor | ||||
|     private readonly ILogger<GrpcExceptionInterceptor> _logger; | ||||
| 
 | ||||
|     public GrpcExceptionInterceptor(ILogger<GrpcExceptionInterceptor> logger) | ||||
|     { | ||||
|         private readonly ILogger<GrpcExceptionInterceptor> _logger; | ||||
|         _logger = logger; | ||||
|     } | ||||
| 
 | ||||
|         public GrpcExceptionInterceptor(ILogger<GrpcExceptionInterceptor> logger) | ||||
|     public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>( | ||||
|         TRequest request, | ||||
|         ClientInterceptorContext<TRequest, TResponse> context, | ||||
|         AsyncUnaryCallContinuation<TRequest, TResponse> continuation) | ||||
|     { | ||||
|         var call = continuation(request, context); | ||||
| 
 | ||||
|         return new AsyncUnaryCall<TResponse>(HandleResponse(call.ResponseAsync), call.ResponseHeadersAsync, call.GetStatus, call.GetTrailers, call.Dispose); | ||||
|     } | ||||
| 
 | ||||
|     private async Task<TResponse> HandleResponse<TResponse>(Task<TResponse> t) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             _logger = logger; | ||||
|             var response = await t; | ||||
|             return response; | ||||
|         } | ||||
| 
 | ||||
|         public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>( | ||||
|             TRequest request, | ||||
|             ClientInterceptorContext<TRequest, TResponse> context, | ||||
|             AsyncUnaryCallContinuation<TRequest, TResponse> continuation) | ||||
|         catch (RpcException e) | ||||
|         { | ||||
|             var call = continuation(request, context); | ||||
| 
 | ||||
|             return new AsyncUnaryCall<TResponse>(HandleResponse(call.ResponseAsync), call.ResponseHeadersAsync, call.GetStatus, call.GetTrailers, call.Dispose); | ||||
|         } | ||||
| 
 | ||||
|         private async Task<TResponse> HandleResponse<TResponse>(Task<TResponse> t) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 var response = await t; | ||||
|                 return response; | ||||
|             } | ||||
|             catch (RpcException e) | ||||
|             { | ||||
|                 _logger.LogError("Error calling via grpc: {Status} - {Message}", e.Status, e.Message); | ||||
|                 return default; | ||||
|             } | ||||
|             _logger.LogError("Error calling via grpc: {Status} - {Message}", e.Status, e.Message); | ||||
|             return default; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,49 +1,40 @@ | ||||
| using Microsoft.AspNetCore.Authentication; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using System.Collections.Generic; | ||||
| using System.Net.Http; | ||||
| using System.Net.Http.Headers; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure; | ||||
| 
 | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure | ||||
| public class HttpClientAuthorizationDelegatingHandler | ||||
|         : DelegatingHandler | ||||
| { | ||||
|     public class HttpClientAuthorizationDelegatingHandler | ||||
|          : DelegatingHandler | ||||
|     private readonly IHttpContextAccessor _httpContextAccessor; | ||||
| 
 | ||||
|     public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccessor) | ||||
|     { | ||||
|         private readonly IHttpContextAccessor _httpContextAccessor; | ||||
|         _httpContextAccessor = httpContextAccessor; | ||||
|     } | ||||
| 
 | ||||
|         public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccessor) | ||||
|     protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) | ||||
|     { | ||||
|         var authorizationHeader = _httpContextAccessor.HttpContext | ||||
|             .Request.Headers["Authorization"]; | ||||
| 
 | ||||
|         if (!string.IsNullOrEmpty(authorizationHeader)) | ||||
|         { | ||||
|             _httpContextAccessor = httpContextAccessor; | ||||
|             request.Headers.Add("Authorization", new List<string>() { authorizationHeader }); | ||||
|         } | ||||
| 
 | ||||
|         protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) | ||||
|         var token = await GetToken(); | ||||
| 
 | ||||
|         if (token != null) | ||||
|         { | ||||
|             var authorizationHeader = _httpContextAccessor.HttpContext | ||||
|                 .Request.Headers["Authorization"]; | ||||
| 
 | ||||
|             if (!string.IsNullOrEmpty(authorizationHeader)) | ||||
|             { | ||||
|                 request.Headers.Add("Authorization", new List<string>() { authorizationHeader }); | ||||
|             } | ||||
| 
 | ||||
|             var token = await GetToken(); | ||||
| 
 | ||||
|             if (token != null) | ||||
|             { | ||||
|                 request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); | ||||
|             } | ||||
| 
 | ||||
|             return await base.SendAsync(request, cancellationToken); | ||||
|             request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); | ||||
|         } | ||||
| 
 | ||||
|         async Task<string> GetToken() | ||||
|         { | ||||
|             const string ACCESS_TOKEN = "access_token"; | ||||
|         return await base.SendAsync(request, cancellationToken); | ||||
|     } | ||||
| 
 | ||||
|             return await _httpContextAccessor.HttpContext | ||||
|                 .GetTokenAsync(ACCESS_TOKEN); | ||||
|         } | ||||
|     async Task<string> GetToken() | ||||
|     { | ||||
|         const string ACCESS_TOKEN = "access_token"; | ||||
| 
 | ||||
|         return await _httpContextAccessor.HttpContext | ||||
|             .GetTokenAsync(ACCESS_TOKEN); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,18 +1,16 @@ | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||
| 
 | ||||
| public class AddBasketItemRequest | ||||
| { | ||||
|     public int CatalogItemId { get; set; } | ||||
| 
 | ||||
|     public class AddBasketItemRequest | ||||
|     public string BasketId { get; set; } | ||||
| 
 | ||||
|     public int Quantity { get; set; } | ||||
| 
 | ||||
|     public AddBasketItemRequest() | ||||
|     { | ||||
|         public int CatalogItemId { get; set; } | ||||
| 
 | ||||
|         public string BasketId { get; set; } | ||||
| 
 | ||||
|         public int Quantity { get; set; } | ||||
| 
 | ||||
|         public AddBasketItemRequest() | ||||
|         { | ||||
|             Quantity = 1; | ||||
|         } | ||||
|         Quantity = 1; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,22 +1,18 @@ | ||||
| using System.Collections.Generic; | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||
| 
 | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models | ||||
| public class BasketData | ||||
| { | ||||
|     public string BuyerId { get; set; } | ||||
| 
 | ||||
|     public class BasketData | ||||
|     public List<BasketDataItem> Items { get; set; } = new List<BasketDataItem>(); | ||||
| 
 | ||||
|     public BasketData() | ||||
|     { | ||||
|         public string BuyerId { get; set; } | ||||
| 
 | ||||
|         public List<BasketDataItem> Items { get; set; } = new List<BasketDataItem>(); | ||||
| 
 | ||||
|         public BasketData() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         public BasketData(string buyerId) | ||||
|         { | ||||
|             BuyerId = buyerId; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public BasketData(string buyerId) | ||||
|     { | ||||
|         BuyerId = buyerId; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,21 +1,18 @@ | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||
| 
 | ||||
| public class BasketDataItem | ||||
| { | ||||
|     public string Id { get; set; } | ||||
| 
 | ||||
|     public class BasketDataItem | ||||
|     { | ||||
|         public string Id { get; set; } | ||||
|     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 OldUnitPrice { get; set; } | ||||
| 
 | ||||
|         public decimal OldUnitPrice { get; set; } | ||||
| 
 | ||||
|         public int Quantity { get; set; } | ||||
| 
 | ||||
|         public string PictureUrl { get; set; } | ||||
|     } | ||||
|     public int Quantity { get; set; } | ||||
| 
 | ||||
|     public string PictureUrl { get; set; } | ||||
| } | ||||
|  | ||||
| @ -1,15 +1,14 @@ | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||
| 
 | ||||
| public class CatalogItem | ||||
| { | ||||
|     public int Id { get; set; } | ||||
| 
 | ||||
|     public class CatalogItem | ||||
|     { | ||||
|         public int Id { get; set; } | ||||
|     public string Name { get; set; } | ||||
| 
 | ||||
|         public string Name { get; set; } | ||||
| 
 | ||||
|         public decimal Price { get; set; } | ||||
| 
 | ||||
|         public string PictureUri { get; set; } | ||||
|     } | ||||
|     public decimal Price { get; set; } | ||||
| 
 | ||||
|     public string PictureUri { get; set; } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -1,48 +1,43 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||
| 
 | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models | ||||
| public class OrderData | ||||
| { | ||||
|     public string OrderNumber { get; set; } | ||||
| 
 | ||||
|     public class OrderData | ||||
|     { | ||||
|         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 List<OrderItemData> OrderItems { get; } = new List<OrderItemData>(); | ||||
|     } | ||||
|     public string Buyer { get; set; } | ||||
| 
 | ||||
|     public List<OrderItemData> OrderItems { get; } = new List<OrderItemData>(); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,19 +1,16 @@ | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||
| 
 | ||||
| public class OrderItemData | ||||
| { | ||||
|     public int ProductId { get; set; } | ||||
| 
 | ||||
|     public class OrderItemData | ||||
|     { | ||||
|         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 string PictureUrl { get; set; } | ||||
|     } | ||||
|     public int Units { get; set; } | ||||
| 
 | ||||
|     public string PictureUrl { get; set; } | ||||
| } | ||||
|  | ||||
| @ -1,16 +1,13 @@ | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||
| 
 | ||||
| public class UpdateBasketItemData | ||||
| { | ||||
|     public string BasketItemId { get; set; } | ||||
| 
 | ||||
|     public class UpdateBasketItemData | ||||
|     public int NewQty { get; set; } | ||||
| 
 | ||||
|     public UpdateBasketItemData() | ||||
|     { | ||||
|         public string BasketItemId { get; set; } | ||||
| 
 | ||||
|         public int NewQty { get; set; } | ||||
| 
 | ||||
|         public UpdateBasketItemData() | ||||
|         { | ||||
|             NewQty = 0; | ||||
|         } | ||||
|         NewQty = 0; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -1,18 +1,13 @@ | ||||
| using System.Collections.Generic; | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||
| 
 | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models | ||||
| public class UpdateBasketItemsRequest | ||||
| { | ||||
|     public string BasketId { get; set; } | ||||
| 
 | ||||
|     public class UpdateBasketItemsRequest | ||||
|     public ICollection<UpdateBasketItemData> Updates { get; set; } | ||||
| 
 | ||||
|     public UpdateBasketItemsRequest() | ||||
|     { | ||||
|         public string BasketId { get; set; } | ||||
| 
 | ||||
|         public ICollection<UpdateBasketItemData> Updates { get; set; } | ||||
| 
 | ||||
|         public UpdateBasketItemsRequest() | ||||
|         { | ||||
|             Updates = new List<UpdateBasketItemData>(); | ||||
|         } | ||||
|         Updates = new List<UpdateBasketItemData>(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -1,13 +1,8 @@ | ||||
| using System.Collections.Generic; | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||
| 
 | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models | ||||
| public class UpdateBasketRequest | ||||
| { | ||||
|     public string BuyerId { get; set; } | ||||
| 
 | ||||
|     public class UpdateBasketRequest | ||||
|     { | ||||
|         public string BuyerId { get; set; } | ||||
| 
 | ||||
|         public IEnumerable<UpdateBasketRequestItemData> Items { get; set; } | ||||
|     } | ||||
| 
 | ||||
|     public IEnumerable<UpdateBasketRequestItemData> Items { get; set; } | ||||
| } | ||||
|  | ||||
| @ -1,11 +1,10 @@ | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||
| 
 | ||||
| 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 | ||||
| } | ||||
|  | ||||
| @ -1,9 +1,4 @@ | ||||
| using Microsoft.AspNetCore; | ||||
| using Microsoft.AspNetCore.Hosting; | ||||
| using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator; | ||||
| using Serilog; | ||||
| 
 | ||||
| BuildWebHost(args).Run(); | ||||
| BuildWebHost(args).Run(); | ||||
| 
 | ||||
| IWebHost BuildWebHost(string[] args) => | ||||
|     WebHost | ||||
|  | ||||
| @ -1,103 +1,96 @@ | ||||
| using GrpcBasket; | ||||
| using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; | ||||
| 
 | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services | ||||
| public class BasketService : IBasketService | ||||
| { | ||||
|     public class BasketService : IBasketService | ||||
|     private readonly Basket.BasketClient _basketClient; | ||||
|     private readonly ILogger<BasketService> _logger; | ||||
| 
 | ||||
|     public BasketService(Basket.BasketClient basketClient, ILogger<BasketService> logger) | ||||
|     { | ||||
|         private readonly Basket.BasketClient _basketClient; | ||||
|         private readonly ILogger<BasketService> _logger; | ||||
|         _basketClient = basketClient; | ||||
|         _logger = logger; | ||||
|     } | ||||
| 
 | ||||
|         public BasketService(Basket.BasketClient basketClient, ILogger<BasketService> logger) | ||||
| 
 | ||||
|     public async Task<BasketData> GetById(string id) | ||||
|     { | ||||
|         _logger.LogDebug("grpc client created, request = {@id}", id); | ||||
|         var response = await _basketClient.GetBasketByIdAsync(new BasketRequest { Id = id }); | ||||
|         _logger.LogDebug("grpc response {@response}", response); | ||||
| 
 | ||||
|         return MapToBasketData(response); | ||||
|     } | ||||
| 
 | ||||
|     public async Task UpdateAsync(BasketData currentBasket) | ||||
|     { | ||||
|         _logger.LogDebug("Grpc update basket currentBasket {@currentBasket}", currentBasket); | ||||
|         var request = MapToCustomerBasketRequest(currentBasket); | ||||
|         _logger.LogDebug("Grpc update basket request {@request}", request); | ||||
| 
 | ||||
|         await _basketClient.UpdateBasketAsync(request); | ||||
|     } | ||||
| 
 | ||||
|     private BasketData MapToBasketData(CustomerBasketResponse customerBasketRequest) | ||||
|     { | ||||
|         if (customerBasketRequest == null) | ||||
|         { | ||||
|             _basketClient = basketClient; | ||||
|             _logger = logger; | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         public async Task<BasketData> GetById(string id) | ||||
|         var map = new BasketData | ||||
|         { | ||||
|             _logger.LogDebug("grpc client created, request = {@id}", id); | ||||
|             var response = await _basketClient.GetBasketByIdAsync(new BasketRequest { Id = id }); | ||||
|             _logger.LogDebug("grpc response {@response}", response); | ||||
|             BuyerId = customerBasketRequest.Buyerid | ||||
|         }; | ||||
| 
 | ||||
|             return MapToBasketData(response); | ||||
|         } | ||||
| 
 | ||||
|         public async Task UpdateAsync(BasketData currentBasket) | ||||
|         customerBasketRequest.Items.ToList().ForEach(item => | ||||
|         { | ||||
|             _logger.LogDebug("Grpc update basket currentBasket {@currentBasket}", currentBasket); | ||||
|             var request = MapToCustomerBasketRequest(currentBasket); | ||||
|             _logger.LogDebug("Grpc update basket request {@request}", request); | ||||
| 
 | ||||
|             await _basketClient.UpdateBasketAsync(request); | ||||
|         } | ||||
| 
 | ||||
|         private BasketData MapToBasketData(CustomerBasketResponse customerBasketRequest) | ||||
|         { | ||||
|             if (customerBasketRequest == null) | ||||
|             if (item.Id != null) | ||||
|             { | ||||
|                 return null; | ||||
|             } | ||||
| 
 | ||||
|             var map = new BasketData | ||||
|             { | ||||
|                 BuyerId = customerBasketRequest.Buyerid | ||||
|             }; | ||||
| 
 | ||||
|             customerBasketRequest.Items.ToList().ForEach(item => | ||||
|             { | ||||
|                 if (item.Id != null) | ||||
|                 map.Items.Add(new BasketDataItem | ||||
|                 { | ||||
|                     map.Items.Add(new BasketDataItem | ||||
|                     { | ||||
|                         Id = item.Id, | ||||
|                         OldUnitPrice = (decimal)item.Oldunitprice, | ||||
|                         PictureUrl = item.Pictureurl, | ||||
|                         ProductId = item.Productid, | ||||
|                         ProductName = item.Productname, | ||||
|                         Quantity = item.Quantity, | ||||
|                         UnitPrice = (decimal)item.Unitprice | ||||
|                     }); | ||||
|                 } | ||||
|             }); | ||||
| 
 | ||||
|             return map; | ||||
|         } | ||||
| 
 | ||||
|         private CustomerBasketRequest MapToCustomerBasketRequest(BasketData basketData) | ||||
|         { | ||||
|             if (basketData == null) | ||||
|             { | ||||
|                 return null; | ||||
|                     Id = item.Id, | ||||
|                     OldUnitPrice = (decimal)item.Oldunitprice, | ||||
|                     PictureUrl = item.Pictureurl, | ||||
|                     ProductId = item.Productid, | ||||
|                     ProductName = item.Productname, | ||||
|                     Quantity = item.Quantity, | ||||
|                     UnitPrice = (decimal)item.Unitprice | ||||
|                 }); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|             var map = new CustomerBasketRequest | ||||
|             { | ||||
|                 Buyerid = basketData.BuyerId | ||||
|             }; | ||||
|         return map; | ||||
|     } | ||||
| 
 | ||||
|             basketData.Items.ToList().ForEach(item => | ||||
|             { | ||||
|                 if (item.Id != null) | ||||
|                 { | ||||
|                     map.Items.Add(new BasketItemResponse | ||||
|                     { | ||||
|                         Id = item.Id, | ||||
|                         Oldunitprice = (double)item.OldUnitPrice, | ||||
|                         Pictureurl = item.PictureUrl, | ||||
|                         Productid = item.ProductId, | ||||
|                         Productname = item.ProductName, | ||||
|                         Quantity = item.Quantity, | ||||
|                         Unitprice = (double)item.UnitPrice | ||||
|                     }); | ||||
|                 } | ||||
|             }); | ||||
| 
 | ||||
|             return map; | ||||
|     private CustomerBasketRequest MapToCustomerBasketRequest(BasketData basketData) | ||||
|     { | ||||
|         if (basketData == null) | ||||
|         { | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|         var map = new CustomerBasketRequest | ||||
|         { | ||||
|             Buyerid = basketData.BuyerId | ||||
|         }; | ||||
| 
 | ||||
|         basketData.Items.ToList().ForEach(item => | ||||
|         { | ||||
|             if (item.Id != null) | ||||
|             { | ||||
|                 map.Items.Add(new BasketItemResponse | ||||
|                 { | ||||
|                     Id = item.Id, | ||||
|                     Oldunitprice = (double)item.OldUnitPrice, | ||||
|                     Pictureurl = item.PictureUrl, | ||||
|                     Productid = item.ProductId, | ||||
|                     Productname = item.ProductName, | ||||
|                     Quantity = item.Quantity, | ||||
|                     Unitprice = (double)item.UnitPrice | ||||
|                 }); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         return map; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,52 +1,44 @@ | ||||
| using CatalogApi; | ||||
| using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||
| using Microsoft.Extensions.Logging; | ||||
| 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 class CatalogService : ICatalogService | ||||
| { | ||||
|     public class CatalogService : ICatalogService | ||||
|     private readonly Catalog.CatalogClient _client; | ||||
|     private readonly ILogger<CatalogService> _logger; | ||||
| 
 | ||||
|     public CatalogService(Catalog.CatalogClient client, ILogger<CatalogService> logger) | ||||
|     { | ||||
|         private readonly Catalog.CatalogClient _client; | ||||
|         private readonly ILogger<CatalogService> _logger; | ||||
|         _client = client; | ||||
|         _logger = logger; | ||||
|     } | ||||
| 
 | ||||
|         public CatalogService(Catalog.CatalogClient client, ILogger<CatalogService> logger) | ||||
|     public async Task<CatalogItem> GetCatalogItemAsync(int id) | ||||
|     { | ||||
|         var request = new CatalogItemRequest { Id = id }; | ||||
|         _logger.LogInformation("grpc request {@request}", request); | ||||
|         var response = await _client.GetItemByIdAsync(request); | ||||
|         _logger.LogInformation("grpc response {@response}", response); | ||||
|         return MapToCatalogItemResponse(response); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public async Task<IEnumerable<CatalogItem>> GetCatalogItemsAsync(IEnumerable<int> ids) | ||||
|     { | ||||
|         var request = new CatalogItemsRequest { Ids = string.Join(",", ids), PageIndex = 1, PageSize = 10 }; | ||||
|         _logger.LogInformation("grpc request {@request}", request); | ||||
|         var response = await _client.GetItemsByIdsAsync(request); | ||||
|         _logger.LogInformation("grpc response {@response}", response); | ||||
|         return response.Data.Select(this.MapToCatalogItemResponse); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     private CatalogItem MapToCatalogItemResponse(CatalogItemResponse catalogItemResponse) | ||||
|     { | ||||
|         return new CatalogItem | ||||
|         { | ||||
|             _client = client; | ||||
|             _logger = logger; | ||||
|         } | ||||
| 
 | ||||
|         public async Task<CatalogItem> GetCatalogItemAsync(int id) | ||||
|         { | ||||
|             var request = new CatalogItemRequest { Id = id }; | ||||
|             _logger.LogInformation("grpc request {@request}", request); | ||||
|             var response = await _client.GetItemByIdAsync(request); | ||||
|             _logger.LogInformation("grpc response {@response}", response); | ||||
|             return MapToCatalogItemResponse(response); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         public async Task<IEnumerable<CatalogItem>> GetCatalogItemsAsync(IEnumerable<int> ids) | ||||
|         { | ||||
|             var request = new CatalogItemsRequest { Ids = string.Join(",", ids), PageIndex = 1, PageSize = 10 }; | ||||
|             _logger.LogInformation("grpc request {@request}", request); | ||||
|             var response = await _client.GetItemsByIdsAsync(request); | ||||
|             _logger.LogInformation("grpc response {@response}", response); | ||||
|             return response.Data.Select(this.MapToCatalogItemResponse); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         private CatalogItem MapToCatalogItemResponse(CatalogItemResponse catalogItemResponse) | ||||
|         { | ||||
|             return new CatalogItem | ||||
|             { | ||||
|                 Id = catalogItemResponse.Id, | ||||
|                 Name = catalogItemResponse.Name, | ||||
|                 PictureUri = catalogItemResponse.PictureUri, | ||||
|                 Price = (decimal)catalogItemResponse.Price | ||||
|             }; | ||||
|         } | ||||
|             Id = catalogItemResponse.Id, | ||||
|             Name = catalogItemResponse.Name, | ||||
|             PictureUri = catalogItemResponse.PictureUri, | ||||
|             Price = (decimal)catalogItemResponse.Price | ||||
|         }; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,12 +1,8 @@ | ||||
| using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||
| using System.Threading.Tasks; | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; | ||||
| 
 | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services | ||||
| public interface IBasketService | ||||
| { | ||||
|     public interface IBasketService | ||||
|     { | ||||
|         Task<BasketData> GetById(string id); | ||||
|     Task<BasketData> GetById(string id); | ||||
| 
 | ||||
|         Task UpdateAsync(BasketData currentBasket); | ||||
|     } | ||||
|     Task UpdateAsync(BasketData currentBasket); | ||||
| } | ||||
|  | ||||
| @ -1,13 +1,8 @@ | ||||
| using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||
| using System.Collections.Generic; | ||||
| using System.Threading.Tasks; | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; | ||||
| 
 | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services | ||||
| public interface ICatalogService | ||||
| { | ||||
|     public interface ICatalogService | ||||
|     { | ||||
|         Task<CatalogItem> GetCatalogItemAsync(int id); | ||||
|     Task<CatalogItem> GetCatalogItemAsync(int id); | ||||
| 
 | ||||
|         Task<IEnumerable<CatalogItem>> GetCatalogItemsAsync(IEnumerable<int> ids); | ||||
|     } | ||||
|     Task<IEnumerable<CatalogItem>> GetCatalogItemsAsync(IEnumerable<int> ids); | ||||
| } | ||||
|  | ||||
| @ -1,10 +1,6 @@ | ||||
| using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||
| using System.Threading.Tasks; | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; | ||||
| 
 | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services | ||||
| public interface IOrderApiClient | ||||
| { | ||||
|     public interface IOrderApiClient | ||||
|     { | ||||
|         Task<OrderData> GetOrderDraftFromBasketAsync(BasketData basket); | ||||
|     } | ||||
|     Task<OrderData> GetOrderDraftFromBasketAsync(BasketData basket); | ||||
| } | ||||
|  | ||||
| @ -1,10 +1,6 @@ | ||||
| using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||
| using System.Threading.Tasks; | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; | ||||
| 
 | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services | ||||
| public interface IOrderingService | ||||
| { | ||||
|     public interface IOrderingService | ||||
|     { | ||||
|         Task<OrderData> GetOrderDraftAsync(BasketData basketData); | ||||
|     } | ||||
| } | ||||
|     Task<OrderData> GetOrderDraftAsync(BasketData basketData); | ||||
| } | ||||
|  | ||||
| @ -1,40 +1,31 @@ | ||||
| using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config; | ||||
| using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using Microsoft.Extensions.Options; | ||||
| using System.Net.Http; | ||||
| using System.Threading.Tasks; | ||||
| using System.Text.Json; | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; | ||||
| 
 | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services | ||||
| public class OrderApiClient : IOrderApiClient | ||||
| { | ||||
|     public class OrderApiClient : IOrderApiClient | ||||
|     private readonly HttpClient _apiClient; | ||||
|     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; | ||||
|         private readonly UrlsConfig _urls; | ||||
|         _apiClient = httpClient; | ||||
|         _logger = logger; | ||||
|         _urls = config.Value; | ||||
|     } | ||||
| 
 | ||||
|         public OrderApiClient(HttpClient httpClient, ILogger<OrderApiClient> logger, IOptions<UrlsConfig> config) | ||||
|     public async Task<OrderData> GetOrderDraftFromBasketAsync(BasketData basket) | ||||
|     { | ||||
|         var url = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft(); | ||||
|         var content = new StringContent(JsonSerializer.Serialize(basket), System.Text.Encoding.UTF8, "application/json"); | ||||
|         var response = await _apiClient.PostAsync(url, content); | ||||
| 
 | ||||
|         response.EnsureSuccessStatusCode(); | ||||
| 
 | ||||
|         var ordersDraftResponse = await response.Content.ReadAsStringAsync(); | ||||
| 
 | ||||
|         return JsonSerializer.Deserialize<OrderData>(ordersDraftResponse, new JsonSerializerOptions | ||||
|         { | ||||
|             _apiClient = httpClient; | ||||
|             _logger = logger; | ||||
|             _urls = config.Value; | ||||
|         } | ||||
| 
 | ||||
|         public async Task<OrderData> GetOrderDraftFromBasketAsync(BasketData basket) | ||||
|         { | ||||
|             var url = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft(); | ||||
|             var content = new StringContent(JsonSerializer.Serialize(basket), System.Text.Encoding.UTF8, "application/json"); | ||||
|             var response = await _apiClient.PostAsync(url, content); | ||||
| 
 | ||||
|             response.EnsureSuccessStatusCode(); | ||||
| 
 | ||||
|             var ordersDraftResponse = await response.Content.ReadAsStringAsync(); | ||||
| 
 | ||||
|             return JsonSerializer.Deserialize<OrderData>(ordersDraftResponse, new JsonSerializerOptions | ||||
|             { | ||||
|                 PropertyNameCaseInsensitive = true | ||||
|             }); | ||||
|         } | ||||
|             PropertyNameCaseInsensitive = true | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,79 +1,72 @@ | ||||
| using GrpcOrdering; | ||||
| using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; | ||||
| 
 | ||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services | ||||
| public class OrderingService : IOrderingService | ||||
| { | ||||
|     public class OrderingService : IOrderingService | ||||
|     private readonly OrderingGrpc.OrderingGrpcClient _orderingGrpcClient; | ||||
|     private readonly ILogger<OrderingService> _logger; | ||||
| 
 | ||||
|     public OrderingService(OrderingGrpc.OrderingGrpcClient orderingGrpcClient, ILogger<OrderingService> logger) | ||||
|     { | ||||
|         private readonly OrderingGrpc.OrderingGrpcClient _orderingGrpcClient; | ||||
|         private readonly ILogger<OrderingService> _logger; | ||||
| 
 | ||||
|         public OrderingService(OrderingGrpc.OrderingGrpcClient orderingGrpcClient, ILogger<OrderingService> logger) | ||||
|         { | ||||
|             _orderingGrpcClient = orderingGrpcClient; | ||||
|             _logger = logger; | ||||
|         } | ||||
| 
 | ||||
|         public async Task<OrderData> GetOrderDraftAsync(BasketData basketData) | ||||
|         { | ||||
|             _logger.LogDebug(" grpc client created, basketData={@basketData}", basketData); | ||||
| 
 | ||||
|             var command = MapToOrderDraftCommand(basketData); | ||||
|             var response = await _orderingGrpcClient.CreateOrderDraftFromBasketDataAsync(command); | ||||
|             _logger.LogDebug(" grpc response: {@response}", response); | ||||
| 
 | ||||
|             return MapToResponse(response, basketData); | ||||
|         } | ||||
| 
 | ||||
|         private OrderData MapToResponse(GrpcOrdering.OrderDraftDTO orderDraft, BasketData basketData) | ||||
|         { | ||||
|             if (orderDraft == null) | ||||
|             { | ||||
|                 return null; | ||||
|             } | ||||
| 
 | ||||
|             var data = new OrderData | ||||
|             { | ||||
|                 Buyer = basketData.BuyerId, | ||||
|                 Total = (decimal)orderDraft.Total, | ||||
|             }; | ||||
| 
 | ||||
|             orderDraft.OrderItems.ToList().ForEach(o => data.OrderItems.Add(new OrderItemData | ||||
|             { | ||||
|                 Discount = (decimal)o.Discount, | ||||
|                 PictureUrl = o.PictureUrl, | ||||
|                 ProductId = o.ProductId, | ||||
|                 ProductName = o.ProductName, | ||||
|                 UnitPrice = (decimal)o.UnitPrice, | ||||
|                 Units = o.Units, | ||||
|             })); | ||||
| 
 | ||||
|             return data; | ||||
|         } | ||||
| 
 | ||||
|         private CreateOrderDraftCommand MapToOrderDraftCommand(BasketData basketData) | ||||
|         { | ||||
|             var command = new CreateOrderDraftCommand | ||||
|             { | ||||
|                 BuyerId = basketData.BuyerId, | ||||
|             }; | ||||
| 
 | ||||
|             basketData.Items.ForEach(i => command.Items.Add(new BasketItem | ||||
|             { | ||||
|                 Id = i.Id, | ||||
|                 OldUnitPrice = (double)i.OldUnitPrice, | ||||
|                 PictureUrl = i.PictureUrl, | ||||
|                 ProductId = i.ProductId, | ||||
|                 ProductName = i.ProductName, | ||||
|                 Quantity = i.Quantity, | ||||
|                 UnitPrice = (double)i.UnitPrice, | ||||
|             })); | ||||
| 
 | ||||
|             return command; | ||||
|         } | ||||
| 
 | ||||
|         _orderingGrpcClient = orderingGrpcClient; | ||||
|         _logger = logger; | ||||
|     } | ||||
| 
 | ||||
|     public async Task<OrderData> GetOrderDraftAsync(BasketData basketData) | ||||
|     { | ||||
|         _logger.LogDebug(" grpc client created, basketData={@basketData}", basketData); | ||||
| 
 | ||||
|         var command = MapToOrderDraftCommand(basketData); | ||||
|         var response = await _orderingGrpcClient.CreateOrderDraftFromBasketDataAsync(command); | ||||
|         _logger.LogDebug(" grpc response: {@response}", response); | ||||
| 
 | ||||
|         return MapToResponse(response, basketData); | ||||
|     } | ||||
| 
 | ||||
|     private OrderData MapToResponse(GrpcOrdering.OrderDraftDTO orderDraft, BasketData basketData) | ||||
|     { | ||||
|         if (orderDraft == null) | ||||
|         { | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|         var data = new OrderData | ||||
|         { | ||||
|             Buyer = basketData.BuyerId, | ||||
|             Total = (decimal)orderDraft.Total, | ||||
|         }; | ||||
| 
 | ||||
|         orderDraft.OrderItems.ToList().ForEach(o => data.OrderItems.Add(new OrderItemData | ||||
|         { | ||||
|             Discount = (decimal)o.Discount, | ||||
|             PictureUrl = o.PictureUrl, | ||||
|             ProductId = o.ProductId, | ||||
|             ProductName = o.ProductName, | ||||
|             UnitPrice = (decimal)o.UnitPrice, | ||||
|             Units = o.Units, | ||||
|         })); | ||||
| 
 | ||||
|         return data; | ||||
|     } | ||||
| 
 | ||||
|     private CreateOrderDraftCommand MapToOrderDraftCommand(BasketData basketData) | ||||
|     { | ||||
|         var command = new CreateOrderDraftCommand | ||||
|         { | ||||
|             BuyerId = basketData.BuyerId, | ||||
|         }; | ||||
| 
 | ||||
|         basketData.Items.ForEach(i => command.Items.Add(new BasketItem | ||||
|         { | ||||
|             Id = i.Id, | ||||
|             OldUnitPrice = (double)i.OldUnitPrice, | ||||
|             PictureUrl = i.PictureUrl, | ||||
|             ProductId = i.ProductId, | ||||
|             ProductName = i.ProductName, | ||||
|             Quantity = i.Quantity, | ||||
|             UnitPrice = (double)i.UnitPrice, | ||||
|         })); | ||||
| 
 | ||||
|         return command; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -1,225 +1,199 @@ | ||||
| using CatalogApi; | ||||
| using Devspaces.Support; | ||||
| using GrpcBasket; | ||||
| using GrpcOrdering; | ||||
| using HealthChecks.UI.Client; | ||||
| using Microsoft.AspNetCore.Authentication.JwtBearer; | ||||
| using Microsoft.AspNetCore.Builder; | ||||
| using Microsoft.AspNetCore.Diagnostics.HealthChecks; | ||||
| using Microsoft.AspNetCore.Hosting; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config; | ||||
| using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters; | ||||
| using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure; | ||||
| using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; | ||||
| using Microsoft.Extensions.Configuration; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using Microsoft.Extensions.Diagnostics.HealthChecks; | ||||
| using Microsoft.Extensions.Hosting; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using Microsoft.Extensions.Options; | ||||
| using Microsoft.OpenApi.Models; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IdentityModel.Tokens.Jwt; | ||||
| 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; | ||||
|         } | ||||
| 
 | ||||
|         public IConfiguration Configuration { get; } | ||||
| 
 | ||||
|         // This method gets called by the runtime. Use this method to add services to the container. | ||||
|         public void ConfigureServices(IServiceCollection services) | ||||
|         { | ||||
|             services.AddHealthChecks() | ||||
|                 .AddCheck("self", () => HealthCheckResult.Healthy()) | ||||
|                 .AddUrlGroup(new Uri(Configuration["CatalogUrlHC"]), name: "catalogapi-check", tags: new string[] { "catalogapi" }) | ||||
|                 .AddUrlGroup(new Uri(Configuration["OrderingUrlHC"]), name: "orderingapi-check", tags: new string[] { "orderingapi" }) | ||||
|                 .AddUrlGroup(new Uri(Configuration["BasketUrlHC"]), name: "basketapi-check", tags: new string[] { "basketapi" }) | ||||
|                 .AddUrlGroup(new Uri(Configuration["IdentityUrlHC"]), name: "identityapi-check", tags: new string[] { "identityapi" }) | ||||
|                 .AddUrlGroup(new Uri(Configuration["PaymentUrlHC"]), name: "paymentapi-check", tags: new string[] { "paymentapi" }); | ||||
| 
 | ||||
|             services.AddCustomMvc(Configuration) | ||||
|                 .AddCustomAuthentication(Configuration) | ||||
|                 .AddDevspaces() | ||||
|                 .AddApplicationServices() | ||||
|                 .AddGrpcServices(); | ||||
|         } | ||||
| 
 | ||||
|         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. | ||||
|         public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) | ||||
|         { | ||||
|             var pathBase = Configuration["PATH_BASE"]; | ||||
|             if (!string.IsNullOrEmpty(pathBase)) | ||||
|             { | ||||
|                 loggerFactory.CreateLogger<Startup>().LogDebug("Using PATH BASE '{pathBase}'", pathBase); | ||||
|                 app.UsePathBase(pathBase); | ||||
|             } | ||||
| 
 | ||||
|             if (env.IsDevelopment()) | ||||
|             { | ||||
|                 app.UseDeveloperExceptionPage(); | ||||
|             } | ||||
| 
 | ||||
|             app.UseHttpsRedirection(); | ||||
| 
 | ||||
|             app.UseSwagger().UseSwaggerUI(c => | ||||
|             { | ||||
|                 c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1"); | ||||
| 
 | ||||
|                 c.OAuthClientId("webshoppingaggswaggerui"); | ||||
|                 c.OAuthClientSecret(string.Empty); | ||||
|                 c.OAuthRealm(string.Empty); | ||||
|                 c.OAuthAppName("web shopping bff Swagger UI"); | ||||
|             }); | ||||
| 
 | ||||
|             app.UseRouting(); | ||||
|             app.UseCors("CorsPolicy"); | ||||
|             app.UseAuthentication(); | ||||
|             app.UseAuthorization(); | ||||
| 
 | ||||
|             app.UseEndpoints(endpoints => | ||||
|             { | ||||
|                 endpoints.MapDefaultControllerRoute(); | ||||
|                 endpoints.MapControllers(); | ||||
|                 endpoints.MapHealthChecks("/hc", new HealthCheckOptions() | ||||
|                 { | ||||
|                     Predicate = _ => true, | ||||
|                     ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse | ||||
|                 }); | ||||
|                 endpoints.MapHealthChecks("/liveness", new HealthCheckOptions | ||||
|                 { | ||||
|                     Predicate = r => r.Name.Contains("self") | ||||
|                 }); | ||||
|             }); | ||||
|         } | ||||
|         Configuration = configuration; | ||||
|     } | ||||
| 
 | ||||
|     public static class ServiceCollectionExtensions | ||||
|     public IConfiguration Configuration { get; } | ||||
| 
 | ||||
|     // This method gets called by the runtime. Use this method to add services to the container. | ||||
|     public void ConfigureServices(IServiceCollection services) | ||||
|     { | ||||
|         public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) | ||||
|         services.AddHealthChecks() | ||||
|             .AddCheck("self", () => HealthCheckResult.Healthy()) | ||||
|             .AddUrlGroup(new Uri(Configuration["CatalogUrlHC"]), name: "catalogapi-check", tags: new string[] { "catalogapi" }) | ||||
|             .AddUrlGroup(new Uri(Configuration["OrderingUrlHC"]), name: "orderingapi-check", tags: new string[] { "orderingapi" }) | ||||
|             .AddUrlGroup(new Uri(Configuration["BasketUrlHC"]), name: "basketapi-check", tags: new string[] { "basketapi" }) | ||||
|             .AddUrlGroup(new Uri(Configuration["IdentityUrlHC"]), name: "identityapi-check", tags: new string[] { "identityapi" }) | ||||
|             .AddUrlGroup(new Uri(Configuration["PaymentUrlHC"]), name: "paymentapi-check", tags: new string[] { "paymentapi" }); | ||||
| 
 | ||||
|         services.AddCustomMvc(Configuration) | ||||
|             .AddCustomAuthentication(Configuration) | ||||
|             .AddDevspaces() | ||||
|             .AddApplicationServices() | ||||
|             .AddGrpcServices(); | ||||
|     } | ||||
| 
 | ||||
|     // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. | ||||
|     public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) | ||||
|     { | ||||
|         var pathBase = Configuration["PATH_BASE"]; | ||||
|         if (!string.IsNullOrEmpty(pathBase)) | ||||
|         { | ||||
|             JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub"); | ||||
|             loggerFactory.CreateLogger<Startup>().LogDebug("Using PATH BASE '{pathBase}'", pathBase); | ||||
|             app.UsePathBase(pathBase); | ||||
|         } | ||||
| 
 | ||||
|             var identityUrl = configuration.GetValue<string>("urls:identity"); | ||||
|             services.AddAuthentication(options => | ||||
|             { | ||||
|                 options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; | ||||
|                 options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; | ||||
|         if (env.IsDevelopment()) | ||||
|         { | ||||
|             app.UseDeveloperExceptionPage(); | ||||
|         } | ||||
| 
 | ||||
|             }) | ||||
|             .AddJwtBearer(options => | ||||
|         app.UseHttpsRedirection(); | ||||
| 
 | ||||
|         app.UseSwagger().UseSwaggerUI(c => | ||||
|         { | ||||
|             c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1"); | ||||
| 
 | ||||
|             c.OAuthClientId("webshoppingaggswaggerui"); | ||||
|             c.OAuthClientSecret(string.Empty); | ||||
|             c.OAuthRealm(string.Empty); | ||||
|             c.OAuthAppName("web shopping bff Swagger UI"); | ||||
|         }); | ||||
| 
 | ||||
|         app.UseRouting(); | ||||
|         app.UseCors("CorsPolicy"); | ||||
|         app.UseAuthentication(); | ||||
|         app.UseAuthorization(); | ||||
| 
 | ||||
|         app.UseEndpoints(endpoints => | ||||
|         { | ||||
|             endpoints.MapDefaultControllerRoute(); | ||||
|             endpoints.MapControllers(); | ||||
|             endpoints.MapHealthChecks("/hc", new HealthCheckOptions() | ||||
|             { | ||||
|                 options.Authority = identityUrl; | ||||
|                 options.RequireHttpsMetadata = false; | ||||
|                 options.Audience = "webshoppingagg"; | ||||
|                 Predicate = _ => true, | ||||
|                 ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse | ||||
|             }); | ||||
| 
 | ||||
|             return services; | ||||
|         } | ||||
| 
 | ||||
|         public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration) | ||||
|         { | ||||
|             services.AddOptions(); | ||||
|             services.Configure<UrlsConfig>(configuration.GetSection("urls")); | ||||
| 
 | ||||
|             services.AddControllers() | ||||
|                     .AddJsonOptions(options => options.JsonSerializerOptions.WriteIndented = true); | ||||
| 
 | ||||
|             services.AddSwaggerGen(options => | ||||
|             endpoints.MapHealthChecks("/liveness", new HealthCheckOptions | ||||
|             { | ||||
|                 options.DescribeAllEnumsAsStrings(); | ||||
| 
 | ||||
|                 options.SwaggerDoc("v1", new OpenApiInfo | ||||
|                 { | ||||
|                     Title = "Shopping Aggregator for Web Clients", | ||||
|                     Version = "v1", | ||||
|                     Description = "Shopping Aggregator for Web Clients" | ||||
|                 }); | ||||
| 
 | ||||
|                 options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme | ||||
|                 { | ||||
|                     Type = SecuritySchemeType.OAuth2, | ||||
|                     Flows = new OpenApiOAuthFlows() | ||||
|                     { | ||||
|                         Implicit = new OpenApiOAuthFlow() | ||||
|                         { | ||||
|                             AuthorizationUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize"), | ||||
|                             TokenUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token"), | ||||
| 
 | ||||
|                             Scopes = new Dictionary<string, string>() | ||||
|                             { | ||||
|                                 { "webshoppingagg", "Shopping Aggregator for Web Clients" } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 }); | ||||
| 
 | ||||
|                 options.OperationFilter<AuthorizeCheckOperationFilter>(); | ||||
|                 Predicate = r => r.Name.Contains("self") | ||||
|             }); | ||||
| 
 | ||||
|             services.AddCors(options => | ||||
|             { | ||||
|                 options.AddPolicy("CorsPolicy", | ||||
|                     builder => builder | ||||
|                     .SetIsOriginAllowed((host) => true) | ||||
|                     .AllowAnyMethod() | ||||
|                     .AllowAnyHeader() | ||||
|                     .AllowCredentials()); | ||||
|             }); | ||||
| 
 | ||||
|             return services; | ||||
|         } | ||||
|         public static IServiceCollection AddApplicationServices(this IServiceCollection services) | ||||
|         { | ||||
|             //register delegating handlers | ||||
|             services.AddTransient<HttpClientAuthorizationDelegatingHandler>(); | ||||
|             services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); | ||||
| 
 | ||||
|             //register http services | ||||
| 
 | ||||
|             services.AddHttpClient<IOrderApiClient, OrderApiClient>() | ||||
|                 .AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>() | ||||
|                 .AddDevspacesSupport(); | ||||
| 
 | ||||
|             return services; | ||||
|         } | ||||
| 
 | ||||
|         public static IServiceCollection AddGrpcServices(this IServiceCollection services) | ||||
|         { | ||||
|             services.AddTransient<GrpcExceptionInterceptor>(); | ||||
| 
 | ||||
|             services.AddScoped<IBasketService, BasketService>(); | ||||
| 
 | ||||
|             services.AddGrpcClient<Basket.BasketClient>((services, options) => | ||||
|             { | ||||
|                 var basketApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcBasket; | ||||
|                 options.Address = new Uri(basketApi); | ||||
|             }).AddInterceptor<GrpcExceptionInterceptor>(); | ||||
| 
 | ||||
|             services.AddScoped<ICatalogService, CatalogService>(); | ||||
| 
 | ||||
|             services.AddGrpcClient<Catalog.CatalogClient>((services, options) => | ||||
|             { | ||||
|                 var catalogApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcCatalog; | ||||
|                 options.Address = new Uri(catalogApi); | ||||
|             }).AddInterceptor<GrpcExceptionInterceptor>(); | ||||
| 
 | ||||
|             services.AddScoped<IOrderingService, OrderingService>(); | ||||
| 
 | ||||
|             services.AddGrpcClient<OrderingGrpc.OrderingGrpcClient>((services, options) => | ||||
|             { | ||||
|                 var orderingApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcOrdering; | ||||
|                 options.Address = new Uri(orderingApi); | ||||
|             }).AddInterceptor<GrpcExceptionInterceptor>(); | ||||
| 
 | ||||
|             return services; | ||||
|         } | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| public static class ServiceCollectionExtensions | ||||
| { | ||||
|     public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) | ||||
|     { | ||||
|         JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub"); | ||||
| 
 | ||||
|         var identityUrl = configuration.GetValue<string>("urls:identity"); | ||||
|         services.AddAuthentication(options => | ||||
|         { | ||||
|             options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; | ||||
|             options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; | ||||
| 
 | ||||
|         }) | ||||
|         .AddJwtBearer(options => | ||||
|         { | ||||
|             options.Authority = identityUrl; | ||||
|             options.RequireHttpsMetadata = false; | ||||
|             options.Audience = "webshoppingagg"; | ||||
|         }); | ||||
| 
 | ||||
|         return services; | ||||
|     } | ||||
| 
 | ||||
|     public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration) | ||||
|     { | ||||
|         services.AddOptions(); | ||||
|         services.Configure<UrlsConfig>(configuration.GetSection("urls")); | ||||
| 
 | ||||
|         services.AddControllers() | ||||
|                 .AddJsonOptions(options => options.JsonSerializerOptions.WriteIndented = true); | ||||
| 
 | ||||
|         services.AddSwaggerGen(options => | ||||
|         { | ||||
|             options.DescribeAllEnumsAsStrings(); | ||||
| 
 | ||||
|             options.SwaggerDoc("v1", new OpenApiInfo | ||||
|             { | ||||
|                 Title = "Shopping Aggregator for Web Clients", | ||||
|                 Version = "v1", | ||||
|                 Description = "Shopping Aggregator for Web Clients" | ||||
|             }); | ||||
| 
 | ||||
|             options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme | ||||
|             { | ||||
|                 Type = SecuritySchemeType.OAuth2, | ||||
|                 Flows = new OpenApiOAuthFlows() | ||||
|                 { | ||||
|                     Implicit = new OpenApiOAuthFlow() | ||||
|                     { | ||||
|                         AuthorizationUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize"), | ||||
|                         TokenUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token"), | ||||
| 
 | ||||
|                         Scopes = new Dictionary<string, string>() | ||||
|                         { | ||||
|                             { "webshoppingagg", "Shopping Aggregator for Web Clients" } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
| 
 | ||||
|             options.OperationFilter<AuthorizeCheckOperationFilter>(); | ||||
|         }); | ||||
| 
 | ||||
|         services.AddCors(options => | ||||
|         { | ||||
|             options.AddPolicy("CorsPolicy", | ||||
|                 builder => builder | ||||
|                 .SetIsOriginAllowed((host) => true) | ||||
|                 .AllowAnyMethod() | ||||
|                 .AllowAnyHeader() | ||||
|                 .AllowCredentials()); | ||||
|         }); | ||||
| 
 | ||||
|         return services; | ||||
|     } | ||||
|     public static IServiceCollection AddApplicationServices(this IServiceCollection services) | ||||
|     { | ||||
|         //register delegating handlers | ||||
|         services.AddTransient<HttpClientAuthorizationDelegatingHandler>(); | ||||
|         services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); | ||||
| 
 | ||||
|         //register http services | ||||
| 
 | ||||
|         services.AddHttpClient<IOrderApiClient, OrderApiClient>() | ||||
|             .AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>() | ||||
|             .AddDevspacesSupport(); | ||||
| 
 | ||||
|         return services; | ||||
|     } | ||||
| 
 | ||||
|     public static IServiceCollection AddGrpcServices(this IServiceCollection services) | ||||
|     { | ||||
|         services.AddTransient<GrpcExceptionInterceptor>(); | ||||
| 
 | ||||
|         services.AddScoped<IBasketService, BasketService>(); | ||||
| 
 | ||||
|         services.AddGrpcClient<Basket.BasketClient>((services, options) => | ||||
|         { | ||||
|             var basketApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcBasket; | ||||
|             options.Address = new Uri(basketApi); | ||||
|         }).AddInterceptor<GrpcExceptionInterceptor>(); | ||||
| 
 | ||||
|         services.AddScoped<ICatalogService, CatalogService>(); | ||||
| 
 | ||||
|         services.AddGrpcClient<Catalog.CatalogClient>((services, options) => | ||||
|         { | ||||
|             var catalogApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcCatalog; | ||||
|             options.Address = new Uri(catalogApi); | ||||
|         }).AddInterceptor<GrpcExceptionInterceptor>(); | ||||
| 
 | ||||
|         services.AddScoped<IOrderingService, OrderingService>(); | ||||
| 
 | ||||
|         services.AddGrpcClient<OrderingGrpc.OrderingGrpcClient>((services, options) => | ||||
|         { | ||||
|             var orderingApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcOrdering; | ||||
|             options.Address = new Uri(orderingApi); | ||||
|         }).AddInterceptor<GrpcExceptionInterceptor>(); | ||||
| 
 | ||||
|         return services; | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user