Tuesday, February 12, 2013

WinRT, Caliburn.Micro and IoC - Part 2 (Unity)

In a previous post I started by wrapping Ninject (or the closest build I could find that worked with WinRT) for use in Caliburn.Micro.

I wanted to do the same thing for Unity, so I could compare and contrast the two in WinRT applications.  The good news is that Unity has a WinRT build. The bad news is only the core dll is available in WinRT.  Also the UnityServiceLocator.cs file is not included in the default build.  You will either need to copy the code into your project, or pull down the source, and rebuild after including the cs file into the WinRT project.

For those who don't want to pull down the source, you can just add this class to your project:


/// <summary>
    /// An implementation of <see cref="IServiceLocator"/> that wraps a Unity container.
    /// </summary>
    public class UnityServiceLocator : ServiceLocatorImplBase, IDisposable
    {
        private IUnityContainer container;

        /// <summary>
        /// Initializes a new instance of the <see cref="UnityServiceLocator"/> class for a container.
        /// </summary>
        /// <param name="container">The <see cref="IUnityContainer"/*gt; to wrap with the <see cref="IServiceLocator"/>
        /// interface implementation.</param>
public UnityServiceLocator(IUnityContainer container)
        {
            this.container = container;
            container.RegisterInstance(this, new ExternallyControlledLifetimeManager());
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        /// <filterpriority>2</filterpriority>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1816:CallGCSuppressFinalizeCorrectly",
            Justification="Object is not finalizable, no reason to call SuppressFinalize")]
        public void Dispose()
        {
            if (container != null)
            {
                container.Dispose();
                container = null;
            }
        }

        /// <summary>
        /// When implemented by inheriting classes, this method will do the actual work of resolving
        ///             the requested service instance.
        /// </summary>
        /// <param name="serviceType">Type of instance requested.</param>
>param name="key">Name of registered service you want. May be null.</param>
/// <returns>
        /// The requested service instance.
        /// </returns>
        protected override object DoGetInstance(Type serviceType, string key)
        {
            if (container == null) throw new ObjectDisposedException("container");
            return container.Resolve(serviceType, key);
        }

        /// <summary>
        /// When implemented by inheriting classes, this method will do the actual work of
        ///             resolving all the requested service instances.
        /// </summary>
        /// <param name="serviceType">Type of service requested.</param>
/// <returns>
        /// Sequence of service instance objects.
        /// </returns>
        protected override IEnumerable<object> DoGetAllInstances(Type serviceType)
        {
            if (container == null) throw new ObjectDisposedException("container");
            return container.ResolveAll(serviceType);
        }
    }

Then implementing a CaliburnApplication wrapper like in Part 1, I ended up with this:



    public class CaliburnUnityApplication : CaliburnApplication
    {
        IUnityContainer container;
        UnityServiceLocator locator;

        public CaliburnUnityApplication()
        {
            container = new UnityContainer();
            locator = new UnityServiceLocator(container);
            ServiceLocator.SetLocatorProvider(() => locator);
            container.RegisterInstance<iservicelocator>(locator);
            container.RegisterInstance<unitycontainer>(container as UnityContainer);
        }

        protected override void Configure()
        {
            base.Configure();
            if (!container.IsRegistered<ieventaggregator>())
            {
                container.RegisterType<IEventAggregator, EventAggregator>(new ContainerControlledLifetimeManager());
            }
        }

        protected override object GetInstance(Type service, string key)
        {
            if (string.IsNullOrWhiteSpace(key))
                return container.Resolve(service);
            else
                return container.Resolve(service, key);
        }

        protected override IEnumerable<object> GetAllInstances(Type service)
        {
            return container.ResolveAll(service);
        }

        protected override void BuildUp(object instance)
        {
            container.BuildUp(instance);
        }

        protected override void PrepareViewFirst(Windows.UI.Xaml.Controls.Frame rootFrame)
        {
            if (!container.IsRegistered<inavigationservice>())
            {
                container.RegisterInstance<inavigationservice>(new FrameAdapter(rootFrame, false));
            }
        }
    }

3 comments:

Rakesh R Nair said...

Can you please upload your sample app. :)

Rakesh R Nair said...
This comment has been removed by the author.
Tom Baker said...

I am preparing a post on Caliburn.Micro with LayoutAware and SuspensionManager integration.