Better MVC Validation Support

Jan 28, 2009 at 11:51 PM
I really like the work behind the validation and business rules you've done. I've been attempting to integrate this in with an ASP.NET MVC project I'm working on and have come across a few difficulties.

Creating an entity validator and validation rules has been easy. I'm running into issues mapping the validation errors back to the MVC ModelState however. When populating the ModelState with errors, it needs to know the attempted value entered, but this data isn't stored in the ValidationError object.

Can you give a suggestion about how to adapt your validation classes to the ModelState requirements? Scott Gu has some examples where he wrote a basic rules validator at:

Jan 29, 2009 at 3:40 AM
I think the current design might actually work. I realized that by the time these rules are run, the model's properties are already going to be set. This setup seems to work well. I did add a ValidationException class that contains the ValidationResult from the EntityValidator. This allows me to throw an exception if validation rules aren't met and to pass on the errors to the calling code. This might be a class worth adding to the NCommon framework.
Jan 30, 2009 at 12:54 PM

I normally don't like using exceptions as a means to communicate validation errors. Exceptions should be used to indicate just that, an exception to the normal execution of code. While validations are expected errors and shouldn't be used to communicate validation errors to the UI. Not only do they require an additional overhead to throw and catch, they also are not sematically correct.

The way I work with validation is to have my EntityValidatorBase implementation injected to my controllers and validate my entities in the appropriate actions. For e.g.:

public class OrdersController
      private IEntityValidator<Order> _validator;

      public OrdersController(IEntityValidator<Order> validator)
          _validator = validator;

     public ActionResult Create()
         return View(new Order());

    public ActionResult Save(Order order)
        Guard.Against<ArgumentNullException>(order == null, "Cannot save a null order");
        var validationResult = _validator.Validate(order)
        if (!validationResult.IsValid)
           //Add erros to the ModelState and return back to create
        //Save the order and redirect to Index

I'm working on a complete sample on how to use the EntityValidatorBase in ASP.Net MVC. I'll update this thread one I've completed the sample.
Jan 30, 2009 at 12:56 PM
Also, that piece of code that does the validation and updates the ModelState, that can be abstracted into a method of a base controller class. That way DRY principle is maintained.
Jan 30, 2009 at 2:26 PM
I understand the reasoning behind calling Validate in the controller class, and that is what I have historically done. However, after reading a post about model validation by Steve Sanderson ( ) I found myself agreeing with his comments.

He basically said that:
1) The model should be responsible for validating itself, not the calling code (Controller, Service, etc).
2) Validation can and should happen at several different points in the model's lifecycle.
3) There needs to be some method of communicating a validation error back up to the calling code.

He certainly makes some good arguments, although for a simple MVC site, either approach is fine.
Feb 1, 2009 at 2:39 PM
I guess this is where I draw the line in how much stuff goes into my domain objects. Steve's post definitely has some valid points but as a design point of view, I don't like having to add attributes to my domain entities in the first place. This reminds me more of the Business Objects route, aka Active Record, where validation, persistence and logic was all stuffed into the domain objects. I'm not saying that the ActiveRecord approach is wrong or anything, I believe in a different design in how my domain entities should behave and what are the responsibilities of the domain objects.

Another design decision I don't agree with is the statement that the Controller or the Service layer is not responsible for validating the model, instead the model entity is responsible for validating itself. In the post, Steve validates the entity in the Repository and refers to that as model validation. I don't believe that can be termed as model validation, because the repository is not part of your domain model. The domain model has no concept of persistence and should not have to rely on any persistence level dependency. Second, I believe that repositories should not have any sort of validation, at all. Period. A repository's only responsibility is to provide persistence semantics for storing your domain entities and if there is any validation that needs to be performed, it should be done to validate the state of the repository and not the entity state. Repositories should return pre-validated entity instances and should receive pre-validated entities. Putting validation logic into repositories in my opinion is a violation of single responsibility rule.

Now, as far as self validating models go, the question arises when and how does it validate? The When question is very valid because validation should be performed at well defined stages. I've seen solutions that perform validation at every property set, and that has some severe performance implications. If the solution is to provide a Validate or EnsureValidate method on every entity, who calls that EnsureValidate method? If the entity should validate itself, then how does the entity know when to validate? If a Controller or Service component calls the EnsureValidate, then the onus of calling that method falls in the scope of Controller or Service component.

Now the how part. The main point of a self validating domain object is that the validation rules are encapsulated within the domain entity and those rules are enforce by the entity when being validated. That means that in the traditional case, like my example, where the controller gets a hold of validation rules and runs those rules against the order entity, in the case of a self validation domain entity, the controller would simply call EnsureValidate and that's it. The controller would not know what validation rules to apply against the entity and what defines a valid or invalid state, it would delegate that to the entity.

You can certainly achieve that level of encapsulation using NCommon. Instead of having the IEntityValidator<T> injected into the Controller, in the EnsureValidate method of every entity, resolve a IEntityValidator for the entity type via ServiceLocator, run the rules and return the result. You could even throw an exception to signal a validation exception (although I'm against that pattern) and even encapsulate this entire logic in a abstract EntityBase class that would run the rules against the entity instance.

The reason I like having validations externalized from the entity instances is because many times the validations performed change based on the context the entity is operating under. That allows me to have the correct set of validations injected into my controllers or service components and allow validating the entities based on the the context. In the case of self valdiating models, that would mean that the entities would have to be aware of what context they are being used in and self adjust the validation rules that need to be performed, and thats a can of worms I would not like to open.
Feb 1, 2009 at 4:37 PM
I absolutely agree with you regarding the validators being external to the model. I don't like the attribute validation either because it just isn't flexible enough. In my project, a given model might be valid in different stages with varying amounts and types of data. That's just the way business works.

Right now I'm having instances of IEntityValidator<T> injected into the controllers and am using those for validation. I'm unsure if I want to further inject them into the repository or not. I do find the ValidationException pattern to be useful and am also using that. I'll see how this evolves over time and if I encounter any significant problems along the way.