Categories
Web Development

Allow HTML in MVC’s Html.ValidationMessageFor or Html.ValidationSummary

Want to Support Me?
Get two free stocks valued up to $1,850 when you open a new Webull investment account through my referral link and fund the account with at least $100!

Have you ever wanted to put HTML in the validation message for a property or in the validation summary? You can’t do this out of the box, since any message that gets run through either of these methods gets put into the element’s InnerText. But thankfully, we can create simple extensions to allow HTML in both of these validation methods.

First thing is to create a ValidationExtensions.cs file in your solution to store these extensions. That could look like this:

public static class ValidationExtensions
{
    public static IHtmlString HtmlValidationSummary(this HtmlHelper htmlHelper)
    {
        //code here
    }
}

ValidationSummary

Here is a ValidationSummary extension method I found from Darin Dimitrov over at Stack Overflow, which allows us to use liBuilder.InnerHtml, instead of liBuilder.InnerText:

public static IHtmlString HtmlValidationSummary(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("");
    }
    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));
}

Usage:

@Html.HtmlValidationSummary()

ValidationMessageFor

Next, let’s create an extension to allow HTML in ValidationMessageFor:

public static MvcHtmlString HtmlValidationMessageFor<TModel, TProperty>(this HtmlHelper htmlHelper, Expression<Func<TModel, TProperty>> expression, string validationMessage = "", IDictionary<string, object> htmlAttributes = null)
{
    string html = htmlHelper.ValidationMessageFor(expression, validationMessage, htmlAttributes).ToString();
    html = WebUtility.HtmlDecode(html);
    return MvcHtmlString.Create(html);
}

Usage:

@* at the top of your page *@
@using YourSolution.Web.Extensions; @* should point to your ValidationExtensions namespace *@

@* a property of your ViewModel *@
@Html.LabelFor(model => model.Email)
@Html.TextBoxFor(model => model.Email)
@Html.HtmlValidationMessageFor(model => model.Email)

Then, in your Controller, you can add a ModelState error and include HTML:

ModelState.AddModelError("Email", "That email is already in use. If this is unexpected, please contact support.");
Want to Support Me?
Get two free stocks valued up to $1,850 when you open a new Webull investment account through my referral link and fund the account with at least $100!