Skip to content

Commit 2f9fa4d

Browse files
committed
Added HTTPClient services and review application on WebMVC
1 parent dc5de83 commit 2f9fa4d

11 files changed

Lines changed: 225 additions & 311 deletions

File tree

src/Services/Basket/Basket.API/Controllers/BasketController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public async Task<IActionResult> Get(string id)
3636
var basket = await _repository.GetBasketAsync(id);
3737
if (basket == null)
3838
{
39-
return NotFound();
39+
return Ok(new CustomerBasket(id) { });
4040
}
4141

4242
return Ok(basket);

src/Web/WebMVC/AppSettings.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@ namespace Microsoft.eShopOnContainers.WebMVC
77
{
88
public class AppSettings
99
{
10-
public Connectionstrings ConnectionStrings { get; set; }
10+
//public Connectionstrings ConnectionStrings { get; set; }
1111
public string MarketingUrl { get; set; }
12-
1312
public string PurchaseUrl { get; set; }
1413
public string SignalrHubUrl { get; set; }
1514
public bool ActivateCampaignDetailFunction { get; set; }
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System;
2+
using System.Net.Http;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
6+
namespace WebMVC.Infrastructure
7+
{
8+
public class HttpClientRequestIdDelegatingHandler
9+
: DelegatingHandler
10+
{
11+
12+
public HttpClientRequestIdDelegatingHandler()
13+
{
14+
}
15+
16+
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
17+
{
18+
if (request.Method == HttpMethod.Post || request.Method == HttpMethod.Put)
19+
{
20+
request.Headers.Add("x-requestid", Guid.NewGuid().ToString());
21+
}
22+
23+
return await base.SendAsync(request, cancellationToken);
24+
}
25+
}
26+
}

src/Web/WebMVC/Infrastructure/IResilientHttpClientFactory.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
55
{
6-
public interface IResilientHttpClientFactory
7-
{
8-
ResilientHttpClient CreateResilientHttpClient();
9-
}
6+
//public interface IResilientHttpClientFactory
7+
//{
8+
// ResilientHttpClient CreateResilientHttpClient();
9+
//}
1010
}

src/Web/WebMVC/Infrastructure/ResilientHttpClientFactory.cs

Lines changed: 52 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -7,60 +7,60 @@
77

88
namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
99
{
10-
public class ResilientHttpClientFactory : IResilientHttpClientFactory
11-
{
12-
private readonly ILogger<ResilientHttpClient> _logger;
13-
private readonly int _retryCount;
14-
private readonly int _exceptionsAllowedBeforeBreaking;
15-
private readonly IHttpContextAccessor _httpContextAccessor;
10+
//public class ResilientHttpClientFactory : IResilientHttpClientFactory
11+
//{
12+
// private readonly ILogger<ResilientHttpClient> _logger;
13+
// private readonly int _retryCount;
14+
// private readonly int _exceptionsAllowedBeforeBreaking;
15+
// private readonly IHttpContextAccessor _httpContextAccessor;
1616

17-
public ResilientHttpClientFactory(ILogger<ResilientHttpClient> logger, IHttpContextAccessor httpContextAccessor, int exceptionsAllowedBeforeBreaking = 5, int retryCount = 6)
18-
{
19-
_logger = logger;
20-
_exceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
21-
_retryCount = retryCount;
22-
_httpContextAccessor = httpContextAccessor;
23-
}
17+
// public ResilientHttpClientFactory(ILogger<ResilientHttpClient> logger, IHttpContextAccessor httpContextAccessor, int exceptionsAllowedBeforeBreaking = 5, int retryCount = 6)
18+
// {
19+
// _logger = logger;
20+
// _exceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
21+
// _retryCount = retryCount;
22+
// _httpContextAccessor = httpContextAccessor;
23+
// }
2424

2525

26-
public ResilientHttpClient CreateResilientHttpClient()
27-
=> new ResilientHttpClient((origin) => CreatePolicies(), _logger, _httpContextAccessor);
26+
// public ResilientHttpClient CreateResilientHttpClient()
27+
// => new ResilientHttpClient((origin) => CreatePolicies(), _logger, _httpContextAccessor);
2828

29-
private Policy[] CreatePolicies()
30-
=> new Policy[]
31-
{
32-
Policy.Handle<HttpRequestException>()
33-
.WaitAndRetryAsync(
34-
// number of retries
35-
_retryCount,
36-
// exponential backofff
37-
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
38-
// on retry
39-
(exception, timeSpan, retryCount, context) =>
40-
{
41-
var msg = $"Retry {retryCount} implemented with Polly's RetryPolicy " +
42-
$"of {context.PolicyKey} " +
43-
$"at {context.OperationKey}, " +
44-
$"due to: {exception}.";
45-
_logger.LogWarning(msg);
46-
_logger.LogDebug(msg);
47-
}),
48-
Policy.Handle<HttpRequestException>()
49-
.CircuitBreakerAsync(
50-
// number of exceptions before breaking circuit
51-
_exceptionsAllowedBeforeBreaking,
52-
// time circuit opened before retry
53-
TimeSpan.FromMinutes(1),
54-
(exception, duration) =>
55-
{
56-
// on circuit opened
57-
_logger.LogTrace("Circuit breaker opened");
58-
},
59-
() =>
60-
{
61-
// on circuit closed
62-
_logger.LogTrace("Circuit breaker reset");
63-
})
64-
};
65-
}
29+
// private Policy[] CreatePolicies()
30+
// => new Policy[]
31+
// {
32+
// Policy.Handle<HttpRequestException>()
33+
// .WaitAndRetryAsync(
34+
// // number of retries
35+
// _retryCount,
36+
// // exponential backofff
37+
// retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
38+
// // on retry
39+
// (exception, timeSpan, retryCount, context) =>
40+
// {
41+
// var msg = $"Retry {retryCount} implemented with Polly's RetryPolicy " +
42+
// $"of {context.PolicyKey} " +
43+
// $"at {context.OperationKey}, " +
44+
// $"due to: {exception}.";
45+
// _logger.LogWarning(msg);
46+
// _logger.LogDebug(msg);
47+
// }),
48+
// Policy.Handle<HttpRequestException>()
49+
// .CircuitBreakerAsync(
50+
// // number of exceptions before breaking circuit
51+
// _exceptionsAllowedBeforeBreaking,
52+
// // time circuit opened before retry
53+
// TimeSpan.FromMinutes(1),
54+
// (exception, duration) =>
55+
// {
56+
// // on circuit opened
57+
// _logger.LogTrace("Circuit breaker opened");
58+
// },
59+
// () =>
60+
// {
61+
// // on circuit closed
62+
// _logger.LogTrace("Circuit breaker reset");
63+
// })
64+
// };
65+
//}
6666
}

src/Web/WebMVC/Services/BasketService.cs

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
1212
{
1313
public class BasketService : IBasketService
1414
{
15-
private readonly IOptionsSnapshot<AppSettings> _settings;
15+
private readonly IOptions<AppSettings> _settings;
1616
private readonly HttpClient _apiClient;
1717
private readonly string _basketByPassUrl;
1818
private readonly string _purchaseUrl;
1919

2020
private readonly string _bffUrl;
2121

22-
public BasketService(HttpClient httpClient,IOptionsSnapshot<AppSettings> settings)
22+
public BasketService(HttpClient httpClient, IOptions<AppSettings> settings)
2323
{
2424
_apiClient = httpClient;
2525
_settings = settings;
@@ -30,21 +30,22 @@ public BasketService(HttpClient httpClient,IOptionsSnapshot<AppSettings> setting
3030

3131
public async Task<Basket> GetBasket(ApplicationUser user)
3232
{
33-
var getBasketUri = API.Basket.GetBasket(_basketByPassUrl, user.Id);
33+
var uri = API.Basket.GetBasket(_basketByPassUrl, user.Id);
3434

35-
var dataString = await _apiClient.GetStringAsync(getBasketUri);
35+
var responseString = await _apiClient.GetStringAsync(uri);
3636

37-
return string.IsNullOrEmpty(dataString) ?
38-
new Basket() { BuyerId = user.Id} :
39-
JsonConvert.DeserializeObject<Basket>(dataString);
37+
return string.IsNullOrEmpty(responseString) ?
38+
new Basket() { BuyerId = user.Id } :
39+
JsonConvert.DeserializeObject<Basket>(responseString);
4040
}
4141

4242
public async Task<Basket> UpdateBasket(Basket basket)
4343
{
44-
var updateBasketUri = API.Basket.UpdateBasket(_basketByPassUrl);
45-
var content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json");
44+
var uri = API.Basket.UpdateBasket(_basketByPassUrl);
4645

47-
var response = await _apiClient.PostAsync(updateBasketUri, content);
46+
var basketContent = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json");
47+
48+
var response = await _apiClient.PostAsync(uri, basketContent);
4849

4950
response.EnsureSuccessStatusCode();
5051

@@ -53,18 +54,18 @@ public async Task<Basket> UpdateBasket(Basket basket)
5354

5455
public async Task Checkout(BasketDTO basket)
5556
{
56-
var updateBasketUri = API.Basket.CheckoutBasket(_basketByPassUrl);
57-
var content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json");
57+
var uri = API.Basket.CheckoutBasket(_basketByPassUrl);
58+
var basketContent = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json");
5859

59-
var response = await _apiClient.PostAsync(updateBasketUri, content);
60+
var response = await _apiClient.PostAsync(uri, basketContent);
6061

6162
response.EnsureSuccessStatusCode();
6263
}
6364

6465
public async Task<Basket> SetQuantities(ApplicationUser user, Dictionary<string, int> quantities)
6566
{
67+
var uri = API.Purchase.UpdateBasketItem(_purchaseUrl);
6668

67-
var updateBasketUri = API.Purchase.UpdateBasketItem(_purchaseUrl);
6869
var basketUpdate = new
6970
{
7071
BasketId = user.Id,
@@ -75,9 +76,9 @@ public async Task<Basket> SetQuantities(ApplicationUser user, Dictionary<string,
7576
}).ToArray()
7677
};
7778

78-
var content = new StringContent(JsonConvert.SerializeObject(basketUpdate), System.Text.Encoding.UTF8, "application/json");
79+
var basketContent = new StringContent(JsonConvert.SerializeObject(basketUpdate), System.Text.Encoding.UTF8, "application/json");
7980

80-
var response = await _apiClient.PutAsync(updateBasketUri,content);
81+
var response = await _apiClient.PutAsync(uri, basketContent);
8182

8283
response.EnsureSuccessStatusCode();
8384

@@ -88,17 +89,18 @@ public async Task<Basket> SetQuantities(ApplicationUser user, Dictionary<string,
8889

8990
public async Task<Order> GetOrderDraft(string basketId)
9091
{
91-
var draftOrderUri = API.Purchase.GetOrderDraft(_purchaseUrl, basketId);
92-
var response = await _apiClient.GetStringAsync(draftOrderUri);
92+
var uri = API.Purchase.GetOrderDraft(_purchaseUrl, basketId);
9393

94-
return JsonConvert.DeserializeObject<Order>(response);
95-
}
94+
var responseString = await _apiClient.GetStringAsync(uri);
9695

96+
var response = JsonConvert.DeserializeObject<Order>(responseString);
9797

98+
return response;
99+
}
98100

99101
public async Task AddItemToBasket(ApplicationUser user, int productId)
100102
{
101-
var updateBasketUri = API.Purchase.AddItemToBasket(_purchaseUrl);
103+
var uri = API.Purchase.AddItemToBasket(_purchaseUrl);
102104

103105
var newItem = new
104106
{
@@ -107,9 +109,9 @@ public async Task AddItemToBasket(ApplicationUser user, int productId)
107109
Quantity = 1
108110
};
109111

110-
var content = new StringContent(JsonConvert.SerializeObject(newItem), System.Text.Encoding.UTF8, "application/json");
112+
var basketContent = new StringContent(JsonConvert.SerializeObject(newItem), System.Text.Encoding.UTF8, "application/json");
111113

112-
var response = await _apiClient.PostAsync(updateBasketUri, content);
114+
var response = await _apiClient.PostAsync(uri, basketContent);
113115
}
114116
}
115117
}
Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,49 @@
11
namespace Microsoft.eShopOnContainers.WebMVC.Services
22
{
33
using global::WebMVC.Infrastructure;
4-
using AspNetCore.Authentication;
5-
using AspNetCore.Http;
6-
using BuildingBlocks.Resilience.Http;
7-
using ViewModels;
84
using Microsoft.Extensions.Logging;
95
using Microsoft.Extensions.Options;
106
using Newtonsoft.Json;
11-
using System;
7+
using System.Net.Http;
128
using System.Threading.Tasks;
9+
using ViewModels;
1310

1411
public class CampaignService : ICampaignService
1512
{
16-
private readonly IOptionsSnapshot<AppSettings> _settings;
17-
private readonly IHttpClient _apiClient;
13+
private readonly IOptions<AppSettings> _settings;
14+
private readonly HttpClient _httpClient;
1815
private readonly ILogger<CampaignService> _logger;
1916
private readonly string _remoteServiceBaseUrl;
20-
private readonly IHttpContextAccessor _httpContextAccesor;
2117

22-
public CampaignService(IOptionsSnapshot<AppSettings> settings, IHttpClient httpClient,
23-
ILogger<CampaignService> logger, IHttpContextAccessor httpContextAccesor)
18+
public CampaignService(IOptions<AppSettings> settings, HttpClient httpClient, ILogger<CampaignService> logger)
2419
{
2520
_settings = settings;
26-
_apiClient = httpClient;
21+
_httpClient = httpClient;
2722
_logger = logger;
2823

2924
_remoteServiceBaseUrl = $"{_settings.Value.MarketingUrl}/api/v1/m/campaigns/";
30-
_httpContextAccesor = httpContextAccesor ?? throw new ArgumentNullException(nameof(httpContextAccesor));
3125
}
3226

3327
public async Task<Campaign> GetCampaigns(int pageSize, int pageIndex)
3428
{
35-
var allCampaignItemsUri = API.Marketing.GetAllCampaigns(_remoteServiceBaseUrl,
36-
pageSize, pageIndex);
29+
var uri = API.Marketing.GetAllCampaigns(_remoteServiceBaseUrl, pageSize, pageIndex);
3730

38-
var authorizationToken = await GetUserTokenAsync();
39-
var dataString = await _apiClient.GetStringAsync(allCampaignItemsUri, authorizationToken);
31+
var responseString = await _httpClient.GetStringAsync(uri);
4032

41-
var response = JsonConvert.DeserializeObject<Campaign>(dataString);
33+
var response = JsonConvert.DeserializeObject<Campaign>(responseString);
4234

4335
return response;
4436
}
4537

4638
public async Task<CampaignItem> GetCampaignById(int id)
4739
{
48-
var campaignByIdItemUri = API.Marketing.GetAllCampaignById(_remoteServiceBaseUrl, id);
40+
var uri = API.Marketing.GetAllCampaignById(_remoteServiceBaseUrl, id);
4941

50-
var authorizationToken = await GetUserTokenAsync();
51-
var dataString = await _apiClient.GetStringAsync(campaignByIdItemUri, authorizationToken);
42+
var responseString = await _httpClient.GetStringAsync(uri);
5243

53-
var response = JsonConvert.DeserializeObject<CampaignItem>(dataString);
44+
var response = JsonConvert.DeserializeObject<CampaignItem>(responseString);
5445

5546
return response;
5647
}
57-
58-
private string GetUserIdentity()
59-
{
60-
return _httpContextAccesor.HttpContext.User.FindFirst("sub").Value;
61-
}
62-
63-
private async Task<string> GetUserTokenAsync()
64-
{
65-
var context = _httpContextAccesor.HttpContext;
66-
return await context.GetTokenAsync("access_token");
67-
}
6848
}
6949
}

0 commit comments

Comments
 (0)