Замените символы разрыва строки на <br /> в представлении ASP.NET MVC Razor.

241

У меня есть элемент управления textarea, который принимает ввод. Я пытаюсь позже сделать этот текст для представления, просто используя:

@ Model.CommentText

Это правильно кодирует любые значения. Однако я хочу заменить символы разрыва строки на <br />и не могу найти способ убедиться, что новые теги br не закодированы. Я пытался использовать HtmlString, но еще не повезло.

bkaid
источник
1
Я предполагаю, что переносы строк хранятся как \nв базе данных, и вы хотите преобразовать в <br />?
Марко
Да - просто пытаюсь заменить \ n на <br /> в представлении.
bkaid

Ответы:

682

Используйте свойство пробела CSS вместо того, чтобы открывать себя уязвимостям XSS!

<span style="white-space: pre-line">@Model.CommentText</span>
Джейкоб Кралл
источник
9
@Jacob Krall - я вошел, чтобы дать вам +1. Фантастический маленький трюк.
Леви Ботельо
6
quirksmode.org/css/whitespace.html имеет хорошее объяснение pre-line(я знал только о nowrapи pre).
Джеймс Скемп
7
Не знал об этом. Определенно лучший ответ, чем мой.
Омар
39
на самом деле white-space: pre-wrap;лучше, так как pre-lineбудет портить ваш текст, группируя пробелы в один пробел.
Chtiwi Malek
4
К сожалению, это не будет работать практически в любом почтовом клиенте (включая Office 2013).
Роджер Фар
115

Попробуйте следующее:

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

Обновить:

Согласно marcind'sкомментариям по этому связанному с этим вопрос , команда 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 />"))
Омар
источник
13
О Боже, нет. Что делать, если я решу прокомментировать некоторые из них <script>.
Дарин Димитров
4
Спасибо - это сработало. Был очень близко, но, должно быть, делал замену слишком рано или слишком поздно. В итоге я использовал это: @ MvcHtmlString.Create (Html.Encode (Model.CommentText) .Replace ("\ n", "<br />")), потому что Environment.NewLine не работал правильно.
bkaid
2
Environment.NewLine на самом деле не применяется к сообщениям формы, поскольку браузеры обычно возвращают только \nвместо этого\r\n
Buildstarted
20
Для выпущенной версии MVC 3 предложение выглядит как @ Html.Raw (Html.Encode (Model.CommentText) .Replace (Environment.NewLine, "<br />"))) вместо использования MvcHtmlString. По крайней мере, для отображения.
Джеймс Скемп
2
Environment.NewLine представляет "\ r \ n". Если мой пользователь вводил данные, используя Linux или Mac, разрывы строк просто "\ n" или "\ r". Есть ли где-нибудь метод, который принимает это во внимание?
SandRock
11

Разделение на новые строки (независимость от среды) и печать регулярно - не нужно беспокоиться о кодировке или xss:

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

(удалять пустые записи необязательно)

drzaus
источник
10

Третье решение Омара в качестве помощника HTML будет:

public static IHtmlString FormatNewLines(this HtmlHelper helper, string input)
{
    return helper.Raw(helper.Encode(input).Replace("\n", "<br />"));
}
Тель
источник
5

Применяя принцип DRY к решению Омара, вот расширение 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 View будет нести большую ответственность за обеспечение безопасности от уязвимостей XSS.


Меня беспокоит решение Джейкоба, что рендеринг разрывов строк с помощью CSS нарушает семантику HTML .

Akaoni
источник
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)
Andrea
источник
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;
}
Джеймс С.
источник