Custom ValidationSummary template Asp.net MVC 3

I am working on a project with Asp.Net MVC3

In a View I have @Html.ValidationSummary(true) and as usually it produces

<div class="validation-summary-errors">
    <ul>
        <li>Something bad Happened!</li>
    </ul>
</div>

How can I extend this ValidationSummary to MyValidationSummary and produces the Html Code template something like this:

<div class="notification warning"> 
    <span></span> 
    <div class="text"> <p>Something bad Happened!</p> </div> 
</div>

My approach is to use a custom ValidationSummary.cshtml:

@model ModelStateDictionary

@if(!Model.IsValid)
{
    <div class="validation-summary-errors">
        <ul>
            @foreach (var modelError in 
                     Model.SelectMany(keyValuePair => keyValuePair.Value.Errors))
            {
                <li>@modelError.ErrorMessage</li>
            }
        </ul>
    </div>
}

Put this partial view in your Shared folder and refer to it from your code:

@Html.Partial("_ValidationSummary", ViewData.ModelState);

This way you remain in full control of your html.


This question details the procedure of writing custom validation summary.

EDIT This will do what you want:

public static class LinqExt 
{
    public static string MyValidationSummary(this HtmlHelper helper, string validationMessage="")
    {
        string retVal = "";
        if (helper.ViewData.ModelState.IsValid)
            return "";

        retVal += "<div class='notification-warnings'><span>";
        if (!String.IsNullOrEmpty(validationMessage))
            retVal += helper.Encode(validationMessage);
        retVal += "</span>";
        retVal += "<div class='text'>";
        foreach (var key in helper.ViewData.ModelState.Keys) 
        {
            foreach(var err in helper.ViewData.ModelState[key].Errors)
                retVal += "<p>" + helper.Encode(err.ErrorMessage) + "</p>";
        }
        retVal += "</div></div>";
        return retVal.ToString();
    }
}

The code is self explanatory; just enumerating through modelstate errors and wrapping errors in dom element of your choice. There is an error that is if i use it like:

<%:Html.MyValidationSummary()%>

It will display html tags on the page as text rather than rendering it.

<%=Html.MyValidationSummary()%>

This works fine.


Building upon flos's answer, I made it compatible with Microsoft's jQuery Unobtrusive Validation and added Bootstrap's 3 panel styling. Here's the new code:

@model ModelStateDictionary

<div class="@(Html.ViewData.ModelState.IsValid ? "validation-summary-valid" : "validation-summary-errors") panel panel-danger"
     data-valmsg-summary="true">
    <div class="panel-heading">
        Please, correct the following errors:
    </div>
    <div class="panel-body">
        <ul>
            @foreach(var modelError in Model.SelectMany(keyValuePair => keyValuePair.Value.Errors))
            {
                <li>@modelError.ErrorMessage</li>
            }
        </ul>
    </div>
</div>

You can read about it in full detail here:

Creating a custom ASP.NET MVC @Html.ValidationSummary styled with Bootstrap 3 panel

I also created a sample ASP.NET MVC project to show this custom ValidationSummary in action. Get it here:

https://github.com/leniel/AspNetMvcCustomHtmlValidationSummary


Just posting my answer here because it's working well for me ;)

I use a simple extension method that takes an MvcHtmlString and decodes it back to HTML:

    public static MvcHtmlString ToMvcHtmlString(this MvcHtmlString htmlString)
    {
        if (htmlString != null)
        {
            return new MvcHtmlString(HttpUtility.HtmlDecode(htmlString.ToString()));
        }
        return null;
    }

To plumb this in, I add the validation summary helper to my chstml like this:

@Html.ValidationSummary(true).ToMvcHtmlString()

This means, I can add custom HTML to my validation summaries:

ModelState.AddModelError("", "<p>This message can have html in it</p>");

And I can even add custom HTML to my field validation messages:

ModelState.AddModelError("MyField", "<p>This message can have html in it</p>");

And to get my field validation messages to work with HTML:

@Html.ValidationMessageFor(model => model.MyField).ToMvcHtmlString();