2
votes

I have a set of ASP.NET 4 projects that culminate in an MVC (3 RC2) app. The solution uses Unity and EntLib Validation for cross-cutting dependency injection and validation. Both are working great for injecting repository and service layer implementations.

However, I can't figure out how to do duplicate key validation. For example, when a user registers, we want to make sure they don't pick a UserID that someone else is already using. For this type of validation, the validating object must have a repository reference... or some other way to get an IQueryable / IEnumerable reference to check against other rows already in the DB.

What I have is a UserMetadata class that has all of the property setters and getters for a user, along with all of the appropriate DataAnnotations and EntLib Validation attributes. There is also a UserEntity class implemented using EF4 POCO Entity Generator templates. The UserEntity depends on UserMetadata, because it has a MetadataTypeAttribute. I also have a UserViewModel class that has the same exact MetadataType attribute. This way, I can apply the same validation rules, via attributes, to both the entity and viewmodel.

There are no concrete references to the Repository classes whatsoever. All repositories are injected using Unity. There is also a service layer that gets dependency injection. In the MVC project, service layer implementation classes are injected into the Controller classes (the controller classes only contain service layer interface references). Unity then injects the Repository implementations into the service layer classes (service classes also only contain interface references).

I've experimented with the DataAnnotations CustomValidationAttribute in the metadata class. The problem with this is the validation method must be static, and the method cannot instantiate a repository implementation directly. My repository interface is IRepository<T>, and I have only one single repository implementation class defined as EntityRepository<T> for all domain objects. To instantiate a repository explicitly I would need to say new EntityRepository<UserEntity>(), which would result in a circular dependency graph: UserMetadata [depends on] DuplicateUserIDValidator [depends on] UserEntity [depends on] UserMetadata.

I've also tried creating a custom EntLib Validator<T> along with a custom validation attribute. Here I don't have the same problem with a static method. I think I could get this to work if I could just figure out how to make Unity inject my EntityRepository into the validator class... which I can't. Right now, all of the validation code is in my Metadata class library, since that's where the custom validation attribute would go.

Any ideas on how to perform validations that need to check against the current repository state? Can Unity be used to inject a dependency into a lower-layer class library?

3

3 Answers

0
votes

Do it in the database. That's the only solution which can be truly multi-user safe.

0
votes

I found a solution, still not sure if it's the best one. Seems kind of like brute force to me.

The first thing I did was combine my Metadata classes into the same project / library as my Entity classes. Since my repository interface is IRepository<T>, the repository needed to be declared as IRepository<UserEntity>. This resolved the circular dependency I was talking about. Now I have UserEntity [depends on] UserMetadata [depends on] DuplicateUserValidationAttribute [depends on] DuplicateUserValidator [depends on] UserEntity. With all of these classes in the same library, though there is still circularity, there are no circular assembly dependencies.

The second thing I did was wrap my IUnityContainer into a singleton and moved it to my cross-cutting utilities library (before it existed only in the MVC 3 project).

Then, in my DuplicateUserValidator constructor, I could do the following:

public class DuplicateUserValidator : Micrsoft.Practices.EnterpriseLibrary.Validation.Validator<string>
{
    public IRepository<UserEntity> UserRepository { get; set; }

    public DuplicateUserValidator(string tag)
        : base(string.Empty, tag)
    {
        IUnityContainer unity = UnityContainerSingleton.Get();
        this.UserRepository = unity.Resolve<IRepository<UserEntity>>() as IRepository<UserEntity>;
    }
}

Now I have a repository dependency injected into the custom entlib validator implementation. Wish I could get unity to automatically inject it into the constructor, maybe I'll look into that next.

0
votes

Okay, I found a better solution that lets me use my previous library architecture.

I was able to keep the UserMetadata class in a separate library from UserEntity. Here is what the dependency graph looks like:

UserMetadata [depends on] DuplicateUserValidationAttribute [depends on] IDuplicateUserValidator

The actual DuplicateUserValidator implementation class is in my service layer, and looks something like this:

public class DuplicateUserValidator : Validator<string>, IDuplicateUserValidator
{
    public DuplicateUserValidator()
        : base(null, null)
    {
    }

    [Dependency]
    public IRepository<UserEntity> UserRepository { get; set; }

    protected override string DefaultMessageTemplate
    {
        get { throw new NotImplementedException(); }
    }

    protected override void DoValidate(string stringToValidate, object currentTarget, string key, ValidationResults validationResults)
    {
        if (this.UserRepository == null)
            throw new InvalidOperationException("This should not happen");

        // actual code to perform validation...
    }
}

The trick is getting the DuplicateUserValidatorAttribute to not depend on DuplicateUserValidator:

public class DuplicateUserValidatorAttribute : ValidatorAttribute
{
    protected override Validator DoCreateValidator(Type targetType)
    {
        var validator = Unity.Container.Resolve<IDuplicateUserValidator>() as Validator;
        validator.Tag = Tag;
        validator.MessageTemplate = GetMessageTemplate();
        return validator;
    }

}

All I needed to do from there was add a mapping to the unity config. When the singleton resolves the IDuplicateUserValidator, it injects my implementation class from the service layer, honoring the [Dependency] attribute on the UserRepository property.