MVC3 Razor model binder and inherited collections
Asked Answered
C

2

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.

Catalepsy answered 21/6, 2011 at 15:17 Comment(2)
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.Catalepsy
The answer at Stack Overlow looks promising. Hmmm, Covariants - never used that beforeCatalepsy
C
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.

Catalepsy answered 5/12, 2011 at 11:41 Comment(0)
C
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/

Carillo answered 14/7, 2011 at 5:42 Comment(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.Catalepsy

© 2022 - 2024 — McMap. All rights reserved.