11

When an error occurs on the back-end, the MVC controller returns a message via the
ModelState.AddModelError("", "message");

I would like to have that 'message' display in 2 lines, so I would like to put a "\r\n"
or a "<br />" in between.

I'm using Razor to display the Message using @Html.ValidationSummary();
But the HTML Output from the View displays that as &lt;br/&gt;

What is the best way to pass New-Lines on a message and get it interpreted into a real
tag at the HTML output level?

================================
Controller code:

ModelState.AddModelError("", "Line one <br /> Line two.");
return Request.IsAjaxRequest() ? (ActionResult) PartialView("ViewName", model) 
            : View(model);

View code:

@using (Ajax.BeginForm("Index", "Home", new AjaxOptions { UpdateTargetId = "tv" })) 
{
    @if (Html.ValidationSummary() != null)
        @Html.Raw(Server.HtmlDecode(Html.ValidationSummary(true).ToString()))   

    ....
}
SF Developer
  • 5,244
  • 14
  • 60
  • 106

4 Answers4

16

The ValidationSummary helper HTML encodes error messages and this is by design. It means that you cannot use HTML tags as they will be encoded. So you could write a custom helper which doesn't encode:

public static class ValidationExtensions
{
    public static IHtmlString MyValidationSummary(this HtmlHelper htmlHelper)
    {
        var formContextForClientValidation = htmlHelper.ViewContext.ClientValidationEnabled ? htmlHelper.ViewContext.FormContext : null;
        if (htmlHelper.ViewData.ModelState.IsValid)
        {
            if (formContextForClientValidation == null)
            {
                return null;
            }
            if (htmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled)
            {
                return null;
            }
        }

        var stringBuilder = new StringBuilder();
        var ulBuilder = new TagBuilder("ul");

        ModelState modelState;
        if (htmlHelper.ViewData.ModelState.TryGetValue(htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix, out modelState))
        {
            foreach (ModelError error in modelState.Errors)
            {
                string userErrorMessageOrDefault = error.ErrorMessage;
                if (!string.IsNullOrEmpty(userErrorMessageOrDefault))
                {
                    var liBuilder = new TagBuilder("li");
                    liBuilder.InnerHtml = userErrorMessageOrDefault;
                    stringBuilder.AppendLine(liBuilder.ToString(TagRenderMode.Normal));
                }
            }
        }

        if (stringBuilder.Length == 0)
        {
            stringBuilder.AppendLine("<li style=\"display:none\"></li>");
        }
        ulBuilder.InnerHtml = stringBuilder.ToString();

        TagBuilder divBuilder = new TagBuilder("div");
        divBuilder.AddCssClass(htmlHelper.ViewData.ModelState.IsValid ? HtmlHelper.ValidationSummaryValidCssClassName : HtmlHelper.ValidationSummaryCssClassName);
        divBuilder.InnerHtml = ulBuilder.ToString(TagRenderMode.Normal);
        if (formContextForClientValidation != null)
        {
            if (!htmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled)
            {
                divBuilder.GenerateId("validationSummary");
                formContextForClientValidation.ValidationSummaryId = divBuilder.Attributes["id"];
                formContextForClientValidation.ReplaceValidationSummary = false;
            }
        }
        return new HtmlString(divBuilder.ToString(TagRenderMode.Normal));
    }
}

and then:

@Html.MyValidationSummary()

It is the following line in our custom helper which explicitly doesn't HTML encode:

liBuilder.InnerHtml = userErrorMessageOrDefault;

In the original helper it looks like this:

liBuilder.SetInnerText(userErrorMessageOrDefault);
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
12

Try wrapping the validation summary in an Html.Raw and a Server.HtmlDecode, like so:

@Html.Raw(Server.HtmlDecode(Html.ValidationSummary().ToString()))
counsellorben
  • 10,924
  • 3
  • 40
  • 38
  • When I put that line of code, it does not even show the partial view. It gives me a "500 internal server error". – SF Developer Nov 16 '11 at 18:40
  • I revised my answer. I tested the revised code, and it returned the error message with a line break when I had `
    ` in the error message.
    – counsellorben Nov 16 '11 at 18:47
  • The problem is with @Html.ValidationSummary; I tried replacing it with ViewBag.Temp ..and it did work. So we need to find out how to make the ValidationSummary work before we start thinking to replace it totally. – SF Developer Nov 16 '11 at 18:48
  • Maybe I have the Validation inside a Ajax.BeginForm. would that be the difference ? – SF Developer Nov 16 '11 at 18:49
  • Please edit your question, and add the view you are trying to return. – counsellorben Nov 16 '11 at 18:54
  • @Filu, there's not much you could do with ValidationSummary. As I said in my comment it HTML encodes messages by default and this is by design. So you need to write a custom helper for this. – Darin Dimitrov Nov 16 '11 at 21:02
  • 2
    Works for me! `@Html.Raw(Server.HtmlDecode(Html.ValidationSummary(true, "", new { @class = "text-danger" }).ToString()))` – Ray Linder Nov 23 '16 at 21:24
  • @DarinDimitrov your custom helper is great thanks - but Coundsellorben and Ray are correct: this solution works too. A good quick option for someone only using it once or twice in a project. Thanks. – MemeDeveloper Mar 19 '19 at 00:44
4

Controller:

ModelState.AddModelError("MyError", "Line 1" + Environment.NewLine + "Line 2");

Razor:

<span style="white-space: pre-line">@Html.ValidationSummary()</span>
ADH
  • 2,971
  • 6
  • 34
  • 53
1

This is a late answer, however this is the top result when I Google, so my solution may help someone.

I went around the problem and added a separate line for each error message line. Displays beautifully.

Controller code:

    public ActionResult Edit(EditModel model)
    {
            try
            {
                //... do update
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains(Environment.NewLine))
                {
                    var messages = ex.Message.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (var message in messages)
                    {
                        this.ModelState.AddModelError(string.Empty, message);
                    }
                }
                else
                {
                    this.ModelState.AddModelError(string.Empty, ex.Message);
                }
            }
        //...

        return this.View(model);
    }
gabnaim
  • 1,103
  • 9
  • 13