Refactor to eliminate unneeded BasketQueryService

This commit is contained in:
Steve Smith
2021-12-02 16:04:30 -05:00
parent 6f5a6c0860
commit 833dc3bd3a
11 changed files with 69 additions and 65 deletions

View File

@@ -10,6 +10,9 @@ public class Basket : BaseEntity, IAggregateRoot
private readonly List<BasketItem> _items = new List<BasketItem>(); private readonly List<BasketItem> _items = new List<BasketItem>();
public IReadOnlyCollection<BasketItem> Items => _items.AsReadOnly(); public IReadOnlyCollection<BasketItem> Items => _items.AsReadOnly();
public int TotalItems => _items.Sum(i => i.Quantity);
public Basket(string buyerId) public Basket(string buyerId)
{ {
BuyerId = buyerId; BuyerId = buyerId;

View File

@@ -1,8 +0,0 @@
using System.Threading.Tasks;
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces;
public interface IBasketQueryService
{
Task<int> CountTotalBasketItems(string username);
}

View File

@@ -1,26 +0,0 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
namespace Microsoft.eShopWeb.Infrastructure.Data;
public class BasketQueryService : IBasketQueryService
{
private readonly CatalogContext _dbContext;
public BasketQueryService(CatalogContext dbContext)
{
_dbContext = dbContext;
}
public async Task<int> CountTotalBasketItems(string username)
{
var totalItems = await _dbContext.Baskets
.Where(basket => basket.BuyerId == username)
.SelectMany(item => item.Items)
.SumAsync(sum => sum.Quantity);
return totalItems;
}
}

View File

@@ -18,7 +18,6 @@ public static class ConfigureCoreServices
services.AddScoped<IBasketService, BasketService>(); services.AddScoped<IBasketService, BasketService>();
services.AddScoped<IOrderService, OrderService>(); services.AddScoped<IOrderService, OrderService>();
services.AddScoped<IBasketQueryService, BasketQueryService>();
services.AddSingleton<IUriComposer>(new UriComposer(configuration.Get<CatalogSettings>())); services.AddSingleton<IUriComposer>(new UriComposer(configuration.Get<CatalogSettings>()));
services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>)); services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>));
services.AddTransient<IEmailSender, EmailSender>(); services.AddTransient<IEmailSender, EmailSender>();

View File

@@ -7,8 +7,5 @@ namespace Microsoft.eShopWeb.Web.Interfaces;
public interface IBasketViewModelService public interface IBasketViewModelService
{ {
Task<BasketViewModel> GetOrCreateBasketForUser(string userName); Task<BasketViewModel> GetOrCreateBasketForUser(string userName);
Task<int> CountTotalBasketItems(string username);
Task<BasketViewModel> Map(Basket basket); Task<BasketViewModel> Map(Basket basket);
} }

View File

@@ -80,7 +80,7 @@
</h3> </h3>
<section class="esh-basket-item"> <section class="esh-basket-item">
<a asp-page="/Index" class="btn esh-basket-checkout text-white">[ Continue Shopping..]</a> <a asp-page="/Index" class="btn esh-basket-checkout text-white">[ Continue Shopping ]</a>
</section> </section>
} }
</div> </div>

View File

@@ -63,7 +63,7 @@
</div> </div>
<div class="row"> <div class="row">
<section class="esh-basket-item col-xs-1"> <section class="esh-basket-item col-xs-1">
<a asp-page="/Index" class="btn esh-basket-checkout text-white">[ Continue Shopping..]</a> <a asp-page="/Index" class="btn esh-basket-checkout text-white">[ Continue Shopping ]</a>
</section> </section>
<section class="esh-basket-item col-xs-push-7 col-xs-4"> <section class="esh-basket-item col-xs-push-7 col-xs-4">
@@ -84,7 +84,7 @@
</h3> </h3>
<section class="esh-basket-item"> <section class="esh-basket-item">
<a asp-page="/Index" class="btn esh-basket-checkout text-white">[ Continue Shopping..]</a> <a asp-page="/Index" class="btn esh-basket-checkout text-white">[ Continue Shopping ]</a>
</section> </section>
} }
</div> </div>

View File

@@ -2,21 +2,27 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
using Microsoft.eShopWeb.ApplicationCore.Specifications;
using Microsoft.eShopWeb.Infrastructure.Identity; using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.Web.Interfaces; using Microsoft.eShopWeb.Web.Interfaces;
using Microsoft.eShopWeb.Web.ViewModels; using Microsoft.eShopWeb.Web.ViewModels;
using BasketEntity = Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate.Basket;
namespace Microsoft.eShopWeb.Web.Pages.Shared.Components.BasketComponent; namespace Microsoft.eShopWeb.Web.Pages.Shared.Components.BasketComponent;
public class Basket : ViewComponent public class Basket : ViewComponent
{ {
private readonly IBasketViewModelService _basketService; private readonly IBasketViewModelService _basketViewModelService;
private readonly IReadRepository<BasketEntity> _basketRepository;
private readonly SignInManager<ApplicationUser> _signInManager; private readonly SignInManager<ApplicationUser> _signInManager;
public Basket(IBasketViewModelService basketService, public Basket(IBasketViewModelService basketViewModelService,
SignInManager<ApplicationUser> signInManager) IReadRepository<BasketEntity> basketRepository,
SignInManager<ApplicationUser> signInManager)
{ {
_basketService = basketService; _basketViewModelService = basketViewModelService;
_basketRepository = basketRepository;
_signInManager = signInManager; _signInManager = signInManager;
} }
@@ -33,18 +39,26 @@ public class Basket : ViewComponent
{ {
if (_signInManager.IsSignedIn(HttpContext.User)) if (_signInManager.IsSignedIn(HttpContext.User))
{ {
return await _basketService.CountTotalBasketItems(User.Identity.Name); var userNameSpec = new BasketWithItemsSpecification(User.Identity.Name);
var userBasket = await _basketRepository.GetBySpecAsync(userNameSpec);
if (userBasket == null) return 0;
return userBasket.TotalItems;
} }
string anonymousId = GetAnnonymousIdFromCookie(); string anonymousId = GetAnnonymousIdFromCookie();
if (anonymousId == null) if (anonymousId == null)
return 0; return 0;
return await _basketService.CountTotalBasketItems(anonymousId); var anonymousSpec = new BasketWithItemsSpecification(anonymousId);
var anonymousBasket = await _basketRepository.GetBySpecAsync(anonymousSpec);
if (anonymousBasket == null) return 0;
return anonymousBasket.TotalItems;
} }
private string GetAnnonymousIdFromCookie() private string GetAnnonymousIdFromCookie()
{ {
// TODO: Add a prefix to anonymous cookie values so they cannot collide with user names
if (Request.Cookies.ContainsKey(Constants.BASKET_COOKIENAME)) if (Request.Cookies.ContainsKey(Constants.BASKET_COOKIENAME))
{ {
var id = Request.Cookies[Constants.BASKET_COOKIENAME]; var id = Request.Cookies[Constants.BASKET_COOKIENAME];

View File

@@ -14,17 +14,14 @@ public class BasketViewModelService : IBasketViewModelService
{ {
private readonly IRepository<Basket> _basketRepository; private readonly IRepository<Basket> _basketRepository;
private readonly IUriComposer _uriComposer; private readonly IUriComposer _uriComposer;
private readonly IBasketQueryService _basketQueryService; private readonly IReadRepository<CatalogItem> _itemRepository;
private readonly IRepository<CatalogItem> _itemRepository;
public BasketViewModelService(IRepository<Basket> basketRepository, public BasketViewModelService(IRepository<Basket> basketRepository,
IRepository<CatalogItem> itemRepository, IReadRepository<CatalogItem> itemRepository,
IUriComposer uriComposer, IUriComposer uriComposer)
IBasketQueryService basketQueryService)
{ {
_basketRepository = basketRepository; _basketRepository = basketRepository;
_uriComposer = uriComposer; _uriComposer = uriComposer;
_basketQueryService = basketQueryService;
_itemRepository = itemRepository; _itemRepository = itemRepository;
} }
@@ -86,11 +83,4 @@ public class BasketViewModelService : IBasketViewModelService
Items = await GetBasketItems(basket.Items) Items = await GetBasketItems(basket.Items)
}; };
} }
public async Task<int> CountTotalBasketItems(string username)
{
var counter = await _basketQueryService.CountTotalBasketItems(username);
return counter;
}
} }

View File

@@ -1,8 +1,8 @@
using System; using System;
using System.Linq; using System.Linq;
using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate; using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate;
using Xunit; using Xunit;
namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Entities.BasketTests; namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Entities.BasketTests;
public class BasketAddItem public class BasketAddItem
@@ -72,4 +72,4 @@ public class BasketAddItem
Assert.Throws<ArgumentOutOfRangeException>(() => basket.AddItem(_testCatalogItemId, _testUnitPrice, -2)); Assert.Throws<ArgumentOutOfRangeException>(() => basket.AddItem(_testCatalogItemId, _testUnitPrice, -2));
} }
} }

View File

@@ -0,0 +1,35 @@
using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate;
using Xunit;
namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Entities.BasketTests;
public class BasketTotalItems
{
private readonly int _testCatalogItemId = 123;
private readonly decimal _testUnitPrice = 1.23m;
private readonly int _testQuantity = 2;
private readonly string _buyerId = "Test buyerId";
[Fact]
public void ReturnsTotalQuantityWithOneItem()
{
var basket = new Basket(_buyerId);
basket.AddItem(_testCatalogItemId, _testUnitPrice, _testQuantity);
var result = basket.TotalItems;
Assert.Equal(_testQuantity, result);
}
[Fact]
public void ReturnsTotalQuantityWithMultipleItems()
{
var basket = new Basket(_buyerId);
basket.AddItem(_testCatalogItemId, _testUnitPrice, _testQuantity);
basket.AddItem(_testCatalogItemId, _testUnitPrice, _testQuantity*2);
var result = basket.TotalItems;
Assert.Equal(_testQuantity*3, result);
}
}