Advanced Unity: Connecting Implementations to Open Generic Types
Jimmy Bogard has an excellent post called “Advanced StructureMap: connecting implementations to open generic types” which he uses the StructureMap IOC container to connect messages to handlers.
This is something I have been using in my codebase to handle domain events, as well as a publish/subscribe mechanism for WCF message handling. I learned about this Handler<T>(or Consumer<T>) approach from the MassTransit codebase. For those that don’t know about MassTransit, it is lean service bus implementation for building loosely coupled applications using the .NET framework. I highly recommend checking it out.
Though I am a big fan of StructureMap, I have also use the Unity dependency injection container to resolve my handlers/consumers.
The Open Generic Handler
As Jimmy described in his post, there is an generic interface describing a contract
public interface IHandler<TEvent>
{
void Handle(TEvent args);
}
The Implementation
The interface is implemented specifying the type (the Domain Event) for the interface contract
public class OrderCanceledEvent
: IHandler<OrderCanceledMessage>
{
public void Handle(OrderCanceledMessage args)
{
// send an email or something
}
}
Resolving the Handler
When a given domain event occurs, the handler(s) is resolved for the given event, the “T”, or OrderCancelledMessage.
var handler = container.Resolve<IHandler<OrderCanceledMessage>>();
Configuring Unity
There are a few ways to do this with Unity. I will show how to do it using a Unity Extension. Since this is fairly trivial, you could easily do it with a regular old Extension method, which would result in less setup code.
Basically the extension going to do is drill into the impl type and extract the interface that matches the passed in generic, and register it in the container.
The Unity Extension
public class OpenGenericExtension : UnityContainerExtension, IOpenGenericExtension
{
protected override void Initialize()
{
}
public void RegisterClosedImpl<T>(Type openGenericInterface)
{
var closedType = typeof(T);
closedType.GetInterfaces()
.Where(x => x.IsGenericType)
.Where(x => x.GetGenericTypeDefinition() == openGenericInterface)
.ToList()
.ForEach(x => Container.RegisterType(x, closedType));
}
}
public interface IOpenGenericExtension : IUnityContainerExtensionConfigurator
{
void RegisterClosedImpl<T>(Type openInterface);
}
The Test
Make it go.
[Test]
public void should_connect_types()
{
var container = new UnityContainer();
container.AddNewExtension<OpenGenericExtension>()
.Configure<IOpenGenericExtension>()
.RegisterClosedImpl<OrderCanceledEvent>(typeof(IHandler<>));
var handler = container.Resolve<IHandler<OrderCanceledMessage>>();
Assert.AreEqual(handler.GetType(), typeof(OrderCanceledEvent));
}



Pingback: Elegant Code » Event Driven Architecture: Publishing Events using an IOC container