0

在 HttpPost 上的验证失败后,我的 ViewModel 没有得到适当的补水,导致在重新显示视图时,'CartItems' 上出现“对象引用未设置为对象的实例”错误。

如何重新水化我的 ViewModel 以便它可以重新显示错误消息?

我曾尝试使用@Html.HiddenFor(...)来保留未显示的值(根据此答案),但这不起作用。

视图模型

    public class CheckoutViewModel
    {
        public List<Cart> CartItems { get; set; }
        [DisplayFormat(DataFormatString = "${0:F2}")]
        public double CartTotal { get; set; }
        public virtual Order Order { get; set; }
    }

控制器 GET:ActionResult

    //GET: /Checkout/AddressAndPayment
    public ActionResult AddressAndPayment()
    {
        var order = new Order();
        order.Username = User.Identity.Name;
        MembershipUser currentUser = Membership.GetUser(User.Identity.Name, true /* userIsOnline */);
        storeDB.SaveChanges();

        var cart = ShoppingCart.GetCart(this.HttpContext);

        // Set up the ViewModel
        var viewModel = new CheckoutViewModel
        {
            CartItems = cart.GetCartItems(),
            CartTotal = cart.GetTotal(),
            Order = order
        };

        // Return the view
        return View(viewModel);
    }

控制器 POST:ActionResult

    [HttpPost]
    public ActionResult AddressAndPayment(CheckoutViewModel checkoutViewModel)
    {
        TryValidateModel(checkoutViewModel);
        try
        {
            checkoutViewModel.Order.Username = User.Identity.Name;
            checkoutViewModel.Order.OrderDate = DateTime.Now;
            storeDB.Orders.Add(checkoutViewModel.Order);

            // Error occurs on the following line if a custom data annotation validation attribute fails
            storeDB.SaveChanges();

            var cart = ShoppingCart.GetCart(this.HttpContext);
            cart.CreateOrder(checkoutViewModel.Order);
            storeDB.SaveChanges();

            return RedirectToAction("Complete", new { id = checkoutViewModel.Order.OrderID });
        }
        catch
        {
            //Invalid - redisplay with errors
            return View(checkoutViewModel);
        }
    }

编辑#1
@SoWeLie 告诉我,我已经解决了这个问题。
为了在将 ViewModel 中的 cartItem 重新水化,然后将其传递回 View,我将以下代码添加到了 HttpPost ActionResult 的 catch 块中。这段代码基本上调用了命中数据库的方法来获取购物车的必要信息:

catch
        {
            //Invalid - redisplay with errors
            //The model is not valid, we need to redisplay the same view so that the user can fix the errors => fetch the cartItems
             var cart = ShoppingCart.GetCart(this.HttpContext);
             checkoutViewModel.CartItems = cart.GetCartItems();
             checkoutViewModel.CartTotal = cart.GetTotal();

            return View(checkoutViewModel);
        }
4

1 回答 1

2

您不希望在隐藏字段中保留整个对象,例如 CartItem 列表。试图将所有数据作为帖子值携带是低效且难以维护的。您的购物车对象需要保存在应用程序中的某个位置,例如数据库。您还可以将购物车存储在用户的会话中。

完成此操作的最佳方法是将用户的购物车保存在数据库中。有多种方法可以做到这一点。在不知道您的数据库模型的情况下,最简单的解决方案是将购物车及其项目添加到数据库中,然后获取购物车 ID 并将其存储在会话或 cookie 中(取决于您希望购物车保留多长时间)。

于 2012-05-09T01:11:12.150 回答