Question

I want to be able to perform validation from within my Service classes. I have a Controller action that looks something like this:

public ActionResult Edit(Post post)
{
    if(!ModelState.IsValid)
       return View();

    _postDataService.SavePost(post);

    return View("Index");
}

I don't like the fact that my _postDataService.SavePost() can save invalid data and I want to move the model validation to my _postDataService.SavePost() method. My question is what is the most elegant way to do this? And if I move my model validation to my Service method, how do I return my model errors back to my controller? Lastly, where would model validation like uniqueness of the email address go since it require's some data access? Of all the similar questions i've looked at, none of them give a straight forward way to do this.

I also considered this solution but this article is old and I have a feeling it's not up-to-date.

Was it helpful?

Solution

I assume you are doing validation by putting attributes on properties in your Post model/entity class. If so, you can validate in your service layer by doing this:

var results = new List<ValidationResult>();
var isValid = Validator.TryValidateObject(post, 
    new ValidationContext(post, null, null), results, true);

This is essentially what the default modelbinder does when it validates and configures the ModelState object for the controller / action.

The beauty of this approach is that you don't have to return validation errors from the service layer. You will just rely on the default modelbinder to do the above code automatically. If someone ever tries to invoke that action without checking ModelState.IsValid, just have your service method throw an exception to remind them.

Update after comment

Yes, my answer recommends doing the validation twice.

How do I feel about it? I don't mind. We use Entity Framework 4.1 with MVC, and do not use entities in MVC. Instead we use automapper to DTO the entities into a separate viewmodel layer. Our EF entities are also decorated with ValidationAttributes, which EF evaluates automatically during any DbContext.SaveChanges() operation. We apply very similar validation attributes on properties of our viewmodel classes. This might not seem DRY, and there is definitely overlap, but in some cases the validation attributes on the UI side can be different than the validation attributes in the domain model.

We do not do validation in a service layer. Our service layer is simply an application flow coordinator, and takes no responsibility for business rules. However, validation still happens twice in our application. First, by the default model binder, against the viewmodel validation rules. Then if the transaction makes it to EF, validation performed against the entities. So we are actually validating 2 separate layers.

If you think about it though, you really are tackling 2 different concerns here. In the UI, you want MVC to display validation messages to users. ModelState is great for this, since it hooks nicely with MVC validation (model binding / jquery / unobtrusive / client-validation / etc).

Conversely in the domain, you are protecting your data integrity and enforcing business rules. The domain doesn't care about displaying messages to a user. For all it knows, the client may be a machine, WCF service, or something else. The role of the domain is to prevent a transaction from occurring, and (in our case) throws an exception rather than quietly trying to "work with" the client.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top