IoC Auto-registration

I’ve used IoC containers on several projects now, and quite frankly never want to live without them again.  They make so many things easier for me that they have become part of my way of designing.  I like deciding in one place how a class will be instantiated.  I like the possibility of making a change in one place an having all the instances of a class become singletons, even though that kind of change is rare.  The one thing I don’t like is maintaining a “registry” class, and adding configuration for each and every class to it when I have a whole category of similar classes that should all behave in the same way.  Take, for example, service proxies.  Regardless of how their endpoints are configured, the code to register them with the IoC is going to look exactly the same for each one.

Container.RegisterType<IFooService, FooServiceProxy>();
Container.RegisterType<IBarService, BarServiceProxy>();
Container.RegisterType<IBazService, BazServiceProxy>();
...

I’ve done some reflection-based “registration” of classes before for things like validators and workflow classes, and it saved me a lot of time.  The idea is simple.  Reflect over an assembly, looking for all the classes that fit a certain pattern, and add them to a list of some kind.  This is usually done at application startup, so whether you’re afraid of some fictional “performance hit” associated with reflection or not, it’s only going to happen once per run anyway, and it saves a lot of tedious typing.  It also automates the addition of new classes to the pattern so you don’t forget and leave anyone behind.

I’ve now written something similar to handle registration of similar classes with an IoC container.  This requires a base interface and a base type.  We then reflect over the assembly containing the base type, and register all classes that implement an interface derived from the provided base interface.  In other words, given IService and ServiceBase, automatically register IFooService/FooServiceProxy.  The method looks like this:

private static void RegisterTypes<TBaseContract, TBaseClass>()
where TBaseClass : TBaseContract
{
var baseContractType = typeof(TBaseContract);
var baseType = typeof(TBaseClass);
var implementationTypes = baseType.Assembly.GetTypes()
.Where(t => t.IsSubclassOf(baseType) && !t.IsAbstract);
foreach (var implementationType in implementationTypes)
{
var contractType = implementationType.GetInterfaces()
.Where(i => (i != baseContractType)
&& baseContractType.IsAssignableFrom(i)
&& !i.IsGenericType)
.SingleOrDefault();
if(contractType != null)
Container.RegisterType(contractType, implementationType);
}
}

Using it is as simple as passing the two parameters in.  Here is the static constructor from an example ServiceRegistry class which registers all the service proxies for a client application.  This example happens to be using a Unity container, but you could do the same thing with StructureMap, or my own Itty Bitty IoC if you want.  I’ve been playing with this idea of using static constructors on an XyzRegistry class for a while, and so far it’s treating me just fine.

static ServiceRegistry()
{
Container = new UnityContainer();
RegisterTypes<IService, ServiceBase>();
}

That’s it.  All my service proxies get found and registered at startup, and I don’t have to worry about adding them by hand anymore.

This entry was posted in Uncategorized. Bookmark the permalink.

One Response to IoC Auto-registration

  1. Steve Horn says:

    I\’ve had this exact thing on my todo list for projects where I\’m using Ninject. Looks like I should be able to adapt this code for Ninject very easily. Thanks for sharing!

Leave a Reply

Fill in your details below or click an icon to log in:

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