diff --git a/src/ApiGateways/ApiGw-Base/Startup.cs b/src/ApiGateways/ApiGw-Base/Startup.cs index da7cd25f4..a574999c1 100644 --- a/src/ApiGateways/ApiGw-Base/Startup.cs +++ b/src/ApiGateways/ApiGw-Base/Startup.cs @@ -10,7 +10,6 @@ namespace OcelotApiGw { public class Startup { - private readonly IConfiguration _cfg; public Startup(IConfiguration configuration) @@ -65,6 +64,7 @@ namespace OcelotApiGw public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { var pathBase = _cfg["PATH_BASE"]; + if (!string.IsNullOrEmpty(pathBase)) { app.UsePathBase(pathBase); diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/BasketController.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/BasketController.cs index 702c805fb..978b1858c 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/BasketController.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/BasketController.cs @@ -5,16 +5,19 @@ using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services; using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers { [Route("api/v1/[controller]")] [Authorize] - public class BasketController : Controller + [ApiController] + public class BasketController : ControllerBase { private readonly ICatalogService _catalog; private readonly IBasketService _basket; + public BasketController(ICatalogService catalogService, IBasketService basketService) { _catalog = catalogService; @@ -23,22 +26,24 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers [HttpPost] [HttpPut] - public async Task UpdateAllBasket([FromBody] UpdateBasketRequest data) + [ProducesResponseType((int)HttpStatusCode.BadRequest)] + [ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)] + public async Task> UpdateAllBasketAsync([FromBody] UpdateBasketRequest data) { - if (data.Items == null || !data.Items.Any()) { return BadRequest("Need to pass at least one basket line"); } // Retrieve the current basket - var currentBasket = await _basket.GetById(data.BuyerId); + var currentBasket = await _basket.GetByIdAsync(data.BuyerId); + if (currentBasket == null) { currentBasket = new BasketData(data.BuyerId); } - var catalogItems = await _catalog.GetCatalogItems(data.Items.Select(x => x.ProductId)); + var catalogItems = await _catalog.GetCatalogItemsAsync(data.Items.Select(x => x.ProductId)); var newBasket = new BasketData(data.BuyerId); foreach (var bitem in data.Items) @@ -60,13 +65,16 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers }); } - await _basket.Update(newBasket); - return Ok(newBasket); + await _basket.UpdateAsync(newBasket); + + return newBasket; } [HttpPut] [Route("items")] - public async Task UpdateQuantities([FromBody] UpdateBasketItemsRequest data) + [ProducesResponseType((int)HttpStatusCode.BadRequest)] + [ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)] + public async Task> UpdateQuantitiesAsync([FromBody] UpdateBasketItemsRequest data) { if (!data.Updates.Any()) { @@ -74,7 +82,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers } // Retrieve the current basket - var currentBasket = await _basket.GetById(data.BasketId); + var currentBasket = await _basket.GetByIdAsync(data.BasketId); if (currentBasket == null) { return BadRequest($"Basket with id {data.BasketId} not found."); @@ -84,21 +92,26 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers foreach (var update in data.Updates) { var basketItem = currentBasket.Items.SingleOrDefault(bitem => bitem.Id == update.BasketItemId); + if (basketItem == null) { return BadRequest($"Basket item with id {update.BasketItemId} not found"); } + basketItem.Quantity = update.NewQty; } // Save the updated basket - await _basket.Update(currentBasket); - return Ok(currentBasket); + await _basket.UpdateAsync(currentBasket); + + return currentBasket; } [HttpPost] [Route("items")] - public async Task AddBasketItem([FromBody] AddBasketItemRequest data) + [ProducesResponseType((int)HttpStatusCode.BadRequest)] + [ProducesResponseType((int)HttpStatusCode.OK)] + public async Task AddBasketItemAsync([FromBody] AddBasketItemRequest data) { if (data == null || data.Quantity == 0) { @@ -106,12 +119,12 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers } // Step 1: Get the item from catalog - var item = await _catalog.GetCatalogItem(data.CatalogItemId); + var item = await _catalog.GetCatalogItemAsync(data.CatalogItemId); //item.PictureUri = // Step 2: Get current basket status - var currentBasket = (await _basket.GetById(data.BasketId)) ?? new BasketData(data.BasketId); + var currentBasket = (await _basket.GetByIdAsync(data.BasketId)) ?? new BasketData(data.BasketId); // Step 3: Merge current status with new product currentBasket.Items.Add(new BasketDataItem() { @@ -124,8 +137,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers }); // Step 4: Update basket - await _basket.Update(currentBasket); - + await _basket.UpdateAsync(currentBasket); return Ok(); } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/OrderController.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/OrderController.cs index 4c18d25ae..a4b33c6cb 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/OrderController.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/OrderController.cs @@ -1,19 +1,20 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services; -using System; -using System.Collections.Generic; -using System.Linq; +using System.Net; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers { [Route("api/v1/[controller]")] [Authorize] - public class OrderController : Controller + [ApiController] + public class OrderController : ControllerBase { private readonly IBasketService _basketService; private readonly IOrderApiClient _orderClient; + public OrderController(IBasketService basketService, IOrderApiClient orderClient) { _basketService = basketService; @@ -22,21 +23,23 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers [Route("draft/{basketId}")] [HttpGet] - public async Task GetOrderDraft(string basketId) + [ProducesResponseType((int)HttpStatusCode.BadRequest)] + [ProducesResponseType(typeof(OrderData), (int)HttpStatusCode.OK)] + public async Task> GetOrderDraftAsync(string basketId) { if (string.IsNullOrEmpty(basketId)) { return BadRequest("Need a valid basketid"); } // Get the basket data and build a order draft based on it - var basket = await _basketService.GetById(basketId); + var basket = await _basketService.GetByIdAsync(basketId); + if (basket == null) { return BadRequest($"No basket found for id {basketId}"); } - var orderDraft = await _orderClient.GetOrderDraftFromBasket(basket); - return Ok(orderDraft); + return await _orderClient.GetOrderDraftFromBasketAsync(basket); } } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/BasketService.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/BasketService.cs index 8339ee44b..5186fe361 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/BasketService.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/BasketService.cs @@ -22,7 +22,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services _urls = config.Value; } - public async Task GetById(string id) + public async Task GetByIdAsync(string id) { var data = await _httpClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id)); @@ -31,7 +31,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services return basket; } - public async Task Update(BasketData currentBasket) + public async Task UpdateAsync(BasketData currentBasket) { var basketContent = new StringContent(JsonConvert.SerializeObject(currentBasket), System.Text.Encoding.UTF8, "application/json"); diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/CatalogService.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/CatalogService.cs index 6c59f0c49..69bca2b39 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/CatalogService.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/CatalogService.cs @@ -22,7 +22,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services _urls = config.Value; } - public async Task GetCatalogItem(int id) + public async Task GetCatalogItemAsync(int id) { var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id)); var catalogItem = JsonConvert.DeserializeObject(stringContent); @@ -30,7 +30,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services return catalogItem; } - public async Task> GetCatalogItems(IEnumerable ids) + public async Task> GetCatalogItemsAsync(IEnumerable ids) { var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemsById(ids)); var catalogItems = JsonConvert.DeserializeObject(stringContent); diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IBasketService.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IBasketService.cs index 6fd6871c1..ad49e1adb 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IBasketService.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IBasketService.cs @@ -1,15 +1,13 @@ using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; -using System; -using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services { public interface IBasketService { - Task GetById(string id); - Task Update(BasketData currentBasket); + Task GetByIdAsync(string id); + + Task UpdateAsync(BasketData currentBasket); } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/ICatalogService.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/ICatalogService.cs index d7e605bfa..832dfc740 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/ICatalogService.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/ICatalogService.cs @@ -1,14 +1,13 @@ using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; -using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services { public interface ICatalogService { - Task GetCatalogItem(int id); - Task> GetCatalogItems(IEnumerable ids); + Task GetCatalogItemAsync(int id); + + Task> GetCatalogItemsAsync(IEnumerable ids); } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IOrderApiClient.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IOrderApiClient.cs index 30ac013b9..1abe545bd 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IOrderApiClient.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IOrderApiClient.cs @@ -1,13 +1,10 @@ using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; -using System; -using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services { public interface IOrderApiClient { - Task GetOrderDraftFromBasket(BasketData basket); + Task GetOrderDraftFromBasketAsync(BasketData basket); } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/OrderApiClient.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/OrderApiClient.cs index 03644c110..da39abbff 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/OrderApiClient.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/OrderApiClient.cs @@ -21,7 +21,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services _urls = config.Value; } - public async Task GetOrderDraftFromBasket(BasketData basket) + public async Task GetOrderDraftFromBasketAsync(BasketData basket) { var uri = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft(); var content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json"); diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs index 3a11975c7..4fe3b4e3b 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure; @@ -53,9 +54,14 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator { app.UseDeveloperExceptionPage(); } + else + { + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } app.UseAuthentication(); - + app.UseHttpsRedirection(); app.UseMvc(); app.UseSwagger().UseSwaggerUI(c => @@ -77,7 +83,8 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator services.AddOptions(); services.Configure(configuration.GetSection("urls")); - services.AddMvc(); + services.AddMvc() + .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddSwaggerGen(options => { @@ -120,12 +127,14 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator { JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); var identityUrl = configuration.GetValue("urls:identity"); + services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - }).AddJwtBearer(options => + }) + .AddJwtBearer(options => { options.Authority = identityUrl; options.RequireHttpsMetadata = false; @@ -143,6 +152,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator return services; } + public static IServiceCollection AddHttpServices(this IServiceCollection services) { //register delegating handlers @@ -163,8 +173,6 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator .AddPolicyHandler(GetRetryPolicy()) .AddPolicyHandler(GetCircuitBreakerPolicy()); - - return services; } @@ -174,7 +182,6 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator .HandleTransientHttpError() .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound) .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); - } private static IAsyncPolicy GetCircuitBreakerPolicy() diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/BasketController.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/BasketController.cs index bfef55726..6745ffa02 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/BasketController.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/BasketController.cs @@ -5,16 +5,19 @@ using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers { [Route("api/v1/[controller]")] [Authorize] - public class BasketController : Controller + [ApiController] + public class BasketController : ControllerBase { private readonly ICatalogService _catalog; private readonly IBasketService _basket; + public BasketController(ICatalogService catalogService, IBasketService basketService) { _catalog = catalogService; @@ -23,22 +26,23 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers [HttpPost] [HttpPut] - public async Task UpdateAllBasket([FromBody] UpdateBasketRequest data) + [ProducesResponseType((int)HttpStatusCode.BadRequest)] + [ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)] + public async Task> UpdateAllBasketAsync([FromBody] UpdateBasketRequest data) { - if (data.Items == null || !data.Items.Any()) { return BadRequest("Need to pass at least one basket line"); } // Retrieve the current basket - var currentBasket = await _basket.GetById(data.BuyerId); + var currentBasket = await _basket.GetByIdAsync(data.BuyerId); if (currentBasket == null) { currentBasket = new BasketData(data.BuyerId); } - var catalogItems = await _catalog.GetCatalogItems(data.Items.Select(x => x.ProductId)); + var catalogItems = await _catalog.GetCatalogItemsAsync(data.Items.Select(x => x.ProductId)); var newBasket = new BasketData(data.BuyerId); foreach (var bitem in data.Items) @@ -60,13 +64,16 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers }); } - await _basket.Update(newBasket); - return Ok(newBasket); + await _basket.UpdateAsync(newBasket); + + return newBasket; } [HttpPut] [Route("items")] - public async Task UpdateQuantities([FromBody] UpdateBasketItemsRequest data) + [ProducesResponseType((int)HttpStatusCode.BadRequest)] + [ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)] + public async Task> UpdateQuantitiesAsync([FromBody] UpdateBasketItemsRequest data) { if (!data.Updates.Any()) { @@ -74,7 +81,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers } // Retrieve the current basket - var currentBasket = await _basket.GetById(data.BasketId); + var currentBasket = await _basket.GetByIdAsync(data.BasketId); if (currentBasket == null) { return BadRequest($"Basket with id {data.BasketId} not found."); @@ -92,13 +99,16 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers } // Save the updated basket - await _basket.Update(currentBasket); - return Ok(currentBasket); + await _basket.UpdateAsync(currentBasket); + + return currentBasket; } [HttpPost] [Route("items")] - public async Task AddBasketItem([FromBody] AddBasketItemRequest data) + [ProducesResponseType((int)HttpStatusCode.BadRequest)] + [ProducesResponseType((int)HttpStatusCode.OK)] + public async Task AddBasketItemAsync([FromBody] AddBasketItemRequest data) { if (data == null || data.Quantity == 0) { @@ -106,12 +116,12 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers } // Step 1: Get the item from catalog - var item = await _catalog.GetCatalogItem(data.CatalogItemId); + var item = await _catalog.GetCatalogItemAsync(data.CatalogItemId); //item.PictureUri = // Step 2: Get current basket status - var currentBasket = (await _basket.GetById(data.BasketId)) ?? new BasketData(data.BasketId); + var currentBasket = (await _basket.GetByIdAsync(data.BasketId)) ?? new BasketData(data.BasketId); // Step 3: Merge current status with new product currentBasket.Items.Add(new BasketDataItem() { @@ -124,8 +134,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers }); // Step 4: Update basket - await _basket.Update(currentBasket); - + await _basket.UpdateAsync(currentBasket); return Ok(); } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/OrderController.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/OrderController.cs index fd108ffb8..de3e4cc55 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/OrderController.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Controllers/OrderController.cs @@ -1,16 +1,19 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers { [Route("api/v1/[controller]")] [Authorize] - public class OrderController : Controller + [ApiController] + public class OrderController : ControllerBase { private readonly IBasketService _basketService; private readonly IOrderApiClient _orderClient; @@ -22,21 +25,23 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers [Route("draft/{basketId}")] [HttpGet] - public async Task GetOrderDraft(string basketId) + [ProducesResponseType((int)HttpStatusCode.BadRequest)] + [ProducesResponseType(typeof(OrderData), (int)HttpStatusCode.OK)] + public async Task> GetOrderDraftAsync(string basketId) { if (string.IsNullOrEmpty(basketId)) { return BadRequest("Need a valid basketid"); } // Get the basket data and build a order draft based on it - var basket = await _basketService.GetById(basketId); + var basket = await _basketService.GetByIdAsync(basketId); + if (basket == null) { return BadRequest($"No basket found for id {basketId}"); } - var orderDraft = await _orderClient.GetOrderDraftFromBasket(basket); - return Ok(orderDraft); + return await _orderClient.GetOrderDraftFromBasketAsync(basket); } } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/BasketService.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/BasketService.cs index 291e98fd3..d0fb5c008 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/BasketService.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/BasketService.cs @@ -10,7 +10,6 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services { public class BasketService : IBasketService { - private readonly HttpClient _apiClient; private readonly ILogger _logger; private readonly UrlsConfig _urls; @@ -22,18 +21,19 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services _urls = config.Value; } - public async Task GetById(string id) + public async Task GetByIdAsync(string id) { var data = await _apiClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id)); var basket = !string.IsNullOrEmpty(data) ? JsonConvert.DeserializeObject(data) : null; + return basket; } - public async Task Update(BasketData currentBasket) + public async Task UpdateAsync(BasketData currentBasket) { var basketContent = new StringContent(JsonConvert.SerializeObject(currentBasket), System.Text.Encoding.UTF8, "application/json"); - var data = await _apiClient.PostAsync(_urls.Basket + UrlsConfig.BasketOperations.UpdateBasket(), basketContent); + await _apiClient.PostAsync(_urls.Basket + UrlsConfig.BasketOperations.UpdateBasket(), basketContent); } } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/CatalogService.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/CatalogService.cs index ba67b7c1e..159e56d85 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/CatalogService.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/CatalogService.cs @@ -11,7 +11,6 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services { public class CatalogService : ICatalogService { - private readonly HttpClient _httpClient; private readonly ILogger _logger; private readonly UrlsConfig _urls; @@ -23,20 +22,18 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services _urls = config.Value; } - public async Task GetCatalogItem(int id) + public async Task GetCatalogItemAsync(int id) { var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id)); - var catalogItem = JsonConvert.DeserializeObject(stringContent); - return catalogItem; + return JsonConvert.DeserializeObject(stringContent); } - public async Task> GetCatalogItems(IEnumerable ids) + public async Task> GetCatalogItemsAsync(IEnumerable ids) { var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemsById(ids)); - var catalogItems = JsonConvert.DeserializeObject(stringContent); - return catalogItems; + return JsonConvert.DeserializeObject(stringContent); } } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IBasketService.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IBasketService.cs index f59c31965..046ef753d 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IBasketService.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IBasketService.cs @@ -1,15 +1,12 @@ using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; -using System; -using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services { public interface IBasketService { - Task GetById(string id); - Task Update(BasketData currentBasket); + Task GetByIdAsync(string id); + Task UpdateAsync(BasketData currentBasket); } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/ICatalogService.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/ICatalogService.cs index 7d192f3cc..9f86b84f9 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/ICatalogService.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/ICatalogService.cs @@ -1,14 +1,13 @@ using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; -using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services { public interface ICatalogService { - Task GetCatalogItem(int id); - Task> GetCatalogItems(IEnumerable ids); + Task GetCatalogItemAsync(int id); + + Task> GetCatalogItemsAsync(IEnumerable ids); } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IOrderApiClient.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IOrderApiClient.cs index c97eccbbd..0e972833c 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IOrderApiClient.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/IOrderApiClient.cs @@ -1,13 +1,10 @@ using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; -using System; -using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services { public interface IOrderApiClient { - Task GetOrderDraftFromBasket(BasketData basket); + Task GetOrderDraftFromBasketAsync(BasketData basket); } } diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/OrderApiClient.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/OrderApiClient.cs index d43e392d3..a26028d69 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/OrderApiClient.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Services/OrderApiClient.cs @@ -10,7 +10,6 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services { public class OrderApiClient : IOrderApiClient { - private readonly HttpClient _apiClient; private readonly ILogger _logger; private readonly UrlsConfig _urls; @@ -22,7 +21,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services _urls = config.Value; } - public async Task GetOrderDraftFromBasket(BasketData basket) + public async Task GetOrderDraftFromBasketAsync(BasketData basket) { var url = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft(); var content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json"); diff --git a/src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs b/src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs index e4a080289..23db1f912 100644 --- a/src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs +++ b/src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config; using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters; using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure; @@ -53,18 +54,22 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator { app.UseDeveloperExceptionPage(); } + else + { + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } app.UseAuthentication(); - + app.UseHttpsRedirection(); app.UseMvc(); - app.UseSwagger().UseSwaggerUI(c => - { - c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1"); - //c.ConfigureOAuth2("Microsoft.eShopOnContainers.Web.Shopping.HttpAggregatorwaggerui", "", "", "Purchase BFF Swagger UI"); - }); - - + app.UseSwagger() + .UseSwaggerUI(c => + { + c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1"); + //c.ConfigureOAuth2("Microsoft.eShopOnContainers.Web.Shopping.HttpAggregatorwaggerui", "", "", "Purchase BFF Swagger UI"); + }); } } @@ -99,12 +104,14 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator return services; } + public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration) { services.AddOptions(); services.Configure(configuration.GetSection("urls")); - services.AddMvc(); + services.AddMvc() + .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddSwaggerGen(options => { @@ -177,6 +184,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); } + static IAsyncPolicy GetCircuitBreakerPolicy() { return HttpPolicyExtensions diff --git a/src/Services/Basket/Basket.API/Controllers/BasketController.cs b/src/Services/Basket/Basket.API/Controllers/BasketController.cs index c7fdac57d..0e15e65dd 100644 --- a/src/Services/Basket/Basket.API/Controllers/BasketController.cs +++ b/src/Services/Basket/Basket.API/Controllers/BasketController.cs @@ -13,54 +13,44 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers { [Route("api/v1/[controller]")] [Authorize] - public class BasketController : Controller + [ApiController] + public class BasketController : ControllerBase { private readonly IBasketRepository _repository; - private readonly IIdentityService _identitySvc; + private readonly IIdentityService _identityService; private readonly IEventBus _eventBus; - public BasketController(IBasketRepository repository, - IIdentityService identityService, - IEventBus eventBus) + public BasketController(IBasketRepository repository, IIdentityService identityService, IEventBus eventBus) { _repository = repository; - _identitySvc = identityService; + _identityService = identityService; _eventBus = eventBus; } - // GET /id [HttpGet("{id}")] [ProducesResponseType(typeof(CustomerBasket), (int)HttpStatusCode.OK)] - public async Task Get(string id) + public async Task> GetBasketByIdAsync(string id) { var basket = await _repository.GetBasketAsync(id); - if (basket == null) - { - return Ok(new CustomerBasket(id) { }); - } - return Ok(basket); + return basket ?? new CustomerBasket(id); } - // POST /value [HttpPost] [ProducesResponseType(typeof(CustomerBasket), (int)HttpStatusCode.OK)] - public async Task Post([FromBody]CustomerBasket value) + public async Task> UpdateBasketAsync([FromBody]CustomerBasket value) { - var basket = await _repository.UpdateBasketAsync(value); - - return Ok(basket); + return await _repository.UpdateBasketAsync(value); } [Route("checkout")] [HttpPost] [ProducesResponseType((int)HttpStatusCode.Accepted)] [ProducesResponseType((int)HttpStatusCode.BadRequest)] - public async Task Checkout([FromBody]BasketCheckout basketCheckout, [FromHeader(Name = "x-requestid")] string requestId) + public async Task CheckoutAsync([FromBody]BasketCheckout basketCheckout, [FromHeader(Name = "x-requestid")] string requestId) { - var userId = _identitySvc.GetUserIdentity(); + var userId = _identityService.GetUserIdentity(); - basketCheckout.RequestId = (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) ? guid : basketCheckout.RequestId; @@ -80,17 +70,17 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers // Once basket is checkout, sends an integration event to // ordering.api to convert basket to order and proceeds with // order creation process - _eventBus.Publish(eventMessage); + _eventBus.Publish(eventMessage); return Accepted(); } // DELETE api/values/5 [HttpDelete("{id}")] - public void Delete(string id) + [ProducesResponseType(typeof(void), (int)HttpStatusCode.OK)] + public async Task DeleteBasketByIdAsync(string id) { - _repository.DeleteBasketAsync(id); + await _repository.DeleteBasketAsync(id); } - } } diff --git a/src/Services/Basket/Basket.API/Model/RedisBasketRepository.cs b/src/Services/Basket/Basket.API/Model/RedisBasketRepository.cs index f748d2c25..5000e6c29 100644 --- a/src/Services/Basket/Basket.API/Model/RedisBasketRepository.cs +++ b/src/Services/Basket/Basket.API/Model/RedisBasketRepository.cs @@ -10,7 +10,6 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model public class RedisBasketRepository : IBasketRepository { private readonly ILogger _logger; - private readonly ConnectionMultiplexer _redis; private readonly IDatabase _database; @@ -30,12 +29,14 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model { var server = GetServer(); var data = server.Keys(); + return data?.Select(k => k.ToString()); } public async Task GetBasketAsync(string customerId) { var data = await _database.StringGetAsync(customerId); + if (data.IsNullOrEmpty) { return null; @@ -47,6 +48,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model public async Task UpdateBasketAsync(CustomerBasket basket) { var created = await _database.StringSetAsync(basket.BuyerId, JsonConvert.SerializeObject(basket)); + if (!created) { _logger.LogInformation("Problem occur persisting the item."); diff --git a/src/Services/Basket/Basket.API/Startup.cs b/src/Services/Basket/Basket.API/Startup.cs index 7d65ba8b4..cc100789d 100644 --- a/src/Services/Basket/Basket.API/Startup.cs +++ b/src/Services/Basket/Basket.API/Startup.cs @@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.ServiceBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; @@ -51,11 +52,13 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API // Add framework services. services.AddMvc(options => - { - options.Filters.Add(typeof(HttpGlobalExceptionFilter)); - options.Filters.Add(typeof(ValidateModelStateFilter)); + { + options.Filters.Add(typeof(HttpGlobalExceptionFilter)); + options.Filters.Add(typeof(ValidateModelStateFilter)); - }).AddControllersAsServices(); + }) + .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) + .AddControllersAsServices(); ConfigureAuthService(services); diff --git a/src/Services/Basket/Basket.UnitTests/Application/BasketWebApiTest.cs b/src/Services/Basket/Basket.UnitTests/Application/BasketWebApiTest.cs index 88dda058d..a2e382b92 100644 --- a/src/Services/Basket/Basket.UnitTests/Application/BasketWebApiTest.cs +++ b/src/Services/Basket/Basket.UnitTests/Application/BasketWebApiTest.cs @@ -44,10 +44,10 @@ namespace UnitTest.Basket.Application //Act var basketController = new BasketController( _basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object); - var actionResult = await basketController.Get(fakeCustomerId) as OkObjectResult; + var actionResult = await basketController.GetBasketByIdAsync(fakeCustomerId); //Assert - Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK); + Assert.Equal((actionResult.Result as OkObjectResult).StatusCode, (int)System.Net.HttpStatusCode.OK); Assert.Equal(((CustomerBasket)actionResult.Value).BuyerId, fakeCustomerId); } @@ -67,10 +67,10 @@ namespace UnitTest.Basket.Application var basketController = new BasketController( _basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object); - var actionResult = await basketController.Post(fakeCustomerBasket) as OkObjectResult; + var actionResult = await basketController.UpdateBasketAsync(fakeCustomerBasket); //Assert - Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK); + Assert.Equal((actionResult.Result as OkObjectResult).StatusCode, (int)System.Net.HttpStatusCode.OK); Assert.Equal(((CustomerBasket)actionResult.Value).BuyerId, fakeCustomerId); } @@ -86,7 +86,7 @@ namespace UnitTest.Basket.Application var basketController = new BasketController( _basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object); - var result = await basketController.Checkout(new BasketCheckout(), Guid.NewGuid().ToString()) as BadRequestResult; + var result = await basketController.CheckoutAsync(new BasketCheckout(), Guid.NewGuid().ToString()) as BadRequestResult; Assert.NotNull(result); } @@ -114,7 +114,7 @@ namespace UnitTest.Basket.Application }; //Act - var result = await basketController.Checkout(new BasketCheckout(), Guid.NewGuid().ToString()) as AcceptedResult; + var result = await basketController.CheckoutAsync(new BasketCheckout(), Guid.NewGuid().ToString()) as AcceptedResult; _serviceBusMock.Verify(mock => mock.Publish(It.IsAny()), Times.Once); diff --git a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs index 584f7a0af..d9fa4002e 100644 --- a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs +++ b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs @@ -28,7 +28,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers _catalogIntegrationEventService = catalogIntegrationEventService ?? throw new ArgumentNullException(nameof(catalogIntegrationEventService)); _settings = settings.Value; - ((DbContext)context).ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; + context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; } // GET api/v1/[controller]/items[?pageSize=3&pageIndex=10] @@ -36,11 +36,19 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers [Route("items")] [ProducesResponseType(typeof(PaginatedItemsViewModel), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(IEnumerable), (int)HttpStatusCode.OK)] - public async Task Items([FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0, [FromQuery] string ids = null) + [ProducesResponseType((int)HttpStatusCode.BadRequest)] + public async Task ItemsAsync([FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0, string ids = null) { if (!string.IsNullOrEmpty(ids)) { - return GetItemsByIds(ids); + var items = await GetItemsByIdsAsync(ids); + + if (!items.Any()) + { + return BadRequest("ids value invalid. Must be comma-separated list of numbers"); + } + + return Ok(items); } var totalItems = await _catalogContext.CatalogItems @@ -54,37 +62,36 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers itemsOnPage = ChangeUriPlaceholder(itemsOnPage); - var model = new PaginatedItemsViewModel( - pageIndex, pageSize, totalItems, itemsOnPage); + var model = new PaginatedItemsViewModel(pageIndex, pageSize, totalItems, itemsOnPage); return Ok(model); } - private IActionResult GetItemsByIds(string ids) + private async Task> GetItemsByIdsAsync(string ids) { - var numIds = ids.Split(',') - .Select(id => (Ok: int.TryParse(id, out int x), Value: x)); + var numIds = ids.Split(',').Select(id => (Ok: int.TryParse(id, out int x), Value: x)); if (!numIds.All(nid => nid.Ok)) { - return BadRequest("ids value invalid. Must be comma-separated list of numbers"); + return new List(); } var idsToSelect = numIds .Select(id => id.Value); - var items = _catalogContext.CatalogItems.Where(ci => idsToSelect.Contains(ci.Id)).ToList(); + var items = await _catalogContext.CatalogItems.Where(ci => idsToSelect.Contains(ci.Id)).ToListAsync(); items = ChangeUriPlaceholder(items); - return Ok(items); + return items; } [HttpGet] [Route("items/{id:int}")] [ProducesResponseType((int)HttpStatusCode.NotFound)] + [ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType(typeof(CatalogItem), (int)HttpStatusCode.OK)] - public async Task GetItemById(int id) + public async Task> ItemByIdAsync(int id) { if (id <= 0) { @@ -95,11 +102,12 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers var baseUri = _settings.PicBaseUrl; var azureStorageEnabled = _settings.AzureStorageEnabled; + item.FillProductUrl(baseUri, azureStorageEnabled: azureStorageEnabled); if (item != null) { - return Ok(item); + return item; } return NotFound(); @@ -107,11 +115,10 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers // GET api/v1/[controller]/items/withname/samplename[?pageSize=3&pageIndex=10] [HttpGet] - [Route("[action]/withname/{name:minlength(1)}")] + [Route("items/withname/{name:minlength(1)}")] [ProducesResponseType(typeof(PaginatedItemsViewModel), (int)HttpStatusCode.OK)] - public async Task Items(string name, [FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0) + public async Task>> ItemsWithNameAsync(string name, [FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0) { - var totalItems = await _catalogContext.CatalogItems .Where(c => c.Name.StartsWith(name)) .LongCountAsync(); @@ -124,17 +131,14 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers itemsOnPage = ChangeUriPlaceholder(itemsOnPage); - var model = new PaginatedItemsViewModel( - pageIndex, pageSize, totalItems, itemsOnPage); - - return Ok(model); + return new PaginatedItemsViewModel(pageIndex, pageSize, totalItems, itemsOnPage); } // GET api/v1/[controller]/items/type/1/brand[?pageSize=3&pageIndex=10] [HttpGet] - [Route("[action]/type/{catalogTypeId}/brand/{catalogBrandId:int?}")] + [Route("items/type/{catalogTypeId}/brand/{catalogBrandId:int?}")] [ProducesResponseType(typeof(PaginatedItemsViewModel), (int)HttpStatusCode.OK)] - public async Task Items(int catalogTypeId, int? catalogBrandId, [FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0) + public async Task>> ItemsByTypeIdAndBrandIdAsync(int catalogTypeId, int? catalogBrandId, [FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0) { var root = (IQueryable)_catalogContext.CatalogItems; @@ -155,16 +159,14 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers itemsOnPage = ChangeUriPlaceholder(itemsOnPage); - var model = new PaginatedItemsViewModel( - pageIndex, pageSize, totalItems, itemsOnPage); - - return Ok(model); + return new PaginatedItemsViewModel(pageIndex, pageSize, totalItems, itemsOnPage); } + // GET api/v1/[controller]/items/type/all/brand[?pageSize=3&pageIndex=10] [HttpGet] - [Route("[action]/type/all/brand/{catalogBrandId:int?}")] + [Route("items/type/all/brand/{catalogBrandId:int?}")] [ProducesResponseType(typeof(PaginatedItemsViewModel), (int)HttpStatusCode.OK)] - public async Task Items(int? catalogBrandId, [FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0) + public async Task>> ItemsByBrandIdAsync(int? catalogBrandId, [FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0) { var root = (IQueryable)_catalogContext.CatalogItems; @@ -183,34 +185,25 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers itemsOnPage = ChangeUriPlaceholder(itemsOnPage); - var model = new PaginatedItemsViewModel( - pageIndex, pageSize, totalItems, itemsOnPage); - - return Ok(model); + return new PaginatedItemsViewModel(pageIndex, pageSize, totalItems, itemsOnPage); } // GET api/v1/[controller]/CatalogTypes [HttpGet] - [Route("[action]")] - [ProducesResponseType(typeof(List), (int)HttpStatusCode.OK)] - public async Task CatalogTypes() + [Route("catalogtypes")] + [ProducesResponseType(typeof(List), (int)HttpStatusCode.OK)] + public async Task>> CatalogTypesAsync() { - var items = await _catalogContext.CatalogTypes - .ToListAsync(); - - return Ok(items); + return await _catalogContext.CatalogTypes.ToListAsync(); } // GET api/v1/[controller]/CatalogBrands [HttpGet] - [Route("[action]")] - [ProducesResponseType(typeof(List), (int)HttpStatusCode.OK)] - public async Task CatalogBrands() + [Route("catalogbrands")] + [ProducesResponseType(typeof(List), (int)HttpStatusCode.OK)] + public async Task>> CatalogBrandsAsync() { - var items = await _catalogContext.CatalogBrands - .ToListAsync(); - - return Ok(items); + return await _catalogContext.CatalogBrands.ToListAsync(); } //PUT api/v1/[controller]/items @@ -218,10 +211,9 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers [HttpPut] [ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.Created)] - public async Task UpdateProduct([FromBody]CatalogItem productToUpdate) + public async Task UpdateProductAsync([FromBody]CatalogItem productToUpdate) { - var catalogItem = await _catalogContext.CatalogItems - .SingleOrDefaultAsync(i => i.Id == productToUpdate.Id); + var catalogItem = await _catalogContext.CatalogItems.SingleOrDefaultAsync(i => i.Id == productToUpdate.Id); if (catalogItem == null) { @@ -231,7 +223,6 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers var oldPrice = catalogItem.Price; var raiseProductPriceChangedEvent = oldPrice != productToUpdate.Price; - // Update current product catalogItem = productToUpdate; _catalogContext.CatalogItems.Update(catalogItem); @@ -252,14 +243,14 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers await _catalogContext.SaveChangesAsync(); } - return CreatedAtAction(nameof(GetItemById), new { id = productToUpdate.Id }, null); + return CreatedAtAction(nameof(ItemByIdAsync), new { id = productToUpdate.Id }, null); } //POST api/v1/[controller]/items [Route("items")] [HttpPost] [ProducesResponseType((int)HttpStatusCode.Created)] - public async Task CreateProduct([FromBody]CatalogItem product) + public async Task CreateProductAsync([FromBody]CatalogItem product) { var item = new CatalogItem { @@ -270,18 +261,20 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers PictureFileName = product.PictureFileName, Price = product.Price }; + _catalogContext.CatalogItems.Add(item); await _catalogContext.SaveChangesAsync(); - return CreatedAtAction(nameof(GetItemById), new { id = item.Id }, null); + return CreatedAtAction(nameof(ItemByIdAsync), new { id = item.Id }, null); } //DELETE api/v1/[controller]/id [Route("{id}")] [HttpDelete] [ProducesResponseType((int)HttpStatusCode.NoContent)] - public async Task DeleteProduct(int id) + [ProducesResponseType((int)HttpStatusCode.NotFound)] + public async Task DeleteProductAsync(int id) { var product = _catalogContext.CatalogItems.SingleOrDefault(x => x.Id == id); diff --git a/src/Services/Catalog/Catalog.API/Controllers/PicController.cs b/src/Services/Catalog/Catalog.API/Controllers/PicController.cs index c7af86eed..7d798597e 100644 --- a/src/Services/Catalog/Catalog.API/Controllers/PicController.cs +++ b/src/Services/Catalog/Catalog.API/Controllers/PicController.cs @@ -9,8 +9,9 @@ using System.Threading.Tasks; // For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860 namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers -{ - public class PicController : Controller +{ + [ApiController] + public class PicController : ControllerBase { private readonly IHostingEnvironment _env; private readonly CatalogContext _catalogContext; @@ -27,7 +28,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers [ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.BadRequest)] // GET: // - public async Task GetImage(int catalogItemId) + public async Task GetImageAsync(int catalogItemId) { if (catalogItemId <= 0) { diff --git a/src/Services/Catalog/Catalog.API/Startup.cs b/src/Services/Catalog/Catalog.API/Startup.cs index 5f0080c44..804ca1eeb 100644 --- a/src/Services/Catalog/Catalog.API/Startup.cs +++ b/src/Services/Catalog/Catalog.API/Startup.cs @@ -139,9 +139,11 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API }); services.AddMvc(options => - { - options.Filters.Add(typeof(HttpGlobalExceptionFilter)); - }).AddControllersAsServices(); + { + options.Filters.Add(typeof(HttpGlobalExceptionFilter)); + }) + .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) + .AddControllersAsServices(); services.AddCors(options => { diff --git a/src/Services/Identity/Identity.API/Startup.cs b/src/Services/Identity/Identity.API/Startup.cs index 789047657..049bac090 100644 --- a/src/Services/Identity/Identity.API/Startup.cs +++ b/src/Services/Identity/Identity.API/Startup.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.eShopOnContainers.Services.Identity.API.Certificates; using Microsoft.eShopOnContainers.Services.Identity.API.Data; @@ -52,7 +53,8 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API services.Configure(Configuration); - services.AddMvc(); + services.AddMvc() + .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); if (Configuration.GetValue("IsClusterEnv") == bool.TrueString) { @@ -159,6 +161,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API // Adds IdentityServer app.UseIdentityServer(); + app.UseHttpsRedirection(); app.UseMvc(routes => { routes.MapRoute( diff --git a/src/Services/Location/Locations.API/Controllers/LocationsController.cs b/src/Services/Location/Locations.API/Controllers/LocationsController.cs index 45f4d2ba7..a9cbae1c2 100644 --- a/src/Services/Location/Locations.API/Controllers/LocationsController.cs +++ b/src/Services/Location/Locations.API/Controllers/LocationsController.cs @@ -12,6 +12,7 @@ namespace Locations.API.Controllers { [Route("api/v1/[controller]")] [Authorize] + [ApiController] public class LocationsController : ControllerBase { private readonly ILocationsService _locationsService; @@ -27,30 +28,27 @@ namespace Locations.API.Controllers [Route("user/{userId:guid}")] [HttpGet] [ProducesResponseType(typeof(UserLocation), (int)HttpStatusCode.OK)] - public async Task GetUserLocation(Guid userId) + public async Task> GetUserLocationAsync(Guid userId) { - var userLocation = await _locationsService.GetUserLocation(userId.ToString()); - return Ok(userLocation); + return await _locationsService.GetUserLocationAsync(userId.ToString()); } //GET api/v1/[controller]/ [Route("")] [HttpGet] - //[ProducesResponseType(typeof(List), (int)HttpStatusCode.OK)] - public async Task GetAllLocations() + [ProducesResponseType(typeof(List), (int)HttpStatusCode.OK)] + public async Task>> GetAllLocationsAsync() { - var locations = await _locationsService.GetAllLocation(); - return Ok(locations); + return await _locationsService.GetAllLocationAsync(); } //GET api/v1/[controller]/1 [Route("{locationId}")] [HttpGet] - //[ProducesResponseType(typeof(List), (int)HttpStatusCode.OK)] - public async Task GetLocation(int locationId) + [ProducesResponseType(typeof(Microsoft.eShopOnContainers.Services.Locations.API.Model.Locations), (int)HttpStatusCode.OK)] + public async Task> GetLocationAsync(int locationId) { - var location = await _locationsService.GetLocation(locationId); - return Ok(location); + return await _locationsService.GetLocationAsync(locationId); } //POST api/v1/[controller]/ @@ -58,14 +56,17 @@ namespace Locations.API.Controllers [HttpPost] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest)] - public async Task CreateOrUpdateUserLocation([FromBody]LocationRequest newLocReq) + public async Task CreateOrUpdateUserLocationAsync([FromBody]LocationRequest newLocReq) { var userId = _identityService.GetUserIdentity(); - var result = await _locationsService.AddOrUpdateUserLocation(userId, newLocReq); - - return result ? - (IActionResult)Ok() : - (IActionResult)BadRequest(); + var result = await _locationsService.AddOrUpdateUserLocationAsync(userId, newLocReq); + + if (!result) + { + return BadRequest(); + } + + return Ok(); } } } diff --git a/src/Services/Location/Locations.API/Infrastructure/Services/ILocationsService.cs b/src/Services/Location/Locations.API/Infrastructure/Services/ILocationsService.cs index 5d55bb25e..11459492a 100644 --- a/src/Services/Location/Locations.API/Infrastructure/Services/ILocationsService.cs +++ b/src/Services/Location/Locations.API/Infrastructure/Services/ILocationsService.cs @@ -7,12 +7,12 @@ public interface ILocationsService { - Task GetLocation(int locationId); + Task GetLocationAsync(int locationId); - Task GetUserLocation(string id); + Task GetUserLocationAsync(string id); - Task> GetAllLocation(); + Task> GetAllLocationAsync(); - Task AddOrUpdateUserLocation(string userId, LocationRequest locRequest); + Task AddOrUpdateUserLocationAsync(string userId, LocationRequest locRequest); } } diff --git a/src/Services/Location/Locations.API/Infrastructure/Services/LocationsService.cs b/src/Services/Location/Locations.API/Infrastructure/Services/LocationsService.cs index 771a075d2..e9c299d23 100644 --- a/src/Services/Location/Locations.API/Infrastructure/Services/LocationsService.cs +++ b/src/Services/Location/Locations.API/Infrastructure/Services/LocationsService.cs @@ -21,22 +21,22 @@ _eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus)); } - public async Task GetLocation(int locationId) + public async Task GetLocationAsync(int locationId) { return await _locationsRepository.GetAsync(locationId); } - public async Task GetUserLocation(string userId) + public async Task GetUserLocationAsync(string userId) { return await _locationsRepository.GetUserLocationAsync(userId); } - public async Task> GetAllLocation() + public async Task> GetAllLocationAsync() { return await _locationsRepository.GetLocationListAsync(); } - public async Task AddOrUpdateUserLocation(string userId, LocationRequest currentPosition) + public async Task AddOrUpdateUserLocationAsync(string userId, LocationRequest currentPosition) { // Get the list of ordered regions the user currently is within var currentUserAreaLocationList = await _locationsRepository.GetCurrentUserRegionsListAsync(currentPosition); diff --git a/src/Services/Location/Locations.API/Startup.cs b/src/Services/Location/Locations.API/Startup.cs index be0263312..eaad3c921 100644 --- a/src/Services/Location/Locations.API/Startup.cs +++ b/src/Services/Location/Locations.API/Startup.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.ServiceBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; @@ -43,9 +44,11 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API RegisterAppInsights(services); services.AddMvc(options => - { - options.Filters.Add(typeof(HttpGlobalExceptionFilter)); - }).AddControllersAsServices(); + { + options.Filters.Add(typeof(HttpGlobalExceptionFilter)); + }) + .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) + .AddControllersAsServices(); ConfigureAuthService(services); diff --git a/src/Services/Marketing/Marketing.API/Controllers/CampaignsController.cs b/src/Services/Marketing/Marketing.API/Controllers/CampaignsController.cs index 313d4d77b..67ac1bca5 100644 --- a/src/Services/Marketing/Marketing.API/Controllers/CampaignsController.cs +++ b/src/Services/Marketing/Marketing.API/Controllers/CampaignsController.cs @@ -20,7 +20,8 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers [Route("api/v1/[controller]")] [Authorize] - public class CampaignsController : Controller + [ApiController] + public class CampaignsController : ControllerBase { private readonly MarketingContext _context; private readonly MarketingSettings _settings; @@ -40,43 +41,37 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers [HttpGet] [ProducesResponseType(typeof(List), (int)HttpStatusCode.OK)] - public async Task GetAllCampaigns() + public async Task>> GetAllCampaignsAsync() { - var campaignList = await _context.Campaigns - .ToListAsync(); + var campaignList = await _context.Campaigns.ToListAsync(); if (campaignList is null) { return Ok(); } - var campaignDtoList = MapCampaignModelListToDtoList(campaignList); - - return Ok(campaignDtoList); + return MapCampaignModelListToDtoList(campaignList); } [HttpGet("{id:int}")] [ProducesResponseType(typeof(CampaignDTO), (int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.NotFound)] - public async Task GetCampaignById(int id) + public async Task> GetCampaignByIdAsync(int id) { - var campaign = await _context.Campaigns - .SingleOrDefaultAsync(c => c.Id == id); + var campaign = await _context.Campaigns.SingleOrDefaultAsync(c => c.Id == id); if (campaign is null) { return NotFound(); } - var campaignDto = MapCampaignModelToDto(campaign); - - return Ok(campaignDto); + return MapCampaignModelToDto(campaign); } [HttpPost] [ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.Created)] - public async Task CreateCampaign([FromBody] CampaignDTO campaignDto) + public async Task CreateCampaignAsync([FromBody] CampaignDTO campaignDto) { if (campaignDto is null) { @@ -88,14 +83,14 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers await _context.Campaigns.AddAsync(campaign); await _context.SaveChangesAsync(); - return CreatedAtAction(nameof(GetCampaignById), new { id = campaign.Id }, null); + return CreatedAtAction(nameof(GetCampaignByIdAsync), new { id = campaign.Id }, null); } [HttpPut("{id:int}")] [ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.Created)] - public async Task UpdateCampaign(int id, [FromBody] CampaignDTO campaignDto) + public async Task UpdateCampaignAsync(int id, [FromBody] CampaignDTO campaignDto) { if (id < 1 || campaignDto is null) { @@ -116,14 +111,14 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers await _context.SaveChangesAsync(); - return CreatedAtAction(nameof(GetCampaignById), new { id = campaignToUpdate.Id }, null); + return CreatedAtAction(nameof(GetCampaignByIdAsync), new { id = campaignToUpdate.Id }, null); } [HttpDelete("{id:int}")] [ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.NoContent)] - public async Task Delete(int id) + public async Task DeleteCampaignByIdAsync(int id) { if (id < 1) { @@ -131,6 +126,7 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers } var campaignToDelete = await _context.Campaigns.FindAsync(id); + if (campaignToDelete is null) { return NotFound(); @@ -144,7 +140,7 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers [HttpGet("user")] [ProducesResponseType(typeof(PaginatedItemsViewModel), (int)HttpStatusCode.OK)] - public async Task GetCampaignsByUserId( int pageSize = 10, int pageIndex = 0) + public async Task>> GetCampaignsByUserIdAsync( int pageSize = 10, int pageIndex = 0) { var userId = _identityService.GetUserIdentity(); @@ -169,21 +165,17 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers var userCampaignDtoList = MapCampaignModelListToDtoList(userCampaignList); campaignDtoList.AddRange(userCampaignDtoList); } - } var totalItems = campaignDtoList.Count(); + campaignDtoList = campaignDtoList .Skip(pageSize * pageIndex) .Take(pageSize).ToList(); - var model = new PaginatedItemsViewModel( - pageIndex, pageSize, totalItems, campaignDtoList); - - return Ok(model); + return new PaginatedItemsViewModel(pageIndex, pageSize, totalItems, campaignDtoList); } - private List MapCampaignModelListToDtoList(List campaignList) { var campaignDtoList = new List(); diff --git a/src/Services/Marketing/Marketing.API/Controllers/LocationsController.cs b/src/Services/Marketing/Marketing.API/Controllers/LocationsController.cs index 0d47a63a4..7d5959cb5 100644 --- a/src/Services/Marketing/Marketing.API/Controllers/LocationsController.cs +++ b/src/Services/Marketing/Marketing.API/Controllers/LocationsController.cs @@ -11,7 +11,8 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers using System.Threading.Tasks; [Authorize] - public class LocationsController : Controller + [ApiController] + public class LocationsController : ControllerBase { private readonly MarketingContext _context; @@ -25,7 +26,7 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers [ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType(typeof(UserLocationRuleDTO),(int)HttpStatusCode.OK)] - public IActionResult GetLocationByCampaignAndLocationRuleId(int campaignId, + public ActionResult GetLocationByCampaignAndLocationRuleId(int campaignId, int userLocationRuleId) { if (campaignId < 1 || userLocationRuleId < 1) @@ -42,9 +43,7 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers return NotFound(); } - var locationDto = MapUserLocationRuleModelToDto(location); - - return Ok(locationDto); + return MapUserLocationRuleModelToDto(location); } [HttpGet] @@ -52,7 +51,7 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers [ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType(typeof(List), (int)HttpStatusCode.OK)] - public IActionResult GetAllLocationsByCampaignId(int campaignId) + public ActionResult> GetAllLocationsByCampaignId(int campaignId) { if (campaignId < 1) { @@ -69,17 +68,14 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers return Ok(); } - var locationDtoList = MapUserLocationRuleModelListToDtoList(locationList); - - return Ok(locationDtoList); + return MapUserLocationRuleModelListToDtoList(locationList); } [HttpPost] [Route("api/v1/campaigns/{campaignId:int}/locations")] [ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.Created)] - public async Task CreateLocation(int campaignId, - [FromBody] UserLocationRuleDTO locationRuleDto) + public async Task CreateLocationAsync(int campaignId, [FromBody] UserLocationRuleDTO locationRuleDto) { if (campaignId < 1 || locationRuleDto is null) { @@ -100,7 +96,7 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers [Route("api/v1/campaigns/{campaignId:int}/locations/{userLocationRuleId:int}")] [ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.NotFound)] - public async Task DeleteLocationById(int campaignId, int userLocationRuleId) + public async Task DeleteLocationByIdAsync(int campaignId, int userLocationRuleId) { if (campaignId < 1 || userLocationRuleId < 1) { @@ -122,8 +118,6 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers return NoContent(); } - - private List MapUserLocationRuleModelListToDtoList(List userLocationRuleList) { var userLocationRuleDtoList = new List(); diff --git a/src/Services/Marketing/Marketing.API/Controllers/PicController.cs b/src/Services/Marketing/Marketing.API/Controllers/PicController.cs index 9c2b73c36..66ce1e750 100644 --- a/src/Services/Marketing/Marketing.API/Controllers/PicController.cs +++ b/src/Services/Marketing/Marketing.API/Controllers/PicController.cs @@ -4,8 +4,8 @@ using Microsoft.AspNetCore.Mvc; using System.IO; - - public class PicController : Controller + [ApiController] + public class PicController : ControllerBase { private readonly IHostingEnvironment _env; public PicController(IHostingEnvironment env) @@ -15,7 +15,7 @@ [HttpGet] [Route("api/v1/campaigns/{campaignId:int}/pic")] - public IActionResult GetImage(int campaignId) + public ActionResult GetImage(int campaignId) { var webRoot = _env.WebRootPath; var path = Path.Combine(webRoot, campaignId + ".png"); diff --git a/src/Services/Marketing/Marketing.API/Startup.cs b/src/Services/Marketing/Marketing.API/Startup.cs index 5683dc72d..04fdc07a2 100644 --- a/src/Services/Marketing/Marketing.API/Startup.cs +++ b/src/Services/Marketing/Marketing.API/Startup.cs @@ -24,6 +24,7 @@ using Microsoft.ApplicationInsights.Extensibility; using Microsoft.ApplicationInsights.ServiceFabric; using Microsoft.AspNetCore.Authentication.JwtBearer; + using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.Middlewares; using RabbitMQ.Client; @@ -53,7 +54,9 @@ services.AddMvc(options => { options.Filters.Add(typeof(HttpGlobalExceptionFilter)); - }).AddControllersAsServices(); //Injecting Controllers themselves thru DIFor further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services + }) + .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) + .AddControllersAsServices(); //Injecting Controllers themselves thru DIFor further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services services.Configure(Configuration); diff --git a/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs b/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs index 5542caf11..e2c711b69 100644 --- a/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs +++ b/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs @@ -15,7 +15,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers [Route("api/v1/[controller]")] [Authorize] [ApiController] - public class OrdersController : Controller + public class OrdersController : ControllerBase { private readonly IMediator _mediator; private readonly IOrderQueries _orderQueries; @@ -23,7 +23,6 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers public OrdersController(IMediator mediator, IOrderQueries orderQueries, IIdentityService identityService) { - _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator)); _orderQueries = orderQueries ?? throw new ArgumentNullException(nameof(orderQueries)); _identityService = identityService ?? throw new ArgumentNullException(nameof(identityService)); @@ -33,84 +32,89 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers [HttpPut] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest)] - public async Task CancelOrder([FromBody]CancelOrderCommand command, [FromHeader(Name = "x-requestid")] string requestId) + public async Task CancelOrderAsync([FromBody]CancelOrderCommand command, [FromHeader(Name = "x-requestid")] string requestId) { bool commandResult = false; + if (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) { var requestCancelOrder = new IdentifiedCommand(command, guid); commandResult = await _mediator.Send(requestCancelOrder); } - - return commandResult ? (IActionResult)Ok() : (IActionResult)BadRequest(); + if (!commandResult) + { + return BadRequest(); + } + + return Ok(); } [Route("ship")] [HttpPut] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest)] - public async Task ShipOrder([FromBody]ShipOrderCommand command, [FromHeader(Name = "x-requestid")] string requestId) + public async Task ShipOrderAsync([FromBody]ShipOrderCommand command, [FromHeader(Name = "x-requestid")] string requestId) { bool commandResult = false; + if (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) { var requestShipOrder = new IdentifiedCommand(command, guid); commandResult = await _mediator.Send(requestShipOrder); } - return commandResult ? (IActionResult)Ok() : (IActionResult)BadRequest(); + if (!commandResult) + { + return BadRequest(); + } + return Ok(); } [Route("{orderId:int}")] [HttpGet] [ProducesResponseType(typeof(Order),(int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.NotFound)] - public async Task GetOrder(int orderId) + public async Task GetOrderAsync(int orderId) { try { - var order = await _orderQueries - .GetOrderAsync(orderId); + var order = await _orderQueries.GetOrderAsync(orderId); return Ok(order); } - catch (KeyNotFoundException) + catch { return NotFound(); } } - [Route("")] [HttpGet] [ProducesResponseType(typeof(IEnumerable), (int)HttpStatusCode.OK)] - public async Task GetOrders() + public async Task>> GetOrdersAsync() { var userid = _identityService.GetUserIdentity(); var orders = await _orderQueries.GetOrdersFromUserAsync(Guid.Parse(userid)); + return Ok(orders); } [Route("cardtypes")] [HttpGet] [ProducesResponseType(typeof(IEnumerable), (int)HttpStatusCode.OK)] - public async Task GetCardTypes() + public async Task>> GetCardTypesAsync() { - var cardTypes = await _orderQueries - .GetCardTypesAsync(); + var cardTypes = await _orderQueries.GetCardTypesAsync(); return Ok(cardTypes); - } + } [Route("draft")] [HttpPost] - public async Task GetOrderDraftFromBasketData([FromBody] CreateOrderDraftCommand createOrderDraftCommand) + public async Task> CreateOrderDraftFromBasketDataAsync([FromBody] CreateOrderDraftCommand createOrderDraftCommand) { - var draft = await _mediator.Send(createOrderDraftCommand); - return Ok(draft); + return await _mediator.Send(createOrderDraftCommand); } } -} - - +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Startup.cs b/src/Services/Ordering/Ordering.API/Startup.cs index f729e6666..59b8f0142 100644 --- a/src/Services/Ordering/Ordering.API/Startup.cs +++ b/src/Services/Ordering/Ordering.API/Startup.cs @@ -154,9 +154,11 @@ { // Add framework services. services.AddMvc(options => - { - options.Filters.Add(typeof(HttpGlobalExceptionFilter)); - }).AddControllersAsServices(); //Injecting Controllers themselves thru DI + { + options.Filters.Add(typeof(HttpGlobalExceptionFilter)); + }) + .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) + .AddControllersAsServices(); //Injecting Controllers themselves thru DI //For further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services services.AddCors(options => diff --git a/src/Services/Ordering/Ordering.UnitTests/Application/OrdersWebApiTest.cs b/src/Services/Ordering/Ordering.UnitTests/Application/OrdersWebApiTest.cs index aadd6c62a..c5b8a1764 100644 --- a/src/Services/Ordering/Ordering.UnitTests/Application/OrdersWebApiTest.cs +++ b/src/Services/Ordering/Ordering.UnitTests/Application/OrdersWebApiTest.cs @@ -36,7 +36,7 @@ namespace UnitTest.Ordering.Application //Act var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object); - var actionResult = await orderController.CancelOrder(new CancelOrderCommand(1), Guid.NewGuid().ToString()) as OkResult; + var actionResult = await orderController.CancelOrderAsync(new CancelOrderCommand(1), Guid.NewGuid().ToString()) as OkResult; //Assert Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK); @@ -52,7 +52,7 @@ namespace UnitTest.Ordering.Application //Act var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object); - var actionResult = await orderController.CancelOrder(new CancelOrderCommand(1), String.Empty) as BadRequestResult; + var actionResult = await orderController.CancelOrderAsync(new CancelOrderCommand(1), String.Empty) as BadRequestResult; //Assert Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.BadRequest); @@ -67,7 +67,7 @@ namespace UnitTest.Ordering.Application //Act var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object); - var actionResult = await orderController.ShipOrder(new ShipOrderCommand(1), Guid.NewGuid().ToString()) as OkResult; + var actionResult = await orderController.ShipOrderAsync(new ShipOrderCommand(1), Guid.NewGuid().ToString()) as OkResult; //Assert Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK); @@ -83,7 +83,7 @@ namespace UnitTest.Ordering.Application //Act var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object); - var actionResult = await orderController.ShipOrder(new ShipOrderCommand(1), String.Empty) as BadRequestResult; + var actionResult = await orderController.ShipOrderAsync(new ShipOrderCommand(1), String.Empty) as BadRequestResult; //Assert Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.BadRequest); @@ -103,10 +103,10 @@ namespace UnitTest.Ordering.Application //Act var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object); - var actionResult = await orderController.GetOrders() as OkObjectResult; + var actionResult = await orderController.GetOrdersAsync(); //Assert - Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK); + Assert.Equal((actionResult.Result as OkObjectResult).StatusCode, (int)System.Net.HttpStatusCode.OK); } [Fact] @@ -120,7 +120,7 @@ namespace UnitTest.Ordering.Application //Act var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object); - var actionResult = await orderController.GetOrder(fakeOrderId) as OkObjectResult; + var actionResult = await orderController.GetOrderAsync(fakeOrderId) as OkObjectResult; //Assert Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK); @@ -136,10 +136,10 @@ namespace UnitTest.Ordering.Application //Act var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object); - var actionResult = await orderController.GetCardTypes() as OkObjectResult; + var actionResult = await orderController.GetCardTypesAsync(); //Assert - Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK); + Assert.Equal((actionResult.Result as OkObjectResult).StatusCode, (int)System.Net.HttpStatusCode.OK); } } } diff --git a/src/Web/WebMVC/Startup.cs b/src/Web/WebMVC/Startup.cs index fe1f5de21..c313f87fd 100644 --- a/src/Web/WebMVC/Startup.cs +++ b/src/Web/WebMVC/Startup.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using Microsoft.eShopOnContainers.WebMVC.Services; using Microsoft.eShopOnContainers.WebMVC.ViewModels; using Microsoft.Extensions.Configuration; @@ -59,6 +60,7 @@ namespace Microsoft.eShopOnContainers.WebMVC else { app.UseExceptionHandler("/Error"); + app.UseHsts(); } var pathBase = Configuration["PATH_BASE"]; @@ -87,6 +89,7 @@ namespace Microsoft.eShopOnContainers.WebMVC WebContextSeed.Seed(app, env, loggerFactory); + app.UseHttpsRedirection(); app.UseMvc(routes => { routes.MapRoute( @@ -149,7 +152,8 @@ namespace Microsoft.eShopOnContainers.WebMVC services.AddOptions(); services.Configure(configuration); - services.AddMvc(); + services.AddMvc() + .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddSession(); diff --git a/src/Web/WebSPA/Startup.cs b/src/Web/WebSPA/Startup.cs index f49eba772..c979dbafb 100644 --- a/src/Web/WebSPA/Startup.cs +++ b/src/Web/WebSPA/Startup.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Antiforgery; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.HealthChecks; @@ -71,6 +72,7 @@ namespace eShopConContainers.WebSPA services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN"); services.AddMvc() + .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) .AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); @@ -89,6 +91,11 @@ namespace eShopConContainers.WebSPA { app.UseDeveloperExceptionPage(); } + else + { + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } // Configure XSRF middleware, This pattern is for SPA style applications where XSRF token is added on Index page // load and passed back token on every subsequent async request diff --git a/src/Web/WebStatus/Startup.cs b/src/Web/WebStatus/Startup.cs index 6a9ed32d1..b4a1049d8 100644 --- a/src/Web/WebStatus/Startup.cs +++ b/src/Web/WebStatus/Startup.cs @@ -10,6 +10,7 @@ using Microsoft.Extensions.Logging; using WebStatus.Extensions; using Microsoft.ApplicationInsights.Extensibility; using Microsoft.ApplicationInsights.ServiceFabric; +using Microsoft.AspNetCore.Mvc; namespace WebStatus { @@ -50,7 +51,8 @@ namespace WebStatus checks.AddUrlCheckIfNotNull(Configuration["spa"], TimeSpan.Zero); //No cache for this HealthCheck, better just for demos }); - services.AddMvc(); + services.AddMvc() + .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -66,6 +68,8 @@ namespace WebStatus else { app.UseExceptionHandler("/Home/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); } var pathBase = Configuration["PATH_BASE"]; @@ -74,13 +78,14 @@ namespace WebStatus app.UsePathBase(pathBase); } - #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously app.Map("/liveness", lapp => lapp.Run(async ctx => ctx.Response.StatusCode = 200)); #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously app.UseStaticFiles(); + app.UseHttpsRedirection(); + app.UseMvc(routes => { routes.MapRoute(