Moved namespaces to globalusing file
This commit is contained in:
parent
21c70f1227
commit
a902b00a3c
@ -1,38 +1,35 @@
|
|||||||
using System.Collections.Generic;
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config
|
public class UrlsConfig
|
||||||
{
|
{
|
||||||
public class UrlsConfig
|
public class CatalogOperations
|
||||||
{
|
{
|
||||||
public class CatalogOperations
|
public static string GetItemById(int id) => $"/api/v1/catalog/items/{id}";
|
||||||
{
|
|
||||||
public static string GetItemById(int id) => $"/api/v1/catalog/items/{id}";
|
|
||||||
|
|
||||||
public static string GetItemsById(IEnumerable<int> ids) => $"/api/v1/catalog/items?ids={string.Join(',', ids)}";
|
public static string GetItemsById(IEnumerable<int> ids) => $"/api/v1/catalog/items?ids={string.Join(',', ids)}";
|
||||||
}
|
|
||||||
|
|
||||||
public class BasketOperations
|
|
||||||
{
|
|
||||||
public 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,156 +1,146 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
|
|
||||||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Mobile.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)]
|
|
||||||
[ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)]
|
var catalogItems = await _catalog.GetCatalogItemsAsync(data.Items.Select(x => x.ProductId));
|
||||||
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,
|
else
|
||||||
ProductId = catalogItem.Id,
|
{
|
||||||
ProductName = catalogItem.Name,
|
itemInBasket.Quantity = bitem.Quantity;
|
||||||
PictureUrl = catalogItem.PictureUri,
|
|
||||||
UnitPrice = catalogItem.Price,
|
|
||||||
Quantity = bitem.Quantity
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
itemInBasket.Quantity = bitem.Quantity;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await _basket.UpdateAsync(basket);
|
|
||||||
|
|
||||||
return basket;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPut]
|
await _basket.UpdateAsync(basket);
|
||||||
[Route("items")]
|
|
||||||
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
|
return basket;
|
||||||
[ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)]
|
}
|
||||||
public async Task<ActionResult<BasketData>> UpdateQuantitiesAsync([FromBody] UpdateBasketItemsRequest data)
|
|
||||||
|
[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())
|
||||||
{
|
{
|
||||||
if (!data.Updates.Any())
|
return BadRequest("No updates sent");
|
||||||
{
|
|
||||||
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]
|
// Retrieve the current basket
|
||||||
[Route("items")]
|
var currentBasket = await _basket.GetById(data.BasketId);
|
||||||
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
|
if (currentBasket == null)
|
||||||
[ProducesResponseType((int)HttpStatusCode.OK)]
|
|
||||||
public async Task<ActionResult> AddBasketItemAsync([FromBody] AddBasketItemRequest data)
|
|
||||||
{
|
{
|
||||||
if (data == null || data.Quantity == 0)
|
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("Invalid payload");
|
return BadRequest($"Basket item with id {update.BasketItemId} not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 1: Get the item from catalog
|
basketItem.Quantity = update.NewQty;
|
||||||
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: 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 4: Update basket
|
|
||||||
await _basket.UpdateAsync(currentBasket);
|
|
||||||
|
|
||||||
return Ok();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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: 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 4: Update basket
|
||||||
|
await _basket.UpdateAsync(currentBasket);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Mobile.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,45 +1,37 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
|
|
||||||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services;
|
|
||||||
using System.Net;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Mobile.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 class OrderController : ControllerBase
|
public OrderController(IBasketService basketService, IOrderingService orderingService)
|
||||||
{
|
{
|
||||||
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,12 +1,5 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Filters
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Filters
|
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace Basket.API.Infrastructure.Filters
|
namespace Basket.API.Infrastructure.Filters
|
||||||
{
|
{
|
||||||
public class AuthorizeCheckOperationFilter : IOperationFilter
|
public class AuthorizeCheckOperationFilter : IOperationFilter
|
||||||
|
@ -1,41 +1,35 @@
|
|||||||
using Grpc.Core;
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure;
|
||||||
using Grpc.Core.Interceptors;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Mobile.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,54 +1,44 @@
|
|||||||
using Microsoft.AspNetCore.Authentication;
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure
|
public class HttpClientAuthorizationDelegatingHandler : DelegatingHandler
|
||||||
{
|
{
|
||||||
public class HttpClientAuthorizationDelegatingHandler : DelegatingHandler
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||||
|
private readonly ILogger<HttpClientAuthorizationDelegatingHandler> _logger;
|
||||||
|
|
||||||
|
public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccessor, ILogger<HttpClientAuthorizationDelegatingHandler> logger)
|
||||||
{
|
{
|
||||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
_httpContextAccessor = httpContextAccessor;
|
||||||
private readonly ILogger<HttpClientAuthorizationDelegatingHandler> _logger;
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccessor, ILogger<HttpClientAuthorizationDelegatingHandler> logger)
|
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
request.Version = new System.Version(2, 0);
|
||||||
|
request.Method = HttpMethod.Get;
|
||||||
|
|
||||||
|
var authorizationHeader = _httpContextAccessor.HttpContext
|
||||||
|
.Request.Headers["Authorization"];
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(authorizationHeader))
|
||||||
{
|
{
|
||||||
_httpContextAccessor = httpContextAccessor;
|
request.Headers.Add("Authorization", new List<string>() { authorizationHeader });
|
||||||
_logger = logger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
var token = await GetToken();
|
||||||
|
|
||||||
|
if (token != null)
|
||||||
{
|
{
|
||||||
request.Version = new System.Version(2, 0);
|
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
||||||
request.Method = HttpMethod.Get;
|
|
||||||
|
|
||||||
var authorizationHeader = _httpContextAccessor.HttpContext
|
|
||||||
.Request.Headers["Authorization"];
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(authorizationHeader))
|
|
||||||
{
|
|
||||||
request.Headers.Add("Authorization", new List<string>() { authorizationHeader });
|
|
||||||
}
|
|
||||||
|
|
||||||
var token = await GetToken();
|
|
||||||
|
|
||||||
if (token != null)
|
|
||||||
{
|
|
||||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await base.SendAsync(request, cancellationToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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,16 +1,15 @@
|
|||||||
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
|
||||||
|
|
||||||
|
public class AddBasketItemRequest
|
||||||
{
|
{
|
||||||
public class AddBasketItemRequest
|
public int CatalogItemId { get; set; }
|
||||||
|
|
||||||
|
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,17 @@
|
|||||||
using System.Collections.Generic;
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Mobile.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.Mobile.Shopping.HttpAggregator.Models
|
namespace Microsoft.eShopOnContainers.Mobile.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,13 +1,12 @@
|
|||||||
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
|
||||||
|
|
||||||
|
public class CatalogItem
|
||||||
{
|
{
|
||||||
public class CatalogItem
|
public int Id { get; set; }
|
||||||
{
|
|
||||||
public int Id { get; set; }
|
|
||||||
|
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
public decimal Price { get; set; }
|
public decimal Price { get; set; }
|
||||||
|
|
||||||
public string PictureUri { get; set; }
|
public string PictureUri { get; set; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,48 +1,42 @@
|
|||||||
using System;
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Mobile.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.Mobile.Shopping.HttpAggregator.Models
|
namespace Microsoft.eShopOnContainers.Mobile.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.Mobile.Shopping.HttpAggregator.Models
|
namespace Microsoft.eShopOnContainers.Mobile.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,19 +1,14 @@
|
|||||||
using System.Collections.Generic;
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models
|
public class UpdateBasketItemsRequest
|
||||||
{
|
{
|
||||||
|
|
||||||
public class UpdateBasketItemsRequest
|
public string BasketId { get; set; }
|
||||||
|
|
||||||
|
public ICollection<UpdateBasketItemData> Updates { get; set; }
|
||||||
|
|
||||||
|
public UpdateBasketItemsRequest()
|
||||||
{
|
{
|
||||||
|
Updates = new List<UpdateBasketItemData>();
|
||||||
public string BasketId { get; set; }
|
|
||||||
|
|
||||||
public ICollection<UpdateBasketItemData> Updates { get; set; }
|
|
||||||
|
|
||||||
public UpdateBasketItemsRequest()
|
|
||||||
{
|
|
||||||
Updates = new List<UpdateBasketItemData>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,8 @@
|
|||||||
using System.Collections.Generic;
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Mobile.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,13 +1,10 @@
|
|||||||
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
|
||||||
|
|
||||||
|
public class UpdateBasketRequestItemData
|
||||||
{
|
{
|
||||||
|
public string Id { get; set; } // Basket id
|
||||||
|
|
||||||
public class UpdateBasketRequestItemData
|
public int ProductId { get; set; } // Catalog item id
|
||||||
{
|
|
||||||
public string Id { get; set; } // Basket id
|
|
||||||
|
|
||||||
public int ProductId { get; set; } // Catalog item id
|
|
||||||
|
|
||||||
public int Quantity { get; set; } // Quantity
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public int Quantity { get; set; } // Quantity
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,4 @@
|
|||||||
using Microsoft.AspNetCore;
|
BuildWebHost(args).Run();
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator;
|
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
|
|
||||||
BuildWebHost(args).Run();
|
|
||||||
IWebHost BuildWebHost(string[] args) =>
|
IWebHost BuildWebHost(string[] args) =>
|
||||||
WebHost
|
WebHost
|
||||||
.CreateDefaultBuilder(args)
|
.CreateDefaultBuilder(args)
|
||||||
|
@ -1,90 +1,83 @@
|
|||||||
using GrpcBasket;
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services;
|
||||||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Mobile.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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<BasketData> GetById(string id)
|
var map = new BasketData
|
||||||
{
|
{
|
||||||
_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 => map.Items.Add(new BasketDataItem
|
||||||
|
{
|
||||||
|
Id = item.Id,
|
||||||
|
OldUnitPrice = (decimal)item.Oldunitprice,
|
||||||
|
PictureUrl = item.Pictureurl,
|
||||||
|
ProductId = item.Productid,
|
||||||
|
ProductName = item.Productname,
|
||||||
|
Quantity = item.Quantity,
|
||||||
|
UnitPrice = (decimal)item.Unitprice
|
||||||
|
}));
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CustomerBasketRequest MapToCustomerBasketRequest(BasketData basketData)
|
||||||
|
{
|
||||||
|
if (basketData == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateAsync(BasketData currentBasket)
|
var map = new CustomerBasketRequest
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Grpc update basket currentBasket {@currentBasket}", currentBasket);
|
Buyerid = basketData.BuyerId
|
||||||
var request = MapToCustomerBasketRequest(currentBasket);
|
};
|
||||||
_logger.LogDebug("Grpc update basket request {@request}", request);
|
|
||||||
|
|
||||||
await _basketClient.UpdateBasketAsync(request);
|
basketData.Items.ToList().ForEach(item => map.Items.Add(new BasketItemResponse
|
||||||
}
|
|
||||||
|
|
||||||
private BasketData MapToBasketData(CustomerBasketResponse customerBasketRequest)
|
|
||||||
{
|
{
|
||||||
if (customerBasketRequest == null)
|
Id = item.Id,
|
||||||
{
|
Oldunitprice = (double)item.OldUnitPrice,
|
||||||
return null;
|
Pictureurl = item.PictureUrl,
|
||||||
}
|
Productid = item.ProductId,
|
||||||
|
Productname = item.ProductName,
|
||||||
|
Quantity = item.Quantity,
|
||||||
|
Unitprice = (double)item.UnitPrice
|
||||||
|
}));
|
||||||
|
|
||||||
var map = new BasketData
|
return map;
|
||||||
{
|
|
||||||
BuyerId = customerBasketRequest.Buyerid
|
|
||||||
};
|
|
||||||
|
|
||||||
customerBasketRequest.Items.ToList().ForEach(item => map.Items.Add(new BasketDataItem
|
|
||||||
{
|
|
||||||
Id = item.Id,
|
|
||||||
OldUnitPrice = (decimal)item.Oldunitprice,
|
|
||||||
PictureUrl = item.Pictureurl,
|
|
||||||
ProductId = item.Productid,
|
|
||||||
ProductName = item.Productname,
|
|
||||||
Quantity = item.Quantity,
|
|
||||||
UnitPrice = (decimal)item.Unitprice
|
|
||||||
}));
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
private CustomerBasketRequest MapToCustomerBasketRequest(BasketData basketData)
|
|
||||||
{
|
|
||||||
if (basketData == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var map = new CustomerBasketRequest
|
|
||||||
{
|
|
||||||
Buyerid = basketData.BuyerId
|
|
||||||
};
|
|
||||||
|
|
||||||
basketData.Items.ToList().ForEach(item => 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,43 +1,36 @@
|
|||||||
using CatalogApi;
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services;
|
||||||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
|
public class CatalogService : ICatalogService
|
||||||
{
|
{
|
||||||
public class CatalogService : ICatalogService
|
private readonly Catalog.CatalogClient _client;
|
||||||
|
|
||||||
|
public CatalogService(Catalog.CatalogClient client)
|
||||||
{
|
{
|
||||||
private readonly Catalog.CatalogClient _client;
|
_client = client;
|
||||||
|
}
|
||||||
|
|
||||||
public CatalogService(Catalog.CatalogClient client)
|
public async Task<CatalogItem> GetCatalogItemAsync(int id)
|
||||||
{
|
{
|
||||||
_client = client;
|
var request = new CatalogItemRequest { Id = id };
|
||||||
}
|
var response = await _client.GetItemByIdAsync(request);
|
||||||
|
return MapToCatalogItemResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<CatalogItem> GetCatalogItemAsync(int id)
|
public async Task<IEnumerable<CatalogItem>> GetCatalogItemsAsync(IEnumerable<int> ids)
|
||||||
{
|
{
|
||||||
var request = new CatalogItemRequest { Id = id };
|
var request = new CatalogItemsRequest { Ids = string.Join(",", ids), PageIndex = 1, PageSize = 10 };
|
||||||
var response = await _client.GetItemByIdAsync(request);
|
var response = await _client.GetItemsByIdsAsync(request);
|
||||||
return MapToCatalogItemResponse(response);
|
return response.Data.Select(MapToCatalogItemResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<CatalogItem>> GetCatalogItemsAsync(IEnumerable<int> ids)
|
private CatalogItem MapToCatalogItemResponse(CatalogItemResponse catalogItemResponse)
|
||||||
|
{
|
||||||
|
return new CatalogItem
|
||||||
{
|
{
|
||||||
var request = new CatalogItemsRequest { Ids = string.Join(",", ids), PageIndex = 1, PageSize = 10 };
|
Id = catalogItemResponse.Id,
|
||||||
var response = await _client.GetItemsByIdsAsync(request);
|
Name = catalogItemResponse.Name,
|
||||||
return response.Data.Select(MapToCatalogItemResponse);
|
PictureUri = catalogItemResponse.PictureUri,
|
||||||
}
|
Price = (decimal)catalogItemResponse.Price
|
||||||
|
};
|
||||||
private CatalogItem MapToCatalogItemResponse(CatalogItemResponse catalogItemResponse)
|
|
||||||
{
|
|
||||||
return new CatalogItem
|
|
||||||
{
|
|
||||||
Id = catalogItemResponse.Id,
|
|
||||||
Name = catalogItemResponse.Name,
|
|
||||||
PictureUri = catalogItemResponse.PictureUri,
|
|
||||||
Price = (decimal)catalogItemResponse.Price
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Mobile.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.Mobile.Shopping.HttpAggregator.Models;
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Mobile.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.Mobile.Shopping.HttpAggregator.Models;
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Mobile.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.Mobile.Shopping.HttpAggregator.Models;
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Mobile.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.Mobile.Shopping.HttpAggregator.Config;
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services;
|
||||||
using Microsoft.eShopOnContainers.Mobile.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.Mobile.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 uri = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft();
|
||||||
|
var content = new StringContent(JsonSerializer.Serialize(basket), System.Text.Encoding.UTF8, "application/json");
|
||||||
|
var response = await _apiClient.PostAsync(uri, 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 uri = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft();
|
|
||||||
var content = new StringContent(JsonSerializer.Serialize(basket), System.Text.Encoding.UTF8, "application/json");
|
|
||||||
var response = await _apiClient.PostAsync(uri, 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.Mobile.Shopping.HttpAggregator.Services;
|
||||||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Mobile.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,222 +1,196 @@
|
|||||||
using CatalogApi;
|
namespace Microsoft.eShopOnContainers.Mobile.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.Mobile.Shopping.HttpAggregator.Config;
|
|
||||||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters;
|
|
||||||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure;
|
|
||||||
using Microsoft.eShopOnContainers.Mobile.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.Mobile.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()
|
|
||||||
.AddHttpServices()
|
|
||||||
.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.UseSwagger().UseSwaggerUI(c =>
|
|
||||||
{
|
|
||||||
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1");
|
|
||||||
|
|
||||||
c.OAuthClientId("mobileshoppingaggswaggerui");
|
|
||||||
c.OAuthClientSecret(string.Empty);
|
|
||||||
c.OAuthRealm(string.Empty);
|
|
||||||
c.OAuthAppName("Purchase 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 AddCustomMvc(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()
|
||||||
|
.AddHttpServices()
|
||||||
|
.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))
|
||||||
{
|
{
|
||||||
services.AddOptions();
|
loggerFactory.CreateLogger<Startup>().LogDebug("Using PATH BASE '{pathBase}'", pathBase);
|
||||||
services.Configure<UrlsConfig>(configuration.GetSection("urls"));
|
app.UsePathBase(pathBase);
|
||||||
|
}
|
||||||
|
|
||||||
services.AddControllers()
|
if (env.IsDevelopment())
|
||||||
.AddJsonOptions(options => options.JsonSerializerOptions.WriteIndented = true);
|
{
|
||||||
|
app.UseDeveloperExceptionPage();
|
||||||
|
}
|
||||||
|
|
||||||
services.AddSwaggerGen(options =>
|
app.UseSwagger().UseSwaggerUI(c =>
|
||||||
|
{
|
||||||
|
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1");
|
||||||
|
|
||||||
|
c.OAuthClientId("mobileshoppingaggswaggerui");
|
||||||
|
c.OAuthClientSecret(string.Empty);
|
||||||
|
c.OAuthRealm(string.Empty);
|
||||||
|
c.OAuthAppName("Purchase 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.DescribeAllEnumsAsStrings();
|
Predicate = _ => true,
|
||||||
options.SwaggerDoc("v1", new OpenApiInfo
|
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
|
||||||
{
|
|
||||||
Title = "Shopping Aggregator for Mobile Clients",
|
|
||||||
Version = "v1",
|
|
||||||
Description = "Shopping Aggregator for Mobile 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>()
|
|
||||||
{
|
|
||||||
{ "mobileshoppingagg", "Shopping Aggregator for Mobile Clients" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
options.OperationFilter<AuthorizeCheckOperationFilter>();
|
|
||||||
});
|
});
|
||||||
|
endpoints.MapHealthChecks("/liveness", new HealthCheckOptions
|
||||||
services.AddCors(options =>
|
|
||||||
{
|
{
|
||||||
options.AddPolicy("CorsPolicy",
|
Predicate = r => r.Name.Contains("self")
|
||||||
builder => builder
|
|
||||||
.AllowAnyMethod()
|
|
||||||
.AllowAnyHeader()
|
|
||||||
.SetIsOriginAllowed((host) => true)
|
|
||||||
.AllowCredentials());
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
return services;
|
|
||||||
}
|
|
||||||
public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration)
|
|
||||||
{
|
|
||||||
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");
|
|
||||||
|
|
||||||
var identityUrl = configuration.GetValue<string>("urls:identity");
|
|
||||||
|
|
||||||
services.AddAuthentication(options =>
|
|
||||||
{
|
|
||||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
||||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
||||||
|
|
||||||
})
|
|
||||||
.AddJwtBearer(options =>
|
|
||||||
{
|
|
||||||
options.Authority = identityUrl;
|
|
||||||
options.RequireHttpsMetadata = false;
|
|
||||||
options.Audience = "mobileshoppingagg";
|
|
||||||
});
|
|
||||||
|
|
||||||
return services;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IServiceCollection AddHttpServices(this IServiceCollection services)
|
|
||||||
{
|
|
||||||
//register delegating handlers
|
|
||||||
services.AddTransient<HttpClientAuthorizationDelegatingHandler>();
|
|
||||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
|
||||||
|
|
||||||
//register http services
|
|
||||||
|
|
||||||
services.AddHttpClient<IOrderApiClient, OrderApiClient>()
|
|
||||||
.AddDevspacesSupport();
|
|
||||||
|
|
||||||
return services;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IServiceCollection AddGrpcServices(this IServiceCollection services)
|
|
||||||
{
|
|
||||||
services.AddTransient<GrpcExceptionInterceptor>();
|
|
||||||
|
|
||||||
services.AddScoped<IBasketService, BasketService>();
|
|
||||||
|
|
||||||
services.AddGrpcClient<Basket.BasketClient>((services, options) =>
|
|
||||||
{
|
|
||||||
var basketApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcBasket;
|
|
||||||
options.Address = new Uri(basketApi);
|
|
||||||
}).AddInterceptor<GrpcExceptionInterceptor>();
|
|
||||||
|
|
||||||
services.AddScoped<ICatalogService, CatalogService>();
|
|
||||||
|
|
||||||
services.AddGrpcClient<Catalog.CatalogClient>((services, options) =>
|
|
||||||
{
|
|
||||||
var catalogApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcCatalog;
|
|
||||||
options.Address = new Uri(catalogApi);
|
|
||||||
}).AddInterceptor<GrpcExceptionInterceptor>();
|
|
||||||
|
|
||||||
services.AddScoped<IOrderingService, OrderingService>();
|
|
||||||
|
|
||||||
services.AddGrpcClient<OrderingGrpc.OrderingGrpcClient>((services, options) =>
|
|
||||||
{
|
|
||||||
var orderingApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcOrdering;
|
|
||||||
options.Address = new Uri(orderingApi);
|
|
||||||
}).AddInterceptor<GrpcExceptionInterceptor>();
|
|
||||||
|
|
||||||
return services;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ServiceCollectionExtensions
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddOptions();
|
||||||
|
services.Configure<UrlsConfig>(configuration.GetSection("urls"));
|
||||||
|
|
||||||
|
services.AddControllers()
|
||||||
|
.AddJsonOptions(options => options.JsonSerializerOptions.WriteIndented = true);
|
||||||
|
|
||||||
|
services.AddSwaggerGen(options =>
|
||||||
|
{
|
||||||
|
options.DescribeAllEnumsAsStrings();
|
||||||
|
options.SwaggerDoc("v1", new OpenApiInfo
|
||||||
|
{
|
||||||
|
Title = "Shopping Aggregator for Mobile Clients",
|
||||||
|
Version = "v1",
|
||||||
|
Description = "Shopping Aggregator for Mobile 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>()
|
||||||
|
{
|
||||||
|
{ "mobileshoppingagg", "Shopping Aggregator for Mobile Clients" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
options.OperationFilter<AuthorizeCheckOperationFilter>();
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy("CorsPolicy",
|
||||||
|
builder => builder
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.SetIsOriginAllowed((host) => true)
|
||||||
|
.AllowCredentials());
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");
|
||||||
|
|
||||||
|
var identityUrl = configuration.GetValue<string>("urls:identity");
|
||||||
|
|
||||||
|
services.AddAuthentication(options =>
|
||||||
|
{
|
||||||
|
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
|
||||||
|
})
|
||||||
|
.AddJwtBearer(options =>
|
||||||
|
{
|
||||||
|
options.Authority = identityUrl;
|
||||||
|
options.RequireHttpsMetadata = false;
|
||||||
|
options.Audience = "mobileshoppingagg";
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddHttpServices(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
//register delegating handlers
|
||||||
|
services.AddTransient<HttpClientAuthorizationDelegatingHandler>();
|
||||||
|
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||||
|
|
||||||
|
//register http services
|
||||||
|
|
||||||
|
services.AddHttpClient<IOrderApiClient, OrderApiClient>()
|
||||||
|
.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