Substitua caracteres de quebra de linha por <br /> no modo de exibição ASP.NET MVC Razor

241

Eu tenho um controle de área de texto que aceita entrada. Mais tarde, estou tentando renderizar esse texto em uma exibição usando:

@ Model.CommentText

Isso está codificando corretamente quaisquer valores. No entanto, quero substituir os caracteres de quebra de linha <br />e não consigo encontrar uma maneira de garantir que as novas tags br não sejam codificadas. Eu tentei usar HtmlString, mas ainda não tive sorte.

bkaid
fonte
1
Presumo que as quebras de linha sejam armazenadas como \nno banco de dados e você deseja converter para um <br />?
Marko
Sim - apenas tentando substituir \ n por <br /> na exibição.
bkaid

Respostas:

680

Use a propriedade espaço em branco CSS em vez de se abrir para as vulnerabilidades XSS!

<span style="white-space: pre-line">@Model.CommentText</span>
Jacob Krall
fonte
9
@ Jacob Krall - Entrei apenas para lhe dar um +1. Truque fantástico.
Levi Botelho
6
quirksmode.org/css/whitespace.html tem uma boa explicação de pre-line(eu só sabia nowrape pre).
James Skemp
7
Não sabia disso. Definitivamente melhor resposta que a minha.
Omar
39
na verdade, white-space: pre-wrap;é melhor, pois pre-lineirá mexer com o seu texto agrupando espaços em branco em um espaço.
Chtiwi Malek
4
Infelizmente, isso não funcionará em quase nenhum cliente de email (incluindo o Office 2013).
Roger Far
115

Tente o seguinte:

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

Atualizar:

De acordo com o marcind'scomentário sobre essa questão relacionada , a equipe do ASP.NET MVC procura implementar algo semelhante ao mecanismo de exibição Razor <%:e <%=para o mesmo.

Atualização 2:

Podemos transformar qualquer pergunta sobre codificação HTML em uma discussão sobre entradas prejudiciais do usuário, mas já existe o suficiente.

De qualquer forma, cuide de possíveis entradas prejudiciais do usuário.

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

Atualização 3 (Asp.Net MVC 3):

@Html.Raw(Html.Encode(Model.CommentText).Replace("\n", "<br />"))
Omar
fonte
13
Oh meu Deus, não. E se eu decidir comentar sobre alguns <script>.
Darin Dimitrov
4
Obrigado - funcionou. Estava muito perto, mas deve ter feito a substituição muito cedo ou muito tarde. Acabei usando isso: @ MvcHtmlString.Create (Html.Encode (Model.CommentText) .Replace ("\ n", "<br />")) porque Environment.NewLine não estava funcionando corretamente.
bkaid
2
Environment.NewLine não se aplica realmente para formar publicações desde navegadores geralmente retornam apenas \nem vez de\r\n
Buildstarted
20
Para a versão lançada do MVC 3, a sugestão parece ser @ Html.Raw (Html.Encode (Model.CommentText). Substitua (Environment.NewLine, "<br />")), em vez de usar MvcHtmlString. Pelo menos para exibição.
James Skemp
2
Environment.NewLine representa "\ r \ n". Se meu usuário inseriu dados usando linux ou mac, as quebras de linha são apenas "\ n" ou "\ r". Não existe um método em algum lugar que leve isso em consideração?
SandRock 18/01/12
11

Divida em novas linhas (independente do ambiente) e imprima regularmente - não precisa se preocupar com codificação ou xss:

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

(remover entradas vazias é opcional)

drzaus
fonte
10

A terceira solução de Omar como auxiliar de HTML seria:

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

Aplicando o princípio DRY à solução do Omar, aqui está uma extensão 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));
        }
    }
}

Uso (com regex aprimorado):

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

Isso também tem o benefício adicional de colocar menos ônus no desenvolvedor do Razor View para garantir a segurança contra vulnerabilidades XSS.


Minha preocupação com a solução de Jacob é que processar as quebras de linha com CSS interrompe a semântica do HTML .

Akaoni
fonte
4

Eu precisava dividir algum texto em parágrafos (tags "p"), então criei um auxiliar simples usando algumas das recomendações das respostas anteriores (obrigado pessoal).

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

Uso:

@Html.ToParagraphs(Model.Comments)
Andrea
fonte
0

Eu prefiro esse método, pois não requer emissão manual de marcação. Eu uso isso porque estou processando Razor Pages em seqüências de caracteres e enviando-as por email, que é um ambiente em que o estilo do espaço em branco nem sempre funciona.

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.
fonte