diff --git a/src/Services/Basket/Basket.API/Controllers/BasketController.cs b/src/Services/Basket/Basket.API/Controllers/BasketController.cs index b6dd5a4b0..ccb81d25f 100644 --- a/src/Services/Basket/Basket.API/Controllers/BasketController.cs +++ b/src/Services/Basket/Basket.API/Controllers/BasketController.cs @@ -36,7 +36,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers var basket = await _repository.GetBasketAsync(id); if (basket == null) { - return NotFound(); + return Ok(new CustomerBasket(id) { }); } return Ok(basket); diff --git a/src/Web/WebMVC/AppSettings.cs b/src/Web/WebMVC/AppSettings.cs index 30403aa9d..a705c5a90 100644 --- a/src/Web/WebMVC/AppSettings.cs +++ b/src/Web/WebMVC/AppSettings.cs @@ -7,9 +7,8 @@ namespace Microsoft.eShopOnContainers.WebMVC { public class AppSettings { - public Connectionstrings ConnectionStrings { get; set; } + //public Connectionstrings ConnectionStrings { get; set; } public string MarketingUrl { get; set; } - public string PurchaseUrl { get; set; } public string SignalrHubUrl { get; set; } public bool ActivateCampaignDetailFunction { get; set; } diff --git a/src/Web/WebMVC/Infrastructure/HttpClientRequestIdDelegatingHandler.cs b/src/Web/WebMVC/Infrastructure/HttpClientRequestIdDelegatingHandler.cs new file mode 100644 index 000000000..17e4591a1 --- /dev/null +++ b/src/Web/WebMVC/Infrastructure/HttpClientRequestIdDelegatingHandler.cs @@ -0,0 +1,26 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace WebMVC.Infrastructure +{ + public class HttpClientRequestIdDelegatingHandler + : DelegatingHandler + { + + public HttpClientRequestIdDelegatingHandler() + { + } + + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + if (request.Method == HttpMethod.Post || request.Method == HttpMethod.Put) + { + request.Headers.Add("x-requestid", Guid.NewGuid().ToString()); + } + + return await base.SendAsync(request, cancellationToken); + } + } +} diff --git a/src/Web/WebMVC/Infrastructure/IResilientHttpClientFactory.cs b/src/Web/WebMVC/Infrastructure/IResilientHttpClientFactory.cs index aa1d31c9b..39b36f141 100644 --- a/src/Web/WebMVC/Infrastructure/IResilientHttpClientFactory.cs +++ b/src/Web/WebMVC/Infrastructure/IResilientHttpClientFactory.cs @@ -3,8 +3,8 @@ using System; namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure { - public interface IResilientHttpClientFactory - { - ResilientHttpClient CreateResilientHttpClient(); - } + //public interface IResilientHttpClientFactory + //{ + // ResilientHttpClient CreateResilientHttpClient(); + //} } \ No newline at end of file diff --git a/src/Web/WebMVC/Infrastructure/ResilientHttpClientFactory.cs b/src/Web/WebMVC/Infrastructure/ResilientHttpClientFactory.cs index 783dae631..09b596f1c 100644 --- a/src/Web/WebMVC/Infrastructure/ResilientHttpClientFactory.cs +++ b/src/Web/WebMVC/Infrastructure/ResilientHttpClientFactory.cs @@ -7,60 +7,60 @@ using System.Net.Http; namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure { - public class ResilientHttpClientFactory : IResilientHttpClientFactory - { - private readonly ILogger _logger; - private readonly int _retryCount; - private readonly int _exceptionsAllowedBeforeBreaking; - private readonly IHttpContextAccessor _httpContextAccessor; + //public class ResilientHttpClientFactory : IResilientHttpClientFactory + //{ + // private readonly ILogger _logger; + // private readonly int _retryCount; + // private readonly int _exceptionsAllowedBeforeBreaking; + // private readonly IHttpContextAccessor _httpContextAccessor; - public ResilientHttpClientFactory(ILogger logger, IHttpContextAccessor httpContextAccessor, int exceptionsAllowedBeforeBreaking = 5, int retryCount = 6) - { - _logger = logger; - _exceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking; - _retryCount = retryCount; - _httpContextAccessor = httpContextAccessor; - } + // public ResilientHttpClientFactory(ILogger logger, IHttpContextAccessor httpContextAccessor, int exceptionsAllowedBeforeBreaking = 5, int retryCount = 6) + // { + // _logger = logger; + // _exceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking; + // _retryCount = retryCount; + // _httpContextAccessor = httpContextAccessor; + // } - public ResilientHttpClient CreateResilientHttpClient() - => new ResilientHttpClient((origin) => CreatePolicies(), _logger, _httpContextAccessor); + // public ResilientHttpClient CreateResilientHttpClient() + // => new ResilientHttpClient((origin) => CreatePolicies(), _logger, _httpContextAccessor); - private Policy[] CreatePolicies() - => new Policy[] - { - Policy.Handle() - .WaitAndRetryAsync( - // number of retries - _retryCount, - // exponential backofff - retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), - // on retry - (exception, timeSpan, retryCount, context) => - { - var msg = $"Retry {retryCount} implemented with Polly's RetryPolicy " + - $"of {context.PolicyKey} " + - $"at {context.OperationKey}, " + - $"due to: {exception}."; - _logger.LogWarning(msg); - _logger.LogDebug(msg); - }), - Policy.Handle() - .CircuitBreakerAsync( - // number of exceptions before breaking circuit - _exceptionsAllowedBeforeBreaking, - // time circuit opened before retry - TimeSpan.FromMinutes(1), - (exception, duration) => - { - // on circuit opened - _logger.LogTrace("Circuit breaker opened"); - }, - () => - { - // on circuit closed - _logger.LogTrace("Circuit breaker reset"); - }) - }; - } + // private Policy[] CreatePolicies() + // => new Policy[] + // { + // Policy.Handle() + // .WaitAndRetryAsync( + // // number of retries + // _retryCount, + // // exponential backofff + // retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), + // // on retry + // (exception, timeSpan, retryCount, context) => + // { + // var msg = $"Retry {retryCount} implemented with Polly's RetryPolicy " + + // $"of {context.PolicyKey} " + + // $"at {context.OperationKey}, " + + // $"due to: {exception}."; + // _logger.LogWarning(msg); + // _logger.LogDebug(msg); + // }), + // Policy.Handle() + // .CircuitBreakerAsync( + // // number of exceptions before breaking circuit + // _exceptionsAllowedBeforeBreaking, + // // time circuit opened before retry + // TimeSpan.FromMinutes(1), + // (exception, duration) => + // { + // // on circuit opened + // _logger.LogTrace("Circuit breaker opened"); + // }, + // () => + // { + // // on circuit closed + // _logger.LogTrace("Circuit breaker reset"); + // }) + // }; + //} } diff --git a/src/Web/WebMVC/Services/BasketService.cs b/src/Web/WebMVC/Services/BasketService.cs index 4a0719f1b..7dffd934b 100644 --- a/src/Web/WebMVC/Services/BasketService.cs +++ b/src/Web/WebMVC/Services/BasketService.cs @@ -12,14 +12,14 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services { public class BasketService : IBasketService { - private readonly IOptionsSnapshot _settings; + private readonly IOptions _settings; private readonly HttpClient _apiClient; private readonly string _basketByPassUrl; private readonly string _purchaseUrl; private readonly string _bffUrl; - public BasketService(HttpClient httpClient,IOptionsSnapshot settings) + public BasketService(HttpClient httpClient, IOptions settings) { _apiClient = httpClient; _settings = settings; @@ -30,21 +30,22 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services public async Task GetBasket(ApplicationUser user) { - var getBasketUri = API.Basket.GetBasket(_basketByPassUrl, user.Id); + var uri = API.Basket.GetBasket(_basketByPassUrl, user.Id); - var dataString = await _apiClient.GetStringAsync(getBasketUri); + var responseString = await _apiClient.GetStringAsync(uri); - return string.IsNullOrEmpty(dataString) ? - new Basket() { BuyerId = user.Id} : - JsonConvert.DeserializeObject(dataString); + return string.IsNullOrEmpty(responseString) ? + new Basket() { BuyerId = user.Id } : + JsonConvert.DeserializeObject(responseString); } public async Task UpdateBasket(Basket basket) { - var updateBasketUri = API.Basket.UpdateBasket(_basketByPassUrl); - var content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json"); + var uri = API.Basket.UpdateBasket(_basketByPassUrl); - var response = await _apiClient.PostAsync(updateBasketUri, content); + var basketContent = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json"); + + var response = await _apiClient.PostAsync(uri, basketContent); response.EnsureSuccessStatusCode(); @@ -53,18 +54,18 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services public async Task Checkout(BasketDTO basket) { - var updateBasketUri = API.Basket.CheckoutBasket(_basketByPassUrl); - var content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json"); + var uri = API.Basket.CheckoutBasket(_basketByPassUrl); + var basketContent = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json"); - var response = await _apiClient.PostAsync(updateBasketUri, content); + var response = await _apiClient.PostAsync(uri, basketContent); response.EnsureSuccessStatusCode(); } public async Task SetQuantities(ApplicationUser user, Dictionary quantities) { + var uri = API.Purchase.UpdateBasketItem(_purchaseUrl); - var updateBasketUri = API.Purchase.UpdateBasketItem(_purchaseUrl); var basketUpdate = new { BasketId = user.Id, @@ -75,9 +76,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services }).ToArray() }; - var content = new StringContent(JsonConvert.SerializeObject(basketUpdate), System.Text.Encoding.UTF8, "application/json"); + var basketContent = new StringContent(JsonConvert.SerializeObject(basketUpdate), System.Text.Encoding.UTF8, "application/json"); - var response = await _apiClient.PutAsync(updateBasketUri,content); + var response = await _apiClient.PutAsync(uri, basketContent); response.EnsureSuccessStatusCode(); @@ -88,17 +89,18 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services public async Task GetOrderDraft(string basketId) { - var draftOrderUri = API.Purchase.GetOrderDraft(_purchaseUrl, basketId); - var response = await _apiClient.GetStringAsync(draftOrderUri); + var uri = API.Purchase.GetOrderDraft(_purchaseUrl, basketId); - return JsonConvert.DeserializeObject(response); + var responseString = await _apiClient.GetStringAsync(uri); + + var response = JsonConvert.DeserializeObject(responseString); + + return response; } - - public async Task AddItemToBasket(ApplicationUser user, int productId) { - var updateBasketUri = API.Purchase.AddItemToBasket(_purchaseUrl); + var uri = API.Purchase.AddItemToBasket(_purchaseUrl); var newItem = new { @@ -107,9 +109,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services Quantity = 1 }; - var content = new StringContent(JsonConvert.SerializeObject(newItem), System.Text.Encoding.UTF8, "application/json"); + var basketContent = new StringContent(JsonConvert.SerializeObject(newItem), System.Text.Encoding.UTF8, "application/json"); - var response = await _apiClient.PostAsync(updateBasketUri, content); + var response = await _apiClient.PostAsync(uri, basketContent); } } } diff --git a/src/Web/WebMVC/Services/CampaignService.cs b/src/Web/WebMVC/Services/CampaignService.cs index 7d61c9e7a..6521fd4ae 100644 --- a/src/Web/WebMVC/Services/CampaignService.cs +++ b/src/Web/WebMVC/Services/CampaignService.cs @@ -1,69 +1,49 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services { using global::WebMVC.Infrastructure; - using AspNetCore.Authentication; - using AspNetCore.Http; - using BuildingBlocks.Resilience.Http; - using ViewModels; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; - using System; + using System.Net.Http; using System.Threading.Tasks; + using ViewModels; public class CampaignService : ICampaignService { - private readonly IOptionsSnapshot _settings; - private readonly IHttpClient _apiClient; + private readonly IOptions _settings; + private readonly HttpClient _httpClient; private readonly ILogger _logger; private readonly string _remoteServiceBaseUrl; - private readonly IHttpContextAccessor _httpContextAccesor; - public CampaignService(IOptionsSnapshot settings, IHttpClient httpClient, - ILogger logger, IHttpContextAccessor httpContextAccesor) + public CampaignService(IOptions settings, HttpClient httpClient, ILogger logger) { _settings = settings; - _apiClient = httpClient; + _httpClient = httpClient; _logger = logger; _remoteServiceBaseUrl = $"{_settings.Value.MarketingUrl}/api/v1/m/campaigns/"; - _httpContextAccesor = httpContextAccesor ?? throw new ArgumentNullException(nameof(httpContextAccesor)); } public async Task GetCampaigns(int pageSize, int pageIndex) { - var allCampaignItemsUri = API.Marketing.GetAllCampaigns(_remoteServiceBaseUrl, - pageSize, pageIndex); + var uri = API.Marketing.GetAllCampaigns(_remoteServiceBaseUrl, pageSize, pageIndex); - var authorizationToken = await GetUserTokenAsync(); - var dataString = await _apiClient.GetStringAsync(allCampaignItemsUri, authorizationToken); + var responseString = await _httpClient.GetStringAsync(uri); - var response = JsonConvert.DeserializeObject(dataString); + var response = JsonConvert.DeserializeObject(responseString); return response; } public async Task GetCampaignById(int id) { - var campaignByIdItemUri = API.Marketing.GetAllCampaignById(_remoteServiceBaseUrl, id); + var uri = API.Marketing.GetAllCampaignById(_remoteServiceBaseUrl, id); - var authorizationToken = await GetUserTokenAsync(); - var dataString = await _apiClient.GetStringAsync(campaignByIdItemUri, authorizationToken); + var responseString = await _httpClient.GetStringAsync(uri); - var response = JsonConvert.DeserializeObject(dataString); + var response = JsonConvert.DeserializeObject(responseString); return response; } - - private string GetUserIdentity() - { - return _httpContextAccesor.HttpContext.User.FindFirst("sub").Value; - } - - private async Task GetUserTokenAsync() - { - var context = _httpContextAccesor.HttpContext; - return await context.GetTokenAsync("access_token"); - } } } \ No newline at end of file diff --git a/src/Web/WebMVC/Services/CatalogService.cs b/src/Web/WebMVC/Services/CatalogService.cs index 5b6fbe26b..d4899b453 100644 --- a/src/Web/WebMVC/Services/CatalogService.cs +++ b/src/Web/WebMVC/Services/CatalogService.cs @@ -1,11 +1,11 @@ using Microsoft.AspNetCore.Mvc.Rendering; -using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http; using Microsoft.eShopOnContainers.WebMVC.ViewModels; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Collections.Generic; +using System.Net.Http; using System.Threading.Tasks; using WebMVC.Infrastructure; @@ -13,16 +13,16 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services { public class CatalogService : ICatalogService { - private readonly IOptionsSnapshot _settings; - private readonly IHttpClient _apiClient; + private readonly IOptions _settings; + private readonly HttpClient _httpClient; private readonly ILogger _logger; private readonly string _remoteServiceBaseUrl; - public CatalogService(IOptionsSnapshot settings, IHttpClient httpClient, ILogger logger) + public CatalogService(HttpClient httpClient, ILogger logger, IOptions settings) { + _httpClient = httpClient; _settings = settings; - _apiClient = httpClient; _logger = logger; _remoteServiceBaseUrl = $"{_settings.Value.PurchaseUrl}/api/v1/c/catalog/"; @@ -30,25 +30,26 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services public async Task GetCatalogItems(int page, int take, int? brand, int? type) { - var allcatalogItemsUri = API.Catalog.GetAllCatalogItems(_remoteServiceBaseUrl, page, take, brand, type); + var uri = API.Catalog.GetAllCatalogItems(_remoteServiceBaseUrl, page, take, brand, type); - var dataString = await _apiClient.GetStringAsync(allcatalogItemsUri); + var responseString = await _httpClient.GetStringAsync(uri); - var response = JsonConvert.DeserializeObject(dataString); + var catalog = JsonConvert.DeserializeObject(responseString); - return response; + return catalog; } public async Task> GetBrands() { - var getBrandsUri = API.Catalog.GetAllBrands(_remoteServiceBaseUrl); + var uri = API.Catalog.GetAllBrands(_remoteServiceBaseUrl); - var dataString = await _apiClient.GetStringAsync(getBrandsUri); + var responseString = await _httpClient.GetStringAsync(uri); var items = new List(); + items.Add(new SelectListItem() { Value = null, Text = "All", Selected = true }); - var brands = JArray.Parse(dataString); + var brands = JArray.Parse(responseString); foreach (var brand in brands.Children()) { @@ -64,14 +65,14 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services public async Task> GetTypes() { - var getTypesUri = API.Catalog.GetAllTypes(_remoteServiceBaseUrl); + var uri = API.Catalog.GetAllTypes(_remoteServiceBaseUrl); - var dataString = await _apiClient.GetStringAsync(getTypesUri); + var responseString = await _httpClient.GetStringAsync(uri); var items = new List(); items.Add(new SelectListItem() { Value = null, Text = "All", Selected = true }); - var brands = JArray.Parse(dataString); + var brands = JArray.Parse(responseString); foreach (var brand in brands.Children()) { items.Add(new SelectListItem() @@ -80,6 +81,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services Text = brand.Value("type") }); } + return items; } } diff --git a/src/Web/WebMVC/Services/LocationService.cs b/src/Web/WebMVC/Services/LocationService.cs index 8bbdf743a..3e58ef125 100644 --- a/src/Web/WebMVC/Services/LocationService.cs +++ b/src/Web/WebMVC/Services/LocationService.cs @@ -1,11 +1,9 @@ -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Http; -using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http; -using Microsoft.eShopOnContainers.WebMVC; +using Microsoft.eShopOnContainers.WebMVC; using Microsoft.eShopOnContainers.WebMVC.Services; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using System; +using Newtonsoft.Json; +using System.Net.Http; using System.Threading.Tasks; using WebMVC.Infrastructure; using WebMVC.Models; @@ -14,36 +12,27 @@ namespace WebMVC.Services { public class LocationService : ILocationService { - private readonly IOptionsSnapshot _settings; - private readonly IHttpClient _apiClient; + private readonly IOptions _settings; + private readonly HttpClient _httpClient; private readonly ILogger _logger; private readonly string _remoteServiceBaseUrl; - private readonly IHttpContextAccessor _httpContextAccesor; - public LocationService(IOptionsSnapshot settings, IHttpClient httpClient, - ILogger logger, IHttpContextAccessor httpContextAccesor) + public LocationService(HttpClient httpClient, IOptions settings, ILogger logger) { + _httpClient = httpClient; _settings = settings; - _apiClient = httpClient; _logger = logger; _remoteServiceBaseUrl = $"{_settings.Value.MarketingUrl}/api/v1/l/locations/"; - _httpContextAccesor = httpContextAccesor ?? throw new ArgumentNullException(nameof(httpContextAccesor)); } public async Task CreateOrUpdateUserLocation(LocationDTO location) { - var createOrUpdateUserLocationUri = API.Locations.CreateOrUpdateUserLocation(_remoteServiceBaseUrl); + var uri = API.Locations.CreateOrUpdateUserLocation(_remoteServiceBaseUrl); + var locationContent = new StringContent(JsonConvert.SerializeObject(location), System.Text.Encoding.UTF8, "application/json"); - var authorizationToken = await GetUserTokenAsync(); - var response = await _apiClient.PostAsync(createOrUpdateUserLocationUri, location, authorizationToken); + var response = await _httpClient.PostAsync(uri, locationContent); response.EnsureSuccessStatusCode(); - } - - private async Task GetUserTokenAsync() - { - var context = _httpContextAccesor.HttpContext; - return await context.GetTokenAsync("access_token"); } } } diff --git a/src/Web/WebMVC/Services/OrderingService.cs b/src/Web/WebMVC/Services/OrderingService.cs index ec9d2e8fd..e3d24422f 100644 --- a/src/Web/WebMVC/Services/OrderingService.cs +++ b/src/Web/WebMVC/Services/OrderingService.cs @@ -1,11 +1,9 @@ -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Http; -using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http; -using Microsoft.eShopOnContainers.WebMVC.ViewModels; +using Microsoft.eShopOnContainers.WebMVC.ViewModels; using Microsoft.Extensions.Options; using Newtonsoft.Json; using System; using System.Collections.Generic; +using System.Net.Http; using System.Threading.Tasks; using WebMVC.Infrastructure; using WebMVC.Models; @@ -14,69 +12,54 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services { public class OrderingService : IOrderingService { - private IHttpClient _apiClient; + private HttpClient _httpClient; private readonly string _remoteServiceBaseUrl; - private readonly IOptionsSnapshot _settings; - private readonly IHttpContextAccessor _httpContextAccesor; + private readonly IOptions _settings; - public OrderingService(IOptionsSnapshot settings, IHttpContextAccessor httpContextAccesor, IHttpClient httpClient) + + public OrderingService(HttpClient httpClient, IOptions settings) { - _remoteServiceBaseUrl = $"{settings.Value.PurchaseUrl}/api/v1/o/orders"; + _httpClient = httpClient; _settings = settings; - _httpContextAccesor = httpContextAccesor; - _apiClient = httpClient; + + _remoteServiceBaseUrl = $"{settings.Value.PurchaseUrl}/api/v1/o/orders"; } async public Task GetOrder(ApplicationUser user, string id) { - var token = await GetUserTokenAsync(); - var getOrderUri = API.Order.GetOrder(_remoteServiceBaseUrl, id); + var uri = API.Order.GetOrder(_remoteServiceBaseUrl, id); - var dataString = await _apiClient.GetStringAsync(getOrderUri, token); + var responseString = await _httpClient.GetStringAsync(uri); - var response = JsonConvert.DeserializeObject(dataString); + var response = JsonConvert.DeserializeObject(responseString); return response; } async public Task> GetMyOrders(ApplicationUser user) { - var token = await GetUserTokenAsync(); - var allMyOrdersUri = API.Order.GetAllMyOrders(_remoteServiceBaseUrl); + var uri = API.Order.GetAllMyOrders(_remoteServiceBaseUrl); - var dataString = await _apiClient.GetStringAsync(allMyOrdersUri, token); - var response = JsonConvert.DeserializeObject>(dataString); + var responseString = await _httpClient.GetStringAsync(uri); + + var response = JsonConvert.DeserializeObject>(responseString); return response; } - public Order MapUserInfoIntoOrder(ApplicationUser user, Order order) - { - order.City = user.City; - order.Street = user.Street; - order.State = user.State; - order.Country = user.Country; - order.ZipCode = user.ZipCode; - order.CardNumber = user.CardNumber; - order.CardHolderName = user.CardHolderName; - order.CardExpiration = new DateTime(int.Parse("20" + user.Expiration.Split('/')[1]), int.Parse(user.Expiration.Split('/')[0]), 1); - order.CardSecurityNumber = user.SecurityNumber; - - return order; - } async public Task CancelOrder(string orderId) { - var token = await GetUserTokenAsync(); var order = new OrderDTO() { OrderNumber = orderId }; - var cancelOrderUri = API.Order.CancelOrder(_remoteServiceBaseUrl); - - var response = await _apiClient.PutAsync(cancelOrderUri, order, token, Guid.NewGuid().ToString()); + var uri = API.Order.CancelOrder(_remoteServiceBaseUrl); + var orderContent = new StringContent(JsonConvert.SerializeObject(order), System.Text.Encoding.UTF8, "application/json"); + + var response = await _httpClient.PutAsync(uri, orderContent); if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError) { @@ -88,15 +71,15 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services async public Task ShipOrder(string orderId) { - var token = await GetUserTokenAsync(); var order = new OrderDTO() { OrderNumber = orderId }; - var shipOrderUri = API.Order.ShipOrder(_remoteServiceBaseUrl); + var uri = API.Order.ShipOrder(_remoteServiceBaseUrl); + var orderContent = new StringContent(JsonConvert.SerializeObject(order), System.Text.Encoding.UTF8, "application/json"); - var response = await _apiClient.PutAsync(shipOrderUri, order, token, Guid.NewGuid().ToString()); + var response = await _httpClient.PutAsync(uri, orderContent); if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError) { @@ -120,6 +103,22 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services destination.CardSecurityNumber = original.CardSecurityNumber; } + public Order MapUserInfoIntoOrder(ApplicationUser user, Order order) + { + order.City = user.City; + order.Street = user.Street; + order.State = user.State; + order.Country = user.Country; + order.ZipCode = user.ZipCode; + + order.CardNumber = user.CardNumber; + order.CardHolderName = user.CardHolderName; + order.CardExpiration = new DateTime(int.Parse("20" + user.Expiration.Split('/')[1]), int.Parse(user.Expiration.Split('/')[0]), 1); + order.CardSecurityNumber = user.SecurityNumber; + + return order; + } + public BasketDTO MapOrderToBasket(Order order) { order.CardExpirationApiFormat(); @@ -140,18 +139,5 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services RequestId = order.RequestId }; } - - void SetFakeIdToProducts(Order order) - { - var id = 1; - order.OrderItems.ForEach(x => { x.ProductId = id; id++; }); - } - - async Task GetUserTokenAsync() - { - var context = _httpContextAccesor.HttpContext; - - return await context.GetTokenAsync("access_token"); - } } } diff --git a/src/Web/WebMVC/Startup.cs b/src/Web/WebMVC/Startup.cs index f93532852..9cc5921a2 100644 --- a/src/Web/WebMVC/Startup.cs +++ b/src/Web/WebMVC/Startup.cs @@ -6,8 +6,6 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http; -using Microsoft.eShopOnContainers.WebMVC.Infrastructure; using Microsoft.eShopOnContainers.WebMVC.Services; using Microsoft.eShopOnContainers.WebMVC.ViewModels; using Microsoft.Extensions.Configuration; @@ -15,15 +13,10 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.HealthChecks; using Microsoft.Extensions.Logging; using Polly; -using Polly.CircuitBreaker; using Polly.Extensions.Http; -using Polly.Registry; -using Polly.Retry; -using Polly.Timeout; using StackExchange.Redis; using System; using System.IdentityModel.Tokens.Jwt; -using System.Net.Http; using WebMVC.Infrastructure; using WebMVC.Infrastructure.Middlewares; using WebMVC.Services; @@ -151,6 +144,9 @@ namespace Microsoft.eShopOnContainers.WebMVC public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration) { + services.AddOptions(); + services.Configure(configuration); + services.AddMvc(); services.AddSession(); @@ -163,124 +159,58 @@ namespace Microsoft.eShopOnContainers.WebMVC }) .PersistKeysToRedis(ConnectionMultiplexer.Connect(configuration["DPConnectionString"]), "DataProtection-Keys"); } - - services.Configure(configuration); - return services; } // Adds all Http client services (like Service-Agents) using resilient Http requests based on HttpClient factory and Polly's policies public static IServiceCollection AddHttpClientServices(this IServiceCollection services, IConfiguration configuration) { - // (CDLTLL) TEMPORAL COMMENT: Do we need this line of code if using HttpClient factory? services.AddSingleton(); - // (CDLTLL) I don't think we need this HttpClientDefaultPolicies if using fluent configuration ,as below... - // Create a singleton object with the by default policies - services.AddSingleton(); - var defaultPolicies = services.BuildServiceProvider().GetService(); - - // Create a Polly-Policy-Registry with the by default policies for resilient Http requests - var pollyPolicyRegistry = services.AddPolicyRegistry(); - - //Using fluent client configuration of Polly policies - - var retriesWithExponentialBackoff = HttpPolicyExtensions - .HandleTransientHttpError() - .WaitAndRetryAsync(7, - retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)) - ); //(CDLTLL) Instead of hardcoded values, use: configuration["HttpClientMaxNumberRetries"], configuration["SecondsBaseForExponentialBackoff"] + var retriesWithExponentialBackoff = HttpPolicyExtensions + .HandleTransientHttpError() + .WaitAndRetryAsync(7,retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); + var circuitBreaker = HttpPolicyExtensions - .HandleTransientHttpError() - .CircuitBreakerAsync(6, - TimeSpan.FromSeconds(30) - ); - //(CDLTLL) Instead of hardcoded values, use: configuration["HttpClientExceptionsAllowedBeforeBreaking"], configuration["DurationOfBreakInMinutes"] + .HandleTransientHttpError() + .CircuitBreakerAsync(6, TimeSpan.FromSeconds(30)); - - pollyPolicyRegistry.Add("DefaultRetriesWithExponentialBackoff", retriesWithExponentialBackoff); - pollyPolicyRegistry.Add("DefaultCircuitBreaker", circuitBreaker); - - - // (CDLTLL) Using "OLD" policies. I don't like it much... - //pollyPolicyRegistry.Add("DefaultRetriesWithExponentialBackoff", defaultPolicies.GetWaitAndRetryPolicy()); // (CDLTLL) TEMPORAL COMMENT: Arguments here would be a good place to propagate the configuration values --> GetWaitAndRetryPolicy(configuration["HttpClientMaxNumberRetries"], configuration["SecondsBaseForExponentialBackoff"]) - //pollyPolicyRegistry.Add("DefaultCircuitBreaker", defaultPolicies.GetCircuitBreakerPolicy()); // (CDLTLL) TEMPORAL COMMENT: Arguments here would be a good place to propagate the configuration values --> GetCircuitBreakerPolicy(configuration["HttpClientExceptionsAllowedBeforeBreaking"], configuration["DurationOfBreakInMinutes"]) - - - - // (CDLTLL) Handlers need to be transient. //(CDLTLL) TEMPORAL COMMENT: This registration was missing, hence the error "InvalidOperationException: No service for type 'WebMVC.Infrastructure.HttpClientAuthorizationDelegatingHandler' has been registered" + //register delegating handlers services.AddTransient(); + services.AddTransient(); - //Add all Typed-Clients (Service-Agents) through the HttpClient factory to implement Resilient Http requests - // - - //Add BasketService typed client (Service Agent) + //add http client servicse services.AddHttpClient() - .AddHttpMessageHandler() //Additional Authentication-Delegating-Handler to add the OAuth-Bearer-token to the Http headers - .AddPolicyHandlerFromRegistry("DefaultRetriesWithExponentialBackoff") - .AddPolicyHandlerFromRegistry("DefaultCircuitBreaker"); + .AddHttpMessageHandler() + .AddPolicyHandler(retriesWithExponentialBackoff) + .AddPolicyHandler(circuitBreaker); - //Add CatalogService typed client (Service Agent) - //services.AddHttpClient() ... + services.AddHttpClient() + .AddPolicyHandler(retriesWithExponentialBackoff) + .AddPolicyHandler(circuitBreaker); - //Add OrderingService typed client (Service Agent) - //services.AddHttpClient() ... + services.AddHttpClient() + .AddHttpMessageHandler() + .AddHttpMessageHandler() + .AddPolicyHandler(retriesWithExponentialBackoff) + .AddPolicyHandler(circuitBreaker); - //Add CampaignService typed client (Service Agent) - //services.AddHttpClient() ... + services.AddHttpClient() + .AddHttpMessageHandler() + .AddPolicyHandler(retriesWithExponentialBackoff) + .AddPolicyHandler(circuitBreaker); - //Add LocationService typed client (Service Agent) - //services.AddHttpClient() ... + services.AddHttpClient() + .AddHttpMessageHandler() + .AddPolicyHandler(retriesWithExponentialBackoff) + .AddPolicyHandler(circuitBreaker); - //Add IdentityParser typed client (Service Agent) - //services.AddHttpClient() ... - - - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // (CDLTLL) TEMPORAL COMMENT: The following Typed-Clients (Service-Agents) have to be coded as BasketService by using AddHttpClient<>(), right? - // This code will be deleted - services.AddTransient(); - services.AddTransient(); - - services.AddTransient(); - services.AddTransient(); + //add custom application services services.AddTransient, IdentityParser>(); - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // TEMPORAL COMMENT: This code will be deleted when using HttpClientFactory, right? - if (configuration.GetValue("UseResilientHttp") == bool.TrueString) - { - services.AddSingleton(sp => - { - var logger = sp.GetRequiredService>(); - var httpContextAccessor = sp.GetRequiredService(); - - var retryCount = 6; - if (!string.IsNullOrEmpty(configuration["HttpClientRetryCount"])) - { - retryCount = int.Parse(configuration["HttpClientRetryCount"]); - } - - var exceptionsAllowedBeforeBreaking = 5; - if (!string.IsNullOrEmpty(configuration["HttpClientExceptionsAllowedBeforeBreaking"])) - { - exceptionsAllowedBeforeBreaking = int.Parse(configuration["HttpClientExceptionsAllowedBeforeBreaking"]); - } - - return new ResilientHttpClientFactory(logger, httpContextAccessor, exceptionsAllowedBeforeBreaking, retryCount); - }); - services.AddSingleton(sp => sp.GetService().CreateResilientHttpClient()); - } - else - { - services.AddSingleton(); - } - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - + return services; } public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration)