In the previous ASP.NET MVC Tutorial:
I talked about using the Enterprise Library Validation Application Block with ASP.NET MVC to handle validation of your business objects in our web applications. I used the Validation Application Block's Validation Facade Class in the Controller and then queried the results of ValidationResults.IsValid to determine if validation was successful. If validation was not successful, I enumerated through each ValidationResult and updated ASP.NET MVC's ModelState via ModelState.AddError appropriately to display the UI input validation errors to the user.
This ASP.NET MVC Tutorial will introduce the Enterprise Library Policy Injection Application Block to handle validation in another way. Please check out the tutorial above first as I won't be duplicating some of the code. Feel free to check out the other ASP.NET MVC Tutorials as well:
Policy Injection Application Block Tutorials
Here are some Policy Injection Application Block Tutorials if you need some background:
Policy Injection Application Block Assemblies Referenced
We need to reference two additional assemblies in addition to what I mentioned in the previous tutorial:
- Microsoft.Practices.EnterpriseLibrary.PolicyInjection
- Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers
ValidationCallHandler in Policy Injection Application Block
There is a particular call handler in the Policy Injection Application Block for use with the Validation Application Block, called ValidationCallHandler. I am adding the ValidationCallHandler Attribute to my ICustomerRepository Interface's Add Method to invoke validation as a cross-cutting concern. When the Add Method is called, the method will be intercepted and validation on my customer instance will take place prior to the Add Method being executed. If validation fails, the Add Method will not be called. Instead, an ArgumentValidationException will be thrown and we will pass those validation errors back to the UI for correction. Nice and tidy :)
public interface ICustomerRepository
{
[ValidationCallHandler]
void Add(Customer customer);
}
public class CustomerRepository : ICustomerRepository
{
public void Add(Customer customer)
{
}
}
The actual code for persistence is unimportant so I left it blank. Notice the [ValidationCallHandler] Attribute mentioned above on the ICustomerRepository Interface.
PolicyInjection.Wrap Returns Remoting Proxy
The Policy Injection Application Block has a PolicyInjection Class with a Wrap Method ( PolicyInjection.Wrap ) that will return a remoting proxy if it detects that interception needs to take place on the class it is wrapping. The remoting proxy returned in this case intercepts the Add Method on ICustomerRepository and first does validation as mentioned above. In my Customers Controller Class I am wrapping CustomerRepository in the constructor.
public class CustomersController : Controller
{
private ICustomerRepository _repository;
public CustomersController() : this(
PolicyInjection.Wrap<ICustomerRepository>
(new CustomerRepository())) {}
public CustomersController(ICustomerRepository repository)
{
_repository = repository;
}
// ...
}
ASP.NET MVC Validation in Action
Now in our Controller Action we can attempt to add the customer to the repository and catch the Policy Injection Application Block's ArgumentValidationException when it detects bad user input:
public ActionResult Save()
{
Customer customer = new Customer();
try
{
UpdateModel(customer, new[] { "Name", "Email" });
_repository.Add(customer);
}
catch(ArgumentValidationException ex)
{
AddValidationResults(ex.ValidationResults,
ViewData.ModelState);
return View(customer);
}
//...
}
This looks a bit cleaner IMHO. None of that nasty cross-cutting concern garbage getting in the way of our reading of the code.
The results are the same as mentioned in the previous ASP.NET MVC Tutorial when input is erroneous:
Conclusion
The use of the Enterprise Library Policy Injection Application Block with the Validation Application Block offers another way of handling validation in the ASP.NET MVC Framework. You can learn more about proven patterns & practices at PnPGuidance.
I want to note that in the Enterprise Library 4.1 and Unity 1.2 Project Kickoff there was mentioning of other interception mechanisms down the road. Very nice!
Hope this helps.
David Hayden