什么是MvcHtmlString,何时应该使用它?

232

对于MvcHtmlString文档并不是特别详细:

表示一个HTML编码的字符串,不应再次编码。

我不清楚这意味着什么。看起来一些HTML助手方法返回MvcHtmlString,但我在网上看到的一些自定义助手的示例只返回常规字符串。

问题:

MvcHtmlString是什么?

在何时应该选择MvcHtmlString而不是string,反之亦然?为什么?


我投票支持文档链接:D 对我很有帮助。谢谢! - Trần Hữu Hiền
4个回答

249

ASP.NET 4引入了一个新的代码块语法<%: %>。实际上,<%: foo %>等价于<%= HttpUtility.HtmlEncode(foo) %>。团队正在努力让开发人员在可能的情况下使用<%: %>而不是<%= %>,以防止XSS攻击。

然而,这引出了一个问题,如果代码块已经对其结果进行编码,<%: %>语法将会重新编码它。这个问题通过引入IHtmlString接口(.NET 4中的新特性)来解决。如果<%: foo() %>中的foo()返回IHtmlString,则<%: %>语法将不会对其进行重新编码。

MVC 2的辅助函数返回MvcHtmlString,在ASP.NET 4上实现IHtmlString接口。因此,当开发人员在ASP.NET 4中使用<%: Html.*() %>时,结果不会被双重编码。

编辑:

这种新语法的一个直接好处是使视图变得更加简洁。例如,您可以编写<%: ViewData["anything"] %>而不是<%= Html.Encode(ViewData["anything"]) %>


我想补充一下,MVC 2是针对.Net 3.5编译的,而不是4。这意味着MvcHtmlString没有实现IHtmlString,因为它只存在于4中。<%:语法必须进行“鸭子类型” - 它将始终在调用接口之前调用.ToHtmlString(),而不管接口如何。 - Keith
2
我承认错误 - 实际上,MvcHtmlString.Create 方法会检测是否可用 IHtmlString 并在需要时动态创建返回的类来支持它:http://www.windowsitpro.com/article/net-framework/Encoding-and-Strings/3.aspx - Keith
跟进:MvcHtmlString和HtmlString之间有实质性的区别吗?在阅读上面链接的文档后,我仍然不知道MvcHtmlString能给我带来什么HtmlString不能。 - flipdoubt
@flipdoubt - 没有任何实质性的区别。 - Levi
2
两者之间有一个非常微小的区别。如果您传递一个空字符串,MvcHtmlString在ToString()或ToHtmlString()中将返回String.Empty。但是,HtmlString仍将继续返回null。 - rossisdead

93
这是一个晚回答,但如果任何人读到这个问题正在使用razor,你需要记住的是razor默认情况下对所有内容进行编码,但是通过在html助手中使用MvcHtmlString,你可以告诉razor不需要对其进行编码。如果你想让razor不编码一个字符串,请使用
@Html.Raw("<span>hi</span>")

反编译 Raw() 函数后,我们可以看到它将字符串包装在 HtmlString 中。

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

"HtmlString 只存在于 ASP.NET 4 中。

MvcHtmlString 是在 MVC 2 中添加的兼容性支持,以支持 .NET 3.5 和 .NET 4。现在 MVC 3 只支持 .NET 4,因此它是 HtmlString 的一个相对较为微不足道的子类,可能是为了实现 MVC 2 到 3 的源代码兼容性。" source


11

一个很好的实际用途是,如果你想要制作自己的HtmlHelper扩展。例如,我讨厌试图记住<link>标签的语法,因此我创建了自己的扩展方法来生成<link>标签:

一个不错的实际用途是,如果您想要创建自己的HtmlHelper扩展,例如,我讨厌试图记住<link>标签的语法,因此我已经创建了自己的扩展方法来生成<link>标签:
<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

我原本可以从这个方法中返回String,但如果我这样做下面的代码将会出错:

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

使用MvcHtmlString,无论是<%: ... %>还是<%= ... %>都能正常工作。


9

如果您想将原始HTML传递给MVC帮助程序方法,并且不希望帮助程序方法对HTML进行编码,则可以使用MvcHtmlString


嗯...我认为HTML助手方法的整个重点就是编码HTML。否则,我会用HTML助手方法做什么呢? - devuxer
此外,什么情况下我会想要从HTML助手方法中返回一个MvcHtmlString - devuxer
传递到或从中返回。如果您的HTML助手生成预转义的HTML并且您不希望任何其他人重新转义它,则应返回一个。 - SLaks
1
好的,我认为这让我更接近一点了,但是(冒着显得自以为是的风险)我如何决定是否希望其他人重新转义它?给某人干扰转义HTML的能力通常是好还是坏的做法?我以前从未见过这样的结构。 "就像一个字符串,但请不要触摸它...虽然没有任何阻止你触摸它的东西,但我们更希望你不要这样做。" 这是怎么回事? - devuxer
1
重点在于,与普通字符串不同,_此_字符串已被编码。因此,无需对其进行操作。 - SLaks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接