NOTE: All of the code here is paraphrased as an example, as I can't show real code.
I have a view model class that looks something like
public SearchViewModel
{
public string Term
{
get; set;
}
public SearchResult Result
{
get; set;
}
public List<Filter> Filters
{
get; set;
}
}
This is bound to a regular controller and everything works fine:
public ActionResult Search (SearchViewModel model)
{
if (ModelState.IsValid)
{
model.Result = _searchService.Search(model.Term);
return View(model);
}
}
I also have another action that handles taking in a POST from a form that contains checkboxes. This controller handles creating Filter classes and redirects to the Search action.
Something like:
public ActionResult Filter(FormCollection formParams)
{
return RedirectToAction("Search", new SearchViewModel
{
Term = formParams["Term"],
Filters =
formParams.Keys
.Cast<String>()
.Where(k => k.Contains("filter"))
.Select(k => Filter.Build(k, formParams[k]))
.ToList()
});
}
This passes a ViewModel with the List collection populated back to the Search action.
However, in the search action, ModelState.IsValid now returns false. This is because the model binder throws this exception:
The parameter conversion from type
'System.String' to type 'Filter'
failed because no type converter can
convert between these types.
Looking at the raw value in ModelState for "Filters" shows that is a string:
System.Collections.Generic.List`1[Filter]
It seems like the actual contents of the List is lost during the transition between actions, likely because it only called ToString() on the property members.
At this point, I have a vague idea of why this is failing, and I figure I could write a custom model binder or type converters to make it work, however, I have a feeling that this approach smells, and this is probably something that is trivial, I'm just approaching it wrong.
So, what is the proper ASP.NET MVC 3 to pass a collection of complex types from one action to another?
See Question&Answers more detail:
os