Help with ModelBinding complex objects in .net

220 views Asked by At

I have a custom modelbinder built to handle my accountRequest class. This class consists of some boolean values and a UserViewModel.

The UserViewModel is made up of strings such as Firstname, Last Name, Address.

Originally I was just passing the UserViewModel as the action parameter but I now I need to package UserViewModel inside of accountRequest.

however, now my modelbinder will not map the strings in the httpContext.Request to my UserViewModel inside of AccountRequest. All of the booleans map just fine.

Is there an easy way to get his data to map to the UserViewModel properties other than hardcoding it?

I have attempted this but I dont like it. (simplified)

Dim accountRequest As New AccountRequest
Dim user As New UserViewModel

If Not String.IsNullOrEmpty(controllerContext.HttpContext.Request("Firstname")) Then
  user.FirstName = controllerContext.HttpContext.Request("Firstname")
End If

accountRequest.CurrentUser = user
Return accountRequest

Obviously any help is greatly appreciated. Thanks in advance!

1

There are 1 answers

0
Andras Zoltan On BEST ANSWER

Sorry - just realised that your code was VB and I've answered in C#

This could be because the model binder is now looking modelname.property instead of just property in the ValueProviders and, previously, because it was a direct action method parameter, it would have just been looking for property.

Now that the model type is a member of another, its property name will be used as a prefix and I don't believe you can remove that requirement (could try Bind(Prefix="") on the parameter, but I don't think that'll work).

This is assuming you aren't custom-binding every property and that the DefaultModelBinder is doing some of these properties for you.

You should be able to make it work, without changing code, by altering your query string to be ?modelname.property=[value]. If you're using a Form, then you should consider using the Html.EditorFor extension method - as it takes care of model naming (so long as your ViewModel member names and input model names are consistent). But as an example from the query string:

public class MyObject{
  public string StringValue { get; set; }
}

public class MyObjectOuter{
  public MyObject Nested { get; set; }
}

public ActionResult Index(MyObjectOuter obj);

The obj.Nested.StringProperty value can be filled with: /Index?Nested.StringValue=hello%20world because the obj prefix is implicit anyway.

If you don't like this, you have a couple of options:

1) Change the signature of the method to take two parameters:

public ActionResult Index(MyObjectOuter outer, MyObject nested)

And then in the body you immediately copy nested to the obj.Nested property. This is a little bit hacky - but it'll work.

2) Manually force the bind of your class' properties to use non-prefixed values from the ValueProviders (but then you're limiting your model type to only work with certain types of request - which isn't exactly flexible).

3) Or, like I said earlier, if these properties are being bound from an Http Form, use Html.EditorFor to generate the markup - it automatically generates inputs with the correct names, so long as they don't change from input->output.