Check out my online course: AngularJS Unit Testing in-depth with ngMock.
Domain Events with Ninject and ASP.Net Web API
Bradley Braithwaite
on
on
on
This post looks at hooking up domain events to implementations using an IoC container and the ASP.Net Web API. This post is part of a blog series ASP.Net 10 Years On. Even though this is part of a series each post tries to be standalone. In the previous post we created the .Net Web API.
In an earlier post the topic of Domain Events in a domain model was discussed. This post revisits this and looks at how the concrete implementations can be injected using Ninject.
To recap, we had the DomainEvents class as follows:
public static class DomainEventsSince the initial post on domain events, the following has been added:
{
/// <summary>
/// The _actions.
/// </summary>
/// <remarks>Marked as ThreadStatic that each thread has its own callbacks</remarks>
[ThreadStatic]
private static List<Delegate> _actions;
/// <summary>
/// The container
/// </summary>
public static IEventContainer Container;
/// <summary>
/// Registers the specified callback for the given domain event.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="callback">The callback.</param>
public static void Register<T>(Action<T> callback) where T : IDomainEvent
{
if (_actions == null)
_actions = new List<Delegate>();
_actions.Add(callback);
}
/// <summary>
/// Raises the specified domain event and calls the event handlers.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="domainEvent">The domain event.</param>
public static void Raise<T>(T domainEvent) where T : IDomainEvent
{
if (Container != null)
foreach (var handler in Container.Handlers(domainEvent))
handler.Handle(domainEvent);
// registered actions, typically used for unit tests.
if (_actions != null)
foreach (var action in _actions)
if (action is Action<T>)
((Action<T>)action)(domainEvent);
}
}
public static IEventContainer Container;Plus the following code in the Raise method that checks the Container property for any handlers to be called:
These two additions provide the link between this class and the IoC container of choice, which in this case is Ninject.
if (Container != null)
foreach (var handler in Container.Handlers(domainEvent))
handler.Handle(domainEvent);
The IEventContainer is as follows:
public interface IEventContainerTo get up and running using Ninject for the Web API we firstly need to go ahead and install Ninject via the Nuget Package Manager (see the post titled creating your first API under the heading "dependency injection" for more details on how to set this up). Next add the following class. This class allows us to interface the domain event handlers with Ninject:
{
IEnumerable<IDomainEventHandler<T>> Handlers<T>(T domainEvent)
where T : IDomainEvent;
}
public class NinjectEventContainer : IEventContainerNext we add the following line to the NinjectWebCommon.CreateKernel() method and the concrete implementations can be hooked up using dependency injection:
{
private readonly IKernel _kernerl;
public NinjectEventContainer(IKernel kernal)
{
_kernerl = kernal;
}
public IEnumerable<IDomainEventHandler<T>> Handlers<T>(T domainEvent) where T : IDomainEvent
{
return _kernerl.GetAll<IDomainEventHandler<T>>();
}
}
private static IKernel CreateKernel()Here's the structure of the WinnerSelectedHandler class:
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
// this is our concrete implementation of handler for winner selected event
kernel.Bind<IDomainEventHandler<WinnerSelectedEvent>>().To<WinnerSelectedHandler>();
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
// ** WIRE UP DOMAIN EVENTS CONTAINER **
DomainEvents.Container = new NinjectEventContainer(kernel);
return kernel;
}
public class WinnerSelectedHandler : IDomainEventHandler<WinnerSelectedEvent>The source code for this project can be found at: github.com/bbraithwaite/smsquiz.
{
public void Handle(WinnerSelectedEvent domainEvent)
{
// send a message here.
}
}
Key code elements discussed in this post: