I’m reading the Pro ASP.NET MVC3 Framework book from Freeman and Sanderson and have a question about some of the code. This might be a newbie question but I have found people’s questions regarding the examples in this book to be useful.
The Cart controller in the SportsStore example marks the Checkout action as HttpPost but neither the AddToCart nor RemoveFromCart actions are marked as HttpPost. But they both receive form submissions and modify the underlying Cart model. Isn’t that the definition of when to use HttpPost?
Granted, the model changes aren’t being persisted in a database in this example but that’s only for simplicity sake. The model is being changed just as much in the AddToCart and RemoveFromCart actions as the Checkout action.
btw – The code works just the same with or without HttpPost. So this is mostly a question about best practices.
Below is the final controller class from the book:
namespace SportsStore.WebUI.Controllers
{
public class CartController : Controller
{
private IProductRepository repository;
private IOrderProcessor orderProcessor;
public CartController(IProductRepository repo, IOrderProcessor proc)
{
repository = repo;
orderProcessor = proc;
}
public RedirectToRouteResult AddToCart(Cart cart, int productID, string returnUrl) {
Product product = repository.Products
.FirstOrDefault(p => p.ProductID == productID);
if (product != null) {
cart.AddItem(product, 1);
}
return RedirectToAction("Index", new {returnUrl});
}
public RedirectToRouteResult RemoveFromCart(Cart cart, int productId, string returnUrl)
{
Product product = repository.Products
.FirstOrDefault(p => p.ProductID == productId);
if (product != null)
{
cart.RemoveLine(product);
}
return RedirectToAction("Index", new { returnUrl });
}
public ViewResult Index(Cart cart, string returnUrl)
{
return View(new CartIndexViewModel
{
Cart = cart,
ReturnUrl = returnUrl
});
}
public ViewResult Summary(Cart cart)
{
return View(cart);
}
[HttpPost]
public ViewResult Checkout(Cart cart, ShippingDetails shippingDetails)
{
if (cart.Lines.Count() == 0)
{
ModelState.AddModelError("", "Sorry your cart is empty");
}
if (ModelState.IsValid)
{
orderProcessor.ProcessOrder(cart, shippingDetails);
cart.Clear();
return View("Completed");
}
else
{
return View(shippingDetails);
}
}
public ViewResult Checkout()
{
return View(new ShippingDetails());
}
}
}
If I recall from the book, Sanderson & pal use a special ModelBinder to access a Session-based Cart object… isn’t that right?
Technically the implementation in the book isn’t incorrect, since the actions do not affect the underlying application. Session-based storage is volatile, so the actions to not represent a permanent change.
A real application might use idempotent HttpPut and HttpDelete (or non-idempotent HttpPost) for the add/remove cart item actions. However a real application would probably not keep these things in volatile session storage.
I think the book is just trying to show you examples of an application without creating a ton of storage tables.