Tuesday, November 3, 2009

Unity auto registration

Auto registration is a great feature for any Dependency Injection container. Suppose you decided to implement the Domain Event pattern. So you have a bunch of events and some event handlers. These event handlers are classes implementing some common interface, say IHandlerFor<TEvent>. You also have a central registry of these handlers, so that you can easily find handlers for particular event – and run them passing the event data. But how does the registry know about these handlers? Well, you probably have to register all of them in the registry with some kind of configuration code. If your registry is built upon your DI container you can take advantage of auto registration feature. That is if your container supports it like Castle does.

Unfortunately Unity doesn’t do that out of the box, but there is a nice library by Artem Govorov on Codeplex, that will let you do just that. It has a nice syntax and offers a great deal of flexibility. Basically in order to achieve auto registration you:

  1. Select which assemblies are scanned for types to register
  2. Specify which types are to be registered by providing conventions
  3. Specify how the types should be registered in the container (select an interface for type, select a name under which it is to be registered)

Of course there are some predefined predicates and other methods that make working with the library easier. For more details, please visit the project’s page.

What I found the library lacked is a predicate that would allow to select types, which implement a generic interface that is constructed from specified open-generic interface (generic type definition).To use an example of domain event: If I have an event called OrderAdded and a handler implementing IHandlerFor<OrderAdded>, the open-generic interface is IHandlerFor<>. By specifying this open-generic interface I can register all handlers at once and later access concrete generics when needed. Of course you can write the predicate yourself, but it would be nice to have it out of the box.

So I introduced this predicate and Artem was kind enough to apply this patch to the library’s codebase. Now having this:

public class OrderAdded { }

public class NotifySalesHandler : IHandlerFor<OrderAdded> { }

public class SendConfirmationHandler : IHandlerFor<OrderAdded> { }

I can do this:

_container
    .ConfigureAutoRegistration()
    .IncludeAssemblies(_testAssemblies)
    .Include(type => type.ImplementsOpenGeneric(typeof(IHandlerFor<>)), 
        Then.Register().AsFirstInterfaceOfType().WithTypeName())
    .ApplyAutoRegistration();

var orderAddedHandlers = _container.Resolve<IHandlerFor<OrderAdded>>();

Of course with no additional setup required I am able to resolve any other hadlers for whatever events I might have.

DotNetKicks Image

4 comments:

Rustamali said...

Marcin, Great articles. Is there any event in unity when container.Resolve is called. For e.g in StructureMap I have this code

public class EventAggregatorInterceptor : TypeInterceptor
{

public object Process(object target, IContext context)
{
Console.WriteLine("Ok found :" + target.ToString());

IEventPublisher eventPublisher = context.GetInstance();
eventPublisher.RegisterHandlers(target);
return target;
}

public bool MatchesType(Type type)
{
Console.WriteLine("The type is :" + type.Name);
bool matchesType = type.ImplementsInterfaceTemplate(typeof(IEventHandler<>));
return matchesType;
}
}

Marcin Budny said...

Hi Rustamali,

I don't quite understand what you're doing here. Are you registering event handlers during type resolving? How do you ensure that all handlers are registered?

Sorry - I don't know StructureMap's API, so I can't figure it out.

As for event on container.Resolve, there is no direct way to handle this I think, but I guess you could achieve this by creating appropriate container extension.

Shiju Varghese said...

Can I specify the lifetime of types in unity container along with Auto registration?

Marcin Budny said...

Yes you can. Please refer to http://autoregistration.codeplex.com/

Share