Integrating Your IOC Container With Agatha

8 commentsWritten on November 28th, 2009 by
Categories: agatha

Agatha relies on the presence of an IOC container, both client-side as well as server-side.  When it was still a closed-source library used by my company, we could get away with using our preferred IOC container (Castle Windsor) directly.  Obviously, when making an open-source library available you want your users to have the ability to not only use their preferred container, but to integrate with their container as well.  With ‘integrate’ i mean that it should be possible to register Agatha’s components in your container, so that you can easily resolve Agatha components (such as the IRequestDispatcher or the IAsyncRequestDispatcher), or to have the ability to have the container automatically inject your dependencies (which are registered in your container) in your Request Handlers (which are resolved and used by Agatha).

I originally planned to use the Common Service Locator project for this, because the project description certainly seemed to fit my need:

The Common Service Locator library contains a shared interface for service location which application and framework developers can reference. The library provides an abstraction over IoC containers and service locators. Using the library allows an application to indirectly access the capabilities without relying on hard references. The hope is that using this library, third-party applications and frameworks can begin to leverage IoC/Service Location without tying themselves down to a specific implementation.

Unfortunately, the shared interface defined in this project only contains method for resolving components.  I really wanted to avoid having an Agatha-user be responsible for the correct registration of each component in their container, so the Common Service Locator project doesn’t really offer me any benefits.  Instead, i defined my own IContainer interface in Agatha which looks like this:

    public interface IContainer
    {
        void Register(Type componentType, Type implementationType, Lifestyle lifeStyle);
        void Register<TComponent, TImplementation>(Lifestyle lifestyle);
        void RegisterInstance(Type componentType, object instance);
        void RegisterInstance<TComponent>(TComponent instance);
 
        TComponent Resolve<TComponent>();
        object Resolve(Type componentType);
 
        void Release(object component);
    }

This interface enables me to perform automatic registration of all of the required components, and whenever Agatha needs to resolve components it will also do so through an instance which implements this interface.  We currently have two specific implementations of this interface: one for Castle Windsor, the other for Unity.  I’m going to cover how these implementations work later on in this post (as it will be useful to anyone who wants to use another IOC container together with Agatha) but first i want to show how Agatha will either obtain a reference to your container, or instantiate its own container if you don’t give it a container instance.

Agatha has two configuration classes: ServiceLayerConfiguration and ClientConfiguration.  ServiceLayerConfiguration defines the following constructors:

        public ServiceLayerConfiguration(Assembly requestHandlersAssembly, Assembly requestsAndResponsesAssembly, IContainer container)
        {
            // not relevant to this post, so i'm skipping this
        }
 
        public ServiceLayerConfiguration(Assembly requestHandlersAssembly, Assembly requestsAndResponsesAssembly, Type containerImplementation)
        {
            // not relevant to this post, so i'm skipping this
        }

And ClientConfiguration defines the following ones:

        public ClientConfiguration(Assembly requestsAndResponsesAssembly, IContainer container)
        {
            // not relevant to this post, so i'm skipping this
        }
 
         public ClientConfiguration(Assembly requestsAndResponsesAssembly, Type containerImplementation)
        {
            // not relevant to this post, so i'm skipping this
        }

As you can see, you can pass either an instance of an object that implements Agatha’s IContainer interface, or you can just pass in the type of the IContainer implementation.  If you pass in an instance, Agatha will simply reuse that instance for both the registration and the resolving of components.  If you pass a type instead of an instance, Agatha will create its own instance and use that for the registration and resolving of components.

Now, how do you integrate your own container? Quite simple, just create a type which implements the IContainer interface and pass an instance of that type to Agatha’s configuration objects.  As an example, i’ll show how i did it for Castle Windsor.  I created a new assembly called Agatha.Castle which contains the following Container class:

using System;
using Agatha.Common.InversionOfControl;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
 
namespace Agatha.Castle
{
    public class Container : IContainer
    {
        private readonly IWindsorContainer windsorContainer;
 
        public Container() : this(new WindsorContainer()) {}
 
        public Container(IWindsorContainer windsorContainer)
        {
            this.windsorContainer = windsorContainer;
        }
 
        public void Register(Type componentType, Type implementationType, Lifestyle lifeStyle)
        {
            var registration = Component.For(componentType).ImplementedBy(implementationType);
            windsorContainer.Register(AddLifeStyleToRegistration(lifeStyle, registration));
        }
 
        public void Register<TComponent, TImplementation>(Lifestyle lifestyle)
        {
            Register(typeof(TComponent), typeof(TImplementation), lifestyle);
        }
 
        public void RegisterInstance(Type componentType, object instance)
        {
            windsorContainer.Register(Component.For(componentType).Instance(instance));
        }
 
        public void RegisterInstance<TComponent>(TComponent instance)
        {
            RegisterInstance(typeof(TComponent), instance);
        }
 
        public TComponent Resolve<TComponent>()
        {
            return windsorContainer.Resolve<TComponent>();
        }
 
        public object Resolve(Type componentType)
        {
            return windsorContainer.Resolve(componentType);
        }
 
        public void Release(object component)
        {
            windsorContainer.Release(component);
        }
 
        private static ComponentRegistration<TInterface> AddLifeStyleToRegistration<TInterface>(Lifestyle lifestyle, ComponentRegistration<TInterface> registration)
        {
            if (lifestyle == Lifestyle.Singleton)
            {
                registration = registration.LifeStyle.Singleton;
            }
            else if (lifestyle == Lifestyle.Transient)
            {
                registration = registration.LifeStyle.Transient;
            }
            else
            {
                throw new ArgumentOutOfRangeException("lifestyle", "Only Transient and Singleton is supported");
            }
 
            return registration;
        }
    }
}

The Agatha.Castle.Container class defines two constructors.  One is the default constructor, which will create a new instance of the Windsor container, and the other requires you to pass an instance to a Windsor container.  The rest of the type simply implements Agatha’s IContainer interface methods and delegates to the real container instance.  If you pass an instance of the Agatha.Castle.Container class to Agatha’s ServiceLayerConfiguration class, Agatha will use this type to register and resolve all components.  Which means it either reuses your container instance, or creates its own if you don’t pass one (which i’d only recommend if you’re not using an IOC container in your code). This makes it pretty easy to integrate whatever IOC container you want to use. 

Agatha currently has ‘out-of-the-box’ support for Castle Windsor and Microsoft’s Unity.  If you want to use your own container, you now know how easily you can integrate it with Agatha.  And i’d be very happy to accept patches which add more Agatha.YourPreferredContainer assemblies :)

  • http://andreasohlund.blogspot.com Andreas

    This is exactly how we do it in NServiceBus, perhaps is time for a “Common Service Configuration” project :)

    Anyways, interesting posts. Good luck with Agatha!

  • http://davybrion.com Davy Brion

    @Andreas

    glad to know other people are using this approach as well… while i was working on this i couldn’t help think “i can’t be the only one who wants to do it like _this_”

  • Pingback: Reducing Code Coupling – Inversion of Control | GrantPalin.com

  • Pingback: Avoiding Memory Leaks With NServiceBus And Your Own Castle Windsor Instance | The Inquisitive Coder – Davy Brion's Blog

  • http://jvance.com/ JarrettV

    I’m not a fan your design.  I prefer the approach the ASP.NET MVC team took.

    For example, it has too many methods to implement.  Also, your approach does not support lifetime or unit of work easily.  Your approach only supports disposal with two containers.  All the other container implementations leak memory.

    I also feel like scanning assemblies should be the responsibility of the container and not Agatha.  Why not make explicit interface for outsourcing these implementations to the container.  NServiceBus does the same thing and it is simply unintuitive for the developer.

    The container should be responsible for what is is good at: registration, resolving dependencies, cleanup and disposal.

    • http://davybrion.com Davy Brion

      not sure what you mean with it not supporting lifetime… lifecycles are actually explicitly dealt with in the interface

      as for disposal: only 2 of the supported containers support automatic disposal of disposable transient dependencies.  All the others don’t, regardless of whether you use something like Agatha or its container abstraction.  The disposal burden rests entirely upon you in those cases.  Agatha’s container abstraction at least uses the ability with the containers that implement it.

      “The container should be responsible for what is is good at: registration, resolving dependencies, cleanup and disposal.”

      the whole point of this abstraction is to use the actual container for all of that (with the possible exception of disposal, since most containers don’t handle that properly) but to not force you, the consumer, to worry about correct registration of all required components.

      i’m pretty sure the time-savings of not having to deal with support-requests from people who misconfigured one of the components are worth it, not to mention the fact that configuration of Agatha is now a very minimal and easy step for users.

      Also, Agatha’s IContainer implementation is meant to be used _by Agatha_, not by the user.  A user can use it, but i’d expect, and recommend, users to use their containers directly without any abstractions.  All they need to do is pass their container instance to Agatha’s configuration object and that’s all there is to it.

  • Afif Mohammed

    Davy,
    Say if your framework does some out of the ordinary type registration for its internals, say if it needs more context at run time to understand what to register, perhaps even add some decoration on top depending on some conventions.. then how does one go about fulfilling all that requirement by simply registering via an interface that merely declares a straight type to implementation method?

    I am hinting towards Ninject. I have an open source library for which I use Ninject internally to register dependencies.