3
votes

How do I avoid needing to repeat validation rules on both my ViewModels and business/domain objects?

For example I can use DataAnnotation attributes on my ViewModel, and this will give me client and server side validation in my MVC web app. But this ViewModel will then generally be mapped to a business/domain object and given to a service preform some business logic, meaning validation will have to happen again, often with the same or simular rules. Is there anyway round this?

2

2 Answers

6
votes

I think what you're describing is normal and acceptable. Consider your UI and data annotation as the friendly UI validation that is capable of showing users immediately any validation problems with the data entered.

I would consider your Business/Domain object's validation to be the complete validation, not just validating values but enforcing business rules (i.e. - Add Item to Cart -->Is the Item in Stock?)

Then there is always back end validation that is often enforced by the database (i.e. Allowing Nulls in a column). Unless your database allows nulls in all fields, your actually performing validation in more than just the two places you mentioned, and this I think is a good thing.

I think the bottom line is that you probably want your Business/Domain objects to enforce all validation, and your client side and back end validation to simply enforce the most basic.

Hope that helps.

0
votes

If you want to validate two separate objects and avoid duplicating code, then I think you may be in for an answer you won't want to hear.

The only exception I can think of is to take the returned view model (unvalidated) and populate your models as you would if you were to perform the database action, then do the validation check there. If there are errors, bring those back to the ModelState dictionary and return the view to the browser with errors. This approach has the big side effect that you'd lose the client-side integration, or at best - it'd involve a lot of AJAX calls to the server side.

Personally, I'd accept defeat and accept that you're going to have duplication of effort and just ensure that as much of your code is re-usable (e.g. as Data Annotation attributes that can be placed on both your view models and business models.

  • Checks in your view models should ensure that the information provided is correct e.g:

    • Its not empty.
    • Its a valid email address
    • The email address hasn't already been used
    • The value entered matched the value of the 'confirm email' box.
  • Checks within your business models check to see that the data is correct. e.g.

    • Its not empty.
    • Its length is less than the maximum length.

However, with the business logic, if you're concerned that the data may get polluted by inconcistent checks by alternative interfaces (or your forgetfulness), then duplicate some of the methods into the business logic or into the model metadata too.