232

The documentation for MvcHtmlString is not terribly enlightening:

Represents an HTML-encoded string that should not be encoded again.

It's not clear to me what exactly the implications of this are. It seems that some HTML helper methods return an MvcHtmlString, but several examples I've seen online of custom helpers just return a regular string.

Questions:

What is an MvcHtmlString?

When should I choose MvcHtmlString over string and vice versa? Why?

devuxer
  • 41,681
  • 47
  • 180
  • 292

4 Answers4

249

ASP.NET 4 introduces a new code nugget syntax <%: %>. Essentially, <%: foo %> translates to <%= HttpUtility.HtmlEncode(foo) %>. The team is trying to get developers to use <%: %> instead of <%= %> wherever possible to prevent XSS.

However, this introduces the problem that if a code nugget already encodes its result, the <%: %> syntax will re-encode it. This is solved by the introduction of the IHtmlString interface (new in .NET 4). If the foo() in <%: foo() %> returns an IHtmlString, the <%: %> syntax will not re-encode it.

MVC 2's helpers return MvcHtmlString, which on ASP.NET 4 implements the interface IHtmlString. Therefore when developers use <%: Html.*() %> in ASP.NET 4, the result won't be double-encoded.

Edit:

An immediate benefit of this new syntax is that your views are a little cleaner. For example, you can write <%: ViewData["anything"] %> instead of <%= Html.Encode(ViewData["anything"]) %>.

Levi
  • 32,628
  • 3
  • 87
  • 88
  • I'd add that MVC 2 is compiled against .Net 3.5, not 4. This means that `MvcHtmlString` doesn't implement `IHtmlString` because that only exists in 4. The `<%:` syntax must _duck-type_ - it will always call `.ToHtmlString()` before `.ToString()` regardless of interface. – Keith Jul 08 '10 at 07:49
  • 2
    I stand corrected - actually the `MvcHtmlString.Create` method detects whether `IHtmlString` is available and dynamically creates the returned class to support it if it is: http://www.windowsitpro.com/article/net-framework/Encoding-and-Strings/3.aspx – Keith Jul 08 '10 at 08:50
  • **Follow Up:** Is there a meaningful difference between MvcHtmlString and HtmlString? After reading the docs linked above, I still did not know what MvcHtmlString gives me that HtmlString does not. – flipdoubt Jan 09 '13 at 13:41
  • @flipdoubt - There is no meaningful difference. – Levi Jan 10 '13 at 06:34
  • 2
    There is one very slight difference between the two. MvcHtmlString will return String.Empty in ToString() or ToHtmlString() if you pass it a null string. HtmlString will continue to return null, though. – rossisdead Mar 06 '13 at 16:59
93

This is a late answer but if anyone reading this question is using razor, what you should remember is that razor encodes everything by default, but by using MvcHtmlString in your html helpers you can tell razor that it doesn't need to encode it.

If you want razor to not encode a string use

@Html.Raw("<span>hi</span>")

Decompiling Raw(), shows us that it's wrapping the string in a HtmlString

public IHtmlString Raw(string value) {
    return new HtmlString(value); 
}

"HtmlString only exists in ASP.NET 4.

MvcHtmlString was a compatibility shim added to MVC 2 to support both .NET 3.5 and .NET 4. Now that MVC 3 is .NET 4 only, it's a fairly trivial subclass of HtmlString presumably for MVC 2->3 for source compatibility." source

Community
  • 1
  • 1
Torbjörn Nomell
  • 3,020
  • 2
  • 24
  • 20
11

A nice practical use of this is if you want to make your own HtmlHelper extensions. For example, I hate trying to remember the <link> tag syntax, so I've created my own extension method to make a <link> tag:

<Extension()> _
Public Function CssBlock(ByVal html As HtmlHelper, ByVal src As String, ByVal Optional ByVal htmlAttributes As Object = Nothing) As MvcHtmlString
    Dim tag = New TagBuilder("link")
    tag.MergeAttribute("type", "text/css")
    tag.MergeAttribute("rel", "stylesheet")
    tag.MergeAttribute("href", src)
    tag.MergeAttributes(New RouteValueDictionary(htmlAttributes))
    Dim result = tag.ToString(TagRenderMode.Normal)
    Return MvcHtmlString.Create(result)
End Function

I could have returned String from this method, but if I had the following would break:

<%: Html.CssBlock(Url.Content("~/sytles/mysite.css")) %>

With MvcHtmlString, using either <%: ... %> or <%= ... %> will both work correctly.

mattmc3
  • 17,595
  • 7
  • 83
  • 103
8

You would use an MvcHtmlString if you want to pass raw HTML to an MVC helper method and you don't want the helper method to encode the HTML.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • Hmm...I thought the whole point of an HTML helper method was to encode HTML. What would I do otherwise with an HTML helper method? – devuxer Feb 19 '10 at 00:47
  • And, besides that, when would I want to *return* an `MvcHtmlString` from an HTML helper method? – devuxer Feb 19 '10 at 00:49
  • Pass to or return from. You would want to return one if your HTML helper generates pre-escaped HTML and you don't want anyone else re-escaping it. – SLaks Feb 19 '10 at 00:51
  • 1
    Okay, I think that gets me a little bit closer, but (at the risk of coming across as a smart ass) how do I decide whether I want anyone else re-escaping it? Is it generally good/bad practice to give someone the ability to mess with escaped html? I've never seen a construct like this before. "It's like a string, but please don't touch it...not that there's anything preventing you from touching it, but we'd prefer you don't." What is that about? – devuxer Feb 19 '10 at 01:15
  • 1
    The point is that unlike a regular string, _this_ string has already been encoded. Therefore, there's no need to touch it. – SLaks Feb 19 '10 at 14:02