This post has been imported from my previous blog. I did my best to parse XML properly, but it might have some errors.
If you find one, send a Pull Request.
I do like domain events perfectly described by Udi. I’d like to share my implementation of this pattern, using Unity (my preferable container), which seems to be simple, short and still powerful. I assume, that you read the Udi’s article carefully. First and foremost: the domain interfaces
/// <summary>
/// The markup interface for any system event.
/// </summary>
public interface IEvent
{
}
/// <summary>
/// The interface of a handler for events of type <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The type of the event to handle.</typeparam>
public interface IEventHandler
where T : IEvent
{
/// <summary>
/// Handles the specified @event.
/// </summary>
/// <param name="event">The @event.</param>
void Handle(T @event);
}
/// <summary>
/// The interface of event manager, allowing raising events based on the <see cref="IEvent"/>.
/// </summary>
public interface IEventManager
{
/// <summary>
/// Raises the specified event, not requiring,
/// that it is handled by any handler.
/// </summary>
/// <typeparam name="T">The type of the event.</typeparam>
/// <param name="event">The @event.</param>
/// <remarks>
/// The method iterates through all of the registered handlers for the event of type <typeparamref name="T"/>.
/// </remarks>
void Raise(T @event)
where T : IEvent;
}
I assume usage of dependency injection and having the IEventManager implementation injected. Speaking about the IEventManager implementation it’s fairly simple, located in a project knowing the Unity assembly (Infrastructure in my case). It’s worth to mention, that I consider handlers to be transient objects, constructed and discarded immediately after event handling.
/// <summary>
/// The implementation of event manager using the container to resolve handlers.
/// </summary>
public class EventManager : IEventManager
{
private readonly IUnityContainer _container;
[DebuggerStepThrough]
public EventManager(IUnityContainer container)
{
_container = container;
}
[DebuggerStepThrough]
public void Raise(T @event)
where T : IEvent
{
var handlers = _container.<ResolveAll>();
foreach (var handler in handlers)
{
try
{
handler.Handle(@event);
}
finally
{
_container.Teardown(handler);
}
}
}
}
The last but not least: how to register all the handlers in the container? I wrote a small unity extension providing assembly scan functionality which can be found below. The are two mouthful method names in the code:
The code itself:
/// <summary>
/// The <see cref="UnityContainer"/> extension registering all the event handlers
/// and unity-based implementation of <see cref="IEventManager"/>.
/// </summary>
/// <remarks>
/// The event handlers are regsitered as classes with transient lifetime.
/// Their instances are tear down immediately after usage.
/// </remarks>
public class EventUnityContainerExtension : UnityContainerExtension
{
protected override void Initialize()
{
var eventManager = new EventManager(Container);
Container.RegisterInstanceWithSingletonLifetimeManager(eventManager);
}
/// <summary>
/// Registers all the event handlers from assembly of the passed type <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The type which assembly should be scanned.</typeparam>
/// <returns>This instance.</returns>
public EventUnityContainerExtension RegisterHandlersFromAssemblyOf<T>()
{
return RegisterHandlersFromAssembly(typeof(T).Assembly);
}
/// <summary>
/// Registers all the event handlers from all <paramref name="eventHandlersAssemblies"/>.
/// </summary>
/// <param name="eventHandlersAssemblies">List of assemblies to scan.</param>
/// <returns>This instance.</returns>
public EventUnityContainerExtension RegisterHandlersFromAssemblies(params Assembly[] eventHandlersAssemblies)
{
foreach (var eventHandlersAssembly in eventHandlersAssemblies)
{
RegisterHandlersFromAssembly(eventHandlersAssembly);
}
return this;
}
private EventUnityContainerExtension RegisterHandlersFromAssembly(Assembly assembly)
{
foreach (var type in assembly.GetTypes())
{
if (type.IsInterface || type.IsAbstract)
{
continue;
}
var handlerInterface = type.GetFirstClosedGenericInterfaceBasedOnOpenGenericInterface(typeof(IEventHandler));
if (handlerInterface == null)
{
continue;
}
// the type is registered with a name, because only named registrations can be resolved by unity.ResolveAll method
Container.RegisterType(handlerInterface, type, type.FullName, new TransientLifetimeManager());
}
return this;
}
}
}
Simple and powerful, isn’t it? :)
I'm trying use the Domain Events With Unity. However, in my implementation the method GetFirstClosedGenericInterfaceBasedOnOpenGenericInterface is missing for the object type. Can you help me? (Sorry for my bad English).
by nrts at 2015-09-19 14:37:09 +0000I no longer use Unity. I'd encourage you to switch to StructureMap or Windsor. They're much better imho
by scooletz at 2015-09-19 15:06:53 +0000
What's the advantage of constraining the generic type to IEvent? Would the type resolver not work equally well worth a model, say ModelClass and am event handler class that implements the IHandler interface? I have an existing domain with over 250 models, and the thought of creating events and event handlers for each entity fills me with dread.
See http://stackoverflow.com/questions/35673412/domain-events-are-specific-events-and-event-handlers-superior-to-domain-event
by reckface at 2016-02-29 20:22:37 +0000