0

I have two nearly identical scenarios regarding model binding on a controller action. One works, and one doesn't. I can't figure out why.

This works:

Given this ViewModel class:

Public Class SeasonCreateViewModel
    Public Property Season As Season
End Class

We have these actions

Function Create() As ActionResult
    Dim seasonVM As New SeasonCreateViewModel()
    Return View("Create", seasonVM)
End Function

<HttpPost()>
<ValidateAntiForgeryToken()>
Function Create(seasonVM As SeasonCreateViewModel) As ActionResult
End Function

And everything binds perfectly. seasonVM.Season contains the values posted from the form.

HOWEVER, this doesn't work:

Given this ViewModel class:

 Public Class UserCreateViewModel    
        Public UserPerson As UserPersonModel
 End Class

And these actions:

    Function Create() As ActionResult
        Dim userVM As New UserCreateViewModel()
        Return View("Create", userVM)
    End Function

    '
    ' POST: /Admin/User/Create

    <HttpPost()>
    <ValidateAntiForgeryToken()>
    Function Create(userVM As UserCreateViewModel) As ActionResult
    End Function

userVM.UserPerson does not bind to the form values the same way seasonVM.Season does. In fact, it is Nothing (aka. null)

Does anyone have any ideas?

If you're curious about the views, they are structured identically, as in:

@Using Html.BeginForm()
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(True)
        <div class="editor-label">
            @Html.LabelFor(Function(model) model.UserPerson.NewUsername)
        </div>
        <div class="editor-field">
            @Html.EditorFor(Function(model) model.UserPerson.NewUsername)
            @Html.ValidationMessageFor(Function(model) model.UserPerson.NewUsername)
        </div>
<p>
            <input type="submit" value="Create" />
        </p>
End Using

AND

@Using Html.BeginForm()
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(True)
        <div class="editor-label">
            @Html.LabelFor(Function(model) model.Season.SeasonDescription)
        </div>
        <div class="editor-field">
            @Html.EditorFor(Function(model) model.Season.SeasonDescription)
            @Html.ValidationMessageFor(Function(model) model.Season.SeasonDescription)
        </div>
<p>
            <input type="submit" value="Create" />
        </p>
End Using

Just a note: I've omitted irrelevant code, mostly just additional properties on the view pages. I will say there is no property named "userVM" on my UserPersonModel as was the case here: Model is null when form submitted

UPDATE

OK. I think I'm about ready to give up on figuring out why Season is binding properly, but UserPerson is not.

I thought I had figured out the answer, but it didn't seem to actually make a difference:

I have

Public Class SeasonCreateViewModel
    Public Property Season As Season
End Class

and I have

Public Class UserCreateViewModel    
    Public UserPerson As UserPersonModel
End Class

When lined up like this, the difference seems obvious. In SeasonCreateViewModel, I have a property Season identically named to the class it is an instance of (Season). In UserCreateViewModel, I have a property UserPerson, which is named slightly differently from its class UserPersonModel. Because of this, I thought the model binder does not automatically match userVM.UserPerson to its corresponding class.

So I changed the class UserPersonModel to UserPerson so the Form values would match up in the same way they do for Season (ie, to the classname), but it STILL did not fix it.

What does fix it, however, is if I change this:

Function Create(userVM As UserCreateViewModel) As ActionResult

to this

Function Create(userPerson As UserPerson) As ActionResult

Why this suddenly binds properly, where it didn't before? I have no idea. Does this help anyone answer this question, though?

2
  • Have you tried to use fully qualified namespaces? Sometimes the problem lies within there. Commented Feb 14, 2013 at 20:51
  • Can you elaborate on that, Dillie-O? I am using fully qualified namespaces, and are being referenced consistently between the Season and UserPerson code. Commented Feb 14, 2013 at 21:05

2 Answers 2

0

As I understand it, you are not creating a new instance of UserPersonModel. I could be very wrong though :)

Public Class UserCreateViewModel    
    Public UserPerson As UserPersonModel
End Class

I think in your action, you should do something like:

Function Create() As ActionResult
    Dim userVM As New UserCreateViewModel()

    //userVM.UserPerson = new UserPersonModel() -- in c#
    //userVM.UserPerson As New UserPersonModel() -- in VB?

    Return View("Create", userVM)
End Function

Or just ignore this answer :P

Sign up to request clarification or add additional context in comments.

Comments

0

I've ran into this before and the answer is not at all obvious, but makes sense after you know. If you bind an entire model (rather than a static type), then every single member of that model must be posted in the form, otherwise, the modelbinder doesn't recognize the posted values as an instance of the model.

If you don't want to post every member, but rather just a subset, then you need to create a view model with just the fields you want to post, and use something like AutoMapper or just manually map the fields on the actual model in your POST action.

3 Comments

But I am posting every single member of the model, in both UserPerson and Season. And it's working with Season but not UserPerson. Or are you seeing something I'm not, maybe (hopefully)?
Are you sure? You didn't post the definition of UserPerson, and that's specifically what I'm talking about here - not the view model that wraps it currently, UserPersonModel. Is NewUsername really the only member of that class?
in my SeasonCreateViewModel there is a Season property. When I post this, I do not provide values for all properties available in Season, yet it works perfectly well - it binds and everything. However, I am supplying every property of UserPerson when I post the UserCreateViewModel, but it isn't binding properly. It makes no sense. Which makes me think it's something bizarre or trivial I'm missing, and not actually related to model binding somehow.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.