views:

650

answers:

6

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 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:

  1. Should the validation be:

    • In the Model being called from the controller?
    • In the Model being called from the binder?
    • In the Service being called from the controller?
    • In the Service being called from the binder?
    • Directly in the Binder?
    • Any other idea?
  2. 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?

    • In the Model being called from the controller?
    • In the Service being called from the controller?
    • Any other idea?
A: 

For what it's worth, here's what I have scrounged up in my current project:

I have Models, Repositories (you can call them Services if you like), and ViewModels. I try to avoid writing custom model binders because (a) it's boring and (b) a strange place to put validation, IMHO. To me, a model binder is just taking items from the request and shoving them into an object. PHP, for example, doesn't do any validation when plucking items from a header into the $_POST array; it's the thing we plug the array into that cares about its contents.

My Model objects generally never allow themselves to enter an invalid state. This means that required parameters are passed in during constructors and properties will throw exceptions if they're attempted to be set with invalid values. And, in general, I try to design my Model objects to be immutable. For example, I have an Address object for mailing addresses that is constructed with an AddressBuilder object with looks at the field requirements for a given country by inspecting an AddressScheme that can be retrieved from the AddressSchemeRepository. Phew. But I think it's a good example because it takes something conceptually simple ("validate a mailing address") and makes it complicated in real world usage ("we accept addresses from over 30 countries, and those formatting rules are sitting in a database, not in my code").

Since constructing this Model object is kind of a pain--as well it should be, since it's being quite particular about the data that gets loaded into it--I have a, say, InputAddressViewModel object that my view binds to. The InputAddressViewModel implements IDataErrorInfo so that I get ASP.NET MVC's DefaultModelBinder to add errors to the ModelState automatically. For simple validation routines that I know ahead of time (phone number formatting, first name required, e-mail address format), I can implement these right in the InputAddressViewModel.

The other advantage of having a view model is that because it is shamelessly tailored to a particular view, your real model is more reusable because it doesn't have to make any weird concessions to make it suitable for UI display (e.g., needs to implement INotifyPropertyChanged or Serializable or any of that mess).

Other validation errors about the address I won't know about until I interact with my AddressScheme in my actual Model. Those errors will be there controller's job of orchestrating into the ModelState. Something like:


public ActionResult InputAddress(InputAddressViewModel model)
{
    if (ModelState.IsValid)
    {
        // "Front-line" validation passed; let's execute the save operation
        // in the our view model
        var result = model.Execute();

        // The view model returns a status code to help the 
        // controller decide where to redirect the user next
        switch (result.Status)
        {
            case InputAddressViewModelExecuteResult.Saved:
                return RedirectToAction("my-work-is-done-here");

            case InputAddressViewModelExecuteResult.UserCorrectableError:
                // Something went wrong after we interacted with the 
                // datastore,  like a bogus Canadian postal code or 
                // something. Our view model will have updated the 
                // Error property, but we need to call TryUpdateModel() 
                // to get these new errors to get added to
                // the ModelState, since they were just added and the
                // model binder ran before this method even got called.
                TryUpdateModel(model);
                break;
        }

        // Redisplay the input form to the user, using that nifty
        // Html.ValidationMessage to convey model state errors
        return View(model);
    }
}

The switch may seem repulsive, but I think it makes sense: the view model is just a plain old class and doesn't have any knowledge of the Request or the HttpContext. This makes the logic of the view model easy to test in isolation without resorting to mocking and leaves the controller code left to, well, control by interpreting the model's result in a manner that makes sense on a Web site--it could redirect, it could set cookies, etc.

And the InputAddressViewModel's Execute() methods looks something like (some people would insist on putting this code into a Service object that the controller would call, but to me the view model will do so much finagling of the data to make it fit the real model that it makes sense to put it here):


public InputAddressViewModelExecuteResult Execute()
{
    InputAddressViewModelExecuteResult result;

    if (this.errors.Count > 0)
    {
        throw new InvalidOperationException(
            "Don't call me when I have errors");
    }

    // This is just my abstraction for clearly demarcating when
    // I have an open connection to a highly contentious resource,
    // like a database connection or a network share
    using (ConnectionScope cs = new ConnectionScope())
    {
        var scheme = new AddressSchemeRepository().Load(this.Country);
        var builder = new AddressBuilder(scheme)
             .WithCityAs(this.City)
             .WithStateOrProvinceAs(this.StateOrProvince);

        if (!builder.CanBuild())
        {
            this.errors.Add("Blah", builder.Error);
            result = new InputAddressViewModelExecuteResult()
            {
                Status = InputAddressViewModelExecuteStatus
                    .UserCorrectableError
            };
        }
        else
        {
            var address = builder.Build();
            // save the address or something...
            result = new InputAddressViewModelExecuteResult()
            {
                Status = InputAddressViewModelExecuteStatus.Success,
                Address = address
            };
        }        
    }

    return result;
}

Does this make sense? Is it a best practice? I have no idea; it's certainly verbose; it's what I just came up with in the past two weeks after thinking about this problem. I think you're going to have some duplication of validation--your UI can't be a complete imbecile and not know what fields are required or not before submitting them to your model/repositories/services/whatever--otherwise the form could simply generate itself.

I should add that the impetus for this is that I've always kind of detested the Microsoft mentality of "set one property -> validate one property" because nothing ever works like that in reality. And you always end up getting an invalid object persisted because someone forgot to call IsValid or some such on the way to the data store. So another reason for having a view model is that it tailors itself to this concession so we get a lot of CRUD work of pulling items from the request, validation errors in the model state, etc quite easily without having to compromise the integrity of our model itself. If I have an Address object in hand, I know it's good. If I have an InputAddressViewModel object in hand, I know I need to call it's Execute() method to get that golden Address object.

I'll look forward to reading some of the other answers.

Nicholas Piasecki
Your view model objects call the database? So much for abstracting the UI and Database logic layers away from each other...
jfar
The model doesn't talk to the db; it's a collection of objects that is hydrated from it. *Something* needs to "get" that model from the database, let the model play with itself, and then persist whatever the heck the model did to itself back to the database. The controller could do that, but since it has its own view model, it doesn't matter which you pick. To me, the controller defers to the view model for most things and only handles redirects and cookies. This leaves the view model easy to unit test. The db is still abstracted, but the network boundary and its access are not ignored.
Nicholas Piasecki
+1  A: 
Soni Ali
You got my vote, however, the drawback with most demos are that they suggest there is a one to one connection between edit views and the controller action. When you need more than one edit screen, like a shopping cart, something will be missing.
Thomas Eyde
Sorry but this sample puts all the validation on the controller what is a bad idea. I think the best to do is "Thin Controller, Fat Model". The controller should work only as a "workflow manager" between the views and the other layers [Model, service, etc...]
homemdelata
Homemdelata, I see the controller validation model all over the place too in the examples, and it's too bad. Validation definitely belongs in the model itself, end of story.
Peter J
@IconicValidation should not belong to the model itself because there can be instances when a model's validation logic depends on other models on the controller or database table.e.g. A customer order number should be unique only within the customer's orders. Or even "At least 1 item must be marked IsDefault" - You cannot delete the only item marked "IsDefault"
Soni Ali
+1  A: 

I'm a big fan of putting calling the validation from the controllers and having the validation routine return an ActionResult so the controller can know what to do with the result.

Peter Mourfield
But it goes in opposition to the "thin controller, fat model" paradigm [what I like most]
homemdelata
A: 

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:

  1. In the Model being called from the REPOSITORY [that is called by the controller]

  2. In the Service being called from the controller

homemdelata
You lose context this way. Sometimes validation rules change depending on what's happening in the business layer. I would suggest moving it up one layer (service layer?) in that case.
Todd Smith
But Todd, the model is the O-RM, so the object [O] should represents the same rules that your relational mapping [RM]. This is why I think the validation won't change. If you'll have a different business rules to the model, you should change the entire O-RM, I think
homemdelata
A: 

This is very interesting and it helps me a lot in deciding where to put validation. currently I feel the most for each model implementing a "Validate" method, which is called from a Repository or a Service.

However, what about validating if a chosen username is unique? Should that code be inside the User model, or inside the UserService class, or in the UserRepository class?

If the uniqueness validation should be inside the User model, then the User model should have access to either the UserService or the UserRepository class. Is that OK, or is that against any "best practice" pattern?

For example:

class User
{
  string Username { get; set; }
  string Email { get; set; }
  string Password { get; set; } // hashed and salted of course :)

  IEnumerable<RuleViolation> Validate()
  {
    List<RuleViolation> violations = new List<RuleViolation>();
    IUserService service = MyApplicationService.UserService; // MyApplicationService is a singleton class, especialy designed so that the User model can access application services

    // Username is required
    if ( string.IsNullOrEmpty(Username) )
       violations.Add(new RuleViolation("Username", "Username is required"));

    // Username must be unique: Should uniqueness be validated here?
    else if( !service.IsUsernameAvailable(Username)
       violations.Add(new RuleViolation("Username", "Username is already taken!"));

    // Validate email etc...

    return violations;
  }
}

interface IUserRepository
{
  void Save(User item);
}

interface IUserService
{
  IUserRepository UserRepository { get; }
  void Save(User item);
}

class UserService : IUserService
{
  public UserService(IUserRepository userRepository)
  {
     this.UserRepository = userRepository;
  }

  IUserRepository UserRepository { get; private set}

  public void Save(User user)
  {
     IEnumerable<RuleViolation> violations = user.Validate();

     if(violations.Count() > 0)
         throw new RuleViolationException(violations); // this will be catched by the Controller, which will copy the violations to the ModelState errors collection. But the question is, should we validat the user here, or in the UserRepository class?

      UserRepository.Save(user);
  }
}

class UserRepository : IUserRepository
{
   void Save(User item)
   {
      IEnumerable<RuleViolation> violations = user.Validate();

     if(violations.Count() > 0)
         throw new RuleViolationException(violations); // this will be catched by the Controller, which will copy the violations to the ModelState errors collection. But the question is, should we validate the user here, or in the UserService class?

      UserRepository.Save(user);

   }
}

My guess would be that validation should be as close to the model as possible. So I'd say that the UserRepository should be the one responsible for validating it's model being added.

The most important queston for me is: Should the User model know about the IUserService / IUserRepository interfaces so that it can validate the Username uniqueness? Or should the IUserService service validate uniqueness?

I'm curious about your views on this!

My view is that I'm going to be very unhappy if I have to write the same if( string.IsNullOrEmpty() ) logic on every object with a Name property for the rest of my life.
jfar
So, what would make you happy then? How do you validate required fields? Perhaps Fluent Validation?
A: 

I'm using the DataAnnotations attributes in combination with a MVC model binder to do my validation and its pretty awesome. Since I treat User input as Command View Models its the cleanest way to keep domain clean from outside concerns.

http://bradwilson.typepad.com/blog/2009/04/dataannotations-and-aspnet-mvc.html

This also allows me to take advantage of AutoForm by LosTechies.com:

http://www.lostechies.com/blogs/hex/archive/2009/06/17/opinionated-input-builders-part-8-the-auto-form.aspx

And I expect the client side validation tools in MVC 2, VS 2010 to take advantage of these attributes as well.

So I'm whipping out user input view models, commands, at a furious pace right now and tying them into not only the AutoForm functionality but my own custom UI templates to get AutoGrid and AutoOutput from these attributes as well.

Nothing is better than saying:

Html.AutoForm(Model);

Or

Html.AutoGrid(Model.Products);

And getting validation and html generation in a very DRY and orthogonal way. My controllers are light, my domain pristine, and my time is unoccupied by writing the same if( string.IsNullOrEmpty() ) method on every object with a FirstName property.

For me the approach was not as "philosophical" as others have written about. I'm trying to be very pragmatic about MVC development and I get a ton of bang for the buck out of these bits.

jfar