diff --git a/src/ApplicationCore/Entities/ApplicationUser.cs b/src/ApplicationCore/Entities/ApplicationUser.cs deleted file mode 100644 index ee361c5..0000000 --- a/src/ApplicationCore/Entities/ApplicationUser.cs +++ /dev/null @@ -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; } - } -} diff --git a/src/ApplicationCore/Entities/Basket.cs b/src/ApplicationCore/Entities/Basket.cs index 1fc989a..e635965 100644 --- a/src/ApplicationCore/Entities/Basket.cs +++ b/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 Items { get; set; } = new List(); + + 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; + } } } diff --git a/src/ApplicationCore/Interfaces/IBasketService.cs b/src/ApplicationCore/Interfaces/IBasketService.cs index a5f25b9..6233083 100644 --- a/src/ApplicationCore/Interfaces/IBasketService.cs +++ b/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 GetBasket(ApplicationUser user); - } - - public interface IIdentityParser - { - T Parse(IPrincipal principal); + Task GetBasket(string basketId); + Task CreateBasket(); + Task CreateBasketForUser(string userId); + Task UpdateBasket(Basket basket); } } diff --git a/src/ApplicationCore/Interfaces/IIdentityParser.cs b/src/ApplicationCore/Interfaces/IIdentityParser.cs new file mode 100644 index 0000000..3b8e746 --- /dev/null +++ b/src/ApplicationCore/Interfaces/IIdentityParser.cs @@ -0,0 +1,9 @@ +using System.Security.Principal; + +namespace ApplicationCore.Interfaces +{ + public interface IIdentityParser + { + T Parse(IPrincipal principal); + } +} diff --git a/src/Infrastructure/Identity/AppIdentityDbContext.cs b/src/Infrastructure/Identity/AppIdentityDbContext.cs index 22e6ed9..b90d951 100644 --- a/src/Infrastructure/Identity/AppIdentityDbContext.cs +++ b/src/Infrastructure/Identity/AppIdentityDbContext.cs @@ -20,8 +20,4 @@ namespace Infrastructure.Identity } } - public class ApplicationUser : IdentityUser - { - } - } diff --git a/src/Infrastructure/Identity/ApplicationUser.cs b/src/Infrastructure/Identity/ApplicationUser.cs new file mode 100644 index 0000000..a8099f3 --- /dev/null +++ b/src/Infrastructure/Identity/ApplicationUser.cs @@ -0,0 +1,10 @@ +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; + + +namespace Infrastructure.Identity +{ + public class ApplicationUser : IdentityUser + { + } +} diff --git a/src/Web/Controllers/CartController.cs b/src/Web/Controllers/CartController.cs index 70613dd..4fcc05a 100644 --- a/src/Web/Controllers/CartController.cs +++ b/src/Web/Controllers/CartController.cs @@ -1,52 +1,63 @@ -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 _appUserParser; + private readonly IBasketService _basketService; + //private readonly IIdentityParser _appUserParser; + private const string _basketSessionKey = "basketId"; - public CartController(IBasketService basketSvc, - IIdentityParser appUserParser) + public CartController(IBasketService basketService) +// IIdentityParser appUserParser) { - //_catalogSvc = catalogSvc; - _basketSvc = basketSvc; - _appUserParser = appUserParser; + _basketService = basketService; + // _appUserParser = appUserParser; } // GET: // public async Task 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); } public async Task AddToCart(CatalogItem productDetails) { - if (productDetails.Id != null) + if (productDetails?.Id == null) { - var user = _appUserParser.Parse(HttpContext.User); - var product = new BasketItem() - { - Id = Guid.NewGuid().ToString(), - Quantity = 1, - UnitPrice = productDetails.Price, - ProductId = productDetails.Id - }; - //await _basketSvc.AddItemToBasket(user, product); + return RedirectToAction("Index", "Catalog"); } - 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 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; } } diff --git a/src/Web/Infrastructure/CatalogContext.cs b/src/Web/Infrastructure/CatalogContext.cs index 066025f..939ec97 100644 --- a/src/Web/Infrastructure/CatalogContext.cs +++ b/src/Web/Infrastructure/CatalogContext.cs @@ -10,6 +10,7 @@ namespace Microsoft.eShopWeb.Infrastructure public CatalogContext(DbContextOptions options) : base(options) { } + public DbSet Baskets { get; set; } public DbSet CatalogItems { get; set; } public DbSet CatalogBrands { get; set; } public DbSet CatalogTypes { get; set; } diff --git a/src/Web/Services/BasketService.cs b/src/Web/Services/BasketService.cs new file mode 100644 index 0000000..60d21a9 --- /dev/null +++ b/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 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 CreateBasket() + { + return CreateBasketForUser(null); + } + + public async Task 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(); + } + + } +} diff --git a/src/Web/Startup.cs b/src/Web/Startup.cs index 7c2f2ed..df14491 100644 --- a/src/Web/Startup.cs +++ b/src/Web/Startup.cs @@ -14,6 +14,7 @@ using Microsoft.AspNetCore.Http; using ApplicationCore.Interfaces; using Infrastructure.FileSystem; using Infrastructure.Logging; +using Web.Services; namespace Microsoft.eShopWeb { @@ -41,8 +42,8 @@ namespace Microsoft.eShopWeb { try { - //c.UseInMemoryDatabase("Catalog"); - c.UseSqlServer(Configuration.GetConnectionString("CatalogConnection")); + c.UseInMemoryDatabase("Catalog"); + //c.UseSqlServer(Configuration.GetConnectionString("CatalogConnection")); c.ConfigureWarnings(wb => { //By default, in this application, we don't want to have client evaluations @@ -57,8 +58,8 @@ namespace Microsoft.eShopWeb // Add Identity DbContext services.AddDbContext(options => - //options.UseInMemoryDatabase("Identity")); - options.UseSqlServer(Configuration.GetConnectionString("IdentityConnection"))); + options.UseInMemoryDatabase("Identity")); + //options.UseSqlServer(Configuration.GetConnectionString("IdentityConnection"))); services.AddIdentity() .AddEntityFrameworkStores() @@ -66,10 +67,19 @@ namespace Microsoft.eShopWeb services.AddMemoryCache(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.Configure(Configuration); services.AddSingleton(); services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>)); + + + // Add memory cache services + services.AddMemoryCache(); + + // Add session related services. + services.AddSession(); + services.AddMvc(); _services = services; @@ -110,6 +120,8 @@ namespace Microsoft.eShopWeb app.UseExceptionHandler("/Catalog/Error"); } + app.UseSession(); + app.UseStaticFiles(); app.UseIdentity(); diff --git a/src/Web/Views/Cart/Index.cshtml b/src/Web/Views/Cart/Index.cshtml new file mode 100644 index 0000000..702db5e --- /dev/null +++ b/src/Web/Views/Cart/Index.cshtml @@ -0,0 +1,32 @@ +@using Microsoft.eShopWeb.ApplicationCore.Entities; +@{ + ViewData["Title"] = "Catalog"; + @model Basket +} +
+
+ +
+
+ +
+ + @if (Model.Items.Any()) + { +
+ @foreach (var item in Model.Items) + { +
+ @item.ProductId +
+ } +
+ + } + else + { +
+ Cart is empty. +
+ } +
diff --git a/src/Web/Views/Catalog/_product.cshtml b/src/Web/Views/Catalog/_product.cshtml index b22fc20..05a1b7b 100644 --- a/src/Web/Views/Catalog/_product.cshtml +++ b/src/Web/Views/Catalog/_product.cshtml @@ -4,7 +4,7 @@
- +
@Model.Name diff --git a/src/Web/Web.csproj b/src/Web/Web.csproj index 745b30e..4ad5dbe 100644 --- a/src/Web/Web.csproj +++ b/src/Web/Web.csproj @@ -15,6 +15,7 @@ +