在ASP.NET MVC Razor视图中将换行符替换为<br />

280

我有一个文本框控件可以接受输入。我尝试使用以下代码在视图中呈现该文本:

@Model.CommentText

这段代码正确地对所有值进行编码。但是,我想用<br />替换换行符,并且我找不到方法来确保新的br标签不会被编码。 我尝试使用HtmlString但是还没有成功。


2
我猜测换行符在数据库中以\n的形式存储,您想要将其转换为<br />吗? - Marko
是的 - 我只是想在视图中用 <br /> 替换 \n。 - bkaid
7个回答

785

使用CSS white-space 属性替代自己暴露于 XSS 漏洞之下!

<span style="white-space: pre-line">@Model.CommentText</span>

14
@Jacob Krall - 我特意登录只是为了给你点赞。这个小技巧太棒了。 - Levi Botelho
9
http://www.quirksmode.org/css/whitespace.html 提供了对 pre-line 属性的良好解释(我之前只知道 nowrappre)。 - James Skemp
10
没想到这个答案,绝对比我的更好。 - Omar
53
实际上,“white-space: pre-wrap;” 更好,因为“pre-line”会将文本中的空格合并成一个空格而影响文本显示。 - Chtioui Malek
7
很不幸,这几乎在任何电子邮件客户端中都不起作用(包括Office 2013)。 - Roger Far
显示剩余9条评论

122

尝试以下方法:

@MvcHtmlString.Create(Model.CommentText.Replace(Environment.NewLine, "<br />"))

更新:

根据 这个相关问题 上的 marcind 评论,ASP.NET MVC 团队正试图实现类似于 Razor 视图引擎的 <%:<%=

更新2:

我们可以把关于 HTML 编码的任何问题都变成有害用户输入的讨论,但已经有足够多的内容了。

无论如何,请注意潜在的有害用户输入。

@MvcHtmlString.Create(Html.Encode(Model.CommentText).Replace(Environment.NewLine, "<br />"))

更新3(Asp.Net MVC 3):

@Html.Raw(Html.Encode(Model.CommentText).Replace("\n", "<br />"))

18
天啊,不行。如果我决定对一些 <script> 发表评论怎么办。 - Darin Dimitrov
4
谢谢 - 这起作用了。我很接近,但可能是替换的时机过早或过晚。我最终使用了这个:@MvcHtmlString.Create(Html.Encode(Model.CommentText).Replace("\n", "<br />")),因为 Environment.NewLine 没有正常工作。 - bkaid
3
在表单提交中,Environment.NewLine并不适用,因为浏览器通常只返回\n而不是\r\n - Buildstarted
20
对于发布版本的MVC 3,建议使用@Html.Raw(Html.Encode(Model.CommentText).Replace(Environment.NewLine, "<br />"))来显示内容,而不是使用MvcHtmlString。 - James Skemp
3
即使使用MVC3,这个解决方案看起来仍然相当丑陋。它相当冗长,需要仔细查看以确保所有内容都被正确编码,并且在处理不同类型的换行符时会遇到问题。下面基于CSS的解决方案要好得多! - Stefan Paul Noack
显示剩余4条评论

12

按照换行符分割(与环境无关),并定期输出 -- 无需担心编码或 XSS 攻击:

@if (!string.IsNullOrWhiteSpace(text)) 
{
    var lines = text.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
    foreach (var line in lines)
    {
        <p>@line</p>
    }
}

(删除空条目是可选的)


11

Omar作为HTML助手的第三个解决方案是:

public static IHtmlString FormatNewLines(this HtmlHelper helper, string input)
{
    return helper.Raw(helper.Encode(input).Replace("\n", "<br />"));
}

5
应用DRY原则到Omar的解决方案,这里提供一个HTML Helper扩展:
using System.Web.Mvc;
using System.Text.RegularExpressions;

namespace System.Web.Mvc.Html {
    public static class MyHtmlHelpers {
        public static MvcHtmlString EncodedReplace(this HtmlHelper helper, string input, string pattern, string replacement) {
            return new MvcHtmlString(Regex.Replace(helper.Encode(input), pattern, replacement));
        }
    }
}

使用方法(带有改进的正则表达式):

@Html.EncodedReplace(Model.CommentText, "[\n\r]+", "<br />")

这样做还有一个额外的好处,即减轻了Razor视图开发人员确保防止XSS漏洞的安全责任。

我对Jacob的解决方案有所担忧,因为使用CSS渲染换行符会破坏HTML语义


4

我需要将一些文本分成段落(“p”标签),因此我使用了一些之前答案中的建议创建了一个简单的辅助程序(谢谢大家)。

public static MvcHtmlString ToParagraphs(this HtmlHelper html, string value) 
    { 
        value = html.Encode(value).Replace("\r", String.Empty);
        var arr = value.Split('\n').Where(a => a.Trim() != string.Empty);
        var htmlStr = "<p>" + String.Join("</p><p>", arr) + "</p>";
        return MvcHtmlString.Create(htmlStr);
    }

使用方法:

@Html.ToParagraphs(Model.Comments)

0

我更喜欢这种方法,因为它不需要手动发出标记。我使用它是因为我将Razor Pages呈现为字符串并通过电子邮件发送它们,这是一个白空间样式不总起作用的环境。

public static IHtmlContent RenderNewlines<TModel>(this IHtmlHelper<TModel> html, string content)
{
    if (string.IsNullOrEmpty(content) || html is null)
    {
        return null;
    }

    TagBuilder brTag = new TagBuilder("br");
    IHtmlContent br = brTag.RenderSelfClosingTag();
    HtmlContentBuilder htmlContent = new HtmlContentBuilder();

    // JAS: On the off chance a browser is using LF instead of CRLF we strip out CR before splitting on LF.
    string lfContent = content.Replace("\r", string.Empty, StringComparison.InvariantCulture);
    string[] lines = lfContent.Split('\n', StringSplitOptions.None);
    foreach(string line in lines)
    {
        _ = htmlContent.Append(line);
        _ = htmlContent.AppendHtml(br);
    }

    return htmlContent;
}

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