Managing One Unity Instance

Jun 26, 2008 at 3:48 PM
Edited Jun 26, 2008 at 3:49 PM
I would like to have the Unity container created once for an application and possibly be available in all the different layers (business, UI, data).  The applicaiton runs inside ASP.NET and I have seen examples of using the Global class with a Container declared in it.  However, I'm not sure I want to pass the container up with each call.  What is the recommended approach here?  Is it better to have each layer have its own container?  The layers are the traditional n-tier UI, Business, Data.  How do I ensure there is only one instance created so as to avoid any expensive reflection or object construction?  Create a Singleton wrapper?
Jul 6, 2008 at 10:15 PM
//Add this code anywhere you want access to the unity container
private IUnityContainer _unity = Unity.Instance.ContainerInstance;
internal IUnityContainer UContainer
{
    get { return _unity; }
}

//Add this class to your Assembly:

     /// <summary>
    /// Class for handing Unity configuration
    /// </summary>
    public class Unity
    {
        private static readonly ILog _Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        private static Unity _instance = new Unity();
        private IUnityContainer _container;

        /// <summary>
        /// These methods support the singleton pattern.
        /// </summary>
        public static Unity Instance
        {
            get
            {
                return _instance;
            }
        }

        /// <summary>
        /// Get or set the current Unity container
        /// </summary>
        public IUnityContainer ContainerInstance
        {
            get { return _container; }
            set { _container = value; }
        }

        //class is a singleton, cant construct...
        private Unity()
        {
            try
            {
                if (_Log.IsDebugEnabled) _Log.Debug("Configuring Unity Container");

                //Create and Configure the Unity Container
                Assembly activeAss = Assembly.GetExecutingAssembly();
                string dllPath = Path.GetDirectoryName(activeAss.Location);
                string[] asmType = activeAss.FullName.Split(new Char[] { ',' });

                Assembly ass = Assembly.GetEntryAssembly();
                string cfgPath = Path.GetDirectoryName(ass.Location);
                string[] exeName = ass.FullName.Split(new Char[] { ',' });

                ContainerInstance = new UnityContainer();
                ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();

                fileMap.ExeConfigFilename = cfgPath + @"\" + exeName[0] + ".exe.config";

                System.Configuration.Configuration config =
                    ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
                UnityConfigurationSection section = (UnityConfigurationSection)config.GetSection("unity");
                section.Containers["Default"].Configure(ContainerInstance);
            }
            catch (System.Exception ex)
            {
                if (_Log.IsErrorEnabled) _Log.Error("Error Configuring Unity Container " + ex.ToString());
            }
        }
    }
Oct 1, 2008 at 3:07 PM
How about this?

Container.RegisterInstance(Container);

Container has been created beforehand, so we register itself.
Oct 6, 2008 at 8:01 PM
Edited Oct 6, 2008 at 9:09 PM
How about this?

Container.RegisterInstance(Container);

Container has been created beforehand, so we register itself.

I'm not sure this helps, because each layer has to get a reference to the container somehow. Look at the Common Service Locator: http://www.codeplex.com/CommonServiceLocator 

This will allow a single container reference to be shared and accessed with ServiceLocator.Current

Plus, it doesn't tie you to using Unity. Just make sure all your configuration or Unity-specific stuff is in one place; then you can swap it out if you need to.

Ray Henry
http://initializecomponent.blogspot.com/ 
Oct 6, 2008 at 8:41 PM
jiffy,

You might want to take a look at a small multi-tiered ASP.NET application I wrote that does just that.

http://www.kingwilder.com/Blog/tabid/54/EntryID/9/Default.aspx

I hope it helps.
Oct 7, 2008 at 6:24 PM
In general, you want to avoid the Service Locator Pattern if possible as it defeats the purpose of IoC and not having your classes seek out their own dependencies. As soon as you depend on a Service Locator it makes testing a pain. The Common Service Locator Project is really there to avoid multiple IOC-specific implementations of the Service Locator Pattern in those applications that cannot live without the pattern.

You shouldn't have a need to have multiple containers and a service locator in a traditional multi-layered web application. When the first object is created, whether this be a Controller in MVC, a presenter in MVP, or possibly an Application Controller, the injection of dependencies will happen automagically throughout the layers of your application and you won't need to use a Service Locator to manually grab a dependency. Unity will cause a cascade of classes being created and their dependencies being filled based on what you have added to the UnityContainer.

Although the WCSF does not use Unity, the documentation and/or examples do an excellent job of explaining Dependency Injection and how it works using MVP and not using MVP in a multi-layered web application. I would check out WCSF for some guidance.

WCSF Project

WCSF Screencasts

Regards,

Dave
Oct 8, 2008 at 9:06 PM
I agree with David. Try to stick to Constructor Injection.

If you want to get a handle to the container so you can control the creation of your dependnecies (i.e., defer instantiation until they are needed), consider using a factory pattern. Let the container inject a factory object into your class and call the factory object at the appropriate time to create the object. (See http://initializecomponent.blogspot.com/2008/06/configuring-and-supplying-factory-with.html).

Ray