MVC3 SportsStore示例:AddToCart应该标记为HttpPost吗?

时间:2012-02-22 15:38:03

标签: asp.net-mvc-3 http-post

我正在阅读Freeman和Sanderson的Pro ASP.NET MVC3框架书,对一些代码有疑问。这可能是一个新手问题,但我发现人们对本书中的例子有用的问题很有用。

SportsStore示例中的Cart控制器将Checkout操作标记为HttpPost,但AddToCart和RemoveFromCart操作都未标记为HttpPost。但他们都收到表单提交并修改底层的Cart模型。难道没有定义什么时候使用HttpPost?

当然,在此示例中,模型更改不会保留在数据库中,但这只是为了简单起见。该模型在AddToCart和RemoveFromCart操作中的更改与Checkout操作一样多。

btw - 无论有没有HttpPost,代码的工作方式都相同。所以这主要是关于最佳实践的问题。

以下是本书中的最终控制器类:

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());
        }
    }
}

3 个答案:

答案 0 :(得分:0)

如果我记得这本书,Sanderson& pal使用特殊的ModelBinder来访问基于会话的Cart对象......不是吗?

从技术上讲,本书中的实现并不正确,因为这些操作不会影响底层应用程序。基于会话的存储是易变的,因此动作不代表永久性的变化。

真正的应用程序可能会使用幂等HttpPut和HttpDelete(或非幂等HttpPost)来添加/删除购物车项目操作。但是,真正的应用程序可能不会将这些内容保存在易失性会话存储中

我认为本书只是试图向您展示应用程序的示例,而不会创建大量的存储表。

答案 1 :(得分:0)

我相信你的代码中的结帐ActionResult是用[HttpPost]修饰的,因为CartController中还有一个默认为HttpGet

的Action
    public ViewResult Checkout()
    {
        return View(new ShippingDetails());
    }

此外,AddToCart和RemoveFromCart操作都没有标记为HttpPost,因为由于模型绑定,它们无法通过HttpGet获得。

答案 2 :(得分:-1)

在我有限的经验中,为了保持一致,我会说它们应该被标记为[HttpPost]。在本书的其他示例中,有两种动作方法具有相同的名称,例如

public ActionResult Edit(intId)
{
...
}

[HttpPost]
public ActionResult Edit(EditViewModel model)
{
...
}

因此,将HttpPost方法标记为可以轻松命名方法。在你给出的例子中,只有一个AddToCart方法,所以可能没有必要区分。