Show Validation Messages Containing Images in ASP.NET MVC

ASP.NET MVC offers HTML helpers for displaying field level validation error
messages as well as validation summary. However, these validation messages are
displayed as a plain string. There is no inbuilt way to include images or HTML
markup with the output of the validation helpers. In this article I will show
how to overcome this limitation using two techniques so that you can display
images along with the validation messages. The techniques I discuss include:
- Use HTML markup in the validation message to display an image.
- Using a CSS class to display an image.
Before I delve into more details, let's quickly see the model that this
example is going to use:
public class Employee
{
public int EmployeeID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
The Employee model class contains three properties namely EmployeeID,
FirstName and LastName. To keep the model clean you won't add data annotations
here. You will add them to metadata class(s) as discussed later.
The Home controller that makes use of this model contains two actions as
shown below:
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult ProcessForm(Employee emp)
{
if(ModelState.IsValid)
{
//do insert here
}
return View("Index", emp);
}
The Index() action simply displays the Index view like this:

The ProcessForm() action receives an instance of Employee model through model
binding. If there are any errors they are shown like this:

Notice how images are being displayed by ValidationMessageFor() and
ValidationSummary() helpers.
Using HTML markup in the validation message to display an image
Now let's create a metadata class that contains data annotations for the
Employee class. This class - EmployeeMetadata - is shown below:
public class EmployeeMetadata
{
[Required]
[Range(1, int.MaxValue,
ErrorMessage = "<img src='/images/error.png' />
Invalid EmployeeID!")]
public int EmployeeID { get; set; }
[Required]
[StringLength(20,
ErrorMessage = "<img src='/images/error.png' />
Invalid first name!")]
public string FirstName { get; set; }
[Required]
[StringLength(20,
ErrorMessage = "<img src='/images/error.png' />
Invalid last name!")]
public string LastName { get; set; }
}
Notice how ErrorMessage property of [StringLength] attribute includes an
image HTML markup tag. Once created attach this metadata class to the Employee
class using [MetadataType] attribute.
[MetadataType(typeof(EmployeeMetadata))]
public class Employee
{
...
}
Add the Index view and change its content as per the following markup.
...
...
@using(Html.BeginForm
("ProcessForm","Home",FormMethod.Post))
{
<table cellpadding="10" border="1">
<tr>
<td>@Html.LabelFor(m=>m.EmployeeID)</td>
<td>
@Html.TextBoxFor(m=>m.EmployeeID)
@Html.ValidationMessageFor(m=>m.EmployeeID)
</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.FirstName)</td>
<td>
@Html.TextBoxFor(m => m.FirstName)
@Html.ValidationMessageFor(m => m.FirstName)
</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.LastName)</td>
<td>
@Html.TextBoxFor(m => m.LastName)
@Html.ValidationMessageFor(m => m.LastName)
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Submit" />
</td>
</tr>
</table>
}
@Html.ValidationSummary()
...
...
So far so good. If you run the application at this point in time you will see
this:

That's because ASP.NET MVC by default HTML encodes the output of validation
helpers. So, your embedded HTML fragment is not treated as actual HTML and no
image is displayed.
Now let's fix this problem with a bit of clever code.
Modify all your ValidationMessageFor() calls like this:
@Html.Raw(
HttpUtility.HtmlDecode(
@Html.ValidationMessageFor(m=>m.EmployeeID).ToHtmlString()
))
Notice the above like of code carefully. The return value of
ValidationMessageFor() is MvcHtmlString. Calling ToHtmlString() method on it
gives you the HTML encoded plain string. This HTML encoded plain string is then
decoded using HtmlDecode() method of HttpUtility object. Doing so will give us
raw HTML string. This string is finally sent to the response stream using Raw()
helper.
Do the same for ValidationSummary() helper:
@Html.Raw(
HttpUtility.HtmlDecode(
@Html.ValidationSummary().ToHtmlString()
))
If you run the application now, you will see the validation errors being
displayed as per Figure 2 of this article.
Using CSS class to display an image
In the above technique you embedded HTML fragment in the data annotation
attributes. You may want to avoid this "ugly" way of specifying validation
errors in some cases. If so, you can still achieve almost identical results
using CSS classes.
Add a new metadata class or modify the existing one as shown below:
public class EmployeeMetadata
{
[Required]
[Range(1, int.MaxValue,
ErrorMessage = "Invalid EmployeeID!")]
public int EmployeeID { get; set; }
[Required]
[StringLength(20,
ErrorMessage = "Invalid first name!")]
public string FirstName { get; set; }
[Required]
[StringLength(20,
ErrorMessage = "Invalid last name!")]
public string LastName { get; set; }
}
As you can see, you no longer embed HTML markup in the validation messages.
Also revert back the Index view as it was before using the Raw() helper.
Next, add a CSS file and modify it to have the following style rules:
.field-validation-error {
color: #b94a48;
background-image: url(Images/error.png);
background-repeat:no-repeat;
padding-left:22px;
background-size:contain;
}
.validation-summary-errors {
color: #b94a48;
background-image: url(Images/error.png);
background-repeat:no-repeat;
padding-left:44px;
background-size: contain;
}
Remember that these CSS class names are assumed by the validation helpers and
hence you should keep them exactly as shown above. The field-validation-error
CSS class is applied to ValidationMessageFor() helpers whenever there is any
validation error. SImilarly, validation-summary-errors CSS class is applied to
ValidationSummary() whenever there is any validation error. Notice the style
rules shown in bold letters. You are using a background image for the field
level validations and the validation summary. You may need to adjust the padding
as per your image dimensions. Note that there will be minor differences between
the way images are shown in the previous technique and this technique. For
example, in this technique ValidationSummary() will display just a single
instance image for all the messages instead of one image per message (as in the
previous technique).
That's it! Run the application and see if images are shown as expected.