Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stop the tag builder escaping single quotes ASP.NET MVC 2

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=&#39;&#39;" type="submit" value="Return to All Audits" />

Is there anyway I can stop this behaviour?

like image 243
dagda1 Avatar asked Oct 13 '10 14:10

dagda1


2 Answers

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.

like image 175
Ryan Avatar answered Oct 26 '22 10:10

Ryan


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.

e.g.

return new MvcHtmlString(tb.ToString(TagRenderMode.Normal).Replace("&#39;", "\'").Replace("&#32;"," "));

A complete ActionLinkButton helper is shown below:

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("&#39;", "\'").Replace("&#32;"," "));
    }
}

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.

like image 45
Gone Coding Avatar answered Oct 26 '22 12:10

Gone Coding