Add query string as route value dictionary to ActionLink

I’m trying to create an ActionLink to export data from a grid. The grid is filtered by values from the query string. Here’s an example of the url:

http://www.mysite.com/GridPage?Column=Name&Direction=Ascending&searchName=text

Here’s the code to add my ActionLink to the page:

@Html.ActionLink("Export to Excel",    // link text
    "Export",                          // action name
    "GridPage",                        // controller name
    Request.QueryString.ToRouteDic(),  // route values
    new { @class = "export"})          // html attributes

When the link is displayed, the url is this:

http://www.mysite.com/GridPage/Export?Count=3&Keys=System.Collections.Generic.Dictionary%602%2BKeyCollection%5BSystem.String%2CSystem.Object%5D&Values=System.Collections.Generic.Dictionary%602%2BValueCollection%5BSystem.String%2CSystem.Object%5D

What am I doing wrong?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Try this:

I’m not sure this is the cleanest or most correct way but it does work

I didn’t use your extension method. You’ll have to reintegrate that:

@{ 
    RouteValueDictionary tRVD = new RouteValueDictionary(ViewContext.RouteData.Values);
    foreach (string key in Request.QueryString.Keys ) 
    { 
        tRVD[key]=Request.QueryString[key].ToString();
    }
}

then

@Html.ActionLink("Export to Excel",    // link text
"Export",                          // action name
"GridPage",                      // controller name
tRVD, 
new Dictionary<string, object> { { "class", "export" } }) // html attributes

Results in

Results

with class exportenter image description here

Method 2

If you look here:
http://msdn.microsoft.com/en-us/library/system.web.mvc.html.linkextensions.actionlink.aspx

//You are currently using:
ActionLink(HtmlHelper, String, String, String, Object, Object)
//You want to be using:
ActionLink(HtmlHelper, String, String, String, RouteValueDictionary, IDictionary<String, Object>)

Method 3

Cross-posting from How do I get the QueryString values into a the RouteValueDictionary using Html.BeginForm()?

Here’s a helper extension so you can dump the querystring in any method accepting a RouteValueDictionary.

/// <summary>
/// Turn the current request's querystring into the appropriate param for <code>Html.BeginForm</code> or <code>Html.ActionLink</code>
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
/// <remarks>
/// See discussions:
/// * https://stackoverflow.com/questions/4675616/how-do-i-get-the-querystring-values-into-a-the-routevaluedictionary-using-html-b
/// * https://stackoverflow.com/questions/6165700/add-query-string-as-route-value-dictionary-to-actionlink
/// </remarks>
public static RouteValueDictionary QueryStringAsRouteValueDictionary(this HtmlHelper html)
{
    // shorthand
    var qs = html.ViewContext.RequestContext.HttpContext.Request.QueryString;

    // because LINQ is the (old) new black
    return qs.AllKeys.Aggregate(new RouteValueDictionary(html.ViewContext.RouteData.Values),
        (rvd, k) => {
            // can't separately add multiple values `?foo=1&foo=2` to dictionary, they'll be combined as `foo=1,2`
            //qs.GetValues(k).ForEach(v => rvd.Add(k, v));
            rvd.Add(k, qs[k]);
            return rvd;
        });
}

Method 4

You can also try CopyTo from System.Collections.Specialized like this:

var queryParams = new Dictionary<string, object>();
Request.QueryString.CopyTo(queryParams);
var routeValueDictionary = new RouteValueDictionary(queryParams);

Method 5

Here is a fixed version that also handles the case where the same key appears several times:

public static RouteValueDictionary QueryStringToRouteValueDictionary(this HtmlHelper html)
{
   var qs = html.ViewContext.RequestContext.HttpContext.Request.QueryString;

   return qs.AllKeys.Aggregate(new RouteValueDictionary(html.ViewContext.RouteData.Values),
    (rvd, k) =>
   {
     // get values
     var values = qs.GetValues(k);
     // if only one value simply add it
     if (values.Length == 1)
     {
       rvd.Add(k, values[0]);
     }
     else
     {
       // an array has to be add using the syntax <k>[<i>] for the key values, where k is the key itself and i is the counter
       for (var i = 0; i < values.Length; ++i)
       {
         rvd.Add($"{k}[{i}]", values[i]);
       }
     }
     return rvd;
  });
}


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x