Added HTTPClient services and review application on WebMVC
This commit is contained in:
parent
dc5de83747
commit
2f9fa4dcca
@ -36,7 +36,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
|
|||||||
var basket = await _repository.GetBasketAsync(id);
|
var basket = await _repository.GetBasketAsync(id);
|
||||||
if (basket == null)
|
if (basket == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return Ok(new CustomerBasket(id) { });
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(basket);
|
return Ok(basket);
|
||||||
|
@ -7,9 +7,8 @@ namespace Microsoft.eShopOnContainers.WebMVC
|
|||||||
{
|
{
|
||||||
public class AppSettings
|
public class AppSettings
|
||||||
{
|
{
|
||||||
public Connectionstrings ConnectionStrings { get; set; }
|
//public Connectionstrings ConnectionStrings { get; set; }
|
||||||
public string MarketingUrl { get; set; }
|
public string MarketingUrl { get; set; }
|
||||||
|
|
||||||
public string PurchaseUrl { get; set; }
|
public string PurchaseUrl { get; set; }
|
||||||
public string SignalrHubUrl { get; set; }
|
public string SignalrHubUrl { get; set; }
|
||||||
public bool ActivateCampaignDetailFunction { get; set; }
|
public bool ActivateCampaignDetailFunction { get; set; }
|
||||||
|
@ -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<HttpResponseMessage> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,8 +3,8 @@ using System;
|
|||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
|
namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
|
||||||
{
|
{
|
||||||
public interface IResilientHttpClientFactory
|
//public interface IResilientHttpClientFactory
|
||||||
{
|
//{
|
||||||
ResilientHttpClient CreateResilientHttpClient();
|
// ResilientHttpClient CreateResilientHttpClient();
|
||||||
}
|
//}
|
||||||
}
|
}
|
@ -7,60 +7,60 @@ using System.Net.Http;
|
|||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
|
namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
|
||||||
{
|
{
|
||||||
public class ResilientHttpClientFactory : IResilientHttpClientFactory
|
//public class ResilientHttpClientFactory : IResilientHttpClientFactory
|
||||||
{
|
//{
|
||||||
private readonly ILogger<ResilientHttpClient> _logger;
|
// private readonly ILogger<ResilientHttpClient> _logger;
|
||||||
private readonly int _retryCount;
|
// private readonly int _retryCount;
|
||||||
private readonly int _exceptionsAllowedBeforeBreaking;
|
// private readonly int _exceptionsAllowedBeforeBreaking;
|
||||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
// private readonly IHttpContextAccessor _httpContextAccessor;
|
||||||
|
|
||||||
public ResilientHttpClientFactory(ILogger<ResilientHttpClient> logger, IHttpContextAccessor httpContextAccessor, int exceptionsAllowedBeforeBreaking = 5, int retryCount = 6)
|
// public ResilientHttpClientFactory(ILogger<ResilientHttpClient> logger, IHttpContextAccessor httpContextAccessor, int exceptionsAllowedBeforeBreaking = 5, int retryCount = 6)
|
||||||
{
|
// {
|
||||||
_logger = logger;
|
// _logger = logger;
|
||||||
_exceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
|
// _exceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
|
||||||
_retryCount = retryCount;
|
// _retryCount = retryCount;
|
||||||
_httpContextAccessor = httpContextAccessor;
|
// _httpContextAccessor = httpContextAccessor;
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
public ResilientHttpClient CreateResilientHttpClient()
|
// public ResilientHttpClient CreateResilientHttpClient()
|
||||||
=> new ResilientHttpClient((origin) => CreatePolicies(), _logger, _httpContextAccessor);
|
// => new ResilientHttpClient((origin) => CreatePolicies(), _logger, _httpContextAccessor);
|
||||||
|
|
||||||
private Policy[] CreatePolicies()
|
// private Policy[] CreatePolicies()
|
||||||
=> new Policy[]
|
// => new Policy[]
|
||||||
{
|
// {
|
||||||
Policy.Handle<HttpRequestException>()
|
// Policy.Handle<HttpRequestException>()
|
||||||
.WaitAndRetryAsync(
|
// .WaitAndRetryAsync(
|
||||||
// number of retries
|
// // number of retries
|
||||||
_retryCount,
|
// _retryCount,
|
||||||
// exponential backofff
|
// // exponential backofff
|
||||||
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
|
// retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
|
||||||
// on retry
|
// // on retry
|
||||||
(exception, timeSpan, retryCount, context) =>
|
// (exception, timeSpan, retryCount, context) =>
|
||||||
{
|
// {
|
||||||
var msg = $"Retry {retryCount} implemented with Polly's RetryPolicy " +
|
// var msg = $"Retry {retryCount} implemented with Polly's RetryPolicy " +
|
||||||
$"of {context.PolicyKey} " +
|
// $"of {context.PolicyKey} " +
|
||||||
$"at {context.OperationKey}, " +
|
// $"at {context.OperationKey}, " +
|
||||||
$"due to: {exception}.";
|
// $"due to: {exception}.";
|
||||||
_logger.LogWarning(msg);
|
// _logger.LogWarning(msg);
|
||||||
_logger.LogDebug(msg);
|
// _logger.LogDebug(msg);
|
||||||
}),
|
// }),
|
||||||
Policy.Handle<HttpRequestException>()
|
// Policy.Handle<HttpRequestException>()
|
||||||
.CircuitBreakerAsync(
|
// .CircuitBreakerAsync(
|
||||||
// number of exceptions before breaking circuit
|
// // number of exceptions before breaking circuit
|
||||||
_exceptionsAllowedBeforeBreaking,
|
// _exceptionsAllowedBeforeBreaking,
|
||||||
// time circuit opened before retry
|
// // time circuit opened before retry
|
||||||
TimeSpan.FromMinutes(1),
|
// TimeSpan.FromMinutes(1),
|
||||||
(exception, duration) =>
|
// (exception, duration) =>
|
||||||
{
|
// {
|
||||||
// on circuit opened
|
// // on circuit opened
|
||||||
_logger.LogTrace("Circuit breaker opened");
|
// _logger.LogTrace("Circuit breaker opened");
|
||||||
},
|
// },
|
||||||
() =>
|
// () =>
|
||||||
{
|
// {
|
||||||
// on circuit closed
|
// // on circuit closed
|
||||||
_logger.LogTrace("Circuit breaker reset");
|
// _logger.LogTrace("Circuit breaker reset");
|
||||||
})
|
// })
|
||||||
};
|
// };
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
@ -12,14 +12,14 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
{
|
{
|
||||||
public class BasketService : IBasketService
|
public class BasketService : IBasketService
|
||||||
{
|
{
|
||||||
private readonly IOptionsSnapshot<AppSettings> _settings;
|
private readonly IOptions<AppSettings> _settings;
|
||||||
private readonly HttpClient _apiClient;
|
private readonly HttpClient _apiClient;
|
||||||
private readonly string _basketByPassUrl;
|
private readonly string _basketByPassUrl;
|
||||||
private readonly string _purchaseUrl;
|
private readonly string _purchaseUrl;
|
||||||
|
|
||||||
private readonly string _bffUrl;
|
private readonly string _bffUrl;
|
||||||
|
|
||||||
public BasketService(HttpClient httpClient,IOptionsSnapshot<AppSettings> settings)
|
public BasketService(HttpClient httpClient, IOptions<AppSettings> settings)
|
||||||
{
|
{
|
||||||
_apiClient = httpClient;
|
_apiClient = httpClient;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
@ -30,21 +30,22 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
|
|
||||||
public async Task<Basket> GetBasket(ApplicationUser user)
|
public async Task<Basket> 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) ?
|
return string.IsNullOrEmpty(responseString) ?
|
||||||
new Basket() { BuyerId = user.Id} :
|
new Basket() { BuyerId = user.Id } :
|
||||||
JsonConvert.DeserializeObject<Basket>(dataString);
|
JsonConvert.DeserializeObject<Basket>(responseString);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Basket> UpdateBasket(Basket basket)
|
public async Task<Basket> UpdateBasket(Basket basket)
|
||||||
{
|
{
|
||||||
var updateBasketUri = API.Basket.UpdateBasket(_basketByPassUrl);
|
var uri = API.Basket.UpdateBasket(_basketByPassUrl);
|
||||||
var content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json");
|
|
||||||
|
|
||||||
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();
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
@ -53,18 +54,18 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
|
|
||||||
public async Task Checkout(BasketDTO basket)
|
public async Task Checkout(BasketDTO basket)
|
||||||
{
|
{
|
||||||
var updateBasketUri = API.Basket.CheckoutBasket(_basketByPassUrl);
|
var uri = API.Basket.CheckoutBasket(_basketByPassUrl);
|
||||||
var content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json");
|
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();
|
response.EnsureSuccessStatusCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Basket> SetQuantities(ApplicationUser user, Dictionary<string, int> quantities)
|
public async Task<Basket> SetQuantities(ApplicationUser user, Dictionary<string, int> quantities)
|
||||||
{
|
{
|
||||||
|
var uri = API.Purchase.UpdateBasketItem(_purchaseUrl);
|
||||||
|
|
||||||
var updateBasketUri = API.Purchase.UpdateBasketItem(_purchaseUrl);
|
|
||||||
var basketUpdate = new
|
var basketUpdate = new
|
||||||
{
|
{
|
||||||
BasketId = user.Id,
|
BasketId = user.Id,
|
||||||
@ -75,9 +76,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
}).ToArray()
|
}).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();
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
@ -88,17 +89,18 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
|
|
||||||
public async Task<Order> GetOrderDraft(string basketId)
|
public async Task<Order> GetOrderDraft(string basketId)
|
||||||
{
|
{
|
||||||
var draftOrderUri = API.Purchase.GetOrderDraft(_purchaseUrl, basketId);
|
var uri = API.Purchase.GetOrderDraft(_purchaseUrl, basketId);
|
||||||
var response = await _apiClient.GetStringAsync(draftOrderUri);
|
|
||||||
|
|
||||||
return JsonConvert.DeserializeObject<Order>(response);
|
var responseString = await _apiClient.GetStringAsync(uri);
|
||||||
|
|
||||||
|
var response = JsonConvert.DeserializeObject<Order>(responseString);
|
||||||
|
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public async Task AddItemToBasket(ApplicationUser user, int productId)
|
public async Task AddItemToBasket(ApplicationUser user, int productId)
|
||||||
{
|
{
|
||||||
var updateBasketUri = API.Purchase.AddItemToBasket(_purchaseUrl);
|
var uri = API.Purchase.AddItemToBasket(_purchaseUrl);
|
||||||
|
|
||||||
var newItem = new
|
var newItem = new
|
||||||
{
|
{
|
||||||
@ -107,9 +109,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
Quantity = 1
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,69 +1,49 @@
|
|||||||
namespace Microsoft.eShopOnContainers.WebMVC.Services
|
namespace Microsoft.eShopOnContainers.WebMVC.Services
|
||||||
{
|
{
|
||||||
using global::WebMVC.Infrastructure;
|
using global::WebMVC.Infrastructure;
|
||||||
using AspNetCore.Authentication;
|
|
||||||
using AspNetCore.Http;
|
|
||||||
using BuildingBlocks.Resilience.Http;
|
|
||||||
using ViewModels;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using ViewModels;
|
||||||
|
|
||||||
public class CampaignService : ICampaignService
|
public class CampaignService : ICampaignService
|
||||||
{
|
{
|
||||||
private readonly IOptionsSnapshot<AppSettings> _settings;
|
private readonly IOptions<AppSettings> _settings;
|
||||||
private readonly IHttpClient _apiClient;
|
private readonly HttpClient _httpClient;
|
||||||
private readonly ILogger<CampaignService> _logger;
|
private readonly ILogger<CampaignService> _logger;
|
||||||
private readonly string _remoteServiceBaseUrl;
|
private readonly string _remoteServiceBaseUrl;
|
||||||
private readonly IHttpContextAccessor _httpContextAccesor;
|
|
||||||
|
|
||||||
public CampaignService(IOptionsSnapshot<AppSettings> settings, IHttpClient httpClient,
|
public CampaignService(IOptions<AppSettings> settings, HttpClient httpClient, ILogger<CampaignService> logger)
|
||||||
ILogger<CampaignService> logger, IHttpContextAccessor httpContextAccesor)
|
|
||||||
{
|
{
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
_apiClient = httpClient;
|
_httpClient = httpClient;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
_remoteServiceBaseUrl = $"{_settings.Value.MarketingUrl}/api/v1/m/campaigns/";
|
_remoteServiceBaseUrl = $"{_settings.Value.MarketingUrl}/api/v1/m/campaigns/";
|
||||||
_httpContextAccesor = httpContextAccesor ?? throw new ArgumentNullException(nameof(httpContextAccesor));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Campaign> GetCampaigns(int pageSize, int pageIndex)
|
public async Task<Campaign> GetCampaigns(int pageSize, int pageIndex)
|
||||||
{
|
{
|
||||||
var allCampaignItemsUri = API.Marketing.GetAllCampaigns(_remoteServiceBaseUrl,
|
var uri = API.Marketing.GetAllCampaigns(_remoteServiceBaseUrl, pageSize, pageIndex);
|
||||||
pageSize, pageIndex);
|
|
||||||
|
|
||||||
var authorizationToken = await GetUserTokenAsync();
|
var responseString = await _httpClient.GetStringAsync(uri);
|
||||||
var dataString = await _apiClient.GetStringAsync(allCampaignItemsUri, authorizationToken);
|
|
||||||
|
|
||||||
var response = JsonConvert.DeserializeObject<Campaign>(dataString);
|
var response = JsonConvert.DeserializeObject<Campaign>(responseString);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<CampaignItem> GetCampaignById(int id)
|
public async Task<CampaignItem> GetCampaignById(int id)
|
||||||
{
|
{
|
||||||
var campaignByIdItemUri = API.Marketing.GetAllCampaignById(_remoteServiceBaseUrl, id);
|
var uri = API.Marketing.GetAllCampaignById(_remoteServiceBaseUrl, id);
|
||||||
|
|
||||||
var authorizationToken = await GetUserTokenAsync();
|
var responseString = await _httpClient.GetStringAsync(uri);
|
||||||
var dataString = await _apiClient.GetStringAsync(campaignByIdItemUri, authorizationToken);
|
|
||||||
|
|
||||||
var response = JsonConvert.DeserializeObject<CampaignItem>(dataString);
|
var response = JsonConvert.DeserializeObject<CampaignItem>(responseString);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetUserIdentity()
|
|
||||||
{
|
|
||||||
return _httpContextAccesor.HttpContext.User.FindFirst("sub").Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> GetUserTokenAsync()
|
|
||||||
{
|
|
||||||
var context = _httpContextAccesor.HttpContext;
|
|
||||||
return await context.GetTokenAsync("access_token");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,11 +1,11 @@
|
|||||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
|
||||||
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using WebMVC.Infrastructure;
|
using WebMVC.Infrastructure;
|
||||||
|
|
||||||
@ -13,16 +13,16 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
{
|
{
|
||||||
public class CatalogService : ICatalogService
|
public class CatalogService : ICatalogService
|
||||||
{
|
{
|
||||||
private readonly IOptionsSnapshot<AppSettings> _settings;
|
private readonly IOptions<AppSettings> _settings;
|
||||||
private readonly IHttpClient _apiClient;
|
private readonly HttpClient _httpClient;
|
||||||
private readonly ILogger<CatalogService> _logger;
|
private readonly ILogger<CatalogService> _logger;
|
||||||
|
|
||||||
private readonly string _remoteServiceBaseUrl;
|
private readonly string _remoteServiceBaseUrl;
|
||||||
|
|
||||||
public CatalogService(IOptionsSnapshot<AppSettings> settings, IHttpClient httpClient, ILogger<CatalogService> logger)
|
public CatalogService(HttpClient httpClient, ILogger<CatalogService> logger, IOptions<AppSettings> settings)
|
||||||
{
|
{
|
||||||
|
_httpClient = httpClient;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
_apiClient = httpClient;
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
_remoteServiceBaseUrl = $"{_settings.Value.PurchaseUrl}/api/v1/c/catalog/";
|
_remoteServiceBaseUrl = $"{_settings.Value.PurchaseUrl}/api/v1/c/catalog/";
|
||||||
@ -30,25 +30,26 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
|
|
||||||
public async Task<Catalog> GetCatalogItems(int page, int take, int? brand, int? type)
|
public async Task<Catalog> 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<Catalog>(dataString);
|
var catalog = JsonConvert.DeserializeObject<Catalog>(responseString);
|
||||||
|
|
||||||
return response;
|
return catalog;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<SelectListItem>> GetBrands()
|
public async Task<IEnumerable<SelectListItem>> 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<SelectListItem>();
|
var items = new List<SelectListItem>();
|
||||||
|
|
||||||
items.Add(new SelectListItem() { Value = null, Text = "All", Selected = true });
|
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<JObject>())
|
foreach (var brand in brands.Children<JObject>())
|
||||||
{
|
{
|
||||||
@ -64,14 +65,14 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
|
|
||||||
public async Task<IEnumerable<SelectListItem>> GetTypes()
|
public async Task<IEnumerable<SelectListItem>> 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<SelectListItem>();
|
var items = new List<SelectListItem>();
|
||||||
items.Add(new SelectListItem() { Value = null, Text = "All", Selected = true });
|
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<JObject>())
|
foreach (var brand in brands.Children<JObject>())
|
||||||
{
|
{
|
||||||
items.Add(new SelectListItem()
|
items.Add(new SelectListItem()
|
||||||
@ -80,6 +81,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
Text = brand.Value<string>("type")
|
Text = brand.Value<string>("type")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.eShopOnContainers.WebMVC;
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
|
||||||
using Microsoft.eShopOnContainers.WebMVC;
|
|
||||||
using Microsoft.eShopOnContainers.WebMVC.Services;
|
using Microsoft.eShopOnContainers.WebMVC.Services;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using System;
|
using Newtonsoft.Json;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using WebMVC.Infrastructure;
|
using WebMVC.Infrastructure;
|
||||||
using WebMVC.Models;
|
using WebMVC.Models;
|
||||||
@ -14,36 +12,27 @@ namespace WebMVC.Services
|
|||||||
{
|
{
|
||||||
public class LocationService : ILocationService
|
public class LocationService : ILocationService
|
||||||
{
|
{
|
||||||
private readonly IOptionsSnapshot<AppSettings> _settings;
|
private readonly IOptions<AppSettings> _settings;
|
||||||
private readonly IHttpClient _apiClient;
|
private readonly HttpClient _httpClient;
|
||||||
private readonly ILogger<CampaignService> _logger;
|
private readonly ILogger<CampaignService> _logger;
|
||||||
private readonly string _remoteServiceBaseUrl;
|
private readonly string _remoteServiceBaseUrl;
|
||||||
private readonly IHttpContextAccessor _httpContextAccesor;
|
|
||||||
|
|
||||||
public LocationService(IOptionsSnapshot<AppSettings> settings, IHttpClient httpClient,
|
public LocationService(HttpClient httpClient, IOptions<AppSettings> settings, ILogger<CampaignService> logger)
|
||||||
ILogger<CampaignService> logger, IHttpContextAccessor httpContextAccesor)
|
|
||||||
{
|
{
|
||||||
|
_httpClient = httpClient;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
_apiClient = httpClient;
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
_remoteServiceBaseUrl = $"{_settings.Value.MarketingUrl}/api/v1/l/locations/";
|
_remoteServiceBaseUrl = $"{_settings.Value.MarketingUrl}/api/v1/l/locations/";
|
||||||
_httpContextAccesor = httpContextAccesor ?? throw new ArgumentNullException(nameof(httpContextAccesor));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task CreateOrUpdateUserLocation(LocationDTO location)
|
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 _httpClient.PostAsync(uri, locationContent);
|
||||||
var response = await _apiClient.PostAsync(createOrUpdateUserLocationUri, location, authorizationToken);
|
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> GetUserTokenAsync()
|
|
||||||
{
|
|
||||||
var context = _httpContextAccesor.HttpContext;
|
|
||||||
return await context.GetTokenAsync("access_token");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
|
||||||
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using WebMVC.Infrastructure;
|
using WebMVC.Infrastructure;
|
||||||
using WebMVC.Models;
|
using WebMVC.Models;
|
||||||
@ -14,69 +12,54 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
{
|
{
|
||||||
public class OrderingService : IOrderingService
|
public class OrderingService : IOrderingService
|
||||||
{
|
{
|
||||||
private IHttpClient _apiClient;
|
private HttpClient _httpClient;
|
||||||
private readonly string _remoteServiceBaseUrl;
|
private readonly string _remoteServiceBaseUrl;
|
||||||
private readonly IOptionsSnapshot<AppSettings> _settings;
|
private readonly IOptions<AppSettings> _settings;
|
||||||
private readonly IHttpContextAccessor _httpContextAccesor;
|
|
||||||
|
|
||||||
public OrderingService(IOptionsSnapshot<AppSettings> settings, IHttpContextAccessor httpContextAccesor, IHttpClient httpClient)
|
|
||||||
|
public OrderingService(HttpClient httpClient, IOptions<AppSettings> settings)
|
||||||
{
|
{
|
||||||
_remoteServiceBaseUrl = $"{settings.Value.PurchaseUrl}/api/v1/o/orders";
|
_httpClient = httpClient;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
_httpContextAccesor = httpContextAccesor;
|
|
||||||
_apiClient = httpClient;
|
_remoteServiceBaseUrl = $"{settings.Value.PurchaseUrl}/api/v1/o/orders";
|
||||||
}
|
}
|
||||||
|
|
||||||
async public Task<Order> GetOrder(ApplicationUser user, string id)
|
async public Task<Order> GetOrder(ApplicationUser user, string id)
|
||||||
{
|
{
|
||||||
var token = await GetUserTokenAsync();
|
var uri = API.Order.GetOrder(_remoteServiceBaseUrl, id);
|
||||||
var getOrderUri = API.Order.GetOrder(_remoteServiceBaseUrl, id);
|
|
||||||
|
|
||||||
var dataString = await _apiClient.GetStringAsync(getOrderUri, token);
|
var responseString = await _httpClient.GetStringAsync(uri);
|
||||||
|
|
||||||
var response = JsonConvert.DeserializeObject<Order>(dataString);
|
var response = JsonConvert.DeserializeObject<Order>(responseString);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
async public Task<List<Order>> GetMyOrders(ApplicationUser user)
|
async public Task<List<Order>> GetMyOrders(ApplicationUser user)
|
||||||
{
|
{
|
||||||
var token = await GetUserTokenAsync();
|
var uri = API.Order.GetAllMyOrders(_remoteServiceBaseUrl);
|
||||||
var allMyOrdersUri = API.Order.GetAllMyOrders(_remoteServiceBaseUrl);
|
|
||||||
|
|
||||||
var dataString = await _apiClient.GetStringAsync(allMyOrdersUri, token);
|
var responseString = await _httpClient.GetStringAsync(uri);
|
||||||
var response = JsonConvert.DeserializeObject<List<Order>>(dataString);
|
|
||||||
|
var response = JsonConvert.DeserializeObject<List<Order>>(responseString);
|
||||||
|
|
||||||
return response;
|
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)
|
async public Task CancelOrder(string orderId)
|
||||||
{
|
{
|
||||||
var token = await GetUserTokenAsync();
|
|
||||||
var order = new OrderDTO()
|
var order = new OrderDTO()
|
||||||
{
|
{
|
||||||
OrderNumber = orderId
|
OrderNumber = orderId
|
||||||
};
|
};
|
||||||
|
|
||||||
var cancelOrderUri = API.Order.CancelOrder(_remoteServiceBaseUrl);
|
var uri = API.Order.CancelOrder(_remoteServiceBaseUrl);
|
||||||
|
var orderContent = new StringContent(JsonConvert.SerializeObject(order), System.Text.Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
var response = await _apiClient.PutAsync(cancelOrderUri, order, token, Guid.NewGuid().ToString());
|
var response = await _httpClient.PutAsync(uri, orderContent);
|
||||||
|
|
||||||
if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
|
if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
|
||||||
{
|
{
|
||||||
@ -88,15 +71,15 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
|
|
||||||
async public Task ShipOrder(string orderId)
|
async public Task ShipOrder(string orderId)
|
||||||
{
|
{
|
||||||
var token = await GetUserTokenAsync();
|
|
||||||
var order = new OrderDTO()
|
var order = new OrderDTO()
|
||||||
{
|
{
|
||||||
OrderNumber = orderId
|
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)
|
if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
|
||||||
{
|
{
|
||||||
@ -120,6 +103,22 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
destination.CardSecurityNumber = original.CardSecurityNumber;
|
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)
|
public BasketDTO MapOrderToBasket(Order order)
|
||||||
{
|
{
|
||||||
order.CardExpirationApiFormat();
|
order.CardExpirationApiFormat();
|
||||||
@ -140,18 +139,5 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
RequestId = order.RequestId
|
RequestId = order.RequestId
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetFakeIdToProducts(Order order)
|
|
||||||
{
|
|
||||||
var id = 1;
|
|
||||||
order.OrderItems.ForEach(x => { x.ProductId = id; id++; });
|
|
||||||
}
|
|
||||||
|
|
||||||
async Task<string> GetUserTokenAsync()
|
|
||||||
{
|
|
||||||
var context = _httpContextAccesor.HttpContext;
|
|
||||||
|
|
||||||
return await context.GetTokenAsync("access_token");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,6 @@ using Microsoft.AspNetCore.Builder;
|
|||||||
using Microsoft.AspNetCore.DataProtection;
|
using Microsoft.AspNetCore.DataProtection;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
|
||||||
using Microsoft.eShopOnContainers.WebMVC.Infrastructure;
|
|
||||||
using Microsoft.eShopOnContainers.WebMVC.Services;
|
using Microsoft.eShopOnContainers.WebMVC.Services;
|
||||||
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
@ -15,15 +13,10 @@ using Microsoft.Extensions.DependencyInjection;
|
|||||||
using Microsoft.Extensions.HealthChecks;
|
using Microsoft.Extensions.HealthChecks;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Polly;
|
using Polly;
|
||||||
using Polly.CircuitBreaker;
|
|
||||||
using Polly.Extensions.Http;
|
using Polly.Extensions.Http;
|
||||||
using Polly.Registry;
|
|
||||||
using Polly.Retry;
|
|
||||||
using Polly.Timeout;
|
|
||||||
using StackExchange.Redis;
|
using StackExchange.Redis;
|
||||||
using System;
|
using System;
|
||||||
using System.IdentityModel.Tokens.Jwt;
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
using System.Net.Http;
|
|
||||||
using WebMVC.Infrastructure;
|
using WebMVC.Infrastructure;
|
||||||
using WebMVC.Infrastructure.Middlewares;
|
using WebMVC.Infrastructure.Middlewares;
|
||||||
using WebMVC.Services;
|
using WebMVC.Services;
|
||||||
@ -151,6 +144,9 @@ namespace Microsoft.eShopOnContainers.WebMVC
|
|||||||
|
|
||||||
public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration)
|
public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
|
services.AddOptions();
|
||||||
|
services.Configure<AppSettings>(configuration);
|
||||||
|
|
||||||
services.AddMvc();
|
services.AddMvc();
|
||||||
|
|
||||||
services.AddSession();
|
services.AddSession();
|
||||||
@ -163,123 +159,57 @@ namespace Microsoft.eShopOnContainers.WebMVC
|
|||||||
})
|
})
|
||||||
.PersistKeysToRedis(ConnectionMultiplexer.Connect(configuration["DPConnectionString"]), "DataProtection-Keys");
|
.PersistKeysToRedis(ConnectionMultiplexer.Connect(configuration["DPConnectionString"]), "DataProtection-Keys");
|
||||||
}
|
}
|
||||||
|
|
||||||
services.Configure<AppSettings>(configuration);
|
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds all Http client services (like Service-Agents) using resilient Http requests based on HttpClient factory and Polly's policies
|
// 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)
|
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<IHttpContextAccessor, HttpContextAccessor>();
|
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||||
|
|
||||||
// (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<HttpClientDefaultPolicies>();
|
|
||||||
var defaultPolicies = services.BuildServiceProvider().GetService<HttpClientDefaultPolicies>();
|
|
||||||
|
|
||||||
// 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
|
//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"]
|
//(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
|
var circuitBreaker = HttpPolicyExtensions
|
||||||
.HandleTransientHttpError()
|
.HandleTransientHttpError()
|
||||||
.CircuitBreakerAsync(6,
|
.CircuitBreakerAsync(6, TimeSpan.FromSeconds(30));
|
||||||
TimeSpan.FromSeconds(30)
|
|
||||||
);
|
|
||||||
//(CDLTLL) Instead of hardcoded values, use: configuration["HttpClientExceptionsAllowedBeforeBreaking"], configuration["DurationOfBreakInMinutes"]
|
|
||||||
|
|
||||||
|
//register delegating handlers
|
||||||
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"
|
|
||||||
services.AddTransient<HttpClientAuthorizationDelegatingHandler>();
|
services.AddTransient<HttpClientAuthorizationDelegatingHandler>();
|
||||||
|
services.AddTransient<HttpClientRequestIdDelegatingHandler>();
|
||||||
|
|
||||||
//Add all Typed-Clients (Service-Agents) through the HttpClient factory to implement Resilient Http requests
|
//add http client servicse
|
||||||
//
|
|
||||||
|
|
||||||
//Add BasketService typed client (Service Agent)
|
|
||||||
services.AddHttpClient<IBasketService, BasketService>()
|
services.AddHttpClient<IBasketService, BasketService>()
|
||||||
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>() //Additional Authentication-Delegating-Handler to add the OAuth-Bearer-token to the Http headers
|
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
|
||||||
.AddPolicyHandlerFromRegistry("DefaultRetriesWithExponentialBackoff")
|
.AddPolicyHandler(retriesWithExponentialBackoff)
|
||||||
.AddPolicyHandlerFromRegistry("DefaultCircuitBreaker");
|
.AddPolicyHandler(circuitBreaker);
|
||||||
|
|
||||||
//Add CatalogService typed client (Service Agent)
|
services.AddHttpClient<ICatalogService, CatalogService>()
|
||||||
//services.AddHttpClient<ICatalogService, CatalogService>() ...
|
.AddPolicyHandler(retriesWithExponentialBackoff)
|
||||||
|
.AddPolicyHandler(circuitBreaker);
|
||||||
|
|
||||||
//Add OrderingService typed client (Service Agent)
|
services.AddHttpClient<IOrderingService, OrderingService>()
|
||||||
//services.AddHttpClient<IOrderingService, OrderingService>() ...
|
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
|
||||||
|
.AddHttpMessageHandler<HttpClientRequestIdDelegatingHandler>()
|
||||||
|
.AddPolicyHandler(retriesWithExponentialBackoff)
|
||||||
|
.AddPolicyHandler(circuitBreaker);
|
||||||
|
|
||||||
//Add CampaignService typed client (Service Agent)
|
services.AddHttpClient<ICampaignService, CampaignService>()
|
||||||
//services.AddHttpClient<ICampaignService, CampaignService>() ...
|
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
|
||||||
|
.AddPolicyHandler(retriesWithExponentialBackoff)
|
||||||
|
.AddPolicyHandler(circuitBreaker);
|
||||||
|
|
||||||
//Add LocationService typed client (Service Agent)
|
services.AddHttpClient<ILocationService, LocationService>()
|
||||||
//services.AddHttpClient<ILocationService, LocationService>() ...
|
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
|
||||||
|
.AddPolicyHandler(retriesWithExponentialBackoff)
|
||||||
|
.AddPolicyHandler(circuitBreaker);
|
||||||
|
|
||||||
//Add IdentityParser typed client (Service Agent)
|
//add custom application services
|
||||||
//services.AddHttpClient<IIdentityParser, IdentityParser>() ...
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// (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<ICatalogService, CatalogService>();
|
|
||||||
services.AddTransient<IOrderingService, OrderingService>();
|
|
||||||
|
|
||||||
services.AddTransient<ICampaignService, CampaignService>();
|
|
||||||
services.AddTransient<ILocationService, LocationService>();
|
|
||||||
services.AddTransient<IIdentityParser<ApplicationUser>, IdentityParser>();
|
services.AddTransient<IIdentityParser<ApplicationUser>, IdentityParser>();
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// TEMPORAL COMMENT: This code will be deleted when using HttpClientFactory, right?
|
|
||||||
if (configuration.GetValue<string>("UseResilientHttp") == bool.TrueString)
|
|
||||||
{
|
|
||||||
services.AddSingleton<IResilientHttpClientFactory, ResilientHttpClientFactory>(sp =>
|
|
||||||
{
|
|
||||||
var logger = sp.GetRequiredService<ILogger<ResilientHttpClient>>();
|
|
||||||
var httpContextAccessor = sp.GetRequiredService<IHttpContextAccessor>();
|
|
||||||
|
|
||||||
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<IHttpClient, ResilientHttpClient>(sp => sp.GetService<IResilientHttpClientFactory>().CreateResilientHttpClient());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
services.AddSingleton<IHttpClient, StandardHttpClient>();
|
|
||||||
}
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user