chobo2
chobo2

Reputation: 85835

Validation on my domain objects or in the view model? Where should it go?

I am trying to keep my service layer free of asp.net mvc dependcies but I have ran into a problem. I want to use Compare but that is part of the asp.net mvc library. So what should I do?

I have a domain class(that is later used with fluent nhibernate)

public class User()
{
   [Required(ErrorMessage = "Required")]
   [Compare()] // can't do this because not my User domain needs to know about mvc and I   rather it not
   public virtual string Email (get; set;}
   public virtual string ConfirmEmail (get; set;} // not mapped with fluent nhibernate
}

public class UserViewModel()
{
   public User User {get; set;}
}


public ActionMethod method()
{
  if(!this.ModelState.isValid)
  {

   }
}

I have this domain object made so I would find it kinda pointless to move all those properties into the UsersViewAModel just to put the validation on them then later on through all those back into the domain model that will be used to commit(nhibernate commit)

Upvotes: 1

Views: 1323

Answers (3)

awrigley
awrigley

Reputation: 13581

You should probably use a "buddy class" for your model class to hold the validation attributes:

// Note the partial keyword below:  the full definition of MyModel 
// can be put in a file in the model
[MetadataType(typeof(MyModelMetadata))]
public partial class MyModel {}

public class MyModelMetadata
{
    //properties with validation attributes (dataannotations)  go here...
}

The validation attributes are one item that does not cleanly split between the MVC concerns: They relate as much to client validation in the views as they do to server validation in the domain, at the point where the data is stored to the database and therefore needs validation.

So @jfar, by saying that they should go in the ViewModel, is as wrong as the person who says they should be in the domain.

In fact, IMHO, it is totally incorrect to put the validation attributes in the ViewModel. The ViewModel should be a container for the data that is sent to the View. It should not port any logic of its own. That logic, in this case Validation Attributes, should be defined outside of the ViewModel and the buddy class is the best option for that, especially if you are using an automated ORM, but not only in that special case.

This question is an illustration of the fact that not every issue maps neatly to MVC, so getting all Stalinistic about where the Validation Attributes should go is plain wrong.

My advice: put them in one place, separate from all other concerns. The way to do that is to use buddy classes.

Upvotes: 4

Jakub Konecki
Jakub Konecki

Reputation: 46008

public class User()
    {
       public virtual string Email (get; set;}
       public virtual string ConfirmEmail (get; set;} // not mapped with fluent nhibernate
    }
public class UserModel()
{
   [Required(ErrorMessage = "Required")]
   [Compare()] // can't do this because not my User domain needs to know about mvc and I   rather it not
   public virtual string Email (get; set;}
   public virtual string ConfirmEmail (get; set;} // not mapped with fluent nhibernate
}

public class UserViewModel()
{
   public UserModel User {get; set;}
}


public ActionMethod method()
{
  if(!this.ModelState.isValid)
  {

   }
}

You might want to use AutoMapper to solve the problem of populating UserModel from User and vice versa.

Upvotes: 2

John Farrell
John Farrell

Reputation: 24754

Putting validation attributes on your domain models is the worse thing you can do if you are trying to separate concerns.

Put validation attributes on ViewModels.

Upvotes: 4

Related Questions