Reputation: 41
I've been learning MVC 3 rapidly over the last couple weeks but something's come up that I just haven't been able to solve searching for hours. I'm developing a simple shopping cart and I'm trying to pass data in a linear path through the checkout process. I've been unable to get a model to POST to the next view no matter what I try.
To start with, the 'Cart' entity is being pulled from Session using an implementation of IModelBinder. It's essentially available for any method. It's been working great for a while. My issue is trying to pass the same model between /cart/confirm and /cart/checkout.
Can someone help figure out why the model is always empty in the controller for /cart/checkout?
public class CartController : Controller
{
public ActionResult Index (Cart cart)
{
//Works fine, anonymous access to the cart
return View(cart);
}
[Authorize]
public ActionResult Confirm (Cart cart)
{
//Turn 'Cart' from session (IModelBinder) into a 'Entities.OrderDetail'
OrderDetail orderDetail = new OrderDetail();
orderDetail.SubTotal = cart.ComputeTotalValue();
...
...
return View(orderDetail);
}
[Authorize]
public ActionResult Checkout(OrderDetail model)
{
//PROBLEM: model is always null here.
}
}
/Views/Cart/Index.aspx looks like this (sorry, no Razor):
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site-1-Panel.Master" Inherits="System.Web.Mvc.ViewPage<My.Namespace.Entities.Cart>" %>
...
...
<% using(Html.BeginForm("confirm", "cart")) { %>
Not much to see here, just a table with the cart line items
<input type="submit" value="Check Out" />
<% } %>
I suspect the problem is here, but I've tried every variation of Html.BeginForm() I can try and can't get the model to pass to /cart/checkout. Anyway, /Views/Cart/Confirm.aspx looks like this:
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site-1-Panel.Master" Inherits="System.Web.Mvc.ViewPage<My.Namespace.Entities.OrderDetail>" %>
...
...
<% using (Html.BeginForm("checkout", "cart", Model)) { %>
<%: Model.DBUserDetail.FName %>
<%: Model.DBUserDetail.LName %>
<%: Html.HiddenFor(m => m.DBOrder.ShippingMethod, new { @value = "UPS Ground" })%>
<%: Html.HiddenFor(m => m.DBOrder.ShippingAmount, new { @value = "29.60" })%>
...
...
<input type="submit" value="Confirm & Pay" />
<% } %>
And finally /Views/Cart/Checkout.aspx looks like this:
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site-1-Panel.Master" Inherits="System.Web.Mvc.ViewPage<My.Namespace.Entities.OrderDetail>" %>
...
...
<%: Html.Hidden("x_first_name", Model.DBUserDetail.FName) %>
<%: Html.Hidden("x_last_name", Model.DBUserDetail.LName) %>
...
It doesn't really matter what's here, an exception gets throw in the controller because the model is always null
Upvotes: 1
Views: 2797
Reputation: 17818
Most likely your model state is invalid. Add this extension method and call it on the first line of the action like:
ModelState.DumpErrors();
Put a breakpoint one line after it and examine the Output window for more information about what is wrong with the binding.
Edit - The full extension method:
public static class ModelExtensions
{
public static void DumpErrors(this System.Web.Mvc.ModelStateDictionary ModelState)
{
var errors = from key in ModelState
let errorList = ModelState[key.Key].Errors
where errorList.Any()
select new
{
Item = key.Key,
Value = key.Value,
errorList
};
foreach (var errorList in errors)
{
System.Diagnostics.Debug.WriteLine("MODEL ERROR:");
System.Diagnostics.Debug.WriteLine(errorList.Item);
System.Diagnostics.Debug.WriteLine(errorList.Value);
foreach (var error in errorList.errorList)
{
System.Diagnostics.Debug.WriteLine(error.ErrorMessage);
System.Diagnostics.Debug.WriteLine(error.Exception);
}
System.Diagnostics.Debug.WriteLine("-----");
}
}
}
Upvotes: 3
Reputation: 156
I don't know asp specifically, but it seems like you have access to cart in index and confirm b/c you are passing it explicitly. Since you are not passing it to checkout, you would not be able to access it. I might be totally off
Upvotes: 0