Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to work with RouteValues with multiple values of the same name

In my ASP.NET MVC 4 application I can filter on multiple tags. In HTML, it looks like this:

<form>
  <label>
    <input type="checkbox" name="tag" value="1">One
  </label>
  <label>
    <input type="checkbox" name="tag" value="2">Two
  </label>
  <label>
    <input type="checkbox" name="tag" value="3">Three
  </label>
  <input type="submit" name="action" value="Filter">
</form>

When checking the first and third checkbox, the querystring is serialized as ?tag=1&tag=3 and my controller nicely passes an object with the type of the following class:

// Filter class
public class Filter { 
    public ICollection<int> tag { get; set; }
}

// Controller method
public ActionResult Index(AdFilter filter)
{
    string url = Url.Action("DoFilter", filter);
    // url gets this value:
    // "/controller/Index?tag=System.Collections.Generic.List%601%5BSystem.Int32%5D"
    // I would expect this:
    // "/controller/Index?tag=1&tag=3"
    ...
 }

However, a call to Url.Action results in the typename of the collection being serialized, instead of the actual values.

How can this be done?


The standard infrastructure of MVC can handle the multi-keys described as input. Is there not standard infrastructure that can handle it the other way around? Am I missing something?

like image 268
doekman Avatar asked Oct 19 '25 15:10

doekman


2 Answers

You can do it in the following way:

string url = Url.Action("DoFilter", TypeHelper2.ObjectToDictionary(filter) );

The TypeHelper2.ObjectToDictionary is a modified version of an internal method of .NET, and can be found in this two file gist.

Changed behavior: when an item implements IEnumerable, for each item an entry is created in the returned dictionary with as key "Name[index]" (the index is 0 based). This is possible because the binder of the MVC controller can handle both tag=1&tag=3 and tag[0]=1&tag[1]=3 query strings.

like image 89
Joanvo Avatar answered Oct 22 '25 04:10

Joanvo


An easy yet no so elegant solution can be:

  public ActionResult Index(AdFilter filter)
  {
     string parameters = "?";
     foreach (var item in filter.tag)
        {
            parameters += string.Format("tag={0}&", item);
        }
     //trimming the last "&"
     parameters = parameters.TrimEnd(parameters[parameters.Length - 1]);
     string url = Url.Action("DoFilter") + parameters;

  }
like image 20
Ziv Weissman Avatar answered Oct 22 '25 05:10

Ziv Weissman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!