¿Qué es un MvcHtmlString y cuándo debo usarlo?

221

La documentación para MvcHtmlStringno es terriblemente esclarecedora:

Representa una cadena codificada en HTML que no debe codificarse nuevamente.

No me queda claro cuáles son exactamente las implicaciones de esto. Parece que algunos métodos de ayuda HTML devuelven un MvcHtmlString, pero varios ejemplos que he visto en línea de ayudantes personalizados solo devuelven una cadena normal.

Preguntas:

¿Qué es un MvcHtmlString?

Cuando debería elegir MvcHtmlStringmás stringy viceversa? ¿Por qué?

devuxer
fuente

Respuestas:

246

ASP.NET 4 presenta una nueva sintaxis de nugget de código <%: %>. Esencialmente, se <%: foo %>traduce en <%= HttpUtility.HtmlEncode(foo) %>. El equipo está tratando de hacer que los desarrolladores lo usen en <%: %>lugar de <%= %>siempre que sea posible para evitar XSS.

Sin embargo, esto introduce el problema de que si un nugget de código ya codifica su resultado, la <%: %>sintaxis lo volverá a codificar . Esto se resuelve con la introducción de la interfaz IHtmlString (nueva en .NET 4). Si foo () en <%: foo() %>devuelve un IHtmlString, la <%: %>sintaxis no lo volverá a codificar.

Los ayudantes de MVC 2 devuelven MvcHtmlString, que en ASP.NET 4 implementa la interfaz IHtmlString. Por lo tanto, cuando los desarrolladores usan <%: Html.*() %>ASP.NET 4, el resultado no tendrá doble codificación.

Editar:

Un beneficio inmediato de esta nueva sintaxis es que sus puntos de vista son un poco más limpios. Por ejemplo, puedes escribir en <%: ViewData["anything"] %>lugar de <%= Html.Encode(ViewData["anything"]) %>.

Levi
fuente
Agregaría que MVC 2 está compilado contra .Net 3.5, no 4. Esto significa que MvcHtmlStringno se implementa IHtmlStringporque eso solo existe en 4. La <%:sintaxis debe ser de tipo pato ; siempre llamará .ToHtmlString()antes, .ToString()independientemente de la interfaz.
Keith
2
Estoy corregido: en realidad, el MvcHtmlString.Createmétodo detecta si IHtmlStringestá disponible y crea dinámicamente la clase devuelta para admitirlo si es: windowsitpro.com/article/net-framework/Encoding-and-Strings/…
Keith
Seguimiento: ¿Hay una diferencia significativa entre MvcHtmlString y HtmlString? Después de leer los documentos vinculados anteriormente, todavía no sabía lo que MvcHtmlString me da que HtmlString no.
flipdoubt
@flipdoubt: no hay una diferencia significativa.
Levi
2
Hay una diferencia muy leve entre los dos. MvcHtmlString devolverá String.Empty en ToString () o ToHtmlString () si le pasa una cadena nula. Sin embargo, HtmlString continuará devolviendo nulo.
rossisdead
87

Esta es una respuesta tardía, pero si alguien que lee esta pregunta está usando la maquinilla de afeitar, lo que debe recordar es que la maquinilla de afeitar codifica todo de manera predeterminada, pero al usar MvcHtmlStringsus ayudantes html puede decirle a la maquinilla de afeitar que no necesita codificarla .

Si desea que la afeitadora no codifique una cadena, use

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

Descompilar Raw (), nos muestra que está envolviendo la cadena en un HtmlString

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

" HtmlString solo existe en ASP.NET 4.

MvcHtmlString fue un complemento de compatibilidad agregado a MVC 2 para admitir .NET 3.5 y .NET 4. Ahora que MVC 3 es solo .NET 4, es una subclase bastante trivial de HtmlString presumiblemente para MVC 2-> 3 para la compatibilidad de fuentes. " fuente

Torbjörn Nomell
fuente
11

Un buen uso práctico de esto es si desea hacer sus propias HtmlHelperextensiones. Por ejemplo, odio tratar de recordar la <link>sintaxis de la etiqueta, así que he creado mi propio método de extensión para hacer una <link>etiqueta:

<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

Podría haber regresado Stringde este método, pero si tuviera lo siguiente se rompería:

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

Con MvcHtmlString, usar cualquiera <%: ... %>o <%= ... %>ambos funcionarán correctamente.

mattmc3
fuente
7

Usaría un MvcHtmlStringsi desea pasar HTML sin formato a un método auxiliar MVC y no desea que el método auxiliar codifique el HTML.

SLaks
fuente
Hmm ... pensé que el objetivo de un método de ayuda HTML era codificar HTML. ¿Qué haría de otro modo con un método de ayuda HTML?
devuxer
Y, además de eso, ¿cuándo querría devolver un MvcHtmlStringmétodo auxiliar de HTML?
devuxer
Pase o regrese de. Desea devolver uno si su ayudante HTML genera HTML previamente escapado y no quiere que nadie más lo vuelva a escapar.
SLaks
1
De acuerdo, creo que eso me acerca un poco más, pero (a riesgo de parecer un asno inteligente), ¿cómo decido si quiero que alguien más vuelva a escapar? ¿Es generalmente una buena / mala práctica darle a alguien la capacidad de meterse con HTML escapado? Nunca antes había visto una construcción como esta. "Es como una cuerda, pero por favor no lo toques ... no es que haya nada que te impida tocarlo, pero preferimos que no lo hagas". ¿De qué se trata eso?
devuxer
1
El punto es que, a diferencia de una cadena normal, esta cadena ya ha sido codificada. Por lo tanto, no hay necesidad de tocarlo.
SLaks