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 <br/>
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()))
....
}
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);
Try wrapping the validation summary in an Html.Raw
and a Server.HtmlDecode
, like so:
@Html.Raw(Server.HtmlDecode(Html.ValidationSummary().ToString()))
Controller:
ModelState.AddModelError("MyError", "Line 1" + Environment.NewLine + "Line 2");
Razor:
<span style="white-space: pre-line">@Html.ValidationSummary()</span>
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);
}