Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.8k views
in Technique[技术] by (71.8m points)

asp.net mvc - The parameter conversion from type 'System.String' to type 'T' failed because no type converter can convert between these types

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

A RedirectToAction is simply a HTTP 302 redirect. Are you sure you need the browser to re-request a new page?

For instance do you want to avoid a page reload from triggerring a "resubmit post data" dialog? (see POST-REDIRECT-GET pattern)

Why not just use:

public ActionResult Filter(FormCollection formParams) 
{
   return Search(new SearchViewModel{
     Term = formParams["Term"], 
     Filters =  
       formParams.Keys 
                .Cast<String>() 
                .Where(k => k.Contains("filter")) 
                .Select(k => Filter.Build(k, formParams[k])) 
                .ToList()                         
    });                                         
} 

Alternatively you could use TempData to store the state between requests, or possibly client side cookies if suitable.

If you want the Search results page to be bookmarkable in a users browser you'll need to represent the search parameter's state in the URL using REST or some form of serilaised string (eg. JSON)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...