5

I am trying to use a combination of Domain Driven Design with Test Driven Development for this application I am building in ASP.NET MVC 3. My archictecture is set up with Repositories, Domain Models, View Models, Controllers and Views. All validation will be handled in the view model. I set up my view model to inherit from "IValidatableObject" so that my validation attributes and my custom validation that i set up in the "Validate" method are both executed when my controller method calls "ModelState.IsValid". The problem I am running into is accessing my repository in the Validate method of my view model. I need to access the repository to check for duplicate records in the database. It seems like the best idea would be to create a property of IRepository type and set that property by passing injecting my repository into the constructor of the view model. For example:

public class UserViewModel : IValidatableObject
{
       public UserViewModel(User user, IUserRepository userRepository)
       {
              FirstName = user.FirstName;
              LastName = user.LastName;
              UserRepository = userRepository;
              UserName = user.UserName;
       }
       public string UserName { get; set; }
       public string FirstName { get; set; }
       public string LastName { get; set; }
       public IUserRepository UserRepository { get; set; }
       public IEnumerable<ValidationResult> Validate()
       {
           UserCriteria criteria = new UserCriteria { UserName = this.UserName };
           IList<User> users = UserRepository.SearchUsers(criteria);

           if (users != null && users.count() > 0)
           {
               yield return new ValidationResult("User with username " + this.UserName + " already exists."
           }
       }
}

Do you guys think this is a good idea?

Erik Funkenbusch
  • 92,674
  • 28
  • 195
  • 291
RiceRiceBaby
  • 1,546
  • 4
  • 16
  • 30
  • Personally I would avoid having a property that performs a database lookup. – Justin Helgerson Sep 28 '12 at 18:41
  • I see what you're saying, but how else would I validate against duplicate records. I was thinking about creating a custom validation method that the controller method would call and pass in the modelstate. The method would then perform my custom validations and add the model errors to the modelstate (side effect- c# object = pass by reference), but it seems like what i posted would be alot cleaner and code would be simpler. – RiceRiceBaby Sep 28 '12 at 18:50
  • 1
    The Domain Validation **must be encapsulated in the domain**. Validation is a concept that must be applied at several places in the application. Typically when you validate a View-Model, you are validating to check that the data provided by the user is safe, (apply sanitizer) and _apparently correct_. Then you usually would call your aggregate root to perform some actions. There you should validate the domain invariants (domain rules). In a CQRS architecture, I have found it's a good practice to validate inside the CommandHandler – Jupaol Sep 28 '12 at 18:54
  • [For more info](http://stackoverflow.com/questions/10879421/domain-validation-in-a-cqrs-architecture) – Jupaol Sep 28 '12 at 18:55

2 Answers2

2

It is good enough but if I were you, I would use

...
private readonly Func<IUserRepository> userRepositoryFactory;
...
public IEnumerable<ValidationResult> Validate()  
   {  
       UserCriteria criteria = new UserCriteria { UserName = this.UserName };  
       using(var UserRepository = userRepositoryFactory())
       {
           IList<User> users = UserRepository.SearchUsers(criteria);  

           if (users != null && users.count() > 0)  
           {  
               yield return new ValidationResult("User with username " + this.UserName + " already exists."  
           }  
       }
   }
Jupaol
  • 21,107
  • 8
  • 68
  • 100
Kirill Bestemyanov
  • 11,946
  • 2
  • 24
  • 38
  • In your first post, it sounds like I shouldn't follow this approach. It seems like you are saying I should only put business logic validation in the domain. – RiceRiceBaby Oct 01 '12 at 16:00
0

You can add Domain Service class to get object match with your criteria and validated at domain service level

 public class PurchaseOrder
    {
        public string Id { get; private set; }
        public string PONumber { get; private set; }
        public string Description { get; private set; }
        public decimal Total { get; private set; }
        public DateTime SubmissionDate { get; private set; }
        public ICollection<Invoice> Invoices { get; private set; }

        public decimal InvoiceTotal
        {
            get { return this.Invoices.Select(x => x.Amount).Sum(); }
        }

    }

    public class PurchaseOrderService
    {
        public PurchaseOrderService(IPurchaseOrderRepository repository)
        {
            this.repository = repository;
        }

        readonly IPurchaseOrderRepository repository;

        public void CheckPurchasedOrderExsist(string purchaseOrderId)
        {
                var purchaseOrder = this.repository.Get(purchaseOrderId);
                if (purchaseOrder != null)
                    throw new Exception("PO already exist!");
        }
    }
  • It seems like you are saying, I should validate my form in the view model, but business logic validation should go in the domain or service which makes sense. The question is, how would i send validation errors back to the modelstate in the controller? – RiceRiceBaby Oct 01 '12 at 16:02
  • you can do this by throwing exception from domain model and catch that in view because as per DDD your domain model should be isolated from your infrastructure logic... – Aditya Nagodra Oct 02 '12 at 18:44