Unity 3.5 with ValidationAttribute

Jul 8, 2014 at 8:07 PM
So.. I am grasping at straws here. I am not even sure this is possible.. but i am hoping that someone much smarter than me knows how to do this..

I have made several custom validation attributes that extend off of this base class
 public abstract class LocalizedValidationAttribute : ValidationAttribute
    {

        public IContentContext ContentProvider { get; set; }
        ....
}
Now I want to use Unity to set the content provider .. so the problem is this is a attribute... and I can't control where in the code it is created.

So.. I had it working when I made a static reference to the unity container, but that make this hard to unit test. So... is there any way using interception or other cool Unity features to do this?

Thanks
Jul 10, 2014 at 2:46 AM
One thing that you might be able to do is to expose the container as a global singleton and then within the attribute use the container to perform a BuildUp on itself and inject the ContentProvider.

Here's an example:
    public abstract public class LocalizedValidationAttribute : ValidationAttribute
    {
        public IContentContext ContentProvider { get; set; }

        public CustomAttribute()
        {
        }

        public override bool IsValid(object value)
        {
            // Container is global singleton
            Globals.Container.BuildUp(this);
            System.Diagnostics.Debug.Assert(ContentProvider != null);

            return true;
        }
    }

This assumes that IContentContext is already registered with the container.

Another approach would be to switch to using ICallHandler and HandlerAttributes since a HandlerAttribute get the UnityContainer passed in to the CreateHandler method which allows you to resolve the actual ICallHandler with the appropriate values injected. The major downside of that approach is that you are moving to an interception model which would not align with the validation approach you (and most people!) are using.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Jul 11, 2014 at 6:33 AM
The core problem here is that you are adding behavior to data, which is a bad idea as explained here and here. So the solution is to move complex business validation logic out of attributes and into 'normal' services. For instance, you can create a generic IValidator<T> abstraction and have all kind of non-generic implementation based on a closed-generic version of that abstraction. When ever you need to validate some object, you can inject an IValidator<T> into some consumer and validate the object in question. In my applications, I mix the use of passive validation attributes with complex business logic using the IValidator<T> abstraction.
Jul 14, 2014 at 2:25 PM
You are 100% correct. I was already working something in this direction before you comment because I saw that it was just not going to work. I now have a validator service that takes the output of the attributes and gets the right content. I inject the IContentContext into the validation service and that gets the right message. You always know when you are on the right track, because as soon as I did that the code was easy and it started working.