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 |         public static string GetItemById(string ids) => $"/api/v1/catalog/items/ids/{string.Join(',', ids)}"; | ||||||
|         { |  | ||||||
|             // 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)}"; |         // REST call standard must go through port 5000 | ||||||
| 
 |         public static string GetItemsById(IEnumerable<int> ids) => $":5000/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; } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     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; | namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers; | ||||||
| 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 | [Route("api/v1/[controller]")]
 | ||||||
|  | [Authorize] | ||||||
|  | [ApiController] | ||||||
|  | public class BasketController : ControllerBase | ||||||
| { | { | ||||||
|     [Route("api/v1/[controller]")]
 |     private readonly ICatalogService _catalog; | ||||||
|     [Authorize] |     private readonly IBasketService _basket; | ||||||
|     [ApiController] | 
 | ||||||
|     public class BasketController : ControllerBase |     public BasketController(ICatalogService catalogService, IBasketService basketService) | ||||||
|     { |     { | ||||||
|         private readonly ICatalogService _catalog; |         _catalog = catalogService; | ||||||
|         private readonly IBasketService _basket; |         _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; |             return BadRequest("Need to pass at least one basket line"); | ||||||
|             _basket = basketService; |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         [HttpPost] |         // Retrieve the current basket | ||||||
|         [HttpPut] |         var basket = await _basket.GetById(data.BuyerId) ?? new BasketData(data.BuyerId); | ||||||
|         [ProducesResponseType((int)HttpStatusCode.BadRequest)] |         var catalogItems = await _catalog.GetCatalogItemsAsync(data.Items.Select(x => x.ProductId)); | ||||||
|         [ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)] | 
 | ||||||
|         public async Task<ActionResult<BasketData>> UpdateAllBasketAsync([FromBody] UpdateBasketRequest data) |         // 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 itemInBasket = basket.Items.FirstOrDefault(x => x.ProductId == bitem.ProductId); | ||||||
|             var basket = await _basket.GetById(data.BuyerId) ?? new BasketData(data.BuyerId); |             if (itemInBasket == null) | ||||||
|             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 catalogItem = catalogItems.SingleOrDefault(ci => ci.Id == bitem.ProductId); |                 basket.Items.Add(new BasketDataItem() | ||||||
|                 if (catalogItem == null) |  | ||||||
|                 { |                 { | ||||||
|                     return BadRequest($"Basket refers to a non-existing catalog item ({bitem.ProductId})"); |                     Id = bitem.Id, | ||||||
|                 } |                     ProductId = catalogItem.Id, | ||||||
| 
 |                     ProductName = catalogItem.Name, | ||||||
|                 var itemInBasket = basket.Items.FirstOrDefault(x => x.ProductId == bitem.ProductId); |                     PictureUrl = catalogItem.PictureUri, | ||||||
|                 if (itemInBasket == null) |                     UnitPrice = catalogItem.Price, | ||||||
|                 { |                     Quantity = bitem.Quantity | ||||||
|                     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; |  | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|                 // Step 4: Merge current status with new product |                 itemInBasket.Quantity = bitem.Quantity; | ||||||
|                 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(); |  | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         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("")] |     [HttpGet()] | ||||||
|     public class HomeController : Controller |     public IActionResult Index() | ||||||
|     { |     { | ||||||
|         [HttpGet()] |         return new RedirectResult("~/swagger"); | ||||||
|         public IActionResult Index() |  | ||||||
|         { |  | ||||||
|             return new RedirectResult("~/swagger"); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,44 +1,36 @@ | |||||||
| using Microsoft.AspNetCore.Authorization; | namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers; | ||||||
| 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 | [Route("api/v1/[controller]")]
 | ||||||
|  | [Authorize] | ||||||
|  | [ApiController] | ||||||
|  | public class OrderController : ControllerBase | ||||||
| { | { | ||||||
|     [Route("api/v1/[controller]")]
 |     private readonly IBasketService _basketService; | ||||||
|     [Authorize] |     private readonly IOrderingService _orderingService; | ||||||
|     [ApiController] |     public OrderController(IBasketService basketService, IOrderingService orderingService) | ||||||
|     public class OrderController : ControllerBase |  | ||||||
|     { |     { | ||||||
|         private readonly IBasketService _basketService; |         _basketService = basketService; | ||||||
|         private readonly IOrderingService _orderingService; |         _orderingService = orderingService; | ||||||
|         public OrderController(IBasketService basketService, IOrderingService 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; |             return BadRequest("Need a valid basketid"); | ||||||
|             _orderingService = orderingService; |         } | ||||||
|  |         // 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}")] |         return await _orderingService.GetOrderDraftAsync(basket); | ||||||
|         [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); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,10 +1,4 @@ | |||||||
| using Microsoft.AspNetCore.Authorization; | namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters | ||||||
| using Microsoft.OpenApi.Models; |  | ||||||
| using Swashbuckle.AspNetCore.SwaggerGen; |  | ||||||
| using System.Collections.Generic; |  | ||||||
| using System.Linq; |  | ||||||
| 
 |  | ||||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters |  | ||||||
| { | { | ||||||
|     namespace Basket.API.Infrastructure.Filters |     namespace Basket.API.Infrastructure.Filters | ||||||
|     { |     { | ||||||
| @ -14,7 +8,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters | |||||||
|             { |             { | ||||||
|                 // Check for authorize attribute |                 // Check for authorize attribute | ||||||
|                 var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any() || |                 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; |                 if (!hasAuthorize) return; | ||||||
| 
 | 
 | ||||||
| @ -27,13 +21,14 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters | |||||||
|                 }; |                 }; | ||||||
| 
 | 
 | ||||||
|                 operation.Security = new List<OpenApiSecurityRequirement> |                 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; | namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure; | ||||||
| using Grpc.Core.Interceptors; |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
| using System.Threading.Tasks; |  | ||||||
| 
 | 
 | ||||||
| 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; | ||||||
|         } |         } | ||||||
| 
 |         catch (RpcException e) | ||||||
|         public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>( |  | ||||||
|             TRequest request, |  | ||||||
|             ClientInterceptorContext<TRequest, TResponse> context, |  | ||||||
|             AsyncUnaryCallContinuation<TRequest, TResponse> continuation) |  | ||||||
|         { |         { | ||||||
|             var call = continuation(request, context); |             _logger.LogError("Error calling via grpc: {Status} - {Message}", e.Status, e.Message); | ||||||
| 
 |             return default; | ||||||
|             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; |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,49 +1,40 @@ | |||||||
| using Microsoft.AspNetCore.Authentication; | namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure; | ||||||
| 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 | public class HttpClientAuthorizationDelegatingHandler | ||||||
|  |         : DelegatingHandler | ||||||
| { | { | ||||||
|     public class HttpClientAuthorizationDelegatingHandler |     private readonly IHttpContextAccessor _httpContextAccessor; | ||||||
|          : DelegatingHandler | 
 | ||||||
|  |     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 = new AuthenticationHeaderValue("Bearer", token); | ||||||
|                 .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); |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         async Task<string> GetToken() |         return await base.SendAsync(request, cancellationToken); | ||||||
|         { |     } | ||||||
|             const string ACCESS_TOKEN = "access_token"; |  | ||||||
| 
 | 
 | ||||||
|             return await _httpContextAccessor.HttpContext |     async Task<string> GetToken() | ||||||
|                 .GetTokenAsync(ACCESS_TOKEN); |     { | ||||||
|         } |         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; } |         Quantity = 1; | ||||||
| 
 |  | ||||||
|         public string BasketId { get; set; } |  | ||||||
| 
 |  | ||||||
|         public int Quantity { get; set; } |  | ||||||
| 
 |  | ||||||
|         public AddBasketItemRequest() |  | ||||||
|         { |  | ||||||
|             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 int ProductId { get; set; } | ||||||
|     { |  | ||||||
|         public string Id { 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 int Quantity { get; set; } |  | ||||||
| 
 |  | ||||||
|         public string PictureUrl { 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 string Name { get; set; } | ||||||
|     { |  | ||||||
|         public int Id { 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; } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | |||||||
| @ -1,48 +1,43 @@ | |||||||
| using System; | namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | ||||||
| using System.Collections.Generic; |  | ||||||
| 
 | 
 | ||||||
| namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models | public class OrderData | ||||||
| { | { | ||||||
|  |     public string OrderNumber { get; set; } | ||||||
| 
 | 
 | ||||||
|     public class OrderData |     public DateTime Date { get; set; } | ||||||
|     { |  | ||||||
|         public string OrderNumber { 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>(); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | |||||||
| @ -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 string ProductName { get; set; } | ||||||
|     { |  | ||||||
|         public int ProductId { 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; } | ||||||
| } | } | ||||||
|  | |||||||
| @ -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; } |         NewQty = 0; | ||||||
| 
 |  | ||||||
|         public int NewQty { get; set; } |  | ||||||
| 
 |  | ||||||
|         public UpdateBasketItemData() |  | ||||||
|         { |  | ||||||
|             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; } |         Updates = new List<UpdateBasketItemData>(); | ||||||
| 
 |  | ||||||
|         public ICollection<UpdateBasketItemData> Updates { get; set; } |  | ||||||
| 
 |  | ||||||
|         public UpdateBasketItemsRequest() |  | ||||||
|         { |  | ||||||
|             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 IEnumerable<UpdateBasketRequestItemData> Items { get; set; } | ||||||
|     { |  | ||||||
|         public string BuyerId { 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; | BuildWebHost(args).Run(); | ||||||
| using Microsoft.AspNetCore.Hosting; |  | ||||||
| using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator; |  | ||||||
| using Serilog; |  | ||||||
| 
 |  | ||||||
| BuildWebHost(args).Run(); |  | ||||||
| 
 | 
 | ||||||
| IWebHost BuildWebHost(string[] args) => | IWebHost BuildWebHost(string[] args) => | ||||||
|     WebHost |     WebHost | ||||||
|  | |||||||
| @ -1,103 +1,96 @@ | |||||||
| using GrpcBasket; | namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; | ||||||
| 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 | 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; |         _basketClient = basketClient; | ||||||
|         private readonly ILogger<BasketService> _logger; |         _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; |             return null; | ||||||
|             _logger = logger; |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| 
 |         var map = new BasketData | ||||||
|         public async Task<BasketData> GetById(string id) |  | ||||||
|         { |         { | ||||||
|             _logger.LogDebug("grpc client created, request = {@id}", id); |             BuyerId = customerBasketRequest.Buyerid | ||||||
|             var response = await _basketClient.GetBasketByIdAsync(new BasketRequest { Id = id }); |         }; | ||||||
|             _logger.LogDebug("grpc response {@response}", response); |  | ||||||
| 
 | 
 | ||||||
|             return MapToBasketData(response); |         customerBasketRequest.Items.ToList().ForEach(item => | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public async Task UpdateAsync(BasketData currentBasket) |  | ||||||
|         { |         { | ||||||
|             _logger.LogDebug("Grpc update basket currentBasket {@currentBasket}", currentBasket); |             if (item.Id != null) | ||||||
|             var request = MapToCustomerBasketRequest(currentBasket); |  | ||||||
|             _logger.LogDebug("Grpc update basket request {@request}", request); |  | ||||||
| 
 |  | ||||||
|             await _basketClient.UpdateBasketAsync(request); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         private BasketData MapToBasketData(CustomerBasketResponse customerBasketRequest) |  | ||||||
|         { |  | ||||||
|             if (customerBasketRequest == null) |  | ||||||
|             { |             { | ||||||
|                 return null; |                 map.Items.Add(new BasketDataItem | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             var map = new BasketData |  | ||||||
|             { |  | ||||||
|                 BuyerId = customerBasketRequest.Buyerid |  | ||||||
|             }; |  | ||||||
| 
 |  | ||||||
|             customerBasketRequest.Items.ToList().ForEach(item => |  | ||||||
|             { |  | ||||||
|                 if (item.Id != null) |  | ||||||
|                 { |                 { | ||||||
|                     map.Items.Add(new BasketDataItem |                     Id = item.Id, | ||||||
|                     { |                     OldUnitPrice = (decimal)item.Oldunitprice, | ||||||
|                         Id = item.Id, |                     PictureUrl = item.Pictureurl, | ||||||
|                         OldUnitPrice = (decimal)item.Oldunitprice, |                     ProductId = item.Productid, | ||||||
|                         PictureUrl = item.Pictureurl, |                     ProductName = item.Productname, | ||||||
|                         ProductId = item.Productid, |                     Quantity = item.Quantity, | ||||||
|                         ProductName = item.Productname, |                     UnitPrice = (decimal)item.Unitprice | ||||||
|                         Quantity = item.Quantity, |                 }); | ||||||
|                         UnitPrice = (decimal)item.Unitprice |  | ||||||
|                     }); |  | ||||||
|                 } |  | ||||||
|             }); |  | ||||||
| 
 |  | ||||||
|             return map; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         private CustomerBasketRequest MapToCustomerBasketRequest(BasketData basketData) |  | ||||||
|         { |  | ||||||
|             if (basketData == null) |  | ||||||
|             { |  | ||||||
|                 return null; |  | ||||||
|             } |             } | ||||||
|  |         }); | ||||||
| 
 | 
 | ||||||
|             var map = new CustomerBasketRequest |         return map; | ||||||
|             { |     } | ||||||
|                 Buyerid = basketData.BuyerId |  | ||||||
|             }; |  | ||||||
| 
 | 
 | ||||||
|             basketData.Items.ToList().ForEach(item => |     private CustomerBasketRequest MapToCustomerBasketRequest(BasketData basketData) | ||||||
|             { |     { | ||||||
|                 if (item.Id != null) |         if (basketData == null) | ||||||
|                 { |         { | ||||||
|                     map.Items.Add(new BasketItemResponse |             return null; | ||||||
|                     { |  | ||||||
|                         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; |  | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         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; | namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; | ||||||
| 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 | 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; |         _client = client; | ||||||
|         private readonly ILogger<CatalogService> _logger; |         _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; |             Id = catalogItemResponse.Id, | ||||||
|             _logger = logger; |             Name = catalogItemResponse.Name, | ||||||
|         } |             PictureUri = catalogItemResponse.PictureUri, | ||||||
| 
 |             Price = (decimal)catalogItemResponse.Price | ||||||
|         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 |  | ||||||
|             }; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,12 +1,8 @@ | |||||||
| using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; | ||||||
| using System.Threading.Tasks; |  | ||||||
| 
 | 
 | ||||||
| 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; | namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; | ||||||
| using System.Collections.Generic; |  | ||||||
| using System.Threading.Tasks; |  | ||||||
| 
 | 
 | ||||||
| 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; | namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; | ||||||
| using System.Threading.Tasks; |  | ||||||
| 
 | 
 | ||||||
| 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; | namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; | ||||||
| using System.Threading.Tasks; |  | ||||||
| 
 | 
 | ||||||
| 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; | namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; | ||||||
| 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 | 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; |         _apiClient = httpClient; | ||||||
|         private readonly ILogger<OrderApiClient> _logger; |         _logger = logger; | ||||||
|         private readonly UrlsConfig _urls; |         _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; |             PropertyNameCaseInsensitive = true | ||||||
|             _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 |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,79 +1,72 @@ | |||||||
| using GrpcOrdering; | namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; | ||||||
| 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 | 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; |         _orderingGrpcClient = orderingGrpcClient; | ||||||
|         private readonly ILogger<OrderingService> _logger; |         _logger = 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; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     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; | namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator; | ||||||
| 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 | public class Startup | ||||||
| { | { | ||||||
|     public class Startup |     public Startup(IConfiguration configuration) | ||||||
|     { |     { | ||||||
|         public Startup(IConfiguration configuration) |         Configuration = 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") |  | ||||||
|                 }); |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     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"); |         if (env.IsDevelopment()) | ||||||
|             services.AddAuthentication(options => |         { | ||||||
|             { |             app.UseDeveloperExceptionPage(); | ||||||
|                 options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; |         } | ||||||
|                 options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; |  | ||||||
| 
 | 
 | ||||||
|             }) |         app.UseHttpsRedirection(); | ||||||
|             .AddJwtBearer(options => | 
 | ||||||
|  |         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; |                 Predicate = _ => true, | ||||||
|                 options.RequireHttpsMetadata = false; |                 ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse | ||||||
|                 options.Audience = "webshoppingagg"; |  | ||||||
|             }); |             }); | ||||||
| 
 |             endpoints.MapHealthChecks("/liveness", new HealthCheckOptions | ||||||
|             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(); |                 Predicate = r => r.Name.Contains("self") | ||||||
| 
 |  | ||||||
|                 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 | public static class ServiceCollectionExtensions | ||||||
|                     .SetIsOriginAllowed((host) => true) | { | ||||||
|                     .AllowAnyMethod() |     public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) | ||||||
|                     .AllowAnyHeader() |     { | ||||||
|                     .AllowCredentials()); |         JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub"); | ||||||
|             }); | 
 | ||||||
| 
 |         var identityUrl = configuration.GetValue<string>("urls:identity"); | ||||||
|             return services; |         services.AddAuthentication(options => | ||||||
|         } |         { | ||||||
|         public static IServiceCollection AddApplicationServices(this IServiceCollection services) |             options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; | ||||||
|         { |             options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; | ||||||
|             //register delegating handlers | 
 | ||||||
|             services.AddTransient<HttpClientAuthorizationDelegatingHandler>(); |         }) | ||||||
|             services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); |         .AddJwtBearer(options => | ||||||
| 
 |         { | ||||||
|             //register http services |             options.Authority = identityUrl; | ||||||
| 
 |             options.RequireHttpsMetadata = false; | ||||||
|             services.AddHttpClient<IOrderApiClient, OrderApiClient>() |             options.Audience = "webshoppingagg"; | ||||||
|                 .AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>() |         }); | ||||||
|                 .AddDevspacesSupport(); | 
 | ||||||
| 
 |         return services; | ||||||
|             return services; |     } | ||||||
|         } | 
 | ||||||
| 
 |     public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration) | ||||||
|         public static IServiceCollection AddGrpcServices(this IServiceCollection services) |     { | ||||||
|         { |         services.AddOptions(); | ||||||
|             services.AddTransient<GrpcExceptionInterceptor>(); |         services.Configure<UrlsConfig>(configuration.GetSection("urls")); | ||||||
| 
 | 
 | ||||||
|             services.AddScoped<IBasketService, BasketService>(); |         services.AddControllers() | ||||||
| 
 |                 .AddJsonOptions(options => options.JsonSerializerOptions.WriteIndented = true); | ||||||
|             services.AddGrpcClient<Basket.BasketClient>((services, options) => | 
 | ||||||
|             { |         services.AddSwaggerGen(options => | ||||||
|                 var basketApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcBasket; |         { | ||||||
|                 options.Address = new Uri(basketApi); |             options.DescribeAllEnumsAsStrings(); | ||||||
|             }).AddInterceptor<GrpcExceptionInterceptor>(); | 
 | ||||||
| 
 |             options.SwaggerDoc("v1", new OpenApiInfo | ||||||
|             services.AddScoped<ICatalogService, CatalogService>(); |             { | ||||||
| 
 |                 Title = "Shopping Aggregator for Web Clients", | ||||||
|             services.AddGrpcClient<Catalog.CatalogClient>((services, options) => |                 Version = "v1", | ||||||
|             { |                 Description = "Shopping Aggregator for Web Clients" | ||||||
|                 var catalogApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcCatalog; |             }); | ||||||
|                 options.Address = new Uri(catalogApi); | 
 | ||||||
|             }).AddInterceptor<GrpcExceptionInterceptor>(); |             options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme | ||||||
| 
 |             { | ||||||
|             services.AddScoped<IOrderingService, OrderingService>(); |                 Type = SecuritySchemeType.OAuth2, | ||||||
| 
 |                 Flows = new OpenApiOAuthFlows() | ||||||
|             services.AddGrpcClient<OrderingGrpc.OrderingGrpcClient>((services, options) => |                 { | ||||||
|             { |                     Implicit = new OpenApiOAuthFlow() | ||||||
|                 var orderingApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcOrdering; |                     { | ||||||
|                 options.Address = new Uri(orderingApi); |                         AuthorizationUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize"), | ||||||
|             }).AddInterceptor<GrpcExceptionInterceptor>(); |                         TokenUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token"), | ||||||
| 
 | 
 | ||||||
|             return services; |                         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