Related: What’s the best way to implement field validation using ASP.NET MVC?
Let's suppose a solution with the following projects:
Foo; // the MVC web project
Foo.Models;
Foo.Repositories;
Foo.Services;
Foo.Models
is the domain of the application with all the entities, doesn't matter if using EF, NH, POCO or whatever. Here's an example:
public class User
{
public string Username { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
In Foo.Repositories
there is a UserRepository
and in Foo.Services
there is a UserService
.
In the web application let's consider a model binder like following:
public class UserBinder : DefaultModelBinder
{
//...
}
I see three different options on where to put the validation:
In Foo.Models
like the following:
public class User
{
public string Username { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public ICollection<KeyValuePair<string, string>> ValidateErrors()
{
//Validate if Username, Email and Password has been passed
}
}
In Foo.Services
like:
public class UserService
{
public ICollection<KeyValuePair<string, string>> ValidateErrors()
{
//Validate if Username, Email and Password has been passed
}
}
In Foo
inside the model binder:
public class UserBinder : DefaultModelBinder
{
protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var user = (User)bindingContext.Model;
// validate everything here
base.OnModelUpdated(controllerContext, bindingContext);
}
}
Another thing to notice is that considering the first 2 options [Model and Service] there is another decision to make: ValidateErrors
method can be called directly on the controller or inside the Binder.
I have 2 questions on the scenario:
Should the validation be:
All the above scenario discuss about the User creation. But what about User logon? Let's say user uses the username and password to login in the application, so it won't need to validate the e-mail. Where this validation should be?
After a lot of research I think I got the answers to my question so i decided to share.
The validation code should be on Model. As per the idea of "thin controller, fat model" AND considering that a model would know what it needs to validate or not.
For example, let's say I decide to user the Foo.Models
in other solution but I decide NOT to use any other project and the validation is in other project.
I'll have to re-code the entire validation in this case what is a total waste of time, right?
OK. The validation code must be in the model but where should it be called?
This validation must be called where you're saving it to your database or file. As in the proposed scenario I'm considering the repository as a domain, then we should consider putting the validation just before the change saving [in this example I'm using Entity Framework but it's not necessary, it's just to show]:
public class UserRepository : IRepository<User>
{
public void Create(User user)
{
user.Validate();
var db = dbFooEntities();
db.AddToUsers(user);
db.SaveChanges();
}
}
As per MS recommendation, the model validation should raise an exception and the controller must populate the ModelState with the errors found [I'll try to update this answer with a sample code on that as soon as I finish my app].
With that we have an answer for question #1.
What about question #2, regarding the login validation?
As login is not a situation where you're persisting your data, the validation should stay on the Service since logging in is a service in this case.
So, the answers for the question are:
In the Model being called from the REPOSITORY [that is called by the controller]
In the Service being called from the controller