Unity Extension for Validation Application Block

May 23, 2008 at 9:36 PM
I'm trying to write an extension that will resolve Validator<T> from Entlib's Validation Application Block. I've got it to resolve properly. However, my code is creating a new instance each time I call resolve. Is there any way I can register an instance as a singleton from my BuilderStrategy?

{{
        [Test]
        public void TestThatValidatorIsResolvedByUnityAsSingleton()
        {
            IUnityContainer container = new UnityContainer();

            container.AddNewExtension<ValidatorExtension>();

            var validator1 = container.Resolve<Validator<Customer>>();

            var validator2 = container.Resolve<Validator<Customer>>();

            Assert.AreSame(validator1, validator2);
        }

public class ValidatorExtension : UnityContainerExtension
    {
        #region Protected Methods

        protected override void Initialize()
        {
            Context.Strategies.AddNew<ValidatorStrategy>(UnityBuildStage.TypeMapping);
        }

        #endregion
    }

public class ValidatorStrategy : BuilderStrategy
    {
        #region Public Methods

        public override void PreBuildUp(IBuilderContext context)
        {
            var originalBuildKey = context.OriginalBuildKey as IBuildKey;

            var policy = context.Policies.Get<IBuildKeyMappingPolicy>(originalBuildKey);

            if (policy == null && originalBuildKey != null && BuildKeyIsForValidator(originalBuildKey))
            {
                IConfigurationSource configSource = GetConfigSource(context);

                Type targetType = originalBuildKey.Type.GetGenericArguments()[0];

                object validator = GetValidator(targetType, configSource);
               
                context.Existing = validator;

                //TODO:Register singleton instance
            }

            base.PreBuildUp(context);
        }

        #endregion

        #region Private Methods

        private static bool BuildKeyIsForValidator(IBuildKey originalBuildKey)
        {
            //A generic type with a single generic parameter that inherits Validator
            return typeof(Validator).IsAssignableFrom(originalBuildKey.Type) && originalBuildKey.Type.IsGenericType && originalBuildKey.Type.GetGenericArguments().Length == 1;
        }

        private static IConfigurationSource GetConfigSource(IBuilderContext context)
        {
            //Check to see if the enterprise library's core extension has registered a configuration policy
            var configPolicy = context.Policies.Get<IConfigurationObjectPolicy>(typeof(IConfigurationSource));

            return configPolicy != null ? configPolicy.ConfigurationSource : null;
        }

        private static object GetValidator(Type targetType, IConfigurationSource configSource)
        {
            var argumentTypes = configSource == null ?
                new[] { typeof(string) } :
                new[] { typeof(string), typeof(IConfigurationSource) };

            var arguments = configSource == null ?
                new object[] { string.Empty } :
                new object[] { string.Empty, configSource };

            var genericArguments = new[] {targetType};

            //You have to call the generic method to get a generic validator
            MethodInfo createValidatorInfo = typeof(ValidationFactory).GetMethod("CreateValidator", argumentTypes);

            createValidatorInfo = createValidatorInfo.MakeGenericMethod(genericArguments);

            return createValidatorInfo.Invoke(null, arguments);
        }

        #endregion
    }
}}