Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC Validation - Keep it DRY with a service layer - What is best practice?

I am trying to adhere to best multi-layer design practices, and don't want my MVC controller to interact with my DAL (or any IRepository for that matter). It must go through my business service layer to enforce proper business rules and validation. Validation - I don't want to perform validation in the controller using the various validation attributes ( such as [Required]) on my domain model entities because this sheds light on my front end. Not to mention this service can also be implemented through a WPF front end.

Since my validation is being done in my service layer, what are best practices for returning values back to the UI? I don't want a 'void addWhatever(int somethingsID)', because I need to know if it failed. Should it be a boolean? Should it be a Enum? Should I take advantage of exception handling? Or should I return some IValidationDictionary object similar to that used by MVC when adorning validation attributes to Model objects? (which I could use an adapter pattern in the UI later if needs be)

I would like to pass my entity from the controller to the service layer, and understand whether or not validation/data-persistence failed. I also don't want to lose sight on the fact that I need to return a view indicating the proper error messages for each field that may have failed validation (I'd like to keep this as painless as possible).

I have had several ideas, all of which don't feel right. I feel the answer includes View-specific-model entities, but this leads to a whole mapping issue that must be dealt with, not to mention this violates the DRY (Don't repeat yourself) principle. What is best practice?

like image 657
spoof3r Avatar asked Nov 10 '11 03:11

spoof3r


People also ask

Should I validate controller or service?

As a general rule of thumb, I would say that business logic of this sort should be in the service. Controllers should be light-weight and pass on requests. Further, there may be other clients of your service, not just controllers, so this allows you to keep validation in one place.

What is the service layer in MVC?

A service layer is an additional layer in an ASP.NET MVC application that mediates communication between a controller and repository layer. The service layer contains business logic. In particular, it contains validation logic. For example, the product service layer in Listing 3 has a CreateProduct() method.

Which methods can be used to perform validation in MVC?

The following three type of validations we can do in ASP.NET MVC web applications: HTML validation / JavaScript validation. ASP.NET MVC Model validation. Database validation.

How do you handle validation in MVC?

In code we need to check the IsValid property of the ModelState object. If there is a validation error in any of the input fields then the IsValid property is set to false. If all the fields are satisfied then the IsValid property is set to true. Depending upon the value of the property, we need to write the code.


2 Answers

I know, it seems like doing MVC validation violates DRY, but in reality.. it doesn't.. at least not for most (non-trivial) applications.

Why? Because your view's validation requirements are quite often different from your business objects validation requirements. Your views validation concerns itself with validating that a specific view is valid, not that your business model is valid.

Sometimes those two are the same, but if you build your app so that the view requires the business model to be valid, then you are locking yourself into this scenario. What happens if you need to split object creation into two pages? What happens if you decide to use the service layer for a web service? By locking your UI into a business layer validation scenario you severly cripple the kinds of solutions you can provide.

The view is validation of the input, not validation of the model.

like image 117
Erik Funkenbusch Avatar answered Sep 17 '22 14:09

Erik Funkenbusch


This is how I have done it.

Have your service layer throw exceptions on business rule/validation rule failure. Create your own validation Exception for this, and include some properties to hold details of the validation error - (e.g. which property has the validation error, and what the message is)

Then create an extension method on Exception which will copy the details of the error to the ModelState (I got this idea from Steve Sandersons rather excellent 'Pro Asp.Net MVC 2 Framework' book) - if you do this right, MVC will highlight invalid fields, show errors in the UI etc.

Then your controller will contain something like this

try
{
    Service.DoSomeThing();
}
catch (Exception err)
{
    err.CopyTo(ModelState);
}

This means that your business rules and validation are now in your service layer, and this could be re-used.

Consider also passing DTOs / View Models to your Views, and mapping your domain objects to DTO's and (vice-versa), rather than passing your domain objects to your views.

Then the DTOs / View Models can reside in the MVC layer, and you can decorate these with the Validation attributes, and have the controller pass these to the views - thus using the built in MVC validation.

You will find that for any complex project, the validation you require at the UI end may be slightly different from what you require at the business rules end, so this helps seperate that.

There is a good library called AutoMapper which makes it easy to map from your domain objects to your DTOs (and vice versa) without a lot of boilerplate code.

like image 24
StanK Avatar answered Sep 19 '22 14:09

StanK