Breaking 05_03 in twain
@ -58,6 +58,7 @@
|
||||
<Compile Include="Models\ShoppingCart.cs" />
|
||||
<Compile Include="Models\ShoppingCartItem.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Requests\UpdateProductRequest.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace HPlusSports.Models
|
||||
namespace HPlusSports.Requests
|
||||
{
|
||||
public class UpdateProductRequest
|
||||
{
|
||||
@ -34,4 +34,4 @@ namespace HPlusSports.Models
|
||||
|
||||
public string LastUpdatedUserId { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,8 @@
|
||||
using HPlusSports.Models;
|
||||
using System;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using HPlusSports.Models;
|
||||
using HPlusSports.Requests;
|
||||
|
||||
namespace HPlusSports.Controllers
|
||||
{
|
||||
@ -10,11 +11,6 @@ namespace HPlusSports.Controllers
|
||||
{
|
||||
private HPlusSportsDbContext _context;
|
||||
|
||||
public InventoryController()
|
||||
: this(new HPlusSportsDbContext())
|
||||
{
|
||||
}
|
||||
|
||||
public InventoryController(HPlusSportsDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
@ -35,7 +31,6 @@ namespace HPlusSports.Controllers
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult Create(CreateProductRequest request)
|
||||
{
|
||||
@ -44,7 +39,8 @@ namespace HPlusSports.Controllers
|
||||
return View();
|
||||
}
|
||||
|
||||
var product = new Product {
|
||||
var product = new Product
|
||||
{
|
||||
CategoryId = request.CategoryId,
|
||||
Description = request.Description,
|
||||
MSRP = request.MSRP,
|
||||
@ -59,8 +55,7 @@ namespace HPlusSports.Controllers
|
||||
_context.Products.Add(product);
|
||||
_context.SaveChanges();
|
||||
|
||||
TempData["SuccessMessage"] =
|
||||
$"Successfully created \"{product.Name}\"";
|
||||
TempData.SuccessMessage($"Successfully created \"{product.Name}\"");
|
||||
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
@ -72,43 +67,41 @@ namespace HPlusSports.Controllers
|
||||
|
||||
if (existing == null)
|
||||
{
|
||||
return ProductListError(
|
||||
$"Couldn't update product #\"{id}\": product not found!"
|
||||
);
|
||||
TempData.ErrorMessage($"Couldn't update product #\"{id}\": product not found!");
|
||||
}
|
||||
|
||||
return View(existing);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult Update(long id, Product product)
|
||||
public ActionResult Update(UpdateProductRequest request)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
var existing = _context.Products.Find(id);
|
||||
request.LastUpdatedUserId = GetUserId(this);
|
||||
|
||||
var existing = _context.Products.Find(request.Id);
|
||||
|
||||
if (existing == null)
|
||||
{
|
||||
return ProductListError(
|
||||
$"Couldn't update product #\"{id}\": product not found!"
|
||||
);
|
||||
TempData.ErrorMessage($"Couldn't update product #\"{request.Id}\": product not found!");
|
||||
return View();
|
||||
}
|
||||
|
||||
var hasPriceChanged = existing.Price != product.Price;
|
||||
var hasPriceChanged = existing.Price != request.Price;
|
||||
|
||||
existing.CategoryId = product.CategoryId;
|
||||
existing.Description = product.Description;
|
||||
existing.MSRP = product.MSRP;
|
||||
existing.Name = product.Name;
|
||||
existing.Price = product.Price;
|
||||
existing.SKU = product.SKU;
|
||||
existing.Summary = product.Summary;
|
||||
existing.CategoryId = request.CategoryId;
|
||||
existing.Description = request.Description;
|
||||
existing.MSRP = request.MSRP;
|
||||
existing.Name = request.Name;
|
||||
existing.Price = request.Price;
|
||||
existing.SKU = request.SKU;
|
||||
existing.Summary = request.Summary;
|
||||
|
||||
existing.LastUpdated = DateTime.UtcNow;
|
||||
existing.LastUpdatedUserId = GetUserId(this);
|
||||
|
||||
_context.SaveChanges();
|
||||
|
||||
@ -117,13 +110,13 @@ namespace HPlusSports.Controllers
|
||||
var cartsToUpdate =
|
||||
_context.ShoppingCarts
|
||||
.Include("Items")
|
||||
.Where(cart => cart.Items.Any(x => x.SKU == product.SKU));
|
||||
.Where(cart => cart.Items.Any(x => x.SKU == request.SKU));
|
||||
|
||||
foreach (var cart in cartsToUpdate)
|
||||
{
|
||||
foreach (var cartItem in cart.Items.Where(x => x.SKU == product.SKU))
|
||||
foreach (var cartItem in cart.Items.Where(x => x.SKU == request.SKU))
|
||||
{
|
||||
cartItem.Price = product.Price;
|
||||
cartItem.Price = request.Price;
|
||||
}
|
||||
|
||||
cart.Recalculate();
|
||||
@ -132,8 +125,7 @@ namespace HPlusSports.Controllers
|
||||
|
||||
_context.SaveChanges();
|
||||
|
||||
TempData["SuccessMessage"] =
|
||||
$"Successfully updated \"{product.Name}\"";
|
||||
TempData.SuccessMessage($"Successfully updated \"{request.Name}\"");
|
||||
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
@ -7,8 +7,19 @@ namespace HPlusSports
|
||||
{
|
||||
public static class TempDataExtensions
|
||||
{
|
||||
const string ErrorMessageKey = "ErrorMessage";
|
||||
const string SuccessMessageKey = "SuccessMessage";
|
||||
|
||||
public static string ErrorMessage(this System.Web.Mvc.TempDataDictionary tempData)
|
||||
{
|
||||
return tempData[ErrorMessageKey] as string;
|
||||
}
|
||||
|
||||
public static void ErrorMessage(this System.Web.Mvc.TempDataDictionary tempData, string errorMessage)
|
||||
{
|
||||
tempData[ErrorMessageKey] = errorMessage;
|
||||
}
|
||||
|
||||
public static string SuccessMessage(this System.Web.Mvc.TempDataDictionary tempData)
|
||||
{
|
||||
return tempData[SuccessMessageKey] as string;
|
||||
|
||||
@ -57,8 +57,8 @@
|
||||
<Compile Include="Models\Review.cs" />
|
||||
<Compile Include="Models\ShoppingCart.cs" />
|
||||
<Compile Include="Models\ShoppingCartItem.cs" />
|
||||
<Compile Include="Requests\UpdateProductRequest.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Requests\UpdateProductRequest.cs" />
|
||||
<Compile Include="Services\ProductUpdateService.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@ -125,7 +125,7 @@ namespace HPlusSports
|
||||
return
|
||||
Regex.Replace(
|
||||
Regex.Replace(
|
||||
source,
|
||||
source.Replace("<h2>Description</h2>", ""),
|
||||
"<[^>]*>",
|
||||
""
|
||||
),
|
||||
|
||||
@ -40,4 +40,4 @@ namespace HPlusSports.Requests
|
||||
|
||||
public string LastUpdatedUserId { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using HPlusSports.Requests;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using HPlusSports.Requests;
|
||||
|
||||
namespace HPlusSports.Services
|
||||
{
|
||||
@ -38,8 +38,8 @@ namespace HPlusSports.Services
|
||||
existing.Price = request.Price;
|
||||
existing.SKU = request.SKU;
|
||||
existing.Summary = request.Summary;
|
||||
|
||||
existing.LastUpdated = DateTime.UtcNow;
|
||||
existing.LastUpdatedUserId = request.LastUpdatedUserId;
|
||||
|
||||
_context.SaveChanges();
|
||||
|
||||
|
||||
26
Ch05/05_03_End/Website/App_Start/Dependencies.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using Autofac;
|
||||
using Autofac.Integration.Mvc;
|
||||
|
||||
namespace HPlusSports.App_Start
|
||||
{
|
||||
public class Dependencies
|
||||
{
|
||||
public static void Register()
|
||||
{
|
||||
var builder = new ContainerBuilder();
|
||||
builder.RegisterControllers(typeof(Dependencies).Assembly);
|
||||
builder.RegisterType<HPlusSportsDbContext>()
|
||||
.InstancePerRequest();
|
||||
|
||||
var container = builder.Build();
|
||||
|
||||
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
175
Ch05/05_03_End/Website/Controllers/InventoryController.cs
Normal file
@ -0,0 +1,175 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using HPlusSports.Models;
|
||||
using HPlusSports.Requests;
|
||||
|
||||
namespace HPlusSports.Controllers
|
||||
{
|
||||
[Authorize(Roles = UserRoles.Admin)]
|
||||
public class InventoryController : Controller
|
||||
{
|
||||
private HPlusSportsDbContext _context;
|
||||
|
||||
public InventoryController(HPlusSportsDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public ActionResult Index()
|
||||
{
|
||||
var products =
|
||||
_context.Products
|
||||
.OrderBy(x => x.CategoryId)
|
||||
.ThenBy(x => x.Name);
|
||||
|
||||
return View(products);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public ActionResult Create()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
[HttpPost]
|
||||
public ActionResult Create(CreateProductRequest request)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
var product = new Product
|
||||
{
|
||||
CategoryId = request.CategoryId,
|
||||
Description = request.Description,
|
||||
MSRP = request.MSRP,
|
||||
Name = request.Name,
|
||||
Price = request.Price,
|
||||
SKU = request.SKU,
|
||||
Summary = request.Summary,
|
||||
LastUpdated = DateTime.UtcNow,
|
||||
LastUpdatedUserId = GetUserId(this),
|
||||
};
|
||||
|
||||
_context.Products.Add(product);
|
||||
_context.SaveChanges();
|
||||
|
||||
TempData.SuccessMessage($"Successfully created \"{product.Name}\"");
|
||||
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public ActionResult Update(long id)
|
||||
{
|
||||
var existing = _context.Products.Find(id);
|
||||
|
||||
if (existing == null)
|
||||
{
|
||||
TempData.ErrorMessage($"Couldn't update product #\"{id}\": product not found!");
|
||||
}
|
||||
|
||||
return View(existing);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult Update(UpdateProductRequest request)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
request.LastUpdatedUserId = GetUserId(this);
|
||||
|
||||
var existing = _context.Products.Find(request.Id);
|
||||
|
||||
if (existing == null)
|
||||
{
|
||||
TempData.ErrorMessage($"Couldn't update product #\"{request.Id}\": product not found!");
|
||||
return View();
|
||||
}
|
||||
|
||||
var hasPriceChanged = existing.Price != request.Price;
|
||||
|
||||
existing.CategoryId = request.CategoryId;
|
||||
existing.Description = request.Description;
|
||||
existing.MSRP = request.MSRP;
|
||||
existing.Name = request.Name;
|
||||
existing.Price = request.Price;
|
||||
existing.SKU = request.SKU;
|
||||
existing.Summary = request.Summary;
|
||||
|
||||
existing.LastUpdated = DateTime.UtcNow;
|
||||
|
||||
_context.SaveChanges();
|
||||
|
||||
if (hasPriceChanged)
|
||||
{
|
||||
var cartsToUpdate =
|
||||
_context.ShoppingCarts
|
||||
.Include("Items")
|
||||
.Where(cart => cart.Items.Any(x => x.SKU == request.SKU));
|
||||
|
||||
foreach (var cart in cartsToUpdate)
|
||||
{
|
||||
foreach (var cartItem in cart.Items.Where(x => x.SKU == request.SKU))
|
||||
{
|
||||
cartItem.Price = request.Price;
|
||||
}
|
||||
|
||||
cart.Recalculate();
|
||||
}
|
||||
}
|
||||
|
||||
_context.SaveChanges();
|
||||
|
||||
TempData.SuccessMessage($"Successfully updated \"{request.Name}\"");
|
||||
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
public ActionResult Delete(long id)
|
||||
{
|
||||
var product = _context.Products.Find(id);
|
||||
|
||||
if (product == null)
|
||||
{
|
||||
return ProductListError(
|
||||
$"Couldn't delete \"{product.Name}\": product not found!"
|
||||
);
|
||||
}
|
||||
|
||||
_context.Products.Remove(product);
|
||||
_context.SaveChanges();
|
||||
|
||||
TempData["SuccessMessage"] =
|
||||
$"Successfully deleted \"{product.Name}\"";
|
||||
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
private ActionResult ProductListError(string error)
|
||||
{
|
||||
TempData["ErrorMessage"] = error;
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
protected override void OnResultExecuting(ResultExecutingContext filterContext)
|
||||
{
|
||||
ViewData["CategoryId"] =
|
||||
_context.Categories
|
||||
.Select(x => new SelectListItem
|
||||
{
|
||||
Text = x.Name,
|
||||
Value = x.Id.ToString(),
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
// Overwriteable function for unit testing
|
||||
internal Func<Controller, string> GetUserId =
|
||||
(controller) => controller.User.Identity.Name;
|
||||
}
|
||||
}
|
||||
@ -10,9 +10,14 @@ namespace HPlusSports
|
||||
const string ErrorMessageKey = "ErrorMessage";
|
||||
const string SuccessMessageKey = "SuccessMessage";
|
||||
|
||||
public static bool HasSuccessMessage(this System.Web.Mvc.TempDataDictionary tempData)
|
||||
public static string ErrorMessage(this System.Web.Mvc.TempDataDictionary tempData)
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(tempData[SuccessMessageKey] as string);
|
||||
return tempData[ErrorMessageKey] as string;
|
||||
}
|
||||
|
||||
public static void ErrorMessage(this System.Web.Mvc.TempDataDictionary tempData, string errorMessage)
|
||||
{
|
||||
tempData[ErrorMessageKey] = errorMessage;
|
||||
}
|
||||
|
||||
public static string SuccessMessage(this System.Web.Mvc.TempDataDictionary tempData)
|
||||
@ -24,21 +29,5 @@ namespace HPlusSports
|
||||
{
|
||||
tempData[SuccessMessageKey] = successMessage;
|
||||
}
|
||||
|
||||
|
||||
public static bool HasErrorMessage(this System.Web.Mvc.TempDataDictionary tempData)
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(tempData[ErrorMessageKey] as string);
|
||||
}
|
||||
|
||||
public static string ErrorMessage(this System.Web.Mvc.TempDataDictionary tempData)
|
||||
{
|
||||
return tempData[ErrorMessageKey] as string;
|
||||
}
|
||||
|
||||
public static void ErrorMessage(this System.Web.Mvc.TempDataDictionary tempData, string errorMessage)
|
||||
{
|
||||
tempData[ErrorMessageKey] = errorMessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,18 +4,18 @@
|
||||
ViewBag.Title = "Inventory";
|
||||
}
|
||||
|
||||
@if (TempData.HasSuccessMessage())
|
||||
@if (TempData["SuccessMessage"] != null)
|
||||
{
|
||||
<div class="alert alert-error alert-dismissible" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
@TempData.SuccessMessage()
|
||||
@TempData["SuccessMessage"]
|
||||
</div>
|
||||
}
|
||||
else if (TempData.HasErrorMessage())
|
||||
else if (TempData["ErrorMessage"] != null)
|
||||
{
|
||||
<div class="alert alert-error alert-dismissible" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
@TempData.ErrorMessage()
|
||||
@TempData["ErrorMessage"]
|
||||
</div>
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
@ -57,8 +57,8 @@
|
||||
<Compile Include="Models\Review.cs" />
|
||||
<Compile Include="Models\ShoppingCart.cs" />
|
||||
<Compile Include="Models\ShoppingCartItem.cs" />
|
||||
<Compile Include="Requests\UpdateProductRequest.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Requests\UpdateProductRequest.cs" />
|
||||
<Compile Include="Services\ProductUpdateService.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -125,7 +125,7 @@ namespace HPlusSports
|
||||
return
|
||||
Regex.Replace(
|
||||
Regex.Replace(
|
||||
source,
|
||||
source.Replace("<h2>Description</h2>", ""),
|
||||
"<[^>]*>",
|
||||
""
|
||||
),
|
||||