6

I hope I'm not missing something incredibly obvious here but is there any reason why model binder is always having trouble binding a view model that inherits from a collection?

Lets say I want to show a paged list and display a combo box and add button above it (dealing with simple lists). Involved classes would look like:

public class PagedList<T> : List<T>
{
    public int TotalCount { get; set; }
}

And then a view model that looks like:

public class MyViewModel : PagedList<ConcreteModel>
{
    public IEnumerable<ChildModel> List { get; set; }
    public int? SelectedChildModelId { get; set; }
}

So in the view (Razor):

@model MyViewModel 
@using (Html.BeginForm())
{
    @Html.DropDownListFor(model => model.SelectedChildModelId, new SelectList(Model.List, "ChildModelId", "DisplayName"))
}

And the controller HttpPost action:

public ActionResult(MyViewModel viewModel)
{
    ...
}

The above will cause viewModel in ActionResult to be null. Is there a logical explanation for it? From what I can tell it's specific only to view models that inherit from collections.

I know I can get around it with custom binder but the properties involved are primitive types and there isn't even any generics or inheritance.

I've reworked the view models to have the collection inherited type as properties and that fixes the issue. However I'm still scratching my head over why the binder breaks down on it. Any constructive thoughts appreciated.

Mark Bell
  • 28,985
  • 26
  • 118
  • 145
Ales Potocnik Hahonina
  • 2,977
  • 2
  • 26
  • 32
  • I've so far stuck to the view models declaring a property with collection inherited type instead on inheriting from one since no other viable solution could be found. The only issue I have with this approach is it complicates things for AutoMapper since the property now has to be explicitly set instead of being auto-mapped. – Ales Potocnik Hahonina Jun 24 '11 at 14:09
  • The answer at [Stack Overlow](http://stackoverflow.com/questions/5762302/why-cant-my-views-model-bind-with-my-generic-viewmodel-which-implements-an-inte) looks promising. Hmmm, Covariants - never used that before – Ales Potocnik Hahonina Jun 29 '11 at 10:24

2 Answers2

1

To answer my own question: All my models that have anything to do with collections no longer inherit from generic list or similar but instead have a property of the required collection type. This works much better because when rendering you can use

@Html.EditorFor(m => m.CollectionProperty)

And create a custom editor under Views/Shared/EditorTemplates for contained type. It also works beautifully with model binder since all individual items from collection get a index and the binder is able to auto bind it when submitted.

Lesson learned: if you plan to use models in views, don't inherit from collection types.

Ales Potocnik Hahonina
  • 2,977
  • 2
  • 26
  • 32
0

Sometimes model binding to a collection works better if the data in the form post is formatted differently.

I use a plugin called postify.

http://www.nickriggs.com/posts/post-complex-javascript-objects-to-asp-net-mvc-controllers/

Devin Garner
  • 1,361
  • 9
  • 20
  • 1
    Thanks Devin. Certainly an interesting plugin but in this case it has nothing do do with javascript. Typically I want all my web apps to work without JavaScript and only use it as enhancement. In this case it's a matter of MVC3 supplied binders not knowing how to work with collection model posts. What I was looking for is a way to structure the view model or inherit from correct base collection is that it is bound correctly. – Ales Potocnik Hahonina Jul 15 '11 at 07:29