Injecting the Unity Container / Automatic Factory

Jun 1, 2010 at 5:11 PM

Dear community

Im facing a problem that even being already solved using a singleton pattern, that contains the UnityContainer, i would like to solve in a more elegant/proper way

Maybe with Automatic Factories or Factories Injection ??

I need unity, to appply a certain interceptor to all object instances recovered from DB by NHibernate. It means that i need to replace the 'new()' that Nhibernate calls before fill the entity with a unity 'Container.Resolve<>();' And to do it, i need to keep a reference of the container in a singleton class DIContainer.UnityContainer.

First step: To change the Nhibernate behaivior with unity Container.Resolve<>(); i need to apply some changes to my SessionProvider class. Being the class SessionProvider class already registered in the unity container,  i have considered (in a not elegant way) to pass the unitycontainer itself to the CustomBytecodeProvider(UnityContainer).

public class SessionProvider : ISessionProvider
    {
        public IUnityContainer UnityContainer
        {
            get { return DIContainer.UnityContainer; }
        }
        
        private Configuration _config;

        public Configuration Config
        {
            get
            {
                if (_config == null)
                {
                   /*Whatever....*/

                    Environment.BytecodeProvider=  new CustomBytecodeProvider(UnityContainer);

                    _config = new Configuration();
                    _config.AddInputStream(NHibernate.Mapping.Attributes.HbmSerializer.Default.Serialize(System.Reflection.Assembly.Load("DocumentVerifiers.Model")));
                    
                    foreach (string assembly in Assemblies)
                        _config.AddAssembly(System.Reflection.Assembly.Load(assembly)); 
   
                }
                return _config;
            }

        }
        private ISessionFactory _sessionFactory;

        public ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                {
                    _sessionFactory = Config.BuildSessionFactory();
                }
                return _sessionFactory;
            }
        }


    }

Why do i need it? This unity container will be received at some point and will create instances just before NHibernate fills it with the data from the DB.

    public class CustomBytecodeProvider : IBytecodeProvider
    {
        private readonly IUnityContainer _unityContainer;
        
        public CustomBytecodeProvider(IUnityContainer unityContainer)
        {
            _unityContainer = unityContainer;
        }

        public IReflectionOptimizer GetReflectionOptimizer(Type clazz, IGetter[] getters, ISetter[] setters)
        {
            return new ReflectionOptimizer(_unityContainer, clazz, getters, setters);
        }
    }

Here is the point where the instances are created and a "NotifyPropertyChangedCallHandler" interceptor is applied:   

NOTE: Problably i could have accessed the DIContainer.UnityContainer directly from the ReflectionOptimizer class.

public class ReflectionOptimizer : NHibernate.Bytecode.Lightweight.ReflectionOptimizer
    {
        private readonly IUnityContainer _container;

        public ReflectionOptimizer(IUnityContainer container, Type mappedType, IGetter[] getters, ISetter[] setters)
            : base(mappedType, getters, setters)
        {
            _container = container;
        }

        public override object CreateInstance()
        {
            if (_container.IsRegistered(mappedType))
            {
                return _container.Resolve(mappedType);
            }
            else
            {
                _container.Configure<Interception>().SetDefaultInterceptorFor(mappedType,new VirtualMethodInterceptor());
                 return _container.Resolve(mappedType);
            }
        }
        protected override void ThrowExceptionForNoDefaultCtor(Type type)
        {
            base.ThrowExceptionForNoDefaultCtor(type);
        }
    }

A Brief explanation of whats going on within ReflectionOptimizer: Every time that nhibernate request a entity from the db, first CreateInstance method will be fired to get the object instance, and then the instance wil be filled with data. The type of the entity to be instanciated is mappedType.

I would like to replace the container that is referenced in ReflectionOptimizer with a proper mechanism ( to a Factory?) that could retreive instances with intereception behavious created by unity. Please be aware that in case of a factory solution, this should be able to pull instances from the unity container of any registered mappedType.

I really appreciate help/guidance guys.


 

 

 

 

 

 

 public class CustomBytecodeProvider : IBytecodeProvider
    {
        private readonly IUnityContainer _unityContainer;
        private readonly IObjectsFactory objectsFactory = new ActivatorObjectsFactory();
        private readonly System.Type collectionTypeFactoryClass = typeof(NHibernate.Type.DefaultCollectionTypeFactory);
        private ICollectionTypeFactory collectionTypeFactory;
        
        public CustomBytecodeProvider(IUnityContainer unityContainer)
        {
            _unityContainer = unityContainer;
        }

        public IReflectionOptimizer GetReflectionOptimizer(Type clazz, IGetter[] getters, ISetter[] setters)
        {
            return new ReflectionOptimizer(_unityContainer, clazz, getters, setters);
        }

        public IProxyFactoryFactory ProxyFactoryFactory
        {
            get { return new NHibernate.ByteCode.LinFu.ProxyFactoryFactory(); }
        }

        public IObjectsFactory ObjectsFactory
        {
            get { return this.objectsFactory; }
        }

        public ICollectionTypeFactory CollectionTypeFactory
        {
            get
            {
                if (collectionTypeFactory == null)
                {
                    try
                    {
                        collectionTypeFactory =
                            (ICollectionTypeFactory)ObjectsFactory.CreateInstance(collectionTypeFactoryClass);
                    }
                    catch (Exception e)
                    {
                        throw new HibernateByteCodeException("Failed to create an instance of CollectionTypeFactory!", e);
                    }
                }
                return collectionTypeFactory;
            }
        }
    }