Browse Source

Merge branch 'ardalis/basket-add' into master

main
Steve Smith 8 years ago
committed by GitHub
parent
commit
acdc072cb9
  1. 10
      src/ApplicationCore/Entities/ApplicationUser.cs
  2. 17
      src/ApplicationCore/Entities/Basket.cs
  3. 14
      src/ApplicationCore/Interfaces/IBasketService.cs
  4. 9
      src/ApplicationCore/Interfaces/IIdentityParser.cs
  5. 4
      src/Infrastructure/Identity/AppIdentityDbContext.cs
  6. 10
      src/Infrastructure/Identity/ApplicationUser.cs
  7. 61
      src/Web/Controllers/CartController.cs
  8. 1
      src/Web/Infrastructure/CatalogContext.cs
  9. 53
      src/Web/Services/BasketService.cs
  10. 12
      src/Web/Startup.cs
  11. 32
      src/Web/Views/Cart/Index.cshtml
  12. 2
      src/Web/Views/Catalog/_product.cshtml
  13. 1
      src/Web/Web.csproj

10
src/ApplicationCore/Entities/ApplicationUser.cs

@ -1,10 +0,0 @@
using System.Security.Claims;
namespace ApplicationCore.Entities
{
public class ApplicationUser : ClaimsIdentity
{
public string UserId { get; set; }
public string UserName { get; set; }
}
}

17
src/ApplicationCore/Entities/Basket.cs

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.eShopWeb.ApplicationCore.Entities
{
@ -6,5 +7,21 @@ namespace Microsoft.eShopWeb.ApplicationCore.Entities
{
public string BuyerId { get; set; }
public List<BasketItem> Items { get; set; } = new List<BasketItem>();
public void AddItem(int productId, decimal unitPrice, int quantity = 1)
{
if(!Items.Any(i => i.ProductId == productId))
{
Items.Add(new BasketItem()
{
ProductId = productId,
Quantity = quantity,
UnitPrice = unitPrice
});
return;
}
var existingItem = Items.FirstOrDefault(i => i.ProductId == productId);
existingItem.Quantity += quantity;
}
}
}

14
src/ApplicationCore/Interfaces/IBasketService.cs

@ -1,17 +1,13 @@
using ApplicationCore.Entities;
using Microsoft.eShopWeb.ApplicationCore.Entities;
using System.Security.Principal;
using Microsoft.eShopWeb.ApplicationCore.Entities;
using System.Threading.Tasks;
namespace ApplicationCore.Interfaces
{
public interface IBasketService
{
Task<Basket> GetBasket(ApplicationUser user);
}
public interface IIdentityParser<T>
{
T Parse(IPrincipal principal);
Task<Basket> GetBasket(string basketId);
Task<Basket> CreateBasket();
Task<Basket> CreateBasketForUser(string userId);
Task UpdateBasket(Basket basket);
}
}

9
src/ApplicationCore/Interfaces/IIdentityParser.cs

@ -0,0 +1,9 @@
using System.Security.Principal;
namespace ApplicationCore.Interfaces
{
public interface IIdentityParser<T>
{
T Parse(IPrincipal principal);
}
}

4
src/Infrastructure/Identity/AppIdentityDbContext.cs

@ -20,8 +20,4 @@ namespace Infrastructure.Identity
}
}
public class ApplicationUser : IdentityUser
{
}
}

10
src/Infrastructure/Identity/ApplicationUser.cs

@ -0,0 +1,10 @@
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace Infrastructure.Identity
{
public class ApplicationUser : IdentityUser
{
}
}

61
src/Web/Controllers/CartController.cs

@ -1,52 +1,65 @@
using Microsoft.eShopWeb.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using ApplicationCore.Interfaces;
using ApplicationCore.Entities;
using Microsoft.eShopWeb.ApplicationCore.Entities;
using System;
using Microsoft.AspNetCore.Http;
namespace Microsoft.eShopWeb.Controllers
{
public class CartController : Controller
{
private readonly ICatalogService _catalogSvc;
private readonly IBasketService _basketSvc;
private readonly IIdentityParser<ApplicationUser> _appUserParser;
private readonly IBasketService _basketService;
//private readonly IIdentityParser<ApplicationUser> _appUserParser;
private const string _basketSessionKey = "basketId";
public CartController(IBasketService basketSvc,
IIdentityParser<ApplicationUser> appUserParser)
public CartController(IBasketService basketService)
// IIdentityParser<ApplicationUser> appUserParser)
{
//_catalogSvc = catalogSvc;
_basketSvc = basketSvc;
_appUserParser = appUserParser;
_basketService = basketService;
// _appUserParser = appUserParser;
}
// GET: /<controller>/
public async Task<IActionResult> Index()
{
var user = _appUserParser.Parse(HttpContext.User);
var viewmodel = await _basketSvc.GetBasket(user);
//var user = _appUserParser.Parse(HttpContext.User);
var basket = await GetBasketFromSessionAsync();
return View(viewmodel);
return View(basket);
}
// GET: /Cart/AddToCart
// TODO: This should be a POST.
public async Task<IActionResult> AddToCart(CatalogItem productDetails)
{
var user = _appUserParser.Parse(HttpContext.User);
var product = new BasketItem()
if (productDetails?.Id == null)
{
Id = Guid.NewGuid().ToString(),
Quantity = 1,
UnitPrice = productDetails.Price,
ProductId = productDetails.Id
};
// TODO: Save the item
//await _basketSvc.AddItemToBasket(user, product);
return RedirectToAction("Index", "Catalog");
}
var basket = await GetBasketFromSessionAsync();
basket.AddItem(productDetails.Id, productDetails.Price, 1);
await _basketService.UpdateBasket(basket);
return RedirectToAction("Index");
}
private async Task<Basket> GetBasketFromSessionAsync()
{
string basketId = HttpContext.Session.GetString(_basketSessionKey);
Basket basket = null;
if (basketId == null)
{
basket = await _basketService.CreateBasketForUser(User.Identity.Name);
HttpContext.Session.SetString(_basketSessionKey, basket.Id);
}
else
{
basket = await _basketService.GetBasket(basketId);
}
return basket;
}
}
}

1
src/Web/Infrastructure/CatalogContext.cs

@ -10,6 +10,7 @@ namespace Microsoft.eShopWeb.Infrastructure
public CatalogContext(DbContextOptions<CatalogContext> options) : base(options)
{
}
public DbSet<Basket> Baskets { get; set; }
public DbSet<CatalogItem> CatalogItems { get; set; }
public DbSet<CatalogBrand> CatalogBrands { get; set; }
public DbSet<CatalogType> CatalogTypes { get; set; }

53
src/Web/Services/BasketService.cs

@ -0,0 +1,53 @@
using ApplicationCore.Interfaces;
using System.Threading.Tasks;
using Microsoft.eShopWeb.ApplicationCore.Entities;
using Microsoft.eShopWeb.Infrastructure;
using Microsoft.EntityFrameworkCore;
namespace Web.Services
{
public class BasketService : IBasketService
{
private readonly CatalogContext _context;
public BasketService(CatalogContext context)
{
_context = context;
}
public async Task<Basket> GetBasket(string basketId)
{
var basket = await _context.Baskets
.Include(b => b.Items)
.FirstOrDefaultAsync(b => b.Id == basketId);
if (basket == null)
{
basket = new Basket();
_context.Baskets.Add(basket);
await _context.SaveChangesAsync();
}
return basket;
}
public Task<Basket> CreateBasket()
{
return CreateBasketForUser(null);
}
public async Task<Basket> CreateBasketForUser(string userId)
{
var basket = new Basket();
_context.Baskets.Add(basket);
await _context.SaveChangesAsync();
return basket;
}
public async Task UpdateBasket(Basket basket)
{
// only need to save changes here
await _context.SaveChangesAsync();
}
}
}

12
src/Web/Startup.cs

@ -15,6 +15,7 @@ using ApplicationCore.Interfaces;
using Infrastructure.FileSystem;
using Infrastructure.Logging;
using Microsoft.AspNetCore.Identity;
using Web.Services;
namespace Microsoft.eShopWeb
{
@ -67,10 +68,19 @@ namespace Microsoft.eShopWeb
services.AddMemoryCache();
services.AddScoped<ICatalogService, CachedCatalogService>();
services.AddScoped<IBasketService, BasketService>();
services.AddScoped<CatalogService>();
services.Configure<CatalogSettings>(Configuration);
services.AddSingleton<IImageService, LocalFileImageService>();
services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>));
// Add memory cache services
services.AddMemoryCache();
// Add session related services.
services.AddSession();
services.AddMvc();
_services = services;
@ -111,6 +121,8 @@ namespace Microsoft.eShopWeb
app.UseExceptionHandler("/Catalog/Error");
}
app.UseSession();
app.UseStaticFiles();
app.UseIdentity();

32
src/Web/Views/Cart/Index.cshtml

@ -0,0 +1,32 @@
@using Microsoft.eShopWeb.ApplicationCore.Entities;
@{
ViewData["Title"] = "Catalog";
@model Basket
}
<section class="esh-catalog-hero">
<div class="container">
<img class="esh-catalog-title" src="../images/main_banner_text.png" />
</div>
</section>
<div class="container">
@if (Model.Items.Any())
{
<div class="esh-catalog-items row">
@foreach (var item in Model.Items)
{
<div class="esh-catalog-item col-md-4">
@item.ProductId
</div>
}
</div>
}
else
{
<div class="esh-catalog-items row">
Cart is empty.
</div>
}
</div>

2
src/Web/Views/Catalog/_product.cshtml

@ -4,7 +4,7 @@
<form asp-controller="Cart" asp-action="AddToCart">
<img class="esh-catalog-thumbnail" src="@Model.PictureUri" />
<input class="esh-catalog-button @((!User.Identity.IsAuthenticated) ? "is-disabled" : "")" type="submit" value="[ ADD TO CART ]" />
<input class="esh-catalog-button" type="submit" value="[ ADD TO CART ]" />
<div class="esh-catalog-name">
<span>@Model.Name</span>

1
src/Web/Web.csproj

@ -15,6 +15,7 @@
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.0.1" />
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Session" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="1.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="1.1.2" />

Loading…
Cancel
Save