Zamień znaki podziału linii na <br /> w widoku Razor ASP.NET MVC

241

Mam kontrolkę textarea, która przyjmuje dane wejściowe. Próbuję później renderować ten tekst do widoku, używając po prostu:

@ Model.CommentText

To poprawnie koduje dowolne wartości. Chcę jednak zastąpić znaki podziału wiersza <br />i nie mogę znaleźć sposobu, aby upewnić się, że nowe znaczniki br nie zostaną zakodowane. Próbowałem użyć HtmlString, ale nie miałem jeszcze szczęścia.

bkaid
źródło
1
Zakładam, że podziały wierszy są przechowywane jak \nw bazie danych i chcesz przekonwertować na <br />?
Marko,
Tak - po prostu próbuję zamienić \ n na <br /> w widoku.
bkaid

Odpowiedzi:

681

Skorzystaj z właściwości białych znaków CSS zamiast otwierać się na luki w XSS!

<span style="white-space: pre-line">@Model.CommentText</span>
Jacob Krall
źródło
9
@Jacob Krall - Zalogowałem się, aby dać ci +1. Fantastyczna sztuczka.
Levi Botelho,
6
quirksmode.org/css/whitespace.html ma dobre wyjaśnienie pre-line(byłem tylko świadomy nowrapi pre).
James Skemp,
7
Nie wiedziałem o tym. Zdecydowanie lepsza odpowiedź niż moja.
Omar,
39
faktycznie white-space: pre-wrap;jest lepszy, ponieważ pre-linebędzie bałagan z tekstem, grupując białe spacje w jednym miejscu.
Chtiwi Malek
4
Niestety nie zadziała to w prawie żadnym kliencie poczty e-mail (w tym Office 2013).
Roger Far
115

Spróbuj wykonać następujące czynności:

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

Aktualizacja:

Według marcind'skomentarza na ten powiązane pytanie , zespół ASP.NET MVC szuka zaimplementować coś podobnego do <%:i <%=na widok silnika Razor.

Aktualizacja 2:

Możemy zamienić dowolne pytanie dotyczące kodowania HTML w dyskusję na temat szkodliwych danych wprowadzanych przez użytkowników, ale wystarczająco dużo tego już istnieje.

W każdym razie, zadbaj o potencjalnie szkodliwy wkład użytkownika.

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

Aktualizacja 3 (Asp.Net MVC 3):

@Html.Raw(Html.Encode(Model.CommentText).Replace("\n", "<br />"))
Omar
źródło
13
O mój Boże, nie. Co jeśli zdecyduję się coś skomentować <script>.
Darin Dimitrov,
4
Dzięki - działało. Był bardzo blisko, ale musiał dokonać wymiany zbyt wcześnie lub za późno. Skończyło się na tym: @ MvcHtmlString.Create (Html.Encode (Model.CommentText) .Replace ("\ n", "<br />")), ponieważ Environment.NewLine nie działał poprawnie.
bkaid
2
Environment.NewLine tak naprawdę nie ma zastosowania do tworzenia postów, ponieważ przeglądarki zwykle zwracają się \nzamiast\r\n
Buildstarted
20
W wydanej wersji MVC 3 sugerowana jest @ Html.Raw (Html.Encode (Model.CommentText) .Replace (Environment.NewLine, „<br />”)), zamiast używania MvcHtmlString. Przynajmniej na pokaz.
James Skemp
2
Environment.NewLine reprezentuje „\ r \ n”. Jeśli mój użytkownik wprowadził dane przy użyciu systemu Linux lub Mac, podziały wiersza to po prostu „\ n” lub „\ r”. Czy gdzieś nie ma takiej metody?
SandRock,
11

Podziel na nowe wiersze (bez względu na środowisko) i drukuj regularnie - nie musisz martwić się o kodowanie lub xss:

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

(remove empty entries is optional)

drzaus
źródło
10

Trzecie rozwiązanie Omara jako pomocnika HTML to:

public static IHtmlString FormatNewLines(this HtmlHelper helper, string input)
{
    return helper.Raw(helper.Encode(input).Replace("\n", "<br />"));
}
thelem
źródło
5

Stosując zasadę DRY do rozwiązania Omara, oto rozszerzenie 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));
        }
    }
}

Użycie (z ulepszonym wyrażeniem regularnym):

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

Ma to również tę dodatkową zaletę, że nakłada mniej obciążenia na programistę Razor View, aby zapewnić bezpieczeństwo przed lukami w zabezpieczeniach XSS.


Obawiam się, że rozwiązanie Jacoba polega na tym, że renderowanie podziałów linii za pomocą CSS przerywa semantykę HTML .

Akaoni
źródło
4

Musiałem podzielić trochę tekstu na akapity (tagi „p”), więc stworzyłem prostego pomocnika, korzystając z niektórych zaleceń z poprzednich odpowiedzi (dziękuję wam).

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);
    }

Stosowanie:

@Html.ToParagraphs(Model.Comments)
Andrea
źródło
0

Wolę tę metodę, ponieważ nie wymaga ręcznego emitowania znaczników. Używam tego, ponieważ renderuję Strony Razor na ciągi i wysyłam je pocztą e-mail, co jest środowiskiem, w którym styl białych znaków nie zawsze działa.

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;
}
James S.
źródło