The recently-released ASP.NET MVC Framework is a refreshing new way to develop your .NET Web applications. The framework is an implementation of the time-tested Model-View-Controller architectural pattern, and includes plenty of powerful paradigms allowing you to quickly build maintainable applications. Likewise, the Enterprise Library
Validation Application Block implements a proven set of best practices that allow you to stop worrying about how to execute validation logic and begin immediately delivering real business value. In this article, you’ll discover just how well these two frameworks work together through powerful examples of this natural pairing in action.
All data-driven systems must validate their inputs. Developers of databases, backend systems, Web services, and end-user applications alike have always had to worry about ensuring the data they receive is as valid as possible. Web applications are arguably the most susceptible to invalid inputs due to their vast exposure to potentially any Internet-connected device in the world. However daunting the task, most of today’s Web application frameworks provide some kind of validation mechanism to help developers combat the evils of invalid data. The ASP.NET MVC Framework is no different.
Validation in ASP.NET MVC
Most Web Forms developers are intimately familiar with the Validation server controls the ASP.NET libraries provide. Controls like the RequiredFieldValidator and RegularExpressionValidator have been helping validate users’ submissions since the framework’s initial release. Given the obvious importance of these controls, it should come as no surprise that the first release of the ASP.NET MVC Framework also includes an easy way to add validation logic to your forms.
Similar to just about everything related to ASP.NET MVC, its approach to validation is much different than its Web Forms cousin. As opposed to the server controls used in Web Forms (which essentially encapsulate the validation logic in the view) ASP.NET MVC instead divides this logic into distinct view-specific and controller-specific portions.
Similar to just about everything related to ASP.NET MVC, its approach to validation is much different than its Web Forms cousin. As opposed to the server controls used in Web Forms (which essentially encapsulate the validation logic in the view) ASP.NET MVC instead divides this logic into distinct view-specific and controller-specific portions.
Listing 1 shows an example of a simple view with these new ASP.NET MVC validators in action. Here you can see how (in customary MVC fashion) the framework leverages extension methods to process view-specific validation logic. The first validation method in this snippet, Html.ValidationSummary(), acts much like its Web Forms server control cousin (ValidationSummary), providing a summary of all of the validation errors for the current page. On the contrary, the extension method used for field-level validation, Html.ValidationMessage(), does not include any logic in the view. In fact, in this particular case calls to this method do not even include error messages beyond “*”! Instead, these calls only serve as placeholders or markers to specify where the errors discovered by the Controller will display when the page renders. As you can see, this helps keep MVC views very simple, avoiding any unnecessary logic that should be performed elsewhere.
Even though you may have accepted the notion that the extension methods displaying the errors in the view are not responsible for performing the actual validation, this still begs the question: where do these validation messages come from?
Listing 2 provides the answer, showing the Controller Action responsible for populating view data. The listing starts out accepting a parameter named username, which corresponds to the field with the same ID in the view shown in Listing 1. The ASP.NET MVC Framework is nice enough to wire this parameter up for us, populating it with the value that the user entered into the form. The Controller then validates the parameter by verifying its length and if the value is not long enough, the Controller adds an error message to the ModelState property to indicate that something has gone wrong.
This ModelState property keeps track of all of the validation errors, making them available to the validation extension methods shown earlier in Figure 1. The important part to notice here is how the Controller passes in the same ID used in the form (e.g. “Username”) to the ModelState.AddModelError() method. The ASP.NET MVC validation framework later will use the errors added to the ModelState to determine which fields are invalid as well as create the link between error messages and their associated fields in the view.
![Figure 1: A simple example of the result of a form that has failed validation due to no value entered in the Username field.](https://codemag.com/Article/Image/0911101/Chadwick_Figure 1.tif)
After the Controller has finished looping through any validation errors and adding them to the ModelState, you may evaluate the ModelState.IsValid property to see if any errors were found during the validation process. If the value of the ModelState.IsValid property is true, you can carry on processing the request knowing that all the inputs met your high standards. Otherwise, you can reject this request and ask the user to correct their mistakes. As a bonus, the rejected request will also contain all of the nice error messages the Controller populated along the way, letting the user know exactly what went wrong and how they can fix their mistakes.
Simplifying Validation with the Enterprise Library Validation Application Block
In the last section you learned how to ensure that the system rejected any invalid data. However, you’ll quickly find that distributing these validation rules throughout Controller logic as opposed to a centralized location (such as a Domain Model) tends to cause problems when the business rules change and need to be corrected throughout the entire application.
Moving the coded business logic into a method or property in a more cohesive class is a good first step, but it does not change the fact that the rules are still expressed in code; and code has bugs. This is where the Validation Application Block comes into play, allowing you to remove that unwanted code and replace it with a declarative syntax that can be easily read, understood, and changed!
What Is the Enterprise Library?
The Enterprise Library (sometimes referred to as “EntLib”) is an implementation of various best practices espoused by Microsoft’s Patterns and Practices group. It comprises numerous application blocks, each tackling a different set of common cross-cutting concerns that many developers face. These blocks include libraries for validation (featured in this article), data access, logging, exception handling, and more.
In addition to providing a robust set of compiled assemblies to help you address these problems, the Enterprise Library also delivers the full set of source code and documentation used to create those libraries. This enables you to jump right into the heart of them if you ever need to make a change or simply become interested in seeing how the components were written. The framework’s transparency, robustness, and usability have driven its wide-spread adoption in development teams of all sizes. I’ll focus on the validation block in this article, but the validation block is only one component in this powerful library. I strongly urge you to evaluate the rest the application blocks the Enterprise Library offers to see how well they may fulfill your other development needs.
Applying the Validation Block
Since the previous example involved only one field/property, the rest of the article will focus on a slightly more complex object model to better show how powerful the Validation Block really is.
First, I’ll introduce a slightly more realistic (albeit still simple) business object, prior to applying any validation logic. As you can see, it’s relatively unimpressive:
public class Product
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public double Price { get; set; }
public int Quantity { get; set; }
}
The Enterprise Library’s transparency, robustness, and usability have driven its wide-spread adoption in development teams of all sizes.
Using the Validation Block I can quickly and easily add a few attributes to these properties (as shown in Listing 3) defining the validation rules for each one. Now when I have an instance of a Product, instead of other components attempting to validate that instance they can simply ask it to validate itself!
Putting the New Validation to Good Use
Now that you have this fancy new validation logic in place, you can really see it in action. As Listing 4, shows, the Controller is no longer troubled with determining which fields are invalid, why they are invalid, or even which error messages to display. Instead, the Controller is only concerned with mapping the submitted data to an instance of the new Product class, asking it to validate itself, and then populating the ModelState with the validation results.
Populating the ModelState using the validation results works very well due to the fact that both the index of the ModelState error collection and the validation result’s Key property both use the name of the invalid field. For example, Figure 2 shows the value “name” used in both the ModelState.Keys collection and the ValidationResult object returned from the call to product.Validate**().** Since the keys used in ModelState are not case-sensitive, it is not an issue that one uses the value “name” while the other uses “Name”.
![Figure 2: This snapshot of the Watch window shows that the Key field on the ValidationResult and the ModelState.Key are the same (since the ModelState.Key is case-insensitive).](https://codemag.com/Article/Image/0911101/Chadwick_Figure 2.tif)
At this point in the process, the Model, Views, and Controllers all contain a clean separation of validation, view, and controller logic. On any given day, I’d usually be comfortable with that knowledge and packing up and heading home, but before I check out for the day, let me revisit the current solution and see how a bit of refactoring can make this code a whole lot cleaner…
Taking Advantage of ASP.NET MVC Model Binding (and Other Refactorings) for Cleaner Code
Though the current state of the Action as seen in Listing 4 works perfectly well, a few quick improvements will make your co-workers thank you when they have to come back in a few months to try to read your code and figure out what you’ve done.
Implementing Model Binders
Taking advantage of a powerful ASP.NET MVC feature called model binders will certainly help make this code easier to understand. With the pre-configured default model binder, you no longer have to worry about that mundane object initialization cruft; instead you let the binder do all the work of populating the object for you! Thus, the following initialization snippet:
public ActionResult Create
(
string name, string description,
double price, int quantity
)
{
var product = new Product
{
Name = name,
Description = description,
Price = price,
Quantity = quantity
};
Now becomes:
public ActionResult Create(Product product)
{
/* Nothing else to do! */
And as you can see, I’ve now replaced that list of parameters with a single business object that is populated from the request via reflection. This allows me to dive right into my controller logic unabated.
With the pre-configured default ASP.NET MVC model binder, you no longer have to worry about that mundane object initialization cruft; instead you let the model binder do all the work of populating the object for you!
After you’re done basking in the power of model binders, let’s look at how to refactor the next part of this action: looping through the validation results and adding them to ModelState.
Creating Extension Methods to Remove Duplication
Extracting this very generic looping code into a helper method would be a step in the right direction… and whenever I think of “helper methods” in .NET 3.0 I think of extension methods!
Here’s what the extension method handling the validation results mapping to the ModelState might look like:
public static class ModelStateExtensions
{
public static void AddValidationResults
(
this ModelStateDictionary modelState,
ValidationResults results
)
{
foreach (var result in results)
{
modelState.AddModelError(
result.Key, result.Message);
}
}
}
With this new extension method in place, I can now revisit the original Controller Action that was initially 29 lines long and turn it into the compact snippet you see in Listing 5, coming in at only 14 lines (including whitespace)! Now there is less code to understand and a greater focus on the actual work at hand-processing the user’s request!
Summary
This article demonstrated how the combination of ASP.NET MVC and its powerful Model Binding functionality coupled with the Enterprise Library Validation Application Block offers an effective and compelling solution to the classic recurring development problem of input validation. This combination not only helped address immediate issues concerning input validation, it also helped deliver a better separation of concerns and higher cohesion throughout. As a result, you have cleaner code that is easier to understand and thus easier to maintain.
Further Research
I am remiss to end this article at this point because there is so much more to discuss on the topic of model binding and validation in ASP.NET MVC. If this article piqued your interest, I highly encourage you to not only try the techniques described for yourself, but also to dig a little deeper on your own.
For example, the approach described in this article also works just as well with any of the other validation solutions available, including the one included right in the .NET 3.5 Framework: data annotations. Also, you will be pleasantly surprised by the results you may find by performing a few Internet searches for some of the terms I’ve discussed such as ASP.NET MVC model binders, ASP.NET MVC validation, Enterprise Library, and particularly the “Enterprise Library Validation Model Binder”.
Good luck and happy coding!
Listing 1: Simple form with validation (Create.aspx)
<h2>Add New User</h2>
<%= Html.ValidationSummary(
"There was a problem with your submission." +
"Please correct the errors and try again.") %>
<% using (Html.BeginForm()) {%>
<fieldset>
<p>
<label for="Username">Username:</label>
<%= Html.TextBox("Username")%>
<%= Html.ValidationMessage("Username", "*")%>
</p>
<p>
<input type="submit" value="Add" />
</p>
</fieldset>
<% } %>
Listing 2: Controller action with validation logic (UsersController.cs)
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(string username)
{
// Validate the posted username
if (string.IsNullOrEmpty(username)
|| username.Length > 200)
{
this.ModelState.AddModelError("Username",
"Username must between 1 and 200 characters");
}
// If there were any validation errors, return now
if (!ModelState.IsValid)
return View();
/* Perform additional logic here... */
}
Listing 3: Product class with validation block attributes applied
using Microsoft.Practices.EnterpriseLibrary.Validation;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;
public class Product
{
[RangeValidator(
1, RangeBoundaryType.Inclusive, /* Lower Bound */
int.MaxValue, RangeBoundaryType.Inclusive,/* Upper Bound */
MessageTemplate = "ID must be greater than 0"
)]
public int ID { get; set; }
// Assume that you have a field length limitation in
// your database of 500 characters, which you'll check for here
[StringLengthValidator(
1, RangeBoundaryType.Inclusive, /* Lower Bound */
500, RangeBoundaryType.Inclusive, /* Upper Bound */
MessageTemplate = "Name length must be between 1 and 500"
)]
public string Name { get; set; }
// No rules for the description - anything goes!
public string Description { get; set; }
// The Price can be whatever you want,
// as long as it's positive
[RangeValidator(
0d, RangeBoundaryType.Inclusive,
double.MaxValue, RangeBoundaryType.Inclusive,
MessageTemplate = "Price must be greater than 0.00"
)]
public double Price { get; set; }
// Same deal with the Quantity -
// you can never have a negative quantity
[RangeValidator(
0d, RangeBoundaryType.Inclusive,
int.MaxValue, RangeBoundaryType.Inclusive,
MessageTemplate = "Quantity must be greater than 0"
)]
public int Quantity { get; set; }
public bool IsValid()
{
return Validate().IsValid;
}
public virtual ValidationResults Validate()
{
return Validation.Validate<Product>(this);
}
}
Listing 4: Putting our new validation logic to the test
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create
(
string name, string description,
double price, int quantity
)
{
var product = new Product
{
Name = name,
Description = description,
Price = price,
Quantity = quantity
};
foreach (var result in product.Validate())
{
this.ModelState.AddModelError(
result.Key, result.Message);
}
if (!ModelState.IsValid)
return View(product);
/* Add new Product to the database */
return View("Index");
}
Listing 5: The refactored Controller Action, after refactoring to use ASP.NET MVC model binding and extension methods
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Product product)
{
ModelState
.AddValidationResults(product.Validate());
if (!ModelState.IsValid)
return View(product);
/* Add new Product to the database */
return View("Index");
}