Remplacer les caractères de saut de ligne par <br /> dans la vue Razor ASP.NET MVC

241

J'ai un contrôle de zone de texte qui accepte une entrée. J'essaie de rendre plus tard ce texte dans une vue en utilisant simplement:

@ Model.CommentText

Il s'agit d'encoder correctement toutes les valeurs. Cependant, je veux remplacer les caractères de saut de ligne par <br />et je ne trouve pas de moyen de m'assurer que les nouvelles balises br ne sont pas encodées. J'ai essayé d'utiliser HtmlString mais je n'ai pas encore eu de chance.

bkaid
la source
1
Je suppose que les sauts de ligne sont stockés comme \ndans la base de données et que vous souhaitez convertir en un <br />?
Marko
Oui - j'essaye simplement de remplacer \ n par <br /> dans la vue.
bkaid

Réponses:

681

Utilisez la propriété CSS white-space au lieu de vous ouvrir aux vulnérabilités XSS!

<span style="white-space: pre-line">@Model.CommentText</span>
Jacob Krall
la source
9
@Jacob Krall - Je me suis connecté juste pour vous donner un +1. Fantastique petit truc.
Levi Botelho
6
quirksmode.org/css/whitespace.html a une bonne explication de pre-line(je ne connaissais que nowrapet pre).
James Skemp
7
Je n'en savais rien. Réponse définitivement meilleure que la mienne.
Omar
39
en fait, white-space: pre-wrap;c'est mieux car vous pre-lineallez jouer avec votre texte en regroupant les espaces blancs en un seul espace.
Chtiwi Malek
4
Malheureusement, cela ne fonctionnera pas dans presque tous les clients de messagerie (y compris Office 2013).
Roger Far
115

Essayez ce qui suit:

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

Mettre à jour:

Selon les marcind'scommentaires sur cette question connexe , l'équipe ASP.NET MVC cherche à implémenter quelque chose de similaire au <%:et <%=pour le moteur de vue Razor.

Mise à jour 2:

Nous pouvons transformer n'importe quelle question sur le codage HTML en une discussion sur les entrées utilisateur nuisibles, mais cela existe déjà.

Quoi qu'il en soit, prenez soin des entrées utilisateur potentiellement nuisibles.

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

Mise à jour 3 (Asp.Net MVC 3):

@Html.Raw(Html.Encode(Model.CommentText).Replace("\n", "<br />"))
Omar
la source
13
Oh mon Dieu, non. Et si je décide de commenter certains <script>.
Darin Dimitrov
4
Merci - cela a fonctionné. Était très proche mais devait avoir fait le remplacement trop tôt ou trop tard. J'ai fini par utiliser ceci: @ MvcHtmlString.Create (Html.Encode (Model.CommentText) .Replace ("\ n", "<br />")) parce que Environment.NewLine ne fonctionnait pas correctement.
bkaid
2
Environment.NewLine ne s'applique pas vraiment aux publications de formulaire, car les navigateurs retournent généralement juste \nau lieu de\r\n
Buildstarted
20
Pour la version finale de MVC 3, la suggestion semble être @ Html.Raw (Html.Encode (Model.CommentText) .Replace (Environment.NewLine, "<br />"))), au lieu d'utiliser MvcHtmlString. Au moins pour l'affichage.
James Skemp
2
Environment.NewLine représente "\ r \ n". Si mon utilisateur a entré des données en utilisant Linux ou Mac, les sauts de ligne sont simplement "\ n" ou "\ r". N'y a-t-il pas quelque part une méthode qui en tienne compte?
SandRock
11

Fractionnez sur les nouvelles lignes (indépendant de l'environnement) et imprimez régulièrement - pas besoin de vous soucier de l'encodage ou du xss:

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

(la suppression des entrées vides est facultative)

drzaus
la source
10

La troisième solution d'Omar en tant qu'assistant HTML serait:

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

En appliquant le principe DRY à la solution d'Omar, voici une extension 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));
        }
    }
}

Utilisation (avec regex amélioré):

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

Cela a également l'avantage supplémentaire de mettre moins de fardeau sur le développeur Razor View pour assurer la sécurité contre les vulnérabilités XSS.


Ma préoccupation avec la solution de Jacob est que le rendu des sauts de ligne avec CSS brise la sémantique HTML .

Akaoni
la source
4

J'avais besoin de briser du texte en paragraphes (balises "p"), j'ai donc créé un assistant simple en utilisant certaines des recommandations des réponses précédentes (merci les gars).

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

Usage:

@Html.ToParagraphs(Model.Comments)
Andrea
la source
0

Je préfère cette méthode car elle ne nécessite pas de balisage à émission manuelle. J'utilise cela parce que je rend les pages Razor aux chaînes et les envoie par e-mail, qui est un environnement où le style d'espace blanc ne fonctionne pas toujours.

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.
la source