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.