Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Autofac with Domain Events

I'm trying to introduce domain events into a project. The concept is described in Udi Dahan's post - http://www.udidahan.com/2009/06/14/domain-events-salvation/

Here's the domain event code

public interface IDomainEvent { }

public interface IHandleDomainEvents<T> where T : IDomainEvent
{
     void Handle(T args); 
}

public interface IEventDispatcher
{
    void Dispatch<TEvent>(TEvent eventToDispatch) where TEvent : IDomainEvent;
}

public static class DomainEvents
{
    public static IEventDispatcher Dispatcher { get; set; }

    public static void Raise<TEvent>(TEvent eventToRaise) where TEvent : IDomainEvent
    {
        Dispatcher.Dispatch(eventToRaise);
    }
}

The most important part is the IEventDispatcher implementation that decouples the domain event from whatever needs to happen when the event is raised. The trick is to wire up this coupling through a container. Here's my attempt

Code for Registering all Domain event handlers....

        var asm = Assembly.GetExecutingAssembly();
        var handlerType = typeof(IHandleDomainEvents<>);

        builder.RegisterAssemblyTypes(asm)
            .Where(t => handlerType.IsAssignableFrom(t)
                        && t.IsClass
                        && !t.IsAbstract)
            .AsClosedTypesOf(handlerType)
            .InstancePerLifetimeScope(); 

And resolving all the event handlers in the dispatcher. The problem is no handlers are resolved.

public class EventDispatcher : IEventDispatcher
{
    private readonly IContainer _container;

    public EventDispatcher(IContainer container)
    {
        _container = container;
    }

    public void Dispatch<TEvent>(TEvent eventToDispatch) where TEvent : IDomainEvent
    {
        var handlers = _container.Resolve<IEnumerable<IHandleDomainEvents<TEvent>>>().ToList();
        handlers.ForEach(handler => handler.Handle(eventToDispatch));
    }
}

So I'm not registering the event handlers correctly or not resolving them. How do I check that the registration is working?

Example code of a handler

public class SendWebQuestionToCSO : IHandleDomainEvents<JobNoteCreated>
{
    private readonly IConfig _config;

    public SendWebQuestionToCSO(IConfig config)
    {
        _config = config;
    } 

    public void Handle(JobNoteCreated args)
    {
        var jobNote = args.JobNote;
        using(var message = new MailMessage())
        {
            var client = new SmtpClient {Host = _config.SmtpHostIp};
            message.From = new MailAddress(_config.WhenSendingEmailFromWebProcessUseThisAddress);
            ...... etc
        }
    }
}

UPDATE After some trial and error the EventDispatcher is working ok! If I manually register a handler and then fire the domain event it works. The assembly scanning/registraion is my problem. The manual registration code...

builder.RegisterType<SendWebQuestionToCSO >().As<IHandleDomainEvents<JobNoteCreated>>();

So how do I scan all assemblies for all IHandleDomainEvents<> given they look like this

public class SendWebQuestionToCSO : IHandleDomainEvents<JobNoteCreated>
like image 582
CRG Avatar asked Apr 12 '11 02:04

CRG


1 Answers

As Peter pointed out, the registration problem was with your Where() clause.

When scanning assemblies Autofac filters components automatically based on the services you specify, so it would be equally correct to just use:

builder.RegisterAssemblyTypes(asm)
    .AsClosedTypesOf(handlerType)
    .InstancePerLifetimeScope();
like image 120
Nicholas Blumhardt Avatar answered Sep 18 '22 15:09

Nicholas Blumhardt