Register | Login

Stacking Code

public interface IBlog { string Dump(Stream consciousness); }

Inversion of Control

Tuesday, 30 November, 2010 @ 7:15 PM < Adam Boddington
Tags: Building Neno, Inversion of Control, Spring

This is post #7 in the Building Neno series. Please click here for a description of the Building Neno project and instructions on how to access the source code for this post.

Before I can build out my repositories the way I want to, I need to add an Inversion of Control (IOC) container. The only one I've ever used is Spring. While it's great for automatic dependency injection, it can be unwieldy to use in code for manual dependency injection, like this...

ContextRegistry.GetContext().ConfigureObject(postService, "PostService");

And for service location, like this...

var postService = (IPostService)ContextRegistry.GetContext().GetObject("PostService");

The result has to be cast, and objects have to be identified by string. Painful -- but the configured automatic dependency injection behind the scenes works like a charm. When I retrieve a service, it automatically has its repositories inserted, the repositories have their context and session objects inserted, and the context objects have their session object inserted too, all with the right scope. So I haven't been tempted just yet to find another container.

The solution for me is to build a simple container with the interface I want that farms out the heavy lifting to Spring. By using the provider pattern I can also decouple Spring from my framework, and make it possible to swap Spring for another container if I ever need to.

When I first implemented this on a personal project last year I was not aware of the Common Service Locator project, which would have been a year old at the time. The Common Service Locator project does something very similar and already has implementations for all the major IOC containers, including Spring.

Container Provider Interface

The first thing to do is define the interface I want my container providers to fulfil. The plan is to expose the same methods through a static Container class which will pass off to the container provider.

namespace StackingCode.Moja.InversionOfControl
{
    public interface IContainerProvider
    {
        void Configure<T>(T target);
        void Configure<T>(T target, string name);
        T Get<T>();
        T Get<T>(string name);
        T Get<T>(object[] args);
        T Get<T>(string name, object[] args);
    }
}

The big improvements in this interface over Spring is the use of generics. I want to be able to retrieve objects by type -- and if there's only one object in the container with that type, I don't want to have to specify a name. And no more casting!

Spring Container Provider

This will depend on the Spring assemblies so I'll make a new project to keep Moja light, StackingCode.Moja.InversionOfControl.Spring.

Right, Spring has methods for finding objects by type, so this provider will be pretty easy to build.

namespace StackingCode.Moja.InversionOfControl.Spring
{
    public class ContainerProvider : IContainerProvider
    {
        public ContainerProvider()
        {
            ApplicationContext = ContextRegistry.GetContext();
        }

        private IApplicationContext ApplicationContext { get; set; }

        #region IContainerProvider Members

        public void Configure<T>(T target)
        {
            ApplicationContext.ConfigureObject(target, GetObjectNameFor<T>());
        }

        // ...

        public T Get<T>()
        {
            return (T)ApplicationContext.GetObject(GetObjectNameFor<T>());
        }

        // ...

        #endregion

        private string GetObjectNameFor<T>()
        {
            string[] names = ApplicationContext.GetObjectNamesForType(typeof(T));

            if (names.Length < 1)
                throw new ApplicationException(string.Format("{0} is not defined in Spring objects.", typeof(T).Name));

            if (names.Length > 1)
                throw new ApplicationException(string.Format("{0} matches more than one object defined in Spring objects.", typeof(T).Name));

            return names[0];
        }
    }
}

Container

As mentioned before, my Container class is a static class with static methods matching the interface above. The static constructor uses a custom configuration section to find the type of the container provider it should be using -- which it instantiates and hangs on to.

namespace StackingCode.Moja.InversionOfControl
{
    public static class Container
    {
        private const string CONFIG_SECTION = "inversionOfControl";

        static Container()
        {
            var configSection = (InversionOfControlSection)ConfigurationManager.GetSection(CONFIG_SECTION);

            if (configSection == null)
                throw new ConfigurationErrorsException(string.Format("The {0} config section cannot be found.", CONFIG_SECTION));

            Type providerType = Type.GetType(configSection.ContainerProvider.Type);

            if (providerType == null)
                throw new ConfigurationErrorsException("The Inversion of Control Container Provider Type cannot be found.", configSection.ContainerProvider.ElementInformation.Source, configSection.ContainerProvider.ElementInformation.LineNumber);

            if (!typeof(IContainerProvider).IsAssignableFrom(providerType))
                throw new ConfigurationErrorsException("The Inversion of Control Container Provider Type does not implement IContainerProvider.", configSection.ContainerProvider.ElementInformation.Source, configSection.ContainerProvider.ElementInformation.LineNumber);

            Provider = (IContainerProvider)Activator.CreateInstance(providerType);
        }

        private static IContainerProvider Provider { get; set; }

        public static void Configure<T>(T target)
        {
            Provider.Configure(target);
        }

        // ...

        public static T Get<T>()
        {
            return Provider.Get<T>();
        }

        // ... and so on
    }
}

Result

Elegance in manual dependency injection...

Container.Configure(postService);

And service location...

var postService = Container.Get<IPostService>();

There are 0 comments.


Comments

Leave a Comment

Please register or login to leave a comment.


Older
Implementing Context and a Base Repository

Newer
Implementing Repositories

Older
Implementing Context and a Base Repository

Newer
Implementing Repositories

browse with Pivot


About


Projects

Building Neno


RSS
Recent Posts

Codility Nitrogenium Challenge
OS X Lock
HACT '13
Codility Challenges
Priority Queue


Tags

Architecture (13)
ASP.NET (2)
ASP.NET MVC (13)
Brisbane Flood (1)
Building Neno (38)
C# (4)
Challenges (3)
Collections (1)
Communicator (1)
Concurrency Control (2)
Configuration (1)
CSS (5)
DataAnnotations (2)
Database (1)
DotNetOpenAuth (2)
Entity Framework (1)
FluentNHibernate (2)
Inversion of Control (5)
JavaScript (1)
jQuery (4)
Kata (2)
Linq (7)
Markdown (4)
Mercurial (5)
NHibernate (20)
Ninject (2)
OpenID (3)
OS X (1)
Pivot (6)
PowerShell (8)
Prettify (2)
RSS (1)
Spring (3)
SQL Server (5)
T-SQL (2)
Validation (2)
Vim (1)
Visual Studio (2)
Windows Forms (3)
Windows Service (1)


Archives


Powered by Neno, ASP.NET MVC, NHibernate, and small furry mammals. Copyright 2010 - 2011 Adam Boddington.
Version 1.0 Alpha (d9e7e4b68c07), Build Date Sunday, 30 January, 2011 @ 11:37 AM