Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strongly typed ViewModel in POST action method contains only null values

Tags:

asp.net-mvc

I am trying to implement my Edit action methods with strongly typed view which receives a custom-shaped ViewModel class. In other words, I want a strongly typed ViewModel which contains the Linq entity that should be edited plus a few other objects that should be displayed in the View.

I can see the view when calling the GET Edit action method, but the strongly typed POST action method receives only a ViewModel class with null parameters and I can't figure out how to retrieve the POST parameters.

The View Model looks as follows:

//my custom-shaped ViewModel
public class CustomersFormViewModel
{
    public SelectList AccountTypesDropDownBox;
    public SelectList CountriesDropDownBox;
    public Customer Customer;
}

The action method looks as follows:

//
// GET: /CustomersController/Edit   

public ActionResult Edit(int ID)
{
   var model = new CustomersFormViewModel
                    {
                        Customer = repository.Load(ID.Value),
                        CountriesDropDownBox = GetCountries(),
                        AccountTypesDropDownBox = GetAccountTypes()
                    };
    return View(model);
}

//
// POST: /CustomersController/Edit  

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(CustomersFormViewModel model)
{
    //THE NEXT LINE THROWS!!!
    Debug.Assert(Model.Customer!=null);
    return View(model);
}

And this is my Edit view:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/CustAdminMaster.master"
    Inherits="System.Web.Mvc.ViewPage<Zeiterfassung.Controllers.CustomersController+CustomersFormViewModel>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    NewEdit
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <h2>
        NewEdit</h2>
    <%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %>
    <% using (Html.BeginForm())
       {%>
    <fieldset>
        <legend>Fields</legend>
        <p>
            <label for="FirstName">FirstName:</label>
            <%= Html.TextBox("FirstName",Model.Customer.FirstName) %>
            <%= Html.ValidationMessage("FirstName", "*") %>
        </p>
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
    <% } %>
    <div>
        <%=Html.ActionLink("Back to List", "Index") %>
    </div>
</asp:Content>

I've also tried a POST action method with formValues parameters, but the the viewmodel still did not contain the posted parameters:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int ID, FormCollection formValues)
{
      CustomersFormViewModel model = new CustomersFormViewModel();            
      UpdateModel(model);
      //THE NEXT LINE STILL THROWS
      Debug.Assert(model.Customer!=null);
      return View("NewEdit",model);
}

The only way I have found so far is to write my own code that grab the posted parameters from the FormCollection and updates my custom ViewModel accordingly. But this approach seems a bit primitive. Is there really no better way to do this?

EDIT: I've just tried a different syntax in the view as tvanfosson suggested, but the problem remains unchanged:

<label for="Customer.FirstName">FirstName:</label>
    <%= Html.TextBox("Customer.FirstName") %>
    <%= Html.ValidationMessage("Customer.FirstName", "*") %>
like image 841
Adrian Grigore Avatar asked Apr 14 '09 16:04

Adrian Grigore


2 Answers

You need to name your fields in accordance with the prefixes in the model. In addition, you will need to modify your view model to use properties instead of fields. The default model binder only looks at the public properties on the model when binding.

    <label for="Customer.FirstName">FirstName:</label>
    <%= Html.TextBox("Customer.FirstName") %>
    <%= Html.ValidationMessage("Customer.FirstName", "*") %>

That way it the model binder knows how to associate the form parameter with the appropriate component and associated property of your model.

like image 170
tvanfosson Avatar answered Sep 27 '22 15:09

tvanfosson


Its been a while but there really hasn't been an answer on this one.

Was tampering with the same problem until I catched the auto property on my viewmodel having a private set.

Looking to your viewmodel you are missing the auto properties get and setters all together!

So change your viewmodel accordingly:

public class CustomersFormViewModel

    {
        public SelectList AccountTypesDropDownBox {get; set;}
        public SelectList CountriesDropDownBox {get; set;}
        public Customer Customer {get; set;}
    }
like image 39
Ithai Avatar answered Sep 27 '22 15:09

Ithai