Refactor and update to C# 7 constructs

Controllers/BasketController:
Use Expression Bodied Members.
Delete() should not be 'fire and forget'

Controllers/HomeController:
Expression bodied constructor

IntegrationEvents/EventHandling/ProductPriceChangedIntegratedEventHandler:
Use valueTask to minimize allocations for 'fast path' tasks. One might
believe that
most users would not have the changing item in the basket at any given
time.
Using ValueTask instead of Task, this minimizes allocations to only when
async
work must actually take place.

IntegrationEvents/EventHandling/ProductPriceChangedIntegratedEvent:
Make the properties ReadOnly

Model/Basket:
Use property initializer

Model/RedisBasketRepository:
Remove redundant ToString()
Use elvis operator instead of statement null check

Startup:
remove redundant ToString()
This commit is contained in:
Bill Wagner 2017-03-21 14:25:49 -04:00
parent 6e4d9461de
commit 53e0d1ee96
7 changed files with 24 additions and 32 deletions

View File

@ -18,10 +18,9 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
{ {
private IBasketRepository _repository; private IBasketRepository _repository;
public BasketController(IBasketRepository repository) public BasketController(IBasketRepository repository) =>
{
_repository = repository; _repository = repository;
}
// GET api/values/5 // GET api/values/5
[HttpGet("{id}")] [HttpGet("{id}")]
public async Task<IActionResult> Get(string id) public async Task<IActionResult> Get(string id)
@ -42,9 +41,9 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
// DELETE api/values/5 // DELETE api/values/5
[HttpDelete("{id}")] [HttpDelete("{id}")]
public void Delete(string id) public Task Delete(string id)
{ {
_repository.DeleteBasket(id); return _repository.DeleteBasket(id);
} }
} }
} }

View File

@ -11,9 +11,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
public class HomeController : Controller public class HomeController : Controller
{ {
// GET: /<controller>/ // GET: /<controller>/
public IActionResult Index() public IActionResult Index() =>
{ new RedirectResult("~/swagger/ui");
return new RedirectResult("~/swagger/ui");
}
} }
} }

View File

@ -4,6 +4,7 @@ using Microsoft.eShopOnContainers.Services.Basket.API.Model;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.EventHandling namespace Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.EventHandling
{ {
public class ProductPriceChangedIntegrationEventHandler : IIntegrationEventHandler<ProductPriceChangedIntegrationEvent> public class ProductPriceChangedIntegrationEventHandler : IIntegrationEventHandler<ProductPriceChangedIntegrationEvent>
@ -20,26 +21,29 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Even
foreach (var id in userIds) foreach (var id in userIds)
{ {
var basket = await _repository.GetBasket(id); var basket = await _repository.GetBasket(id);
await UpdateBasket(@event.ProductId, @event.NewPrice, basket); await UpdateBasket(@event.ProductId, @event.NewPrice, basket);
} }
} }
private async Task UpdateBasket(int productId, decimal newPrice, CustomerBasket basket) private ValueTask<CustomerBasket> UpdateBasket(int productId, decimal newPrice, CustomerBasket basket)
{ {
var itemsToUpdate = basket?.Items?.Where(x => int.Parse(x.ProductId) == productId).ToList(); var itemsToUpdate = basket?.Items?.Where(x => int.Parse(x.ProductId) == productId).ToList();
if (itemsToUpdate != null) if (itemsToUpdate != null)
{ {
foreach (var item in itemsToUpdate) foreach (var item in itemsToUpdate)
{ {
if(item.UnitPrice != newPrice) if (item.UnitPrice != newPrice)
{ {
var originalPrice = item.UnitPrice; var originalPrice = item.UnitPrice;
item.UnitPrice = newPrice; item.UnitPrice = newPrice;
item.OldUnitPrice = originalPrice; item.OldUnitPrice = originalPrice;
} }
} }
await _repository.UpdateBasket(basket); return new ValueTask<CustomerBasket>(_repository.UpdateBasket(basket));
} } else
{
return new ValueTask<CustomerBasket>(default(CustomerBasket));
}
} }
} }
} }

View File

@ -10,11 +10,11 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Even
// An Integration Event is an event that can cause side effects to other microsrvices, Bounded-Contexts or external systems. // An Integration Event is an event that can cause side effects to other microsrvices, Bounded-Contexts or external systems.
public class ProductPriceChangedIntegrationEvent : IntegrationEvent public class ProductPriceChangedIntegrationEvent : IntegrationEvent
{ {
public int ProductId { get; private set; } public int ProductId { get; }
public decimal NewPrice { get; private set; } public decimal NewPrice { get; }
public decimal OldPrice { get; private set; } public decimal OldPrice { get; }
public ProductPriceChangedIntegrationEvent(int productId, decimal newPrice, decimal oldPrice) public ProductPriceChangedIntegrationEvent(int productId, decimal newPrice, decimal oldPrice)
{ {

View File

@ -8,12 +8,9 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
public class CustomerBasket public class CustomerBasket
{ {
public string BuyerId { get; set; } public string BuyerId { get; set; }
public List<BasketItem> Items { get; set; } public List<BasketItem> Items { get; set; } = new List<BasketItem>();
public CustomerBasket(string customerId) public CustomerBasket(string customerId) =>
{
BuyerId = customerId; BuyerId = customerId;
Items = new List<Model.BasketItem>();
}
} }
} }

View File

@ -28,7 +28,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
public async Task<bool> DeleteBasket(string id) public async Task<bool> DeleteBasket(string id)
{ {
var database = await GetDatabase(); var database = await GetDatabase();
return await database.KeyDeleteAsync(id.ToString()); return await database.KeyDeleteAsync(id);
} }
public async Task<IEnumerable<string>> GetUsers() public async Task<IEnumerable<string>> GetUsers()
@ -36,11 +36,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
var server = await GetServer(); var server = await GetServer();
IEnumerable<RedisKey> data = server.Keys(); IEnumerable<RedisKey> data = server.Keys();
if (data == null) return data?.Select(k => k.ToString());
{
return null;
}
return data.Select(k => k.ToString());
} }
public async Task<CustomerBasket> GetBasket(string customerId) public async Task<CustomerBasket> GetBasket(string customerId)
@ -99,8 +95,6 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
_logger.LogInformation($"Connecting to database {_settings.ConnectionString} at IP {ips.First().ToString()}"); _logger.LogInformation($"Connecting to database {_settings.ConnectionString} at IP {ips.First().ToString()}");
_redis = await ConnectionMultiplexer.ConnectAsync(ips.First().ToString()); _redis = await ConnectionMultiplexer.ConnectAsync(ips.First().ToString());
} }
} }
} }

View File

@ -114,7 +114,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
var identityUrl = Configuration.GetValue<string>("IdentityUrl"); var identityUrl = Configuration.GetValue<string>("IdentityUrl");
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{ {
Authority = identityUrl.ToString(), Authority = identityUrl,
ScopeName = "basket", ScopeName = "basket",
RequireHttpsMetadata = false RequireHttpsMetadata = false
}); });