Domain events with Unity Container extension

Posted on October 29, 2010 · 6 mins read · tagged with: #architecture #design patterns

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.&lt;ResolveAll&gt;();

            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:

  • GetFirstCl osedGenericInterfaceBasedOnOpenGenericInterface, which tries to do what is written it does :P
  • RegisterInstanceWithSingletonLifetimeManager,an extension methods using a I-have-nothing-to-do-with-monitors LifetimeManager for setting up the singletons

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? :)


Comments

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 +0000

I 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