Snake Eyes
Snake Eyes

Reputation: 16764

Extending Html.BeginForm renders wrong url in ASP.NET MVC

I have the following helpers:

public static MvcForm BeginFormEx(this HtmlHelper htmlHelper, string actionName, string controllerName, FormMethod method, object htmlAttributes)
{
  return htmlHelper.BeginForm(actionName, controllerName, new { environment = "test" }, method, htmlAttributes);
}

public static MvcForm BeginFormEx(this HtmlHelper htmlHelper, string actionName, string controllerName, RouteValueDictionary routeValues, FormMethod method, object htmlAttributes)
{
  if (routeValues == null)
  {
    return htmlHelper.BeginFormEx(actionName, controllerName, method, htmlAttributes);
  }

  routeValues["environment"] = "test";
  return htmlHelper.BeginForm(actionName, controllerName, routeValues, method, htmlAttributes);
}

public static MvcForm BeginFormEx(this HtmlHelper htmlHelper, string actionName, string controllerName, object routeValues, FormMethod method, object htmlAttributes)
{
  if (routeValues == null)
  {
    return htmlHelper.BeginFormEx(actionName, controllerName, method, htmlAttributes);
  }

  return htmlHelper.BeginFormEx(actionName, controllerName, new RouteValueDictionary(routeValues), method, htmlAttributes);
}

I call it like:

@using (Html.BeginFormEx("myAction", "myController", new { returnUrl = ... }, FormMethod.Post, new { role = "form" }))

It renders form like:

<form action="/myController/myAction?Count=2&amp;Keys=System.Collections.Generic.Dictionary%602%2BKeyCollection%5BSystem.String%2CSystem.Object%5D&amp;Values=System.Collections.Generic.Dictionary%602%2BValueCollection%5BSystem.String%2CSystem.Object%5D" method="post" role="form">

Why ?

I expected to get

<form action="/myController/myAction?returnUrl=...&environment=test" ... >

Why is not working ?

If use

@using(Html.BeginForm(.., ..., new { environment = "test" }, ....)

it works fine. Only if is called as extension is not working.

Also works fine if

@using (Html.BeginFormEx("myAction", "myController", null, FormMethod.Post, new { role = "form" }))

Seems that not working the extending/adding new property to already existing routeValues. How to fix that ?

I made similar with ActionLink and it works fine, I mean that I see environment in query string.

Upvotes: 0

Views: 318

Answers (1)

GSerg
GSerg

Reputation: 78185

The

return htmlHelper.BeginForm(actionName, controllerName, routeValues, method, htmlAttributes);

calls the (HtmlHelper, String, String, Object, FormMethod, Object) overload, passing the RouteValueDictionary routeValues for object routeValues, which serializes the properties of the dictionary as if it was an anonymous object.

There isn't an overload of BeginForm that accepts RouteValueDictionary routeValues and object htmlAttributes at the same time. It's either object+object or Dictionary+Dictionary.

You can make a dictionary out of your object htmlAttributes to end up calling the right overload:

routeValues["environment"] = "test";
return htmlHelper.BeginForm(actionName, controllerName, routeValues, method, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));

Upvotes: 1

Related Questions