12

Say I have an action method:

[HttpGet]
public ActionResult Search(List<int> category){
    ...
}

The way the MVC model binding works, it expects a list of category like this:

/search?category=1&category=2

So my questions are:

How do I create that link using Url.Action() if I just hardcode it?

Url.Action("Search", new {category=???}) //Expect: /search?category=1&category=2

How do I create that link using Url.Action() if my input is a list of int?

var categories = new List<int>(){1,2}; //Expect: /search?category=1&category=2

Url.Action("Search", new {category=categories}) //does not work, 
1

4 Answers 4

20

Instead of using an Anonymous Type, build a RouteValueDictionary. Format the parameters as parameter[index].

@{
    var categories = new List<int>() { 6, 7 };

    var parameters = new RouteValueDictionary();

    for (int i = 0; i < categories.Count; ++i)
    {
        parameters.Add("category[" + i + "]", categories[i]);
    }
}

Then,

@Url.Action("Test", parameters)
Sign up to request clarification or add additional context in comments.

4 Comments

It works, but it's not HTML form compatible, and adds unnecessary complexity to the querystring.
I can confirm this works. @MaxToro: Can you elaborate on those two statements?
@Kjensen e.g. you have a checkbox list to select categories, the default HTML behavior is to send category=val1&category=val2 and not category[1]=val1&category[2]=val2, unless you name the checkboxes like that, and that's the unnecessary complexity.
the baove solution is not working for me, can you please help me out
3

Build the querystring yourself, it's evident that UrlHelper was not designed for this use case.

Using:

   static class QueryStringBuilder {

      public static string ToQueryString(this NameValueCollection qs) {
         return ToQueryString(qs, includeDelimiter: false);
      }

      public static string ToQueryString(this NameValueCollection qs, bool includeDelimiter) {

         var sb = new StringBuilder();

         for (int i = 0; i < qs.AllKeys.Length; i++) {

            string key = qs.AllKeys[i];
            string[] values = qs.GetValues(key);

            if (values != null) {
               for (int j = 0; j < values.Length; j++) {

                  if (sb.Length > 0)
                     sb.Append('&');

                  sb.Append(HttpUtility.UrlEncode(key))
                     .Append('=')
                     .Append(HttpUtility.UrlEncode(values[j]));
               }
            }
         }

         if (includeDelimiter && sb.Length > 0)
            sb.Insert(0, '?');

         return sb.ToString();
      }
   }

You can write this:

var parameters = new NameValueCollection {
  { "category", "1" },
  { "category", "2" }
};

var url = Url.Action("Search") + parameters.ToQueryString(includeDelimiter: true);

Comments

1

Instead Type Casting to “object” or “object[]” or using RouteValueDictionary. A simple way to achieve the same is using “Newtonsoft.Json”

If using .Net Core 3.0 or later;

Default to using the built in System.Text.Json parser implementation.

@using System.Text.Json;

…….

@Url.Action(“ActionName”, “ControllerName”, new {object = JsonConvert.SerializeObject(‘@ModalObject’)  }))

If stuck using .Net Core 2.2 or earlier;

Default to using Newtonsoft JSON.Net as your first choice JSON Parser.

@using Newtonsoft.Json;

…..

@Url.Action(“ActionName”, “ControllerName”, new {object = JsonConvert.SerializeObject(‘@ModalObject’)  }))

you may need to install the package first.

PM> Install-Package Newtonsoft.Json

Then,

public ActionResult ActionName(string modalObjectJSON)
{
    Modal modalObj = new Modal();
    modalObj = JsonConvert.DeserializeObject<Modal>(modalObjectJSON);

}

Comments

-2

It´s not the best way but you can Join the category list with your QueryString parameter name.

@Url.Action("Search", new {category = string.Join("&category=", categories)});

1 Comment

This does not work because the '&' and '=' are url encoded. The end result looks like: /Search?category=category1%26category%3Dcategory2 rather than: /Search?category=category1&category=category2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.