UNITY: Resolve on Demand

Unity is the core of most programs that I now write. But, in the 1.x version, it couldn’t do something that I occasionally needed. I wanted a particular dependency to resolve more than once, not just when the object was composed.

Example:

new SomeService(new SomeRepository(new SomeConnectionProvider()))

You can configure Unity to do that for you. The problem is that maybe you don’t want to use the same connection provider over and over; maybe you want it to resolve every time something needs a connection. Lifetime managers don’t help for a single instance, because those only do things during resolve, and you only resolve once.

In Unity 1.x, there were some workarounds. I’ll cover 2 here. (Any work-arounds involving static variables not worthy of comment, are henceforth ignored.)

Old Solution #1: Pass in the Unity Container rather than a Connection Provider.

new SomeService(new SomeRepository(unity))

Now, SomeRepository can resolve IConnectionProvider whenever it wants.

Pros

  • It works. Swell.

Cons

  • It binds the object to Unity.
  • You now have a full container when all you really need is one object.

I used this solution in the AW BUS SERVER, but it was a calculated decision. Everything in the server has lots of shared dependencies, and the whole thing was Unity aware to begin with, so I didn’t mind this approach. However, if I used Unity 2, then I wouldn’t have needed this approach.

Old Solution #2: Pass a connection provider factory rather than a connection provider

In this approach, rather than pass in SomeConnectionProvider(), you pass in SomeConnectionProviderFactory(). The factory will instantiate a new instance of SomeConnectionProvider() each time it needs to. As far as SomeRepository is concerned, the factory is just a provider…

Pros

  • It works. Swell.
  • It doesn’t bind you to Unity

Cons

  • Do you really want to create a new factory class for each class that you want to resolve?
  • It feels a little kludgy… Unity supports lifetime management. By using a factory, you’re not able to take advantage of what unity offers.

Unity 2 Solution: Delegate of Func<TResult>

Unity now recognizes Func<TResult> parameters. If a parameter is a Func<TResult>, then it assigns the delegate to the containers Resolve<T> method. If a parameters if of type IEnumerable<Func<TResult>>, then it performs a ResolveAll<T>.

To revisit our example, SomeRepository accepts a constructor parameter of type IConnectionProvider. To take advantage of the new feature, simply change it to Func<IConnectionProvider>(). Whenever your code executes the delegate, it will resolve.

Pros

  • It works. Swell.
  • It doesn’t bind you to unity
  • It doesn’t require you to write a bunch of factory classes

Cons

  • None, really. It might seem unusual to have a delegate as a parameter, but that’s a result of the requirements of your object, not unity. You have determined that some outside source needs to server you another type of object. That other type of thing is unity in this case, but it can be anything.

The Code

This code demonstrates the following:

  1. The problem. It’s only a problem, though, when you want to resolve after instantiation, which doesn’t come up to often for me.
  2. Unity 1.x solution – pass the container
  3. Unity 1.x solution – pass a factory
  4. Unity 2.x solution – change paramters to Func<TResult>. This shows that it solves the problem.
  5. Unity 2.x solution singleton – This is the same as solution #4, but shows that you can use this solution with a lifetime a manager. (It resolves every time, but the resolves all return the same object.)
namespace UnityTest2
{
    using System;
    using System.Threading;
    using Microsoft.Practices.Unity;

    class Program
    {
        private static void Demo(IUnityContainer unity)
        {
            ConsoleColor original = Console.ForegroundColor;

            Demo demo = unity.Resolve<Demo>();
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine(demo.Title);
            Console.ForegroundColor = original;
            Console.WriteLine();
            Console.WriteLine(demo.Explanation);
            Console.WriteLine();

            Console.WriteLine(demo.Ticker.GetTicks());
            Thread.Sleep(500);
            Console.WriteLine(demo.Ticker.GetTicks());

            Console.WriteLine();
            Console.WriteLine();
        }

        /// <summary>
        /// Shows that the ticker provider is only instantiated once.
        /// It will always use the same ticker provider, so the ticks will never
        /// change despite a sleep
        /// </summary>
        private static void TheProblem()
        {
            IUnityContainer unity = new UnityContainer();
            unity.RegisterType<Demo, DemoTheProblem>();
            unity.RegisterType<ITickProvider, TickProvider>();
            Demo(unity);
        }

        private static void OldSolution_PassTheContainer()
        {
            IUnityContainer unity = new UnityContainer();
            unity.RegisterType<Demo, DemoOldSolution1_PassAContainer>();
            unity.RegisterType<ITickProvider, TickProvider>();
            Demo(unity);
        }

        private static void OldSolution_PassAFactory()
        {
            IUnityContainer unity = new UnityContainer();
            unity.RegisterType<Demo, DemoOldSolution2_PassAFactory>();
            unity.RegisterType<ITickProvider, TickerFactory>();
            Demo(unity);
        }

        private static void NewSolution_NewOneEveryTime()
        {
            IUnityContainer unity = new UnityContainer();
            unity.RegisterType<Demo, DemoNewSolution>();
            unity.RegisterType<ITickProvider, TickProvider>();
            Demo(unity);
        }

        private static void NewSolution_Singleton()
        {
            IUnityContainer unity = new UnityContainer();
            unity.RegisterType<Demo, DemoNewSolution>();
            unity.RegisterType<ITickProvider, TickProvider>(new ContainerControlledLifetimeManager());
            Demo(unity);
        }

        static void Main(string[] args)
        {
            TheProblem();
            OldSolution_PassTheContainer();
            OldSolution_PassAFactory();

            Console.WriteLine("Problem solved...");
            NewSolution_NewOneEveryTime();

            Console.WriteLine("Same as previous, but tell unity it's to be a singleton.");
            NewSolution_Singleton();
            Console.ReadLine();
        }
    }

    public interface ITickProvider
    {
        long GetTicks();
    }

    public class TickProvider : ITickProvider
    {
        private readonly long ticks = DateTime.Now.Ticks;
        public long GetTicks()
        {
            return this.ticks;
        }
    }

    public abstract class Demo
    {
        public abstract ITickProvider Ticker { get; }
        public abstract string Title { get; }
        public abstract string Explanation { get; }
    }

    public class DemoTheProblem : Demo
    {
        private readonly ITickProvider ticks;
        public DemoTheProblem(ITickProvider ticks)
        {
            this.ticks = ticks;
        }

        public override ITickProvider Ticker
        {
            get { return this.ticks; }
        }

        public override string Title
        {
            get { return "The Problem"; }
        }

        public override string Explanation
        {
            get { return "Unity composes the object graph once. But, what if you want to go back to the unity container to resolve dependencies again after the instantiation? There's not a great way to do it in Unity 1.x.\r\n\r\nOur goal is to be able to configure, in unity, if a dependency should resolve on each use or not."; }
        }
    }

    public class DemoOldSolution1_PassAContainer : Demo
    {
        private readonly IUnityContainer unity;
        public DemoOldSolution1_PassAContainer(IUnityContainer unity)
        {
            this.unity = unity;
        }

        public override ITickProvider Ticker
        {
            // resolves every time it calls
            get { return this.unity.Resolve<ITickProvider>(); }
        }

        public override string Title
        {
            get { return "Old solution 1: Pass the container and resolve every time."; }
        }

        public override string Explanation
        {
            get { return "The object has a reference to the unity container, so it resolves things as it needs it. But, now it's bound to unity."; }
        }
    }

    public class TickerFactory : ITickProvider
    {
        public long GetTicks()
        {
            return new TickProvider().GetTicks();
        }
    }

    public class DemoOldSolution2_PassAFactory : Demo
    {
        private readonly ITickProvider ticker;
        public DemoOldSolution2_PassAFactory(ITickProvider ticker)
        {
            this.ticker = ticker;
        }

        public override ITickProvider Ticker
        {
            get { return this.ticker; }
        }

        public override string Title
        {
            get { return "Old solution #2: Pass a factory."; }
        }

        public override string Explanation
        {
            get { return "Unity serves a factory instead of an actual implementation. The factory creates new instance every time. It works, but you'd end up with a bunch of factories. Also, you're not using the Unity Lifetime managers... you've created your own."; }
        }
    }

    public class DemoNewSolution : Demo
    {
        private readonly Func<ITickProvider> tickerGetter;
        public DemoNewSolution(Func<ITickProvider> tickerGetter)
        {
            this.tickerGetter = tickerGetter;
        }

        public override ITickProvider Ticker
        {
            get { return this.tickerGetter(); }
        }

        public override string Title
        {
            get { return "Unity 2 Solution: Pass a delegate that will resolve."; }
        }

        public override string Explanation
        {
            get { return "Unity 2 supports the Func<T> delegate, where T is the type you want to resolve. Each time Ticker is called, it will resolve again. The object itself, though, remains unity ignorant... it only knows to call the delegate. It has no intimate knowledge of what the delegate does."; }
        }
    }
}

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: