How do I get the QueryString values into a the RouteValueDictionary using Html.BeginForm()?
Asked Answered
K

2

2

I've found that Html.BeginForm() automatically populates the routeValueDictionary with the RawUrl (ie. QueryStringParamters). However I need to specify an HtmlAttribute so I need to use the override...

public static MvcForm BeginForm(this HtmlHelper htmlHelper, string actionName, string controllerName, FormMethod method, object htmlAttributes)

When I do the QueryString values are NOT automatically added to the RouteValueDictionary. How can I accomplish this?

Here is my best attempt but it doesn't seem to be working.

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

       using (Html.BeginForm("Login", "Membership", routeValueDictionary, FormMethod.Post, new { @class = "signin-form" }))
       {%> ...

My Controller Action looks like this...

    [HttpPost]
    public ActionResult Login(Login member, string returnUrl)
    { ...

But the value of "returnUrl" which is part of the QueryString is always NULL unless I use the default parameterless Html.BeginForm() in my View.

Thanks, Justin

Konya answered 13/1, 2011 at 0:35 Comment(3)
You never mentioned returnUrl in your route value dictionary, or you have?Thibaut
The routeValueDictionary variable is suppose to be populated with all the key/value pairs in the Request.QueryString. I can hack it by just using new { returnUrl = Request.QueryString["ReturnUrl"] } but what if there is more than ReturnUrl in the querystring.Konya
What does the <form> tag generated by your code look like? The reason I ask is because in the case that works you might be POSTing to a URL like "mysite.com?returnUrl=foobar"Harpole
P
6

You could write a helper:

public static MvcHtmlString QueryAsHiddenFields(this HtmlHelper htmlHelper)
{
    var result = new StringBuilder();
    var query = htmlHelper.ViewContext.HttpContext.Request.QueryString;
    foreach (string key in query.Keys)
    {
        result.Append(htmlHelper.Hidden(key, query[key]).ToHtmlString());
    }
    return MvcHtmlString.Create(result.ToString());
}

and then:

<% using (Html.BeginForm("Login", "Membership", null, FormMethod.Post, new { @class = "signin-form" })) { %>
    <%= Html.QueryAsHiddenFields() %>
<% } %>
Pubilis answered 13/1, 2011 at 7:54 Comment(0)
W
3

Inspecting the source code for Html.BeginForm() at http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/Html/FormExtensions.cs doesn't help too much, but it shows the reason the parameterless method does what you want -- it's literally setting the formAction from the request url.

If you'd rather have the querystring remain as the querystring, rather than potentially be part of a POST, here's an alternative extension:

/// <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://mcmap.net/q/1013555/-how-do-i-get-the-querystring-values-into-a-the-routevaluedictionary-using-html-beginform
/// * https://mcmap.net/q/959323/-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;
        });
}
Weakwilled answered 23/10, 2014 at 16:42 Comment(2)
Your code still turns duplicate keys into comma separated lists - did you mean to prevent that? It's not 100% clear from your comment.Brahear
@Brahear my comment meant I was unable to figure out how to prevent adding them as comma-separated values, because the RouteValueDictionary is a dictionary and so can't have duplicate keysWeakwilled

© 2022 - 2024 — McMap. All rights reserved.