Thay thế các ký tự ngắt dòng bằng <br /> trong chế độ xem ASP.NET MVC Razor


241

Tôi có một điều khiển textarea chấp nhận đầu vào. Tôi đang cố gắng để hiển thị văn bản đó thành một khung nhìn bằng cách sử dụng:

@ Model.CommentText

Đây là mã hóa chính xác bất kỳ giá trị. Tuy nhiên, tôi muốn thay thế các ký tự ngắt dòng bằng <br />và tôi không thể tìm ra cách nào để đảm bảo rằng các thẻ br mới không được mã hóa. Tôi đã thử sử dụng HtmlString nhưng chưa có may mắn nào.


1
Tôi đoán rằng ngắt dòng được lưu trữ như \ntrong cơ sở dữ liệu và bạn muốn chuyển đổi sang <br />?
Marko

Có - chỉ cố gắng thay thế \ n bằng <br /> trong chế độ xem.
bkaid

Câu trả lời:


678

Sử dụng thuộc tính khoảng trắng CSS thay vì tự mở các lỗ hổng XSS!

<span style="white-space: pre-line">@Model.CommentText</span>

9
@Jacob Krall - Tôi đã đăng nhập chỉ để cho bạn +1. Thủ thuật nhỏ tuyệt vời.
Levi Botelho

6
quirksmode.org/css/whitespace.html có một lời giải thích tốt về pre-line(tôi chỉ biết nowrappre).
James Skemp

7
Không biết về điều này. Chắc chắn câu trả lời tốt hơn của tôi.
Omar

39
thực sự white-space: pre-wrap;là tốt hơn vì pre-linesẽ gây rối với văn bản của bạn bằng cách nhóm các khoảng trắng vào một không gian.
Chtiwi Malek

4
Thật không may, điều này sẽ không hoạt động trong hầu hết mọi ứng dụng email (bao gồm cả Office 2013).
Roger Far

115

Hãy thử như sau:

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

Cập nhật:

Theo marcind'snhận xét về câu hỏi liên quan này , nhóm ASP.NET MVC đang tìm cách triển khai một cái gì đó tương tự <%:<%=cho công cụ xem dao cạo.

Cập nhật 2:

Chúng tôi có thể biến bất kỳ câu hỏi nào về mã hóa HTML thành một cuộc thảo luận về đầu vào của người dùng có hại, nhưng đủ điều đó đã tồn tại.

Dù sao, hãy quan tâm đến đầu vào người dùng có hại.

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

Cập nhật 3 (Asp.Net MVC 3):

@Html.Raw(Html.Encode(Model.CommentText).Replace("\n", "<br />"))

13
Ôi Chúa ơi, không. Điều gì xảy ra nếu tôi quyết định bình luận về một số <script>.
Darin Dimitrov

4
Cảm ơn - đã làm việc. Đã rất gần nhưng phải làm thay thế quá sớm hoặc quá muộn. Tôi đã kết thúc bằng cách sử dụng cái này: @ MvcHtmlString.Create (Html.Encode (Model.CommentText) .Replace ("\ n", "<br />")) vì Môi trường.NewLine không hoạt động đúng.
bkaid

2
Environment.NewLine không thực sự áp dụng để tạo bài mới từ các trình duyệt thường trở lại chỉ \nthay vì\r\n
Buildstarted

20
Đối với phiên bản phát hành của MVC 3, đề xuất dường như là @ Html.Raw (Html.Encode (Model.CommentText) .Replace (Môi trường.NewLine, "<br />")), thay vì sử dụng MvcHtmlString. Ít nhất là để hiển thị.
James Skemp

2
Môi trường.NewLine đại diện cho "\ r \ n". Nếu người dùng của tôi nhập dữ liệu bằng linux hoặc mac, ngắt dòng chỉ là "\ n" hoặc "\ r". Không có một phương pháp nào đó có tính đến điều này?
SandRock

11

Tách trên dòng mới (bất khả tri môi trường) và in thường xuyên - không cần phải lo lắng về mã hóa hoặc xss:

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

(loại bỏ các mục trống là tùy chọn)


10

Giải pháp thứ ba của Omar với tư cách là Người trợ giúp HTML sẽ là:

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

5

Áp dụng nguyên tắc DRY cho giải pháp của Omar, đây là tiện ích mở rộng Trình trợ giúp HTML:

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

Cách sử dụng (với regex được cải thiện):

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

Điều này cũng có thêm lợi ích của việc đưa ít trách nhiệm hơn cho nhà phát triển Razor View để đảm bảo an ninh khỏi các lỗ hổng XSS.


Mối quan tâm của tôi với giải pháp của Jacob là việc kết xuất các ngắt dòng bằng CSS sẽ phá vỡ ngữ nghĩa HTML .


4

Tôi cần chia một số văn bản thành các đoạn văn (thẻ "p"), vì vậy tôi đã tạo một trình trợ giúp đơn giản bằng cách sử dụng một số đề xuất trong các câu trả lời trước (cảm ơn các bạn).

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

Sử dụng:

@Html.ToParagraphs(Model.Comments)

0

Tôi thích phương pháp này vì nó không yêu cầu đánh dấu thủ công. Tôi sử dụng điều này bởi vì tôi kết xuất các Trang dao cạo thành chuỗi và gửi chúng qua email, đây là môi trường mà kiểu dáng không gian trắng sẽ không luôn hoạt động.

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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.