Reemplace los caracteres de salto de línea con <br /> en la vista de ASP.NET MVC Razor

241

Tengo un control de área de texto que acepta entradas. Estoy tratando de representar ese texto en una vista simplemente usando:

@ Model.CommentText

Esto está codificando correctamente cualquier valor. Sin embargo, quiero reemplazar los caracteres de salto de línea con <br />y no puedo encontrar una manera de asegurarme de que las nuevas etiquetas br no se codifiquen. He intentado usar HtmlString pero aún no he tenido suerte.

bkaid
fuente
1
Supongo que los saltos de línea se almacenan como \nen la base de datos y desea convertir a un <br />?
Marko
Sí, solo trato de reemplazar \ n con <br /> en la vista.
bkaid

Respuestas:

680

¡Use la propiedad de espacio en blanco CSS en lugar de abrirse a vulnerabilidades XSS!

<span style="white-space: pre-line">@Model.CommentText</span>
Jacob Krall
fuente
99
@Jacob Krall: me conecté solo para darte un +1. Pequeño truco fantástico.
Levi Botelho
66
quirksmode.org/css/whitespace.html tiene una buena explicación de pre-line(solo conocía nowrapy pre).
James Skemp
77
No sabía sobre esto. Definitivamente mejor respuesta que la mía.
Omar
39
en realidad white-space: pre-wrap;es mejor ya que pre-linejugará con su texto al agrupar espacios en blanco en un espacio.
Chtiwi Malek
44
Lamentablemente, esto no funcionará en casi ningún cliente de correo electrónico (incluido Office 2013).
Roger Far
115

Intenta lo siguiente:

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

Actualizar:

Según el marcind'scomentario sobre esta pregunta relacionada , el equipo ASP.NET MVC está buscando implementar algo similar al <%:y <%=para el motor de vista Razor.

Actualización 2:

Podemos convertir cualquier pregunta sobre la codificación HTML en una discusión sobre las entradas dañinas del usuario, pero ya existe suficiente.

De todos modos, tenga cuidado con los posibles aportes dañinos del usuario.

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

Actualización 3 (Asp.Net MVC 3):

@Html.Raw(Html.Encode(Model.CommentText).Replace("\n", "<br />"))
Omar
fuente
13
Dios mío, no. ¿Qué pasa si decido comentar sobre algunos <script>?
Darin Dimitrov
44
Gracias, eso funcionó. Estaba muy cerca pero debe haber estado haciendo el reemplazo demasiado pronto o demasiado tarde. Terminé usando esto: @ MvcHtmlString.Create (Html.Encode (Model.CommentText) .Replace ("\ n", "<br />")) porque Environment.NewLine no funcionaba correctamente.
bkaid
2
Environment.NewLine realmente no se aplica a las publicaciones de formularios ya que los navegadores generalmente regresan solo en \nlugar de\r\n
Buildstarted
20
Para la versión lanzada de MVC 3, la sugerencia parece ser @ Html.Raw (Html.Encode (Model.CommentText) .Replace (Environment.NewLine, "<br />")), en lugar de usar MvcHtmlString. Al menos para mostrar.
James Skemp
2
Environment.NewLine representa "\ r \ n". Si mi usuario ingresó datos usando Linux o Mac, los saltos de línea son solo "\ n" o "\ r". ¿No hay un método en algún lugar que tenga esto en cuenta?
SandRock
11

Divida en nuevas líneas (independiente del entorno) e imprima regularmente, sin necesidad de preocuparse por la codificación o xss:

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

(eliminar entradas vacías es opcional)

drzaus
fuente
10

La tercera solución de Omar como HTML Helper sería:

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

Aplicando el principio DRY a la solución de Omar, aquí hay una extensión 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 (con expresiones regulares mejoradas):

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

Esto también tiene el beneficio adicional de poner menos responsabilidad en el desarrollador de Razor View para garantizar la seguridad de las vulnerabilidades XSS.


Mi preocupación con la solución de Jacob es que renderizar los saltos de línea con CSS rompe la semántica HTML .

Akaoni
fuente
4

Necesitaba dividir algo de texto en párrafos (etiquetas "p"), así que creé un simple ayudante usando algunas de las recomendaciones en respuestas anteriores (gracias chicos).

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
fuente
0

Prefiero este método, ya que no requiere marcado de emisión manual. Lo uso porque renderizo las páginas de Razor en cadenas y las envío por correo electrónico, que es un entorno en el que el estilo de espacios en blanco no siempre funcionará.

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