14

我正在尝试将领域事件引入项目中。这个概念在 Udi Dahan 的帖子中有所描述 - http://www.udidahan.com/2009/06/14/domain-events-salvation/

这是域事件代码

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);
    }
}

最重要的部分是 IEventDispatcher 实现,它将域事件与引发事件时需要发生的任何事情分离。诀窍是通过一个容器连接这个耦合。这是我的尝试

注册所有域事件处理程序的代码......

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

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

并解析调度程序中的所有事件处理程序。问题是没有处理程序被解决。

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));
    }
}

所以我没有正确注册事件处理程序或没有解决它们。如何检查注册是否有效?

处理程序的示例代码

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
        }
    }
}

更新 经过反复试验,EventDispatcher 工作正常!如果我手动注册一个处理程序,然后触发它工作的域事件。程序集扫描/注册是我的问题。手动注册码...

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

那么我如何扫描所有程序集,IHandleDomainEvents<>因为它们看起来像这样

public class SendWebQuestionToCSO : IHandleDomainEvents<JobNoteCreated>
4

2 回答 2

8

正如彼得指出的那样,注册问题出在您的Where()条款上。

扫描程序集时 Autofac 会根据您指定的服务自动过滤组件,因此仅使用以下命令同样正确:

builder.RegisterAssemblyTypes(asm)
    .AsClosedTypesOf(handlerType)
    .InstancePerLifetimeScope();
于 2011-04-13T11:13:27.153 回答
2

您的汇编扫描代码中的问题是当您使用IsAssignableFrom. 过滤器会问:“可以将 的实例SendWebQuestionToCSO分配给 的变量IHandleDomainEvents<>吗?” 答案显然是“不”,因为您永远不能拥有开放泛型类型的变量。

诀窍是检查每种类型实现的接口并检查它们中的任何一个是否正在关闭开放的通用接口类型。这是修改后的扫描仪:

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

    builder.RegisterAssemblyTypes(asm)
        .Where(t => t.GetInterfaces().Any(t => t.IsClosedTypeOf(handlerType)))
        .AsImplementedInterfaces()
        .InstancePerLifetimeScope(); 
于 2011-04-13T00:16:45.337 回答