8

MVC4 razor view. Given that a string backgroundImage is set like this:

backgroundImage = string.Format("background: url('{0}') top left no-repeat;", project.MainImage);

Why does this

<div class="spotlight slide teaser-text" id="@slideId" style="@Html.Raw(backgroundImage)">

produce

<div class="spotlight slide teaser-text" id="spotlight-0" style="background: url(&#39;/media/215/spotlight01.jpg&#39;) top left no-repeat;">

Html.Raw, new MvcHtmlString and MvcHtmlString.Create all behave similarly.

I would expect it to produce

<div class="spotlight slide teaser-text" id="spotlight-0" style="background: url('/media/215/spotlight01.jpg') top left no-repeat;">

(note the quotes).

AndyC
  • 353
  • 3
  • 15
  • `Html.Raw()` just returns an `HtmlString`, and `MvcHtmlString` extends `HtmlString`; I think what you see is expected? – kenchilada Jul 11 '13 at 15:52
  • @radium: No; the whole point of those is to prevent escaping. – SLaks Jul 11 '13 at 16:00
  • Just tried on MVC3 and got the expected results (I don't have MVC4 on this machine). So maybe it changed in 4. – Joe Enos Jul 11 '13 at 16:02
  • What happens if you just write it out directly, rather than putting it in an attribute? – Joe Enos Jul 11 '13 at 16:03
  • @JoeEnos It is encoded. Curiously, if it is output not as an attribute value, it is **not** encoded. – AndyC Jul 11 '13 at 16:08
  • Your result and what you expect are equivalent. Is something not working, or do you just not want the single quote to be encoded? – kenchilada Jul 11 '13 at 16:08
  • @radium exactly - the single quote character is being encoded to `'` in the style attribute. I don't want that. – AndyC Jul 11 '13 at 16:13
  • Well `WebUtility.HtmlEncode()` does encode single quotes. I'm guessing some part of the Razor engine applies that to attribute values as an XSS prevention. Interested to hear the answer. – kenchilada Jul 11 '13 at 16:19
  • Can't find an actual answer, but I'm seeing that others are seeing the same thing [here](http://stackoverflow.com/questions/12321616/why-is-mvc-4-razor-escaping-ampersand-when-using-html-raw-in-a-title-attribute) and [here](http://stackoverflow.com/questions/11963453/why-is-html-raw-escaping-ampersand-in-anchor-tag-in-asp-net-mvc-4). Appears to be the framework's way of "helping you out" when writing inside of HTML attributes by preventing invalid characters in attributes. I'd expect that even though it looks weird, it should still work ok, right? – Joe Enos Jul 11 '13 at 16:27
  • It does in (at least) IE10 and Chrome27, but the fact that I'm sending duff HTML to the client bothers me. Looks like the answer is "by design", and an acceptable workaround is to put it all into a separate style section. – AndyC Jul 11 '13 at 18:01

1 Answers1

3

I have had a look at the compiled DLL for a razor template containing this markup. As far as I can see, the issue is this.

Html.Raw turns a string into an HtmlString. HttpUtility.HtmlEncode treats IHtmlString instances differently to normal strings, in that it doesn't apply Html encoding.

When the programmatically defined string is given in the context of the attribute, a call is made to

this.WriteAttribute(...)

with data appropriate to generate the attribute. Part of this data is the HtmlString generated by the call to Html.Raw. Another part is a flag indicating that the value is not a literal.

Because of the not-literal flag status, the WriteAttribute method eventually calls HtmlEncode. But it calls this not on the HtmlString, but on the string value of this object. So you do end up with an HTML encoded value in the output.

Outside the context of an attribute, the call is made to

this.Write(...)

and this doesn't suffer from the same problem. So it seems like a bug to me (at least if I've accurately traced it all through).

Erik Schierboom
  • 16,301
  • 10
  • 64
  • 81
Yellowfog
  • 2,323
  • 2
  • 20
  • 36