I have the following HtmlHelper
method that I want to create a button that does a redirect with JavaScript:
public static string JavaScriptButton(this HtmlHelper helper, string value,
string action, string controller, object routeValues = null, object htmlAttributes = null)
{
var a = (new UrlHelper(helper.ViewContext.RequestContext))
.Action(action, controller, routeValues);
var builder = new TagBuilder("input");
builder.Attributes.Add("type", "submit");
builder.Attributes.Add("value", value);
builder.Attributes.Add("class", "button");
builder.Attributes.Add("onclick", string.Format("javascript:location.href='{0}'", a));
builder.MergeAttributes(new RouteValueDictionary(htmlAttributes));
return MvcHtmlString.Create(builder.ToString(TagRenderMode.SelfClosing)).ToString();
}
The problem is that the line that creates the onclick handler is getting escaped by the tagbuilder, the resulting html is:
<input class="button" onclick="javascript:location.href=''" type="submit" value="Return to All Audits" />
Is there anyway I can stop this behaviour?
This is actually an issue with .NET 4.0. To fix it you need to override the attribute encoding process.
public class HtmlAttributeNoEncoding : System.Web.Util.HttpEncoder
{
protected override void HtmlAttributeEncode(string value, System.IO.TextWriter output)
{
output.Write(value);
}
}
Then put this in your web.config file under the <system.web>
element:
<httpRuntime encoderType="HtmlAttributeNoEncoding"/>
I found this here.
While the solution provided by Ryan may work, it is a little like using a hammer to swat a fly.
The issue is that TagBuilder encodes strings during calls to MergeAttributes(). For the required Javascript in a button link this affects single quotes and spaces.
The last step of the required extension method is the return of an MvcHtmlString
(which receives no further encoding), so it is perfectly reasonable to make some simple text corrections to the string (to undo the encoding) before creating that object.
return new MvcHtmlString(tb.ToString(TagRenderMode.Normal).Replace("'", "\'").Replace(" "," "));
public static class ActionLinkButtonHelper
{
public static MvcHtmlString ActionLinkButton(this HtmlHelper htmlHelper, string buttonText, string actionName, object routeValuesObject = null, object htmlAttributes = null)
{
return ActionLinkButton(htmlHelper, buttonText, actionName, "", routeValuesObject, htmlAttributes);
}
public static MvcHtmlString ActionLinkButton(this HtmlHelper htmlHelper, string buttonText, string actionName, string controllerName, object routeValuesObject = null, object htmlAttributes = null)
{
if (string.IsNullOrEmpty(controllerName))
{
controllerName = HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString();
}
RouteValueDictionary routeValues = new RouteValueDictionary(routeValuesObject);
RouteValueDictionary htmlAttr = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
TagBuilder tb = new TagBuilder("button");
tb.MergeAttributes(htmlAttr, false);
string href = UrlHelper.GenerateUrl("default", actionName, controllerName, routeValues, RouteTable.Routes, htmlHelper.ViewContext.RequestContext, false);
tb.MergeAttribute("type", "button");
tb.SetInnerText(buttonText);
tb.MergeAttribute("value", buttonText);
tb.MergeAttribute("onclick", "location.href=\'"+ href +"\';return false;");
return new MvcHtmlString(tb.ToString(TagRenderMode.Normal).Replace("'", "\'").Replace(" "," "));
}
}
This does everything you need to add button links, has the most useful overloads you use with ActionLink
and does not potentially cause unexpected application-wide changes by changing the attribute encoding process.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With