Merge pull request #851 from erikpique/feature/60697

Feature/60697
This commit is contained in:
RamonTC 2018-11-26 17:40:27 +01:00 committed by GitHub
commit 06e641a97f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 347 additions and 311 deletions

View File

@ -10,7 +10,6 @@ namespace OcelotApiGw
{ {
public class Startup public class Startup
{ {
private readonly IConfiguration _cfg; private readonly IConfiguration _cfg;
public Startup(IConfiguration configuration) public Startup(IConfiguration configuration)
@ -65,6 +64,7 @@ namespace OcelotApiGw
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{ {
var pathBase = _cfg["PATH_BASE"]; var pathBase = _cfg["PATH_BASE"];
if (!string.IsNullOrEmpty(pathBase)) if (!string.IsNullOrEmpty(pathBase))
{ {
app.UsePathBase(pathBase); app.UsePathBase(pathBase);

View File

@ -5,16 +5,19 @@ using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers
{ {
[Route("api/v1/[controller]")] [Route("api/v1/[controller]")]
[Authorize] [Authorize]
public class BasketController : Controller [ApiController]
public class BasketController : ControllerBase
{ {
private readonly ICatalogService _catalog; private readonly ICatalogService _catalog;
private readonly IBasketService _basket; private readonly IBasketService _basket;
public BasketController(ICatalogService catalogService, IBasketService basketService) public BasketController(ICatalogService catalogService, IBasketService basketService)
{ {
_catalog = catalogService; _catalog = catalogService;
@ -23,22 +26,24 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers
[HttpPost] [HttpPost]
[HttpPut] [HttpPut]
public async Task<IActionResult> UpdateAllBasket([FromBody] UpdateBasketRequest data) [ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)]
public async Task<ActionResult<BasketData>> UpdateAllBasketAsync([FromBody] UpdateBasketRequest data)
{ {
if (data.Items == null || !data.Items.Any()) if (data.Items == null || !data.Items.Any())
{ {
return BadRequest("Need to pass at least one basket line"); return BadRequest("Need to pass at least one basket line");
} }
// Retrieve the current basket // Retrieve the current basket
var currentBasket = await _basket.GetById(data.BuyerId); var currentBasket = await _basket.GetByIdAsync(data.BuyerId);
if (currentBasket == null) if (currentBasket == null)
{ {
currentBasket = new BasketData(data.BuyerId); 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); var newBasket = new BasketData(data.BuyerId);
foreach (var bitem in data.Items) foreach (var bitem in data.Items)
@ -60,13 +65,16 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers
}); });
} }
await _basket.Update(newBasket); await _basket.UpdateAsync(newBasket);
return Ok(newBasket);
return newBasket;
} }
[HttpPut] [HttpPut]
[Route("items")] [Route("items")]
public async Task<IActionResult> UpdateQuantities([FromBody] UpdateBasketItemsRequest data) [ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)]
public async Task<ActionResult<BasketData>> UpdateQuantitiesAsync([FromBody] UpdateBasketItemsRequest data)
{ {
if (!data.Updates.Any()) if (!data.Updates.Any())
{ {
@ -74,7 +82,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers
} }
// Retrieve the current basket // Retrieve the current basket
var currentBasket = await _basket.GetById(data.BasketId); var currentBasket = await _basket.GetByIdAsync(data.BasketId);
if (currentBasket == null) if (currentBasket == null)
{ {
return BadRequest($"Basket with id {data.BasketId} not found."); 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) foreach (var update in data.Updates)
{ {
var basketItem = currentBasket.Items.SingleOrDefault(bitem => bitem.Id == update.BasketItemId); var basketItem = currentBasket.Items.SingleOrDefault(bitem => bitem.Id == update.BasketItemId);
if (basketItem == null) if (basketItem == null)
{ {
return BadRequest($"Basket item with id {update.BasketItemId} not found"); return BadRequest($"Basket item with id {update.BasketItemId} not found");
} }
basketItem.Quantity = update.NewQty; basketItem.Quantity = update.NewQty;
} }
// Save the updated basket // Save the updated basket
await _basket.Update(currentBasket); await _basket.UpdateAsync(currentBasket);
return Ok(currentBasket);
return currentBasket;
} }
[HttpPost] [HttpPost]
[Route("items")] [Route("items")]
public async Task<IActionResult> AddBasketItem([FromBody] AddBasketItemRequest data) [ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType((int)HttpStatusCode.OK)]
public async Task<ActionResult> AddBasketItemAsync([FromBody] AddBasketItemRequest data)
{ {
if (data == null || data.Quantity == 0) if (data == null || data.Quantity == 0)
{ {
@ -106,12 +119,12 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers
} }
// Step 1: Get the item from catalog // Step 1: Get the item from catalog
var item = await _catalog.GetCatalogItem(data.CatalogItemId); var item = await _catalog.GetCatalogItemAsync(data.CatalogItemId);
//item.PictureUri = //item.PictureUri =
// Step 2: Get current basket status // 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 // Step 3: Merge current status with new product
currentBasket.Items.Add(new BasketDataItem() currentBasket.Items.Add(new BasketDataItem()
{ {
@ -124,8 +137,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers
}); });
// Step 4: Update basket // Step 4: Update basket
await _basket.Update(currentBasket); await _basket.UpdateAsync(currentBasket);
return Ok(); return Ok();
} }

View File

@ -1,19 +1,20 @@
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services;
using System; using System.Net;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers
{ {
[Route("api/v1/[controller]")] [Route("api/v1/[controller]")]
[Authorize] [Authorize]
public class OrderController : Controller [ApiController]
public class OrderController : ControllerBase
{ {
private readonly IBasketService _basketService; private readonly IBasketService _basketService;
private readonly IOrderApiClient _orderClient; private readonly IOrderApiClient _orderClient;
public OrderController(IBasketService basketService, IOrderApiClient orderClient) public OrderController(IBasketService basketService, IOrderApiClient orderClient)
{ {
_basketService = basketService; _basketService = basketService;
@ -22,21 +23,23 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers
[Route("draft/{basketId}")] [Route("draft/{basketId}")]
[HttpGet] [HttpGet]
public async Task<IActionResult> GetOrderDraft(string basketId) [ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(OrderData), (int)HttpStatusCode.OK)]
public async Task<ActionResult<OrderData>> GetOrderDraftAsync(string basketId)
{ {
if (string.IsNullOrEmpty(basketId)) if (string.IsNullOrEmpty(basketId))
{ {
return BadRequest("Need a valid basketid"); return BadRequest("Need a valid basketid");
} }
// Get the basket data and build a order draft based on it // 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) if (basket == null)
{ {
return BadRequest($"No basket found for id {basketId}"); return BadRequest($"No basket found for id {basketId}");
} }
var orderDraft = await _orderClient.GetOrderDraftFromBasket(basket); return await _orderClient.GetOrderDraftFromBasketAsync(basket);
return Ok(orderDraft);
} }
} }
} }

View File

@ -22,7 +22,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
_urls = config.Value; _urls = config.Value;
} }
public async Task<BasketData> GetById(string id) public async Task<BasketData> GetByIdAsync(string id)
{ {
var data = await _httpClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(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; 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 basketContent = new StringContent(JsonConvert.SerializeObject(currentBasket), System.Text.Encoding.UTF8, "application/json");

View File

@ -22,7 +22,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
_urls = config.Value; _urls = config.Value;
} }
public async Task<CatalogItem> GetCatalogItem(int id) public async Task<CatalogItem> GetCatalogItemAsync(int id)
{ {
var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id)); var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id));
var catalogItem = JsonConvert.DeserializeObject<CatalogItem>(stringContent); var catalogItem = JsonConvert.DeserializeObject<CatalogItem>(stringContent);
@ -30,7 +30,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
return catalogItem; return catalogItem;
} }
public async Task<IEnumerable<CatalogItem>> GetCatalogItems(IEnumerable<int> ids) public async Task<IEnumerable<CatalogItem>> GetCatalogItemsAsync(IEnumerable<int> ids)
{ {
var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemsById(ids)); var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemsById(ids));
var catalogItems = JsonConvert.DeserializeObject<CatalogItem[]>(stringContent); var catalogItems = JsonConvert.DeserializeObject<CatalogItem[]>(stringContent);

View File

@ -1,15 +1,13 @@
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
{ {
public interface IBasketService public interface IBasketService
{ {
Task<BasketData> GetById(string id); Task<BasketData> GetByIdAsync(string id);
Task Update(BasketData currentBasket);
Task UpdateAsync(BasketData currentBasket);
} }
} }

View File

@ -1,14 +1,13 @@
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
{ {
public interface ICatalogService public interface ICatalogService
{ {
Task<CatalogItem> GetCatalogItem(int id); Task<CatalogItem> GetCatalogItemAsync(int id);
Task<IEnumerable<CatalogItem>> GetCatalogItems(IEnumerable<int> ids);
Task<IEnumerable<CatalogItem>> GetCatalogItemsAsync(IEnumerable<int> ids);
} }
} }

View File

@ -1,13 +1,10 @@
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
{ {
public interface IOrderApiClient public interface IOrderApiClient
{ {
Task<OrderData> GetOrderDraftFromBasket(BasketData basket); Task<OrderData> GetOrderDraftFromBasketAsync(BasketData basket);
} }
} }

View File

@ -21,7 +21,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
_urls = config.Value; _urls = config.Value;
} }
public async Task<OrderData> GetOrderDraftFromBasket(BasketData basket) public async Task<OrderData> GetOrderDraftFromBasketAsync(BasketData basket)
{ {
var uri = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft(); var uri = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft();
var content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json"); var content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json");

View File

@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure;
@ -53,9 +54,14 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
{ {
app.UseDeveloperExceptionPage(); 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.UseAuthentication();
app.UseHttpsRedirection();
app.UseMvc(); app.UseMvc();
app.UseSwagger().UseSwaggerUI(c => app.UseSwagger().UseSwaggerUI(c =>
@ -77,7 +83,8 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
services.AddOptions(); services.AddOptions();
services.Configure<UrlsConfig>(configuration.GetSection("urls")); services.Configure<UrlsConfig>(configuration.GetSection("urls"));
services.AddMvc(); services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddSwaggerGen(options => services.AddSwaggerGen(options =>
{ {
@ -120,12 +127,14 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
{ {
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
var identityUrl = configuration.GetValue<string>("urls:identity"); var identityUrl = configuration.GetValue<string>("urls:identity");
services.AddAuthentication(options => services.AddAuthentication(options =>
{ {
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options => })
.AddJwtBearer(options =>
{ {
options.Authority = identityUrl; options.Authority = identityUrl;
options.RequireHttpsMetadata = false; options.RequireHttpsMetadata = false;
@ -143,6 +152,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
return services; return services;
} }
public static IServiceCollection AddHttpServices(this IServiceCollection services) public static IServiceCollection AddHttpServices(this IServiceCollection services)
{ {
//register delegating handlers //register delegating handlers
@ -163,8 +173,6 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
.AddPolicyHandler(GetRetryPolicy()) .AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy()); .AddPolicyHandler(GetCircuitBreakerPolicy());
return services; return services;
} }
@ -174,7 +182,6 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
.HandleTransientHttpError() .HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound) .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
} }
private static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy() private static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()

View File

@ -5,16 +5,19 @@ using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers
{ {
[Route("api/v1/[controller]")] [Route("api/v1/[controller]")]
[Authorize] [Authorize]
public class BasketController : Controller [ApiController]
public class BasketController : ControllerBase
{ {
private readonly ICatalogService _catalog; private readonly ICatalogService _catalog;
private readonly IBasketService _basket; private readonly IBasketService _basket;
public BasketController(ICatalogService catalogService, IBasketService basketService) public BasketController(ICatalogService catalogService, IBasketService basketService)
{ {
_catalog = catalogService; _catalog = catalogService;
@ -23,22 +26,23 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers
[HttpPost] [HttpPost]
[HttpPut] [HttpPut]
public async Task<IActionResult> UpdateAllBasket([FromBody] UpdateBasketRequest data) [ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)]
public async Task<ActionResult<BasketData>> UpdateAllBasketAsync([FromBody] UpdateBasketRequest data)
{ {
if (data.Items == null || !data.Items.Any()) if (data.Items == null || !data.Items.Any())
{ {
return BadRequest("Need to pass at least one basket line"); return BadRequest("Need to pass at least one basket line");
} }
// Retrieve the current basket // Retrieve the current basket
var currentBasket = await _basket.GetById(data.BuyerId); var currentBasket = await _basket.GetByIdAsync(data.BuyerId);
if (currentBasket == null) if (currentBasket == null)
{ {
currentBasket = new BasketData(data.BuyerId); 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); var newBasket = new BasketData(data.BuyerId);
foreach (var bitem in data.Items) foreach (var bitem in data.Items)
@ -60,13 +64,16 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers
}); });
} }
await _basket.Update(newBasket); await _basket.UpdateAsync(newBasket);
return Ok(newBasket);
return newBasket;
} }
[HttpPut] [HttpPut]
[Route("items")] [Route("items")]
public async Task<IActionResult> UpdateQuantities([FromBody] UpdateBasketItemsRequest data) [ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)]
public async Task<ActionResult<BasketData>> UpdateQuantitiesAsync([FromBody] UpdateBasketItemsRequest data)
{ {
if (!data.Updates.Any()) if (!data.Updates.Any())
{ {
@ -74,7 +81,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers
} }
// Retrieve the current basket // Retrieve the current basket
var currentBasket = await _basket.GetById(data.BasketId); var currentBasket = await _basket.GetByIdAsync(data.BasketId);
if (currentBasket == null) if (currentBasket == null)
{ {
return BadRequest($"Basket with id {data.BasketId} not found."); return BadRequest($"Basket with id {data.BasketId} not found.");
@ -92,13 +99,16 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers
} }
// Save the updated basket // Save the updated basket
await _basket.Update(currentBasket); await _basket.UpdateAsync(currentBasket);
return Ok(currentBasket);
return currentBasket;
} }
[HttpPost] [HttpPost]
[Route("items")] [Route("items")]
public async Task<IActionResult> AddBasketItem([FromBody] AddBasketItemRequest data) [ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType((int)HttpStatusCode.OK)]
public async Task<ActionResult> AddBasketItemAsync([FromBody] AddBasketItemRequest data)
{ {
if (data == null || data.Quantity == 0) if (data == null || data.Quantity == 0)
{ {
@ -106,12 +116,12 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers
} }
// Step 1: Get the item from catalog // Step 1: Get the item from catalog
var item = await _catalog.GetCatalogItem(data.CatalogItemId); var item = await _catalog.GetCatalogItemAsync(data.CatalogItemId);
//item.PictureUri = //item.PictureUri =
// Step 2: Get current basket status // 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 // Step 3: Merge current status with new product
currentBasket.Items.Add(new BasketDataItem() currentBasket.Items.Add(new BasketDataItem()
{ {
@ -124,8 +134,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers
}); });
// Step 4: Update basket // Step 4: Update basket
await _basket.Update(currentBasket); await _basket.UpdateAsync(currentBasket);
return Ok(); return Ok();
} }

View File

@ -1,16 +1,19 @@
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models;
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers
{ {
[Route("api/v1/[controller]")] [Route("api/v1/[controller]")]
[Authorize] [Authorize]
public class OrderController : Controller [ApiController]
public class OrderController : ControllerBase
{ {
private readonly IBasketService _basketService; private readonly IBasketService _basketService;
private readonly IOrderApiClient _orderClient; private readonly IOrderApiClient _orderClient;
@ -22,21 +25,23 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers
[Route("draft/{basketId}")] [Route("draft/{basketId}")]
[HttpGet] [HttpGet]
public async Task<IActionResult> GetOrderDraft(string basketId) [ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(OrderData), (int)HttpStatusCode.OK)]
public async Task<ActionResult<OrderData>> GetOrderDraftAsync(string basketId)
{ {
if (string.IsNullOrEmpty(basketId)) if (string.IsNullOrEmpty(basketId))
{ {
return BadRequest("Need a valid basketid"); return BadRequest("Need a valid basketid");
} }
// Get the basket data and build a order draft based on it // 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) if (basket == null)
{ {
return BadRequest($"No basket found for id {basketId}"); return BadRequest($"No basket found for id {basketId}");
} }
var orderDraft = await _orderClient.GetOrderDraftFromBasket(basket); return await _orderClient.GetOrderDraftFromBasketAsync(basket);
return Ok(orderDraft);
} }
} }
} }

View File

@ -10,7 +10,6 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
{ {
public class BasketService : IBasketService public class BasketService : IBasketService
{ {
private readonly HttpClient _apiClient; private readonly HttpClient _apiClient;
private readonly ILogger<BasketService> _logger; private readonly ILogger<BasketService> _logger;
private readonly UrlsConfig _urls; private readonly UrlsConfig _urls;
@ -22,18 +21,19 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
_urls = config.Value; _urls = config.Value;
} }
public async Task<BasketData> GetById(string id) public async Task<BasketData> GetByIdAsync(string id)
{ {
var data = await _apiClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id)); var data = await _apiClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id));
var basket = !string.IsNullOrEmpty(data) ? JsonConvert.DeserializeObject<BasketData>(data) : null; var basket = !string.IsNullOrEmpty(data) ? JsonConvert.DeserializeObject<BasketData>(data) : null;
return basket; 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 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);
} }
} }
} }

View File

@ -11,7 +11,6 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
{ {
public class CatalogService : ICatalogService public class CatalogService : ICatalogService
{ {
private readonly HttpClient _httpClient; private readonly HttpClient _httpClient;
private readonly ILogger<CatalogService> _logger; private readonly ILogger<CatalogService> _logger;
private readonly UrlsConfig _urls; private readonly UrlsConfig _urls;
@ -23,20 +22,18 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
_urls = config.Value; _urls = config.Value;
} }
public async Task<CatalogItem> GetCatalogItem(int id) public async Task<CatalogItem> GetCatalogItemAsync(int id)
{ {
var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id)); var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id));
var catalogItem = JsonConvert.DeserializeObject<CatalogItem>(stringContent);
return catalogItem; return JsonConvert.DeserializeObject<CatalogItem>(stringContent);
} }
public async Task<IEnumerable<CatalogItem>> GetCatalogItems(IEnumerable<int> ids) public async Task<IEnumerable<CatalogItem>> GetCatalogItemsAsync(IEnumerable<int> ids)
{ {
var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemsById(ids)); var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemsById(ids));
var catalogItems = JsonConvert.DeserializeObject<CatalogItem[]>(stringContent);
return catalogItems; return JsonConvert.DeserializeObject<CatalogItem[]>(stringContent);
} }
} }
} }

View File

@ -1,15 +1,12 @@
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
{ {
public interface IBasketService public interface IBasketService
{ {
Task<BasketData> GetById(string id); Task<BasketData> GetByIdAsync(string id);
Task Update(BasketData currentBasket);
Task UpdateAsync(BasketData currentBasket);
} }
} }

View File

@ -1,14 +1,13 @@
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
{ {
public interface ICatalogService public interface ICatalogService
{ {
Task<CatalogItem> GetCatalogItem(int id); Task<CatalogItem> GetCatalogItemAsync(int id);
Task<IEnumerable<CatalogItem>> GetCatalogItems(IEnumerable<int> ids);
Task<IEnumerable<CatalogItem>> GetCatalogItemsAsync(IEnumerable<int> ids);
} }
} }

View File

@ -1,13 +1,10 @@
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
{ {
public interface IOrderApiClient public interface IOrderApiClient
{ {
Task<OrderData> GetOrderDraftFromBasket(BasketData basket); Task<OrderData> GetOrderDraftFromBasketAsync(BasketData basket);
} }
} }

View File

@ -10,7 +10,6 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
{ {
public class OrderApiClient : IOrderApiClient public class OrderApiClient : IOrderApiClient
{ {
private readonly HttpClient _apiClient; private readonly HttpClient _apiClient;
private readonly ILogger<OrderApiClient> _logger; private readonly ILogger<OrderApiClient> _logger;
private readonly UrlsConfig _urls; private readonly UrlsConfig _urls;
@ -22,7 +21,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
_urls = config.Value; _urls = config.Value;
} }
public async Task<OrderData> GetOrderDraftFromBasket(BasketData basket) public async Task<OrderData> GetOrderDraftFromBasketAsync(BasketData basket)
{ {
var url = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft(); var url = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft();
var content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json"); var content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json");

View File

@ -2,6 +2,7 @@
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config; using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config;
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters; using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters;
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure; using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure;
@ -53,18 +54,22 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
{ {
app.UseDeveloperExceptionPage(); 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.UseAuthentication();
app.UseHttpsRedirection();
app.UseMvc(); app.UseMvc();
app.UseSwagger().UseSwaggerUI(c => 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"); 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; return services;
} }
public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration) public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration)
{ {
services.AddOptions(); services.AddOptions();
services.Configure<UrlsConfig>(configuration.GetSection("urls")); services.Configure<UrlsConfig>(configuration.GetSection("urls"));
services.AddMvc(); services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddSwaggerGen(options => services.AddSwaggerGen(options =>
{ {
@ -177,6 +184,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
} }
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy() static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{ {
return HttpPolicyExtensions return HttpPolicyExtensions

View File

@ -13,53 +13,43 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
{ {
[Route("api/v1/[controller]")] [Route("api/v1/[controller]")]
[Authorize] [Authorize]
public class BasketController : Controller [ApiController]
public class BasketController : ControllerBase
{ {
private readonly IBasketRepository _repository; private readonly IBasketRepository _repository;
private readonly IIdentityService _identitySvc; private readonly IIdentityService _identityService;
private readonly IEventBus _eventBus; private readonly IEventBus _eventBus;
public BasketController(IBasketRepository repository, public BasketController(IBasketRepository repository, IIdentityService identityService, IEventBus eventBus)
IIdentityService identityService,
IEventBus eventBus)
{ {
_repository = repository; _repository = repository;
_identitySvc = identityService; _identityService = identityService;
_eventBus = eventBus; _eventBus = eventBus;
} }
// GET /id
[HttpGet("{id}")] [HttpGet("{id}")]
[ProducesResponseType(typeof(CustomerBasket), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(CustomerBasket), (int)HttpStatusCode.OK)]
public async Task<IActionResult> Get(string id) public async Task<ActionResult<CustomerBasket>> GetBasketByIdAsync(string id)
{ {
var basket = await _repository.GetBasketAsync(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] [HttpPost]
[ProducesResponseType(typeof(CustomerBasket), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(CustomerBasket), (int)HttpStatusCode.OK)]
public async Task<IActionResult> Post([FromBody]CustomerBasket value) public async Task<ActionResult<CustomerBasket>> UpdateBasketAsync([FromBody]CustomerBasket value)
{ {
var basket = await _repository.UpdateBasketAsync(value); return await _repository.UpdateBasketAsync(value);
return Ok(basket);
} }
[Route("checkout")] [Route("checkout")]
[HttpPost] [HttpPost]
[ProducesResponseType((int)HttpStatusCode.Accepted)] [ProducesResponseType((int)HttpStatusCode.Accepted)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.BadRequest)]
public async Task<IActionResult> Checkout([FromBody]BasketCheckout basketCheckout, [FromHeader(Name = "x-requestid")] string requestId) public async Task<ActionResult> 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) ? basketCheckout.RequestId = (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) ?
guid : basketCheckout.RequestId; guid : basketCheckout.RequestId;
@ -87,10 +77,10 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
// DELETE api/values/5 // DELETE api/values/5
[HttpDelete("{id}")] [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);
} }
} }
} }

View File

@ -10,7 +10,6 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
public class RedisBasketRepository : IBasketRepository public class RedisBasketRepository : IBasketRepository
{ {
private readonly ILogger<RedisBasketRepository> _logger; private readonly ILogger<RedisBasketRepository> _logger;
private readonly ConnectionMultiplexer _redis; private readonly ConnectionMultiplexer _redis;
private readonly IDatabase _database; private readonly IDatabase _database;
@ -30,12 +29,14 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
{ {
var server = GetServer(); var server = GetServer();
var data = server.Keys(); var data = server.Keys();
return data?.Select(k => k.ToString()); return data?.Select(k => k.ToString());
} }
public async Task<CustomerBasket> GetBasketAsync(string customerId) public async Task<CustomerBasket> GetBasketAsync(string customerId)
{ {
var data = await _database.StringGetAsync(customerId); var data = await _database.StringGetAsync(customerId);
if (data.IsNullOrEmpty) if (data.IsNullOrEmpty)
{ {
return null; return null;
@ -47,6 +48,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
public async Task<CustomerBasket> UpdateBasketAsync(CustomerBasket basket) public async Task<CustomerBasket> UpdateBasketAsync(CustomerBasket basket)
{ {
var created = await _database.StringSetAsync(basket.BuyerId, JsonConvert.SerializeObject(basket)); var created = await _database.StringSetAsync(basket.BuyerId, JsonConvert.SerializeObject(basket));
if (!created) if (!created)
{ {
_logger.LogInformation("Problem occur persisting the item."); _logger.LogInformation("Problem occur persisting the item.");

View File

@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.ServiceBus; using Microsoft.Azure.ServiceBus;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
@ -51,11 +52,13 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
// Add framework services. // Add framework services.
services.AddMvc(options => services.AddMvc(options =>
{ {
options.Filters.Add(typeof(HttpGlobalExceptionFilter)); options.Filters.Add(typeof(HttpGlobalExceptionFilter));
options.Filters.Add(typeof(ValidateModelStateFilter)); options.Filters.Add(typeof(ValidateModelStateFilter));
}).AddControllersAsServices(); })
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddControllersAsServices();
ConfigureAuthService(services); ConfigureAuthService(services);

View File

@ -44,10 +44,10 @@ namespace UnitTest.Basket.Application
//Act //Act
var basketController = new BasketController( var basketController = new BasketController(
_basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object); _basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object);
var actionResult = await basketController.Get(fakeCustomerId) as OkObjectResult; var actionResult = await basketController.GetBasketByIdAsync(fakeCustomerId);
//Assert //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); Assert.Equal(((CustomerBasket)actionResult.Value).BuyerId, fakeCustomerId);
} }
@ -67,10 +67,10 @@ namespace UnitTest.Basket.Application
var basketController = new BasketController( var basketController = new BasketController(
_basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object); _basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object);
var actionResult = await basketController.Post(fakeCustomerBasket) as OkObjectResult; var actionResult = await basketController.UpdateBasketAsync(fakeCustomerBasket);
//Assert //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); Assert.Equal(((CustomerBasket)actionResult.Value).BuyerId, fakeCustomerId);
} }
@ -86,7 +86,7 @@ namespace UnitTest.Basket.Application
var basketController = new BasketController( var basketController = new BasketController(
_basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object); _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); Assert.NotNull(result);
} }
@ -114,7 +114,7 @@ namespace UnitTest.Basket.Application
}; };
//Act //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<UserCheckoutAcceptedIntegrationEvent>()), Times.Once); _serviceBusMock.Verify(mock => mock.Publish(It.IsAny<UserCheckoutAcceptedIntegrationEvent>()), Times.Once);

View File

@ -28,7 +28,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
_catalogIntegrationEventService = catalogIntegrationEventService ?? throw new ArgumentNullException(nameof(catalogIntegrationEventService)); _catalogIntegrationEventService = catalogIntegrationEventService ?? throw new ArgumentNullException(nameof(catalogIntegrationEventService));
_settings = settings.Value; _settings = settings.Value;
((DbContext)context).ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
} }
// GET api/v1/[controller]/items[?pageSize=3&pageIndex=10] // GET api/v1/[controller]/items[?pageSize=3&pageIndex=10]
@ -36,11 +36,19 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
[Route("items")] [Route("items")]
[ProducesResponseType(typeof(PaginatedItemsViewModel<CatalogItem>), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(PaginatedItemsViewModel<CatalogItem>), (int)HttpStatusCode.OK)]
[ProducesResponseType(typeof(IEnumerable<CatalogItem>), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(IEnumerable<CatalogItem>), (int)HttpStatusCode.OK)]
public async Task<IActionResult> Items([FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0, [FromQuery] string ids = null) [ProducesResponseType((int)HttpStatusCode.BadRequest)]
public async Task<IActionResult> ItemsAsync([FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0, string ids = null)
{ {
if (!string.IsNullOrEmpty(ids)) 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 var totalItems = await _catalogContext.CatalogItems
@ -54,37 +62,36 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
itemsOnPage = ChangeUriPlaceholder(itemsOnPage); itemsOnPage = ChangeUriPlaceholder(itemsOnPage);
var model = new PaginatedItemsViewModel<CatalogItem>( var model = new PaginatedItemsViewModel<CatalogItem>(pageIndex, pageSize, totalItems, itemsOnPage);
pageIndex, pageSize, totalItems, itemsOnPage);
return Ok(model); return Ok(model);
} }
private IActionResult GetItemsByIds(string ids) private async Task<List<CatalogItem>> GetItemsByIdsAsync(string ids)
{ {
var numIds = ids.Split(',') var numIds = ids.Split(',').Select(id => (Ok: int.TryParse(id, out int x), Value: x));
.Select(id => (Ok: int.TryParse(id, out int x), Value: x));
if (!numIds.All(nid => nid.Ok)) if (!numIds.All(nid => nid.Ok))
{ {
return BadRequest("ids value invalid. Must be comma-separated list of numbers"); return new List<CatalogItem>();
} }
var idsToSelect = numIds var idsToSelect = numIds
.Select(id => id.Value); .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); items = ChangeUriPlaceholder(items);
return Ok(items); return items;
} }
[HttpGet] [HttpGet]
[Route("items/{id:int}")] [Route("items/{id:int}")]
[ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(CatalogItem), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(CatalogItem), (int)HttpStatusCode.OK)]
public async Task<IActionResult> GetItemById(int id) public async Task<ActionResult<CatalogItem>> ItemByIdAsync(int id)
{ {
if (id <= 0) if (id <= 0)
{ {
@ -95,11 +102,12 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
var baseUri = _settings.PicBaseUrl; var baseUri = _settings.PicBaseUrl;
var azureStorageEnabled = _settings.AzureStorageEnabled; var azureStorageEnabled = _settings.AzureStorageEnabled;
item.FillProductUrl(baseUri, azureStorageEnabled: azureStorageEnabled); item.FillProductUrl(baseUri, azureStorageEnabled: azureStorageEnabled);
if (item != null) if (item != null)
{ {
return Ok(item); return item;
} }
return NotFound(); return NotFound();
@ -107,11 +115,10 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
// GET api/v1/[controller]/items/withname/samplename[?pageSize=3&pageIndex=10] // GET api/v1/[controller]/items/withname/samplename[?pageSize=3&pageIndex=10]
[HttpGet] [HttpGet]
[Route("[action]/withname/{name:minlength(1)}")] [Route("items/withname/{name:minlength(1)}")]
[ProducesResponseType(typeof(PaginatedItemsViewModel<CatalogItem>), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(PaginatedItemsViewModel<CatalogItem>), (int)HttpStatusCode.OK)]
public async Task<IActionResult> Items(string name, [FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0) public async Task<ActionResult<PaginatedItemsViewModel<CatalogItem>>> ItemsWithNameAsync(string name, [FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0)
{ {
var totalItems = await _catalogContext.CatalogItems var totalItems = await _catalogContext.CatalogItems
.Where(c => c.Name.StartsWith(name)) .Where(c => c.Name.StartsWith(name))
.LongCountAsync(); .LongCountAsync();
@ -124,17 +131,14 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
itemsOnPage = ChangeUriPlaceholder(itemsOnPage); itemsOnPage = ChangeUriPlaceholder(itemsOnPage);
var model = new PaginatedItemsViewModel<CatalogItem>( return new PaginatedItemsViewModel<CatalogItem>(pageIndex, pageSize, totalItems, itemsOnPage);
pageIndex, pageSize, totalItems, itemsOnPage);
return Ok(model);
} }
// GET api/v1/[controller]/items/type/1/brand[?pageSize=3&pageIndex=10] // GET api/v1/[controller]/items/type/1/brand[?pageSize=3&pageIndex=10]
[HttpGet] [HttpGet]
[Route("[action]/type/{catalogTypeId}/brand/{catalogBrandId:int?}")] [Route("items/type/{catalogTypeId}/brand/{catalogBrandId:int?}")]
[ProducesResponseType(typeof(PaginatedItemsViewModel<CatalogItem>), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(PaginatedItemsViewModel<CatalogItem>), (int)HttpStatusCode.OK)]
public async Task<IActionResult> Items(int catalogTypeId, int? catalogBrandId, [FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0) public async Task<ActionResult<PaginatedItemsViewModel<CatalogItem>>> ItemsByTypeIdAndBrandIdAsync(int catalogTypeId, int? catalogBrandId, [FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0)
{ {
var root = (IQueryable<CatalogItem>)_catalogContext.CatalogItems; var root = (IQueryable<CatalogItem>)_catalogContext.CatalogItems;
@ -155,16 +159,14 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
itemsOnPage = ChangeUriPlaceholder(itemsOnPage); itemsOnPage = ChangeUriPlaceholder(itemsOnPage);
var model = new PaginatedItemsViewModel<CatalogItem>( return new PaginatedItemsViewModel<CatalogItem>(pageIndex, pageSize, totalItems, itemsOnPage);
pageIndex, pageSize, totalItems, itemsOnPage);
return Ok(model);
} }
// GET api/v1/[controller]/items/type/all/brand[?pageSize=3&pageIndex=10] // GET api/v1/[controller]/items/type/all/brand[?pageSize=3&pageIndex=10]
[HttpGet] [HttpGet]
[Route("[action]/type/all/brand/{catalogBrandId:int?}")] [Route("items/type/all/brand/{catalogBrandId:int?}")]
[ProducesResponseType(typeof(PaginatedItemsViewModel<CatalogItem>), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(PaginatedItemsViewModel<CatalogItem>), (int)HttpStatusCode.OK)]
public async Task<IActionResult> Items(int? catalogBrandId, [FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0) public async Task<ActionResult<PaginatedItemsViewModel<CatalogItem>>> ItemsByBrandIdAsync(int? catalogBrandId, [FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0)
{ {
var root = (IQueryable<CatalogItem>)_catalogContext.CatalogItems; var root = (IQueryable<CatalogItem>)_catalogContext.CatalogItems;
@ -183,34 +185,25 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
itemsOnPage = ChangeUriPlaceholder(itemsOnPage); itemsOnPage = ChangeUriPlaceholder(itemsOnPage);
var model = new PaginatedItemsViewModel<CatalogItem>( return new PaginatedItemsViewModel<CatalogItem>(pageIndex, pageSize, totalItems, itemsOnPage);
pageIndex, pageSize, totalItems, itemsOnPage);
return Ok(model);
} }
// GET api/v1/[controller]/CatalogTypes // GET api/v1/[controller]/CatalogTypes
[HttpGet] [HttpGet]
[Route("[action]")] [Route("catalogtypes")]
[ProducesResponseType(typeof(List<CatalogItem>), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(List<CatalogType>), (int)HttpStatusCode.OK)]
public async Task<IActionResult> CatalogTypes() public async Task<ActionResult<List<CatalogType>>> CatalogTypesAsync()
{ {
var items = await _catalogContext.CatalogTypes return await _catalogContext.CatalogTypes.ToListAsync();
.ToListAsync();
return Ok(items);
} }
// GET api/v1/[controller]/CatalogBrands // GET api/v1/[controller]/CatalogBrands
[HttpGet] [HttpGet]
[Route("[action]")] [Route("catalogbrands")]
[ProducesResponseType(typeof(List<CatalogItem>), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(List<CatalogBrand>), (int)HttpStatusCode.OK)]
public async Task<IActionResult> CatalogBrands() public async Task<ActionResult<List<CatalogBrand>>> CatalogBrandsAsync()
{ {
var items = await _catalogContext.CatalogBrands return await _catalogContext.CatalogBrands.ToListAsync();
.ToListAsync();
return Ok(items);
} }
//PUT api/v1/[controller]/items //PUT api/v1/[controller]/items
@ -218,10 +211,9 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
[HttpPut] [HttpPut]
[ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType((int)HttpStatusCode.Created)] [ProducesResponseType((int)HttpStatusCode.Created)]
public async Task<IActionResult> UpdateProduct([FromBody]CatalogItem productToUpdate) public async Task<ActionResult> UpdateProductAsync([FromBody]CatalogItem productToUpdate)
{ {
var catalogItem = await _catalogContext.CatalogItems var catalogItem = await _catalogContext.CatalogItems.SingleOrDefaultAsync(i => i.Id == productToUpdate.Id);
.SingleOrDefaultAsync(i => i.Id == productToUpdate.Id);
if (catalogItem == null) if (catalogItem == null)
{ {
@ -231,7 +223,6 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
var oldPrice = catalogItem.Price; var oldPrice = catalogItem.Price;
var raiseProductPriceChangedEvent = oldPrice != productToUpdate.Price; var raiseProductPriceChangedEvent = oldPrice != productToUpdate.Price;
// Update current product // Update current product
catalogItem = productToUpdate; catalogItem = productToUpdate;
_catalogContext.CatalogItems.Update(catalogItem); _catalogContext.CatalogItems.Update(catalogItem);
@ -252,14 +243,14 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
await _catalogContext.SaveChangesAsync(); 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 //POST api/v1/[controller]/items
[Route("items")] [Route("items")]
[HttpPost] [HttpPost]
[ProducesResponseType((int)HttpStatusCode.Created)] [ProducesResponseType((int)HttpStatusCode.Created)]
public async Task<IActionResult> CreateProduct([FromBody]CatalogItem product) public async Task<ActionResult> CreateProductAsync([FromBody]CatalogItem product)
{ {
var item = new CatalogItem var item = new CatalogItem
{ {
@ -270,18 +261,20 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
PictureFileName = product.PictureFileName, PictureFileName = product.PictureFileName,
Price = product.Price Price = product.Price
}; };
_catalogContext.CatalogItems.Add(item); _catalogContext.CatalogItems.Add(item);
await _catalogContext.SaveChangesAsync(); 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 //DELETE api/v1/[controller]/id
[Route("{id}")] [Route("{id}")]
[HttpDelete] [HttpDelete]
[ProducesResponseType((int)HttpStatusCode.NoContent)] [ProducesResponseType((int)HttpStatusCode.NoContent)]
public async Task<IActionResult> DeleteProduct(int id) [ProducesResponseType((int)HttpStatusCode.NotFound)]
public async Task<ActionResult> DeleteProductAsync(int id)
{ {
var product = _catalogContext.CatalogItems.SingleOrDefault(x => x.Id == id); var product = _catalogContext.CatalogItems.SingleOrDefault(x => x.Id == id);

View File

@ -10,7 +10,8 @@ using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
{ {
public class PicController : Controller [ApiController]
public class PicController : ControllerBase
{ {
private readonly IHostingEnvironment _env; private readonly IHostingEnvironment _env;
private readonly CatalogContext _catalogContext; private readonly CatalogContext _catalogContext;
@ -27,7 +28,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
[ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.BadRequest)]
// GET: /<controller>/ // GET: /<controller>/
public async Task<IActionResult> GetImage(int catalogItemId) public async Task<ActionResult> GetImageAsync(int catalogItemId)
{ {
if (catalogItemId <= 0) if (catalogItemId <= 0)
{ {

View File

@ -139,9 +139,11 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API
}); });
services.AddMvc(options => services.AddMvc(options =>
{ {
options.Filters.Add(typeof(HttpGlobalExceptionFilter)); options.Filters.Add(typeof(HttpGlobalExceptionFilter));
}).AddControllersAsServices(); })
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddControllersAsServices();
services.AddCors(options => services.AddCors(options =>
{ {

View File

@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.eShopOnContainers.Services.Identity.API.Certificates; using Microsoft.eShopOnContainers.Services.Identity.API.Certificates;
using Microsoft.eShopOnContainers.Services.Identity.API.Data; using Microsoft.eShopOnContainers.Services.Identity.API.Data;
@ -52,7 +53,8 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API
services.Configure<AppSettings>(Configuration); services.Configure<AppSettings>(Configuration);
services.AddMvc(); services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
if (Configuration.GetValue<string>("IsClusterEnv") == bool.TrueString) if (Configuration.GetValue<string>("IsClusterEnv") == bool.TrueString)
{ {
@ -159,6 +161,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API
// Adds IdentityServer // Adds IdentityServer
app.UseIdentityServer(); app.UseIdentityServer();
app.UseHttpsRedirection();
app.UseMvc(routes => app.UseMvc(routes =>
{ {
routes.MapRoute( routes.MapRoute(

View File

@ -12,6 +12,7 @@ namespace Locations.API.Controllers
{ {
[Route("api/v1/[controller]")] [Route("api/v1/[controller]")]
[Authorize] [Authorize]
[ApiController]
public class LocationsController : ControllerBase public class LocationsController : ControllerBase
{ {
private readonly ILocationsService _locationsService; private readonly ILocationsService _locationsService;
@ -27,30 +28,27 @@ namespace Locations.API.Controllers
[Route("user/{userId:guid}")] [Route("user/{userId:guid}")]
[HttpGet] [HttpGet]
[ProducesResponseType(typeof(UserLocation), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(UserLocation), (int)HttpStatusCode.OK)]
public async Task<IActionResult> GetUserLocation(Guid userId) public async Task<ActionResult<UserLocation>> GetUserLocationAsync(Guid userId)
{ {
var userLocation = await _locationsService.GetUserLocation(userId.ToString()); return await _locationsService.GetUserLocationAsync(userId.ToString());
return Ok(userLocation);
} }
//GET api/v1/[controller]/ //GET api/v1/[controller]/
[Route("")] [Route("")]
[HttpGet] [HttpGet]
//[ProducesResponseType(typeof(List<Locations>), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(List<Microsoft.eShopOnContainers.Services.Locations.API.Model.Locations>), (int)HttpStatusCode.OK)]
public async Task<IActionResult> GetAllLocations() public async Task<ActionResult<List<Microsoft.eShopOnContainers.Services.Locations.API.Model.Locations>>> GetAllLocationsAsync()
{ {
var locations = await _locationsService.GetAllLocation(); return await _locationsService.GetAllLocationAsync();
return Ok(locations);
} }
//GET api/v1/[controller]/1 //GET api/v1/[controller]/1
[Route("{locationId}")] [Route("{locationId}")]
[HttpGet] [HttpGet]
//[ProducesResponseType(typeof(List<Locations>), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(Microsoft.eShopOnContainers.Services.Locations.API.Model.Locations), (int)HttpStatusCode.OK)]
public async Task<IActionResult> GetLocation(int locationId) public async Task<ActionResult<Microsoft.eShopOnContainers.Services.Locations.API.Model.Locations>> GetLocationAsync(int locationId)
{ {
var location = await _locationsService.GetLocation(locationId); return await _locationsService.GetLocationAsync(locationId);
return Ok(location);
} }
//POST api/v1/[controller]/ //POST api/v1/[controller]/
@ -58,14 +56,17 @@ namespace Locations.API.Controllers
[HttpPost] [HttpPost]
[ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.BadRequest)]
public async Task<IActionResult> CreateOrUpdateUserLocation([FromBody]LocationRequest newLocReq) public async Task<ActionResult> CreateOrUpdateUserLocationAsync([FromBody]LocationRequest newLocReq)
{ {
var userId = _identityService.GetUserIdentity(); var userId = _identityService.GetUserIdentity();
var result = await _locationsService.AddOrUpdateUserLocation(userId, newLocReq); var result = await _locationsService.AddOrUpdateUserLocationAsync(userId, newLocReq);
return result ? if (!result)
(IActionResult)Ok() : {
(IActionResult)BadRequest(); return BadRequest();
}
return Ok();
} }
} }
} }

View File

@ -7,12 +7,12 @@
public interface ILocationsService public interface ILocationsService
{ {
Task<Locations> GetLocation(int locationId); Task<Locations> GetLocationAsync(int locationId);
Task<UserLocation> GetUserLocation(string id); Task<UserLocation> GetUserLocationAsync(string id);
Task<List<Locations>> GetAllLocation(); Task<List<Locations>> GetAllLocationAsync();
Task<bool> AddOrUpdateUserLocation(string userId, LocationRequest locRequest); Task<bool> AddOrUpdateUserLocationAsync(string userId, LocationRequest locRequest);
} }
} }

View File

@ -21,22 +21,22 @@
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus)); _eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
} }
public async Task<Locations> GetLocation(int locationId) public async Task<Locations> GetLocationAsync(int locationId)
{ {
return await _locationsRepository.GetAsync(locationId); return await _locationsRepository.GetAsync(locationId);
} }
public async Task<UserLocation> GetUserLocation(string userId) public async Task<UserLocation> GetUserLocationAsync(string userId)
{ {
return await _locationsRepository.GetUserLocationAsync(userId); return await _locationsRepository.GetUserLocationAsync(userId);
} }
public async Task<List<Locations>> GetAllLocation() public async Task<List<Locations>> GetAllLocationAsync()
{ {
return await _locationsRepository.GetLocationListAsync(); return await _locationsRepository.GetLocationListAsync();
} }
public async Task<bool> AddOrUpdateUserLocation(string userId, LocationRequest currentPosition) public async Task<bool> AddOrUpdateUserLocationAsync(string userId, LocationRequest currentPosition)
{ {
// Get the list of ordered regions the user currently is within // Get the list of ordered regions the user currently is within
var currentUserAreaLocationList = await _locationsRepository.GetCurrentUserRegionsListAsync(currentPosition); var currentUserAreaLocationList = await _locationsRepository.GetCurrentUserRegionsListAsync(currentPosition);

View File

@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.ServiceBus; using Microsoft.Azure.ServiceBus;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
@ -43,9 +44,11 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API
RegisterAppInsights(services); RegisterAppInsights(services);
services.AddMvc(options => services.AddMvc(options =>
{ {
options.Filters.Add(typeof(HttpGlobalExceptionFilter)); options.Filters.Add(typeof(HttpGlobalExceptionFilter));
}).AddControllersAsServices(); })
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddControllersAsServices();
ConfigureAuthService(services); ConfigureAuthService(services);

View File

@ -20,7 +20,8 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers
[Route("api/v1/[controller]")] [Route("api/v1/[controller]")]
[Authorize] [Authorize]
public class CampaignsController : Controller [ApiController]
public class CampaignsController : ControllerBase
{ {
private readonly MarketingContext _context; private readonly MarketingContext _context;
private readonly MarketingSettings _settings; private readonly MarketingSettings _settings;
@ -40,43 +41,37 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers
[HttpGet] [HttpGet]
[ProducesResponseType(typeof(List<CampaignDTO>), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(List<CampaignDTO>), (int)HttpStatusCode.OK)]
public async Task<IActionResult> GetAllCampaigns() public async Task<ActionResult<List<CampaignDTO>>> GetAllCampaignsAsync()
{ {
var campaignList = await _context.Campaigns var campaignList = await _context.Campaigns.ToListAsync();
.ToListAsync();
if (campaignList is null) if (campaignList is null)
{ {
return Ok(); return Ok();
} }
var campaignDtoList = MapCampaignModelListToDtoList(campaignList); return MapCampaignModelListToDtoList(campaignList);
return Ok(campaignDtoList);
} }
[HttpGet("{id:int}")] [HttpGet("{id:int}")]
[ProducesResponseType(typeof(CampaignDTO), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(CampaignDTO), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.NotFound)]
public async Task<IActionResult> GetCampaignById(int id) public async Task<ActionResult<CampaignDTO>> GetCampaignByIdAsync(int id)
{ {
var campaign = await _context.Campaigns var campaign = await _context.Campaigns.SingleOrDefaultAsync(c => c.Id == id);
.SingleOrDefaultAsync(c => c.Id == id);
if (campaign is null) if (campaign is null)
{ {
return NotFound(); return NotFound();
} }
var campaignDto = MapCampaignModelToDto(campaign); return MapCampaignModelToDto(campaign);
return Ok(campaignDto);
} }
[HttpPost] [HttpPost]
[ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType((int)HttpStatusCode.Created)] [ProducesResponseType((int)HttpStatusCode.Created)]
public async Task<IActionResult> CreateCampaign([FromBody] CampaignDTO campaignDto) public async Task<ActionResult> CreateCampaignAsync([FromBody] CampaignDTO campaignDto)
{ {
if (campaignDto is null) if (campaignDto is null)
{ {
@ -88,14 +83,14 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers
await _context.Campaigns.AddAsync(campaign); await _context.Campaigns.AddAsync(campaign);
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
return CreatedAtAction(nameof(GetCampaignById), new { id = campaign.Id }, null); return CreatedAtAction(nameof(GetCampaignByIdAsync), new { id = campaign.Id }, null);
} }
[HttpPut("{id:int}")] [HttpPut("{id:int}")]
[ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType((int)HttpStatusCode.Created)] [ProducesResponseType((int)HttpStatusCode.Created)]
public async Task<IActionResult> UpdateCampaign(int id, [FromBody] CampaignDTO campaignDto) public async Task<ActionResult> UpdateCampaignAsync(int id, [FromBody] CampaignDTO campaignDto)
{ {
if (id < 1 || campaignDto is null) if (id < 1 || campaignDto is null)
{ {
@ -116,14 +111,14 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
return CreatedAtAction(nameof(GetCampaignById), new { id = campaignToUpdate.Id }, null); return CreatedAtAction(nameof(GetCampaignByIdAsync), new { id = campaignToUpdate.Id }, null);
} }
[HttpDelete("{id:int}")] [HttpDelete("{id:int}")]
[ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType((int)HttpStatusCode.NoContent)] [ProducesResponseType((int)HttpStatusCode.NoContent)]
public async Task<IActionResult> Delete(int id) public async Task<ActionResult> DeleteCampaignByIdAsync(int id)
{ {
if (id < 1) if (id < 1)
{ {
@ -131,6 +126,7 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers
} }
var campaignToDelete = await _context.Campaigns.FindAsync(id); var campaignToDelete = await _context.Campaigns.FindAsync(id);
if (campaignToDelete is null) if (campaignToDelete is null)
{ {
return NotFound(); return NotFound();
@ -144,7 +140,7 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers
[HttpGet("user")] [HttpGet("user")]
[ProducesResponseType(typeof(PaginatedItemsViewModel<CampaignDTO>), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(PaginatedItemsViewModel<CampaignDTO>), (int)HttpStatusCode.OK)]
public async Task<IActionResult> GetCampaignsByUserId( int pageSize = 10, int pageIndex = 0) public async Task<ActionResult<PaginatedItemsViewModel<CampaignDTO>>> GetCampaignsByUserIdAsync( int pageSize = 10, int pageIndex = 0)
{ {
var userId = _identityService.GetUserIdentity(); var userId = _identityService.GetUserIdentity();
@ -169,21 +165,17 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers
var userCampaignDtoList = MapCampaignModelListToDtoList(userCampaignList); var userCampaignDtoList = MapCampaignModelListToDtoList(userCampaignList);
campaignDtoList.AddRange(userCampaignDtoList); campaignDtoList.AddRange(userCampaignDtoList);
} }
} }
var totalItems = campaignDtoList.Count(); var totalItems = campaignDtoList.Count();
campaignDtoList = campaignDtoList campaignDtoList = campaignDtoList
.Skip(pageSize * pageIndex) .Skip(pageSize * pageIndex)
.Take(pageSize).ToList(); .Take(pageSize).ToList();
var model = new PaginatedItemsViewModel<CampaignDTO>( return new PaginatedItemsViewModel<CampaignDTO>(pageIndex, pageSize, totalItems, campaignDtoList);
pageIndex, pageSize, totalItems, campaignDtoList);
return Ok(model);
} }
private List<CampaignDTO> MapCampaignModelListToDtoList(List<Campaign> campaignList) private List<CampaignDTO> MapCampaignModelListToDtoList(List<Campaign> campaignList)
{ {
var campaignDtoList = new List<CampaignDTO>(); var campaignDtoList = new List<CampaignDTO>();

View File

@ -11,7 +11,8 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers
using System.Threading.Tasks; using System.Threading.Tasks;
[Authorize] [Authorize]
public class LocationsController : Controller [ApiController]
public class LocationsController : ControllerBase
{ {
private readonly MarketingContext _context; private readonly MarketingContext _context;
@ -25,7 +26,7 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers
[ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType(typeof(UserLocationRuleDTO),(int)HttpStatusCode.OK)] [ProducesResponseType(typeof(UserLocationRuleDTO),(int)HttpStatusCode.OK)]
public IActionResult GetLocationByCampaignAndLocationRuleId(int campaignId, public ActionResult<UserLocationRuleDTO> GetLocationByCampaignAndLocationRuleId(int campaignId,
int userLocationRuleId) int userLocationRuleId)
{ {
if (campaignId < 1 || userLocationRuleId < 1) if (campaignId < 1 || userLocationRuleId < 1)
@ -42,9 +43,7 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers
return NotFound(); return NotFound();
} }
var locationDto = MapUserLocationRuleModelToDto(location); return MapUserLocationRuleModelToDto(location);
return Ok(locationDto);
} }
[HttpGet] [HttpGet]
@ -52,7 +51,7 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers
[ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType(typeof(List<UserLocationRuleDTO>), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(List<UserLocationRuleDTO>), (int)HttpStatusCode.OK)]
public IActionResult GetAllLocationsByCampaignId(int campaignId) public ActionResult<List<UserLocationRuleDTO>> GetAllLocationsByCampaignId(int campaignId)
{ {
if (campaignId < 1) if (campaignId < 1)
{ {
@ -69,17 +68,14 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers
return Ok(); return Ok();
} }
var locationDtoList = MapUserLocationRuleModelListToDtoList(locationList); return MapUserLocationRuleModelListToDtoList(locationList);
return Ok(locationDtoList);
} }
[HttpPost] [HttpPost]
[Route("api/v1/campaigns/{campaignId:int}/locations")] [Route("api/v1/campaigns/{campaignId:int}/locations")]
[ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType((int)HttpStatusCode.Created)] [ProducesResponseType((int)HttpStatusCode.Created)]
public async Task<IActionResult> CreateLocation(int campaignId, public async Task<ActionResult> CreateLocationAsync(int campaignId, [FromBody] UserLocationRuleDTO locationRuleDto)
[FromBody] UserLocationRuleDTO locationRuleDto)
{ {
if (campaignId < 1 || locationRuleDto is null) 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}")] [Route("api/v1/campaigns/{campaignId:int}/locations/{userLocationRuleId:int}")]
[ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.NotFound)]
public async Task<IActionResult> DeleteLocationById(int campaignId, int userLocationRuleId) public async Task<ActionResult> DeleteLocationByIdAsync(int campaignId, int userLocationRuleId)
{ {
if (campaignId < 1 || userLocationRuleId < 1) if (campaignId < 1 || userLocationRuleId < 1)
{ {
@ -122,8 +118,6 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers
return NoContent(); return NoContent();
} }
private List<UserLocationRuleDTO> MapUserLocationRuleModelListToDtoList(List<UserLocationRule> userLocationRuleList) private List<UserLocationRuleDTO> MapUserLocationRuleModelListToDtoList(List<UserLocationRule> userLocationRuleList)
{ {
var userLocationRuleDtoList = new List<UserLocationRuleDTO>(); var userLocationRuleDtoList = new List<UserLocationRuleDTO>();

View File

@ -4,8 +4,8 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.IO; using System.IO;
[ApiController]
public class PicController : Controller public class PicController : ControllerBase
{ {
private readonly IHostingEnvironment _env; private readonly IHostingEnvironment _env;
public PicController(IHostingEnvironment env) public PicController(IHostingEnvironment env)
@ -15,7 +15,7 @@
[HttpGet] [HttpGet]
[Route("api/v1/campaigns/{campaignId:int}/pic")] [Route("api/v1/campaigns/{campaignId:int}/pic")]
public IActionResult GetImage(int campaignId) public ActionResult GetImage(int campaignId)
{ {
var webRoot = _env.WebRootPath; var webRoot = _env.WebRootPath;
var path = Path.Combine(webRoot, campaignId + ".png"); var path = Path.Combine(webRoot, campaignId + ".png");

View File

@ -24,6 +24,7 @@
using Microsoft.ApplicationInsights.Extensibility; using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.ApplicationInsights.ServiceFabric; using Microsoft.ApplicationInsights.ServiceFabric;
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.Middlewares; using Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.Middlewares;
using RabbitMQ.Client; using RabbitMQ.Client;
@ -53,7 +54,9 @@
services.AddMvc(options => services.AddMvc(options =>
{ {
options.Filters.Add(typeof(HttpGlobalExceptionFilter)); 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<MarketingSettings>(Configuration); services.Configure<MarketingSettings>(Configuration);

View File

@ -15,7 +15,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
[Route("api/v1/[controller]")] [Route("api/v1/[controller]")]
[Authorize] [Authorize]
[ApiController] [ApiController]
public class OrdersController : Controller public class OrdersController : ControllerBase
{ {
private readonly IMediator _mediator; private readonly IMediator _mediator;
private readonly IOrderQueries _orderQueries; private readonly IOrderQueries _orderQueries;
@ -23,7 +23,6 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
public OrdersController(IMediator mediator, IOrderQueries orderQueries, IIdentityService identityService) public OrdersController(IMediator mediator, IOrderQueries orderQueries, IIdentityService identityService)
{ {
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator)); _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
_orderQueries = orderQueries ?? throw new ArgumentNullException(nameof(orderQueries)); _orderQueries = orderQueries ?? throw new ArgumentNullException(nameof(orderQueries));
_identityService = identityService ?? throw new ArgumentNullException(nameof(identityService)); _identityService = identityService ?? throw new ArgumentNullException(nameof(identityService));
@ -33,84 +32,89 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
[HttpPut] [HttpPut]
[ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.BadRequest)]
public async Task<IActionResult> CancelOrder([FromBody]CancelOrderCommand command, [FromHeader(Name = "x-requestid")] string requestId) public async Task<IActionResult> CancelOrderAsync([FromBody]CancelOrderCommand command, [FromHeader(Name = "x-requestid")] string requestId)
{ {
bool commandResult = false; bool commandResult = false;
if (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) if (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty)
{ {
var requestCancelOrder = new IdentifiedCommand<CancelOrderCommand, bool>(command, guid); var requestCancelOrder = new IdentifiedCommand<CancelOrderCommand, bool>(command, guid);
commandResult = await _mediator.Send(requestCancelOrder); commandResult = await _mediator.Send(requestCancelOrder);
} }
return commandResult ? (IActionResult)Ok() : (IActionResult)BadRequest(); if (!commandResult)
{
return BadRequest();
}
return Ok();
} }
[Route("ship")] [Route("ship")]
[HttpPut] [HttpPut]
[ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.BadRequest)]
public async Task<IActionResult> ShipOrder([FromBody]ShipOrderCommand command, [FromHeader(Name = "x-requestid")] string requestId) public async Task<IActionResult> ShipOrderAsync([FromBody]ShipOrderCommand command, [FromHeader(Name = "x-requestid")] string requestId)
{ {
bool commandResult = false; bool commandResult = false;
if (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) if (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty)
{ {
var requestShipOrder = new IdentifiedCommand<ShipOrderCommand, bool>(command, guid); var requestShipOrder = new IdentifiedCommand<ShipOrderCommand, bool>(command, guid);
commandResult = await _mediator.Send(requestShipOrder); commandResult = await _mediator.Send(requestShipOrder);
} }
return commandResult ? (IActionResult)Ok() : (IActionResult)BadRequest(); if (!commandResult)
{
return BadRequest();
}
return Ok();
} }
[Route("{orderId:int}")] [Route("{orderId:int}")]
[HttpGet] [HttpGet]
[ProducesResponseType(typeof(Order),(int)HttpStatusCode.OK)] [ProducesResponseType(typeof(Order),(int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.NotFound)]
public async Task<IActionResult> GetOrder(int orderId) public async Task<ActionResult> GetOrderAsync(int orderId)
{ {
try try
{ {
var order = await _orderQueries var order = await _orderQueries.GetOrderAsync(orderId);
.GetOrderAsync(orderId);
return Ok(order); return Ok(order);
} }
catch (KeyNotFoundException) catch
{ {
return NotFound(); return NotFound();
} }
} }
[Route("")]
[HttpGet] [HttpGet]
[ProducesResponseType(typeof(IEnumerable<OrderSummary>), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(IEnumerable<OrderSummary>), (int)HttpStatusCode.OK)]
public async Task<IActionResult> GetOrders() public async Task<ActionResult<IEnumerable<OrderSummary>>> GetOrdersAsync()
{ {
var userid = _identityService.GetUserIdentity(); var userid = _identityService.GetUserIdentity();
var orders = await _orderQueries.GetOrdersFromUserAsync(Guid.Parse(userid)); var orders = await _orderQueries.GetOrdersFromUserAsync(Guid.Parse(userid));
return Ok(orders); return Ok(orders);
} }
[Route("cardtypes")] [Route("cardtypes")]
[HttpGet] [HttpGet]
[ProducesResponseType(typeof(IEnumerable<CardType>), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(IEnumerable<CardType>), (int)HttpStatusCode.OK)]
public async Task<IActionResult> GetCardTypes() public async Task<ActionResult<IEnumerable<CardType>>> GetCardTypesAsync()
{ {
var cardTypes = await _orderQueries var cardTypes = await _orderQueries.GetCardTypesAsync();
.GetCardTypesAsync();
return Ok(cardTypes); return Ok(cardTypes);
} }
[Route("draft")] [Route("draft")]
[HttpPost] [HttpPost]
public async Task<IActionResult> GetOrderDraftFromBasketData([FromBody] CreateOrderDraftCommand createOrderDraftCommand) public async Task<ActionResult<OrderDraftDTO>> CreateOrderDraftFromBasketDataAsync([FromBody] CreateOrderDraftCommand createOrderDraftCommand)
{ {
var draft = await _mediator.Send(createOrderDraftCommand); return await _mediator.Send(createOrderDraftCommand);
return Ok(draft);
} }
} }
} }

View File

@ -154,9 +154,11 @@
{ {
// Add framework services. // Add framework services.
services.AddMvc(options => services.AddMvc(options =>
{ {
options.Filters.Add(typeof(HttpGlobalExceptionFilter)); options.Filters.Add(typeof(HttpGlobalExceptionFilter));
}).AddControllersAsServices(); //Injecting Controllers themselves thru DI })
.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 //For further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services
services.AddCors(options => services.AddCors(options =>

View File

@ -36,7 +36,7 @@ namespace UnitTest.Ordering.Application
//Act //Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object); 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
Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK); Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK);
@ -52,7 +52,7 @@ namespace UnitTest.Ordering.Application
//Act //Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object); 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
Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.BadRequest); Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.BadRequest);
@ -67,7 +67,7 @@ namespace UnitTest.Ordering.Application
//Act //Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object); 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
Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK); Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK);
@ -83,7 +83,7 @@ namespace UnitTest.Ordering.Application
//Act //Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object); 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
Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.BadRequest); Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.BadRequest);
@ -103,10 +103,10 @@ namespace UnitTest.Ordering.Application
//Act //Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object); var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
var actionResult = await orderController.GetOrders() as OkObjectResult; var actionResult = await orderController.GetOrdersAsync();
//Assert //Assert
Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK); Assert.Equal((actionResult.Result as OkObjectResult).StatusCode, (int)System.Net.HttpStatusCode.OK);
} }
[Fact] [Fact]
@ -120,7 +120,7 @@ namespace UnitTest.Ordering.Application
//Act //Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object); 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
Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK); Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK);
@ -136,10 +136,10 @@ namespace UnitTest.Ordering.Application
//Act //Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object); var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
var actionResult = await orderController.GetCardTypes() as OkObjectResult; var actionResult = await orderController.GetCardTypesAsync();
//Assert //Assert
Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK); Assert.Equal((actionResult.Result as OkObjectResult).StatusCode, (int)System.Net.HttpStatusCode.OK);
} }
} }
} }

View File

@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopOnContainers.WebMVC.Services; using Microsoft.eShopOnContainers.WebMVC.Services;
using Microsoft.eShopOnContainers.WebMVC.ViewModels; using Microsoft.eShopOnContainers.WebMVC.ViewModels;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
@ -59,6 +60,7 @@ namespace Microsoft.eShopOnContainers.WebMVC
else else
{ {
app.UseExceptionHandler("/Error"); app.UseExceptionHandler("/Error");
app.UseHsts();
} }
var pathBase = Configuration["PATH_BASE"]; var pathBase = Configuration["PATH_BASE"];
@ -87,6 +89,7 @@ namespace Microsoft.eShopOnContainers.WebMVC
WebContextSeed.Seed(app, env, loggerFactory); WebContextSeed.Seed(app, env, loggerFactory);
app.UseHttpsRedirection();
app.UseMvc(routes => app.UseMvc(routes =>
{ {
routes.MapRoute( routes.MapRoute(
@ -149,7 +152,8 @@ namespace Microsoft.eShopOnContainers.WebMVC
services.AddOptions(); services.AddOptions();
services.Configure<AppSettings>(configuration); services.Configure<AppSettings>(configuration);
services.AddMvc(); services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddSession(); services.AddSession();

View File

@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.HealthChecks; using Microsoft.Extensions.HealthChecks;
@ -71,6 +72,7 @@ namespace eShopConContainers.WebSPA
services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN"); services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
services.AddMvc() services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddJsonOptions(options => .AddJsonOptions(options =>
{ {
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
@ -89,6 +91,11 @@ namespace eShopConContainers.WebSPA
{ {
app.UseDeveloperExceptionPage(); 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 // 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 // load and passed back token on every subsequent async request

View File

@ -10,6 +10,7 @@ using Microsoft.Extensions.Logging;
using WebStatus.Extensions; using WebStatus.Extensions;
using Microsoft.ApplicationInsights.Extensibility; using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.ApplicationInsights.ServiceFabric; using Microsoft.ApplicationInsights.ServiceFabric;
using Microsoft.AspNetCore.Mvc;
namespace WebStatus namespace WebStatus
{ {
@ -50,7 +51,8 @@ namespace WebStatus
checks.AddUrlCheckIfNotNull(Configuration["spa"], TimeSpan.Zero); //No cache for this HealthCheck, better just for demos 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. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@ -66,6 +68,8 @@ namespace WebStatus
else else
{ {
app.UseExceptionHandler("/Home/Error"); 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"]; var pathBase = Configuration["PATH_BASE"];
@ -74,13 +78,14 @@ namespace WebStatus
app.UsePathBase(pathBase); app.UsePathBase(pathBase);
} }
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously #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)); 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 #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
app.UseStaticFiles(); app.UseStaticFiles();
app.UseHttpsRedirection();
app.UseMvc(routes => app.UseMvc(routes =>
{ {
routes.MapRoute( routes.MapRoute(