diff --git a/src/BuildingBlocks/Resilience/Resilience.Http/IHttpClient.cs b/src/BuildingBlocks/Resilience/Resilience.Http/IHttpClient.cs index 0e56a66da..5ea3003ed 100644 --- a/src/BuildingBlocks/Resilience/Resilience.Http/IHttpClient.cs +++ b/src/BuildingBlocks/Resilience/Resilience.Http/IHttpClient.cs @@ -1,16 +1,16 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; +using System.Net.Http; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http { public interface IHttpClient { - HttpClient Inst { get; } - Task GetStringAsync(string uri); - Task PostAsync(string uri, T item); - Task DeleteAsync(string uri); + Task GetStringAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer"); + + Task PostAsync(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer"); + + Task DeleteAsync(string uri, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer"); + + Task PutAsync(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer"); } } diff --git a/src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs b/src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs index 2ccc84aaa..a76e60f0b 100644 --- a/src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs +++ b/src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs @@ -4,8 +4,10 @@ using Polly; using Polly.Wrap; using System; using System.Collections.Generic; +using System.Linq; using System.Net; using System.Net.Http; +using System.Net.Http.Headers; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http @@ -18,47 +20,134 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http public class ResilientHttpClient : IHttpClient { private HttpClient _client; - private PolicyWrap _policyWrapper; + private readonly Dictionary _policiesPerOrigin; private ILogger _logger; - public HttpClient Inst => _client; + private readonly Func> _policyCreator; + //public HttpClient Inst => _client; - public ResilientHttpClient(Policy[] policies, ILogger logger) + public ResilientHttpClient(Func> policyCreator, ILogger logger) { _client = new HttpClient(); _logger = logger; + _policiesPerOrigin = new Dictionary(); + _policyCreator = policyCreator; + } - // Add Policies to be applied - _policyWrapper = Policy.WrapAsync(policies); - } + private Task HttpInvoker(string origin, Func> action) + { + var normalizedOrigin = NormalizeOrigin(origin); + + if (!_policiesPerOrigin.ContainsKey(normalizedOrigin)) + { + var newWrapper = Policy.WrapAsync(_policyCreator(normalizedOrigin).ToArray()); + _policiesPerOrigin.Add(normalizedOrigin, newWrapper); + } + + var policyWrapper = _policiesPerOrigin[normalizedOrigin]; + + // Executes the action applying all + // the policies defined in the wrapper + return policyWrapper.ExecuteAsync(() => action()); + } + + private static string NormalizeOrigin(string origin) + { + return origin?.Trim()?.ToLower(); + } - public Task GetStringAsync(string uri) => - HttpInvoker(() => - _client.GetStringAsync(uri)); + public Task GetStringAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer") + { + var origin = GetOriginFromUri(uri); + return HttpInvoker(origin, async () => + { + var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri); + + if (authorizationToken != null) + { + requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken); + } + + var response = await _client.SendAsync(requestMessage); + + return await response.Content.ReadAsStringAsync(); + }); + } + + private static string GetOriginFromUri(string uri) + { + var url = new Uri(uri); + var origin = $"{url.Scheme}://{url.DnsSafeHost}:{url.Port}"; + return origin; + } + + private Task DoPostPutAsync(HttpMethod method, string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer") + { + if (method != HttpMethod.Post && method != HttpMethod.Put) + { + throw new ArgumentException("Value must be either post or put.", nameof(method)); + } - public Task PostAsync(string uri, T item) => // a new StringContent must be created for each retry // as it is disposed after each call - HttpInvoker(() => + var origin = GetOriginFromUri(uri); + return HttpInvoker(origin, async () => { - var response = _client.PostAsync(uri, new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json")); + var requestMessage = new HttpRequestMessage(method, uri); + + requestMessage.Content = new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json"); + + if (authorizationToken != null) + { + requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken); + } + + if (requestId != null) + { + requestMessage.Headers.Add("x-requestid", requestId); + } + + var response = await _client.SendAsync(requestMessage); + // raise exception if HttpResponseCode 500 // needed for circuit breaker to track fails - if (response.Result.StatusCode == HttpStatusCode.InternalServerError) + + if (response.StatusCode == HttpStatusCode.InternalServerError) { throw new HttpRequestException(); } return response; }); + } - public Task DeleteAsync(string uri) => - HttpInvoker(() => _client.DeleteAsync(uri)); + public Task PostAsync(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer") + { + return DoPostPutAsync(HttpMethod.Post, uri, item, authorizationToken, requestId, authorizationMethod); + } + public Task PutAsync(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer") + { + return DoPostPutAsync(HttpMethod.Put, uri, item, authorizationToken, requestId, authorizationMethod); + } + public Task DeleteAsync(string uri, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer") + { + var origin = GetOriginFromUri(uri); + return HttpInvoker(origin, async () => + { + var requestMessage = new HttpRequestMessage(HttpMethod.Delete, uri); + if (authorizationToken != null) + { + requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken); + } - private Task HttpInvoker(Func> action) => - // Executes the action applying all - // the policies defined in the wrapper - _policyWrapper.ExecuteAsync(() => action()); - } + if (requestId != null) + { + requestMessage.Headers.Add("x-requestid", requestId); + } + return await _client.SendAsync(requestMessage); + }); + } + + } } diff --git a/src/BuildingBlocks/Resilience/Resilience.Http/StandardHttpClient.cs b/src/BuildingBlocks/Resilience/Resilience.Http/StandardHttpClient.cs index 4f400caf5..3d5217064 100644 --- a/src/BuildingBlocks/Resilience/Resilience.Http/StandardHttpClient.cs +++ b/src/BuildingBlocks/Resilience/Resilience.Http/StandardHttpClient.cs @@ -1,7 +1,9 @@ using Microsoft.Extensions.Logging; using Newtonsoft.Json; using System; +using System.Net; using System.Net.Http; +using System.Net.Http.Headers; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http @@ -10,24 +12,90 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http { private HttpClient _client; private ILogger _logger; - public HttpClient Inst => _client; + public StandardHttpClient(ILogger logger) { _client = new HttpClient(); _logger = logger; } - - public Task GetStringAsync(string uri) => - _client.GetStringAsync(uri); - public Task PostAsync(string uri, T item) + public async Task GetStringAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer") { - var contentString = new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json"); - return _client.PostAsync(uri, contentString); + var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri); + + if (authorizationToken != null) + { + requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken); + } + + var response = await _client.SendAsync(requestMessage); + + return await response.Content.ReadAsStringAsync(); } - public Task DeleteAsync(string uri) => - _client.DeleteAsync(uri); + private async Task DoPostPutAsync(HttpMethod method, string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer") + { + if (method != HttpMethod.Post && method != HttpMethod.Put) + { + throw new ArgumentException("Value must be either post or put.", nameof(method)); + } + + // a new StringContent must be created for each retry + // as it is disposed after each call + + var requestMessage = new HttpRequestMessage(HttpMethod.Post, uri); + + requestMessage.Content = new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json"); + + if (authorizationToken != null) + { + requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken); + } + + if (requestId != null) + { + requestMessage.Headers.Add("x-requestid", requestId); + } + + var response = await _client.SendAsync(requestMessage); + + // raise exception if HttpResponseCode 500 + // needed for circuit breaker to track fails + + if (response.StatusCode == HttpStatusCode.InternalServerError) + { + throw new HttpRequestException(); + } + + return response; + } + + + public async Task PostAsync(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer") + { + return await DoPostPutAsync(HttpMethod.Post, uri, item, authorizationToken, requestId, authorizationToken); + } + + public async Task PutAsync(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer") + { + return await DoPostPutAsync(HttpMethod.Put, uri, item, authorizationToken, requestId, authorizationToken); + } + public async Task DeleteAsync(string uri, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer") + { + var requestMessage = new HttpRequestMessage(HttpMethod.Delete, uri); + + if (authorizationToken != null) + { + requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken); + } + + if (requestId != null) + { + requestMessage.Headers.Add("x-requestid", requestId); + } + + return await _client.SendAsync(requestMessage); + } } } diff --git a/src/Web/WebMVC/Infrastructure/API.cs b/src/Web/WebMVC/Infrastructure/API.cs new file mode 100644 index 000000000..c837b8067 --- /dev/null +++ b/src/Web/WebMVC/Infrastructure/API.cs @@ -0,0 +1,68 @@ +namespace WebMVC.Infrastructure +{ + public static class API + { + public static class Basket + { + public static string GetBasket(string baseUri, string basketId) + { + return $"{baseUri}/{basketId}"; + } + + public static string UpdateBasket(string baseUri) + { + return baseUri; + } + + public static string CleanBasket(string baseUri, string basketId) + { + return $"{baseUri}/{basketId}"; + } + } + + public static class Order + { + public static string GetOrder(string baseUri, string orderId) + { + return $"{baseUri}/{orderId}"; + } + + public static string GetAllMyOrders(string baseUri) + { + return baseUri; + } + + public static string AddNewOrder(string baseUri) + { + return $"{baseUri}/new"; + } + } + + public static class Catalog + { + public static string GetAllCatalogItems(string baseUri, int page, int take, int? brand, int? type) + { + var filterQs = ""; + + if (brand.HasValue || type.HasValue) + { + var brandQs = (brand.HasValue) ? brand.Value.ToString() : "null"; + var typeQs = (type.HasValue) ? type.Value.ToString() : "null"; + filterQs = $"/type/{typeQs}/brand/{brandQs}"; + } + + return $"{baseUri}items{filterQs}?pageIndex={page}&pageSize={take}"; + } + + public static string GetAllBrands(string baseUri) + { + return $"{baseUri}catalogBrands"; + } + + public static string GetAllTypes(string baseUri) + { + return $"{baseUri}catalogTypes"; + } + } + } +} diff --git a/src/Web/WebMVC/Infrastructure/ResilientHttpClientFactory.cs b/src/Web/WebMVC/Infrastructure/ResilientHttpClientFactory.cs index 8efadf366..8eb43179d 100644 --- a/src/Web/WebMVC/Infrastructure/ResilientHttpClientFactory.cs +++ b/src/Web/WebMVC/Infrastructure/ResilientHttpClientFactory.cs @@ -17,7 +17,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure =>_logger = logger; public ResilientHttpClient CreateResilientHttpClient() - => new ResilientHttpClient(CreatePolicies(), _logger); + => new ResilientHttpClient((origin) => CreatePolicies(), _logger); private Policy[] CreatePolicies() diff --git a/src/Web/WebMVC/Services/BasketService.cs b/src/Web/WebMVC/Services/BasketService.cs index 7d82a0fc6..bd418ea26 100644 --- a/src/Web/WebMVC/Services/BasketService.cs +++ b/src/Web/WebMVC/Services/BasketService.cs @@ -5,9 +5,8 @@ using Microsoft.eShopOnContainers.WebMVC.ViewModels; using Microsoft.Extensions.Options; using Newtonsoft.Json; using System.Collections.Generic; -using System.Linq; -using System.Net.Http; using System.Threading.Tasks; +using WebMVC.Infrastructure; namespace Microsoft.eShopOnContainers.WebMVC.Services { @@ -28,15 +27,13 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services public async Task GetBasket(ApplicationUser user) { - var context = _httpContextAccesor.HttpContext; - var token = await context.Authentication.GetTokenAsync("access_token"); + var token = await GetUserTokenAsync(); + var getBasketUri = API.Basket.GetBasket(_remoteServiceBaseUrl, user.Id); - _apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + var dataString = await _apiClient.GetStringAsync(getBasketUri, token); - var basketUrl = $"{_remoteServiceBaseUrl}/{user.Id}"; - var dataString = await _apiClient.GetStringAsync(basketUrl); // Use the ?? Null conditional operator to simplify the initialization of response - var response = JsonConvert.DeserializeObject(dataString) ?? + var response = JsonConvert.DeserializeObject(dataString) ?? new Basket() { BuyerId = user.Id @@ -47,14 +44,10 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services public async Task UpdateBasket(Basket basket) { - var context = _httpContextAccesor.HttpContext; - var token = await context.Authentication.GetTokenAsync("access_token"); - - _apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + var token = await GetUserTokenAsync(); + var updateBasketUri = API.Basket.UpdateBasket(_remoteServiceBaseUrl); - var basketUrl = _remoteServiceBaseUrl; - - var response = await _apiClient.PostAsync(basketUrl, basket); + var response = await _apiClient.PostAsync(updateBasketUri, basket, token); response.EnsureSuccessStatusCode(); @@ -88,7 +81,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services order.OrderItems.Add(new OrderItem() { ProductId = int.Parse(x.ProductId), - + PictureUrl = x.PictureUrl, ProductName = x.ProductName, Units = x.Quantity, @@ -102,7 +95,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services public async Task AddItemToBasket(ApplicationUser user, BasketItem product) { - Basket basket = await GetBasket(user); + var basket = await GetBasket(user); + if (basket == null) { basket = new Basket() @@ -113,20 +107,25 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services } basket.Items.Add(product); + await UpdateBasket(basket); } public async Task CleanBasket(ApplicationUser user) { - var context = _httpContextAccesor.HttpContext; - var token = await context.Authentication.GetTokenAsync("access_token"); + var token = await GetUserTokenAsync(); + var cleanBasketUri = API.Basket.CleanBasket(_remoteServiceBaseUrl, user.Id); + + var response = await _apiClient.DeleteAsync(cleanBasketUri, token); - _apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); - var basketUrl = $"{_remoteServiceBaseUrl}/{user.Id}"; - var response = await _apiClient.DeleteAsync(basketUrl); - //CCE: response status code... } + + async Task GetUserTokenAsync() + { + var context = _httpContextAccesor.HttpContext; + return await context.Authentication.GetTokenAsync("access_token"); + } } } diff --git a/src/Web/WebMVC/Services/CatalogService.cs b/src/Web/WebMVC/Services/CatalogService.cs index f7225ff0b..2af428e2e 100644 --- a/src/Web/WebMVC/Services/CatalogService.cs +++ b/src/Web/WebMVC/Services/CatalogService.cs @@ -7,43 +7,32 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Collections.Generic; using System.Threading.Tasks; +using WebMVC.Infrastructure; namespace Microsoft.eShopOnContainers.WebMVC.Services { public class CatalogService : ICatalogService { private readonly IOptionsSnapshot _settings; - private IHttpClient _apiClient; + private readonly IHttpClient _apiClient; + private readonly ILogger _logger; + private readonly string _remoteServiceBaseUrl; - - public CatalogService(IOptionsSnapshot settings, ILoggerFactory loggerFactory, IHttpClient httpClient) { + + public CatalogService(IOptionsSnapshot settings, IHttpClient httpClient, ILogger logger) + { _settings = settings; - _remoteServiceBaseUrl = $"{_settings.Value.CatalogUrl}/api/v1/catalog/"; _apiClient = httpClient; - var log = loggerFactory.CreateLogger("catalog service"); - log.LogDebug(settings.Value.CatalogUrl); - } - - public async Task GetCatalogItems(int page,int take, int? brand, int? type) - { - var itemsQs = $"items?pageIndex={page}&pageSize={take}"; - var filterQs = ""; + _logger = logger; - if (brand.HasValue || type.HasValue) - { - var brandQs = (brand.HasValue) ? brand.Value.ToString() : "null"; - var typeQs = (type.HasValue) ? type.Value.ToString() : "null"; - filterQs = $"/type/{typeQs}/brand/{brandQs}"; - } - - var catalogUrl = $"{_remoteServiceBaseUrl}items{filterQs}?pageIndex={page}&pageSize={take}"; + _remoteServiceBaseUrl = $"{_settings.Value.CatalogUrl}/api/v1/catalog/"; + } - var dataString = ""; + public async Task GetCatalogItems(int page, int take, int? brand, int? type) + { + var allcatalogItemsUri = API.Catalog.GetAllCatalogItems(_remoteServiceBaseUrl, page, take, brand, type); - // - // Using a HttpClient wrapper with Retry and Exponential Backoff - // - dataString = await _apiClient.GetStringAsync(catalogUrl); + var dataString = await _apiClient.GetStringAsync(allcatalogItemsUri); var response = JsonConvert.DeserializeObject(dataString); @@ -52,14 +41,16 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services public async Task> GetBrands() { - var url = $"{_remoteServiceBaseUrl}catalogBrands"; - var dataString = await _apiClient.GetStringAsync(url); + var getBrandsUri = API.Catalog.GetAllBrands(_remoteServiceBaseUrl); + + var dataString = await _apiClient.GetStringAsync(getBrandsUri); var items = new List(); items.Add(new SelectListItem() { Value = null, Text = "All", Selected = true }); - JArray brands = JArray.Parse(dataString); - foreach (JObject brand in brands.Children()) + var brands = JArray.Parse(dataString); + + foreach (var brand in brands.Children()) { items.Add(new SelectListItem() { @@ -73,14 +64,15 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services public async Task> GetTypes() { - var url = $"{_remoteServiceBaseUrl}catalogTypes"; - var dataString = await _apiClient.GetStringAsync(url); + var getTypesUri = API.Catalog.GetAllTypes(_remoteServiceBaseUrl); + + var dataString = await _apiClient.GetStringAsync(getTypesUri); var items = new List(); items.Add(new SelectListItem() { Value = null, Text = "All", Selected = true }); - JArray brands = JArray.Parse(dataString); - foreach (JObject brand in brands.Children()) + var brands = JArray.Parse(dataString); + foreach (var brand in brands.Children()) { items.Add(new SelectListItem() { diff --git a/src/Web/WebMVC/Services/OrderingService.cs b/src/Web/WebMVC/Services/OrderingService.cs index 570a48361..8f198fbed 100644 --- a/src/Web/WebMVC/Services/OrderingService.cs +++ b/src/Web/WebMVC/Services/OrderingService.cs @@ -1,14 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.eShopOnContainers.WebMVC.ViewModels; +using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; +using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http; +using Microsoft.eShopOnContainers.WebMVC.ViewModels; using Microsoft.Extensions.Options; -using System.Net.Http; using Newtonsoft.Json; -using Microsoft.AspNetCore.Authentication; -using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using WebMVC.Infrastructure; namespace Microsoft.eShopOnContainers.WebMVC.Services { @@ -27,15 +26,13 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services _apiClient = httpClient; } - async public Task GetOrder(ApplicationUser user, string Id) + async public Task GetOrder(ApplicationUser user, string id) { - var context = _httpContextAccesor.HttpContext; - var token = await context.Authentication.GetTokenAsync("access_token"); - _apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + var token = await GetUserTokenAsync(); + var getOrderUri = API.Order.GetOrder(_remoteServiceBaseUrl, id); + + var dataString = await _apiClient.GetStringAsync(getOrderUri, token); - var ordersUrl = $"{_remoteServiceBaseUrl}/{Id}"; - var dataString = await _apiClient.GetStringAsync(ordersUrl); - var response = JsonConvert.DeserializeObject(dataString); return response; @@ -43,16 +40,13 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services async public Task> GetMyOrders(ApplicationUser user) { - var context = _httpContextAccesor.HttpContext; - var token = await context.Authentication.GetTokenAsync("access_token"); + var token = await GetUserTokenAsync(); + var allMyOrdersUri = API.Order.GetAllMyOrders(_remoteServiceBaseUrl); - _apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); - - var ordersUrl = _remoteServiceBaseUrl; - var dataString = await _apiClient.GetStringAsync(ordersUrl); + var dataString = await _apiClient.GetStringAsync(allMyOrdersUri, token); var response = JsonConvert.DeserializeObject>(dataString); - return response; + return response; } public Order MapUserInfoIntoOrder(ApplicationUser user, Order order) @@ -62,10 +56,10 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services 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.CardExpiration = new DateTime(int.Parse("20" + user.Expiration.Split('/')[1]), int.Parse(user.Expiration.Split('/')[0]), 1); order.CardSecurityNumber = user.SecurityNumber; return order; @@ -73,21 +67,21 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services async public Task CreateOrder(Order order) { - var context = _httpContextAccesor.HttpContext; - var token = await context.Authentication.GetTokenAsync("access_token"); - - _apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); - _apiClient.Inst.DefaultRequestHeaders.Add("x-requestid", order.RequestId.ToString()); + var token = await GetUserTokenAsync(); + var requestId = order.RequestId.ToString(); + var addNewOrderUri = API.Order.AddNewOrder(_remoteServiceBaseUrl); - var ordersUrl = $"{_remoteServiceBaseUrl}/new"; order.CardTypeId = 1; order.CardExpirationApiFormat(); + SetFakeIdToProducts(order); - var response = await _apiClient.PostAsync(ordersUrl, order); + var response = await _apiClient.PostAsync(addNewOrderUri, order, token, requestId); if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError) - throw new Exception("Error creating order, try later"); + { + throw new Exception("Error creating order, try later."); + } response.EnsureSuccessStatusCode(); } @@ -106,10 +100,17 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services destination.CardSecurityNumber = original.CardSecurityNumber; } - private void SetFakeIdToProducts(Order order) + 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.Authentication.GetTokenAsync("access_token"); + } } } diff --git a/src/Web/WebMVC/Startup.cs b/src/Web/WebMVC/Startup.cs index e86c88c04..afc266051 100644 --- a/src/Web/WebMVC/Startup.cs +++ b/src/Web/WebMVC/Startup.cs @@ -70,11 +70,11 @@ namespace Microsoft.eShopOnContainers.WebMVC if (Configuration.GetValue("UseResilientHttp") == bool.TrueString) { services.AddTransient(); - services.AddTransient(sp => sp.GetService().CreateResilientHttpClient()); + services.AddSingleton(sp => sp.GetService().CreateResilientHttpClient()); } else { - services.AddTransient(); + services.AddSingleton(); } }