Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing an array to RouteValues and have it render model binder-friendly url

When passing a RouteValueDicitonary or anonymous object into a @Url.Action method (or any of its analogs), is there a way to properly pass in a collection object or IEnumerable so that it would generate a url that would be compatible with the default model binder?

For example, say I have an action like this:

public ActionResult Index(ICollection<int> ids)
  {
    ...do something
  }

and in my template I do something like this:

@Url.Action("Index", routeValues:new int[]{1,2,3})

the goal is to have a url output like this:

... /index?ids=1&ids=2&ids=3

but the url output is actually something like this:

... /index?ids=System.Int[]

I'm assuming there is no support for this currently. If not, then at what part in MVC do I need to create a custom handler or whatever to override this default functionality?

like image 498
DMac the Destroyer Avatar asked Dec 05 '11 19:12

DMac the Destroyer


3 Answers

Unfortunately currently there is no existing helper that will allow you to generate such url. So one possibility is to do it manually:

@(Url.Action("Index") + "?" + string.Join("&", new int[] { 1, 2, 3 }.Select(x => "ids=" + x)))

or write an extension method to encapsulate the logic:

@Url.ActionWithIds("Index", new int[] { 1, 2, 3 })

Since those are integers we don't need url encoding but if you want to do the same thing with a collection of strings the values should be properly url encoded.

like image 159
Darin Dimitrov Avatar answered Nov 12 '22 22:11

Darin Dimitrov


Pass each element of the array to a RouteValueDictionary using the model binding syntax for round trip purposes.

int i = 0;
var temprvd = arr.ToDictionary(m => String.Format("name[{0}]", i++), m => (object) m);
@Url.Action("index", new RouteValueDictionary(temprvd));

or concat on to an existing route value dictionary.

Cast the value to an object (as shown above) to ensure the correct RouteValueDictionary constructor overload is used.

like image 25
Gerard ONeill Avatar answered Nov 12 '22 22:11

Gerard ONeill


For use the default model binder, you should end up with something like :

?ids=1&ids=2&ids=3

you can returns a private collection named HttpValueCollection even the documentation says it's a NameValueCollection using the ParseQueryString utility. Then add the keys manually, HttpValueCollection do the encoding for you. And then just append the QueryString manually :

var qs = HttpUtility.ParseQueryString(""); 
new List<int> { 1, 2, 3, 4, 5 }.ForEach(x => qs.Add("ids", x.ToString()));

@Url.Action("Index")?@qs
like image 1
Bart Calixto Avatar answered Nov 12 '22 22:11

Bart Calixto