Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validation in a layered application

I'm wondering what's the best way to do validation of database constraints (e.g. UNIQUE) in a ASP.NET MVC application, build with DDD in mind, where the underlying layers are Application Layer (application services), Domain Layer (domain model) and Infrastructure Layer (persistance logic, logging, etc.).

I've been looking through lots of DDD samples, but what many of them doesn't mention is how to do validation in the repository (I suppose that this is where this type of validation fits). If you know of any samples doing this, please share them it will be much appreciated.

More specific, I have two questions. How would you perform the actual validation? Would you explicitly check if a customer name already exists by querying the database, or would you try inserting it directly in the database and catching the error if any (seems messy)? I prefer the first one, and if choosing this, should it be done in the repository, or should it be the job of a application service?

When the error is detected, how would you pass it to ASP.NET MVC so the user can be informed nicely about the error? Preferably using the ModelStateDictionary so the error is easily highlighted on the form.

In the N-Lyered app by Microsoft Spain, they use the IValidatableObject interface and the most simple property validation is placed on the entity itself, such as:

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    var validationResults = new List<ValidationResult>();

    if (String.IsNullOrWhiteSpace(this.FirstName))
        validationResults.Add(new ValidationResult(Messages.validation_CustomerFirstNameCannotBeNull, new string[] { "FirstName" }));

    return validationResults;
}

Before the entity is persisted, the Validate message is called to ensure that the properties are valid:

void SaveCustomer(Customer customer)
{
    var validator = EntityValidatorFactory.CreateValidator();

    if (validator.IsValid(customer)) //if customer is valid
    {
        _customerRepository.Add(customer);
        _customerRepository.UnitOfWork.Commit();
    }
    else
        throw new ApplicationValidationErrorsException(validator.GetInvalidMessages<Customer>(customer));
}

The ApplicationValidationErrorsException can then be catched in the MVC application and the validation error messages can be parsed and inserted into the ModelStateDictionary.

I could add all the validation logic into the SaveCustomer method, e.g. querying the database checking if a customer already exists using a given column (the UNIQUE one). Maybe this is okay, but I would rather that the validator.IsValid (or something similar) would do this for me, or that validation is performed once again in the Infrastructure layer (if it belongs here, im not sure).

What do you think? How do you do it? I'm very interesting in gaining more insight into different validation techniques in layered applications.


Possible solution #1

In the case where the validation logic can't be done in the presentation layer (like Iulian Margarintescu suggests) and needs to be done in the service layer, how would you pass validation errors up to the presentation layer?

Microsoft has a suggestion here (see listing 5). What do you think about that approach?

like image 444
Tommy Jakobsen Avatar asked May 01 '12 20:05

Tommy Jakobsen


People also ask

What is data validation layer?

Data layer validation is the process whereby you can verify that: Your data layer object is always present. The variables within the object are present. The variable values are in the correct format.

Where should validation take place?

Data validation should occur in two locations: The point where data is acted upon, for example validating input parameters to an SQL query. General validation at the point where data is submitted, for example in a web application some validation should occur on the client.

What should service layer contains?

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.

What is the service layer responsible for?

A Service Layer defines an application's boundary and its set of available operations from the perspective of interfacing client layers. It encapsulates the application's business logic, controlling transactions and coordinating responses in the implementation of its operations.


1 Answers

You mention DDD, yet there is a lot more to DDD than entities and repositories. I assume you are familiar with Mr Eric Evans's book Domain Driven Design and i would strongly suggest you re-read the chapters about strategic design and bounded contexts. Also Mr Evans has a very nice talk called "What i've learned about DDD since the book" that you can find here. Talks about SOA, CQRS and event sourcing from Greg Young or Udi Dahan also contain a lot of information about DDD and applying DDD. I must warn you that you might discover things that will change the way you think about applying DDD.

Now for your question about validation - One approach might be to query the db (using an Ajax call that is directed to an app service) as soon as the user types something in the "name" field and try to suggest an alternative name if the one he entered already exists. When the user submits the form, try to insert the record in the db and handle any duplicate key exception (at the repository or app service level) . Since you are already checking for duplicates ahead of time the cases where you get an exception should be fairly rare so any decent "We are sorry, please retry" message should do since, unless you have A LOT of users they will probably never see it.

This post from Udi Dahan also has some information on approaching validation. Remember that this might be a constraint you are imposing on the business instead of a constraint that the business imposes on you - Maybe it provides more value for the business to allow customers with the same name to register, instead of rejecting them.

Also remember that DDD is a lot more about business than it is about technology. You can do DDD and deploy your app as a single assembly. Layers of client code on top of services on top of entities on top of repositories on top of databases have been abused so many times in the name of "good" design, without any reasons for why it is a good design.

I'm not sure this will answer your question(s) but i hope it will guide you to find the answers yourself.

like image 94
Iulian Margarintescu Avatar answered Sep 30 '22 21:09

Iulian Margarintescu