将Autofac与域事件一起使用

将Autofac与域事件一起使用,autofac,domain-events,Autofac,Domain Events,我正在尝试将域事件引入到项目中。Udi Dahan的帖子中描述了这一概念- 这是域事件代码 public interface IDomainEvent { } public interface IHandleDomainEvents<T> where T : IDomainEvent { void Handle(T args); } public interface IEventDispatcher { void Dispatch<TEvent>(

我正在尝试将域事件引入到项目中。Udi Dahan的帖子中描述了这一概念-

这是域事件代码

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);
    }
}
公共接口IDomainEvent{}
公共接口IHandleDomainEvents,其中T:IDomainEvent
{
无效句柄(T参数);
}
公共接口IEventDispatcher
{
无效调度(TEvent eventToDispatch),其中TEvent:IDomainEvent;
}
公共静态类DomainEvents
{
公共静态IEventDispatcher调度程序{get;set;}
公共静态无效提升(TEvent eventToRaise),其中TEvent:IDoMain事件
{
调度员。调度(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(); 
var asm=Assembly.getExecutionGassembly();
var handlerType=类型(IHandleDomainEvents);
builder.RegisterAssemblyTypes(asm)
.Where(t=>handlerType.IsAssignableFrom(t)
&&t.I类
&&!t.IsAbstract)
.AsClosedTypesOf(handlerType)
.InstancePerLifetimeScope();
以及解析dispatcher中的所有事件处理程序。问题是没有解决任何处理程序

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));
    }
}
公共类事件调度程序:IEventDispatcher
{
专用只读IContainer\u容器;
公共事件调度器(IContainer容器)
{
_容器=容器;
}
公共无效调度(TEvent eventToDispatch),其中TEvent:IDomainEvent
{
var handlers=_container.Resolve().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
        }
    }
}
公共类发送Web问题给SO:IHandleDomainEvents
{
私有只读IConfig\u config;
公共SendWebQuestionToCSO(IConfig配置)
{
_config=config;
} 
公共无效句柄(JobNoteCreated参数)
{
var jobNote=args.jobNote;
使用(var message=new MailMessage())
{
var client=new SmtpClient{Host=_config.SmtpHostIp};
message.From=新邮件地址(_config.WhenSendingEmailFromWebProcessUseThisAddress);
等
}
}
}
更新 经过一些尝试和错误后,EventDispatcher工作正常!如果我手动注册一个处理程序,然后触发域事件,它就会工作。组装扫描/注册是我的问题。 手动注册码

builder.RegisterType<SendWebQuestionToCSO >().As<IHandleDomainEvents<JobNoteCreated>>();
builder.RegisterType().As();
那么,如果所有
IHandleDomainEvents
看起来像这样,我如何扫描所有程序集

public class SendWebQuestionToCSO : IHandleDomainEvents<JobNoteCreated>
公共类发送Web问题给SO:IHandleDomainEvents

程序集扫描代码中的问题是,当您使用
时,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(); 
var asm=Assembly.getExecutionGassembly();
var handlerType=类型(IHandleDomainEvents);
builder.RegisterAssemblyTypes(asm)
.Where(t=>t.GetInterfaces().Any(t=>t.IsClosedTypeOf(handlerType)))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();

正如Peter指出的,注册问题在于您的
Where()
子句

扫描部件时,Autofac会根据您指定的服务自动筛选部件,因此仅使用以下选项同样正确:

builder.RegisterAssemblyTypes(asm)
    .AsClosedTypesOf(handlerType)
    .InstancePerLifetimeScope();

嗨,Peter,我可以在什么名称空间中找到“IsClosingTypeOf”您是指IsClosedTypeOf吗?我试过了,但没用。然而,它看起来确实很有希望!任何其他想法都会很有帮助,我已经在这里混了很久了……我已经在code.google.com hg/src/source/Autofac/Util/ReflectionExtensions.cs上查看了源代码,扩展方法IsClosingTypeOf非常简单,所以我复制了代码,得到-.Where(t=>t.GetInterfaces().Any)(i=>i.IsGenericType&&i.GetGenericTypeDefinition()==handlerType)).这很有效!!!最大的问题是扩展方法在版本2.4.5.724.Net4中去了哪里?啊,是的,现在更新了我的本地源代码并找到了它。方法现在是
TypeExtensions.IsClosedTypeOf
。啊,是的,甚至更平滑。不过,剥夺了我15个代表!呵呵,好像你需要它,L先生;)你还是得到了我的选票。嘿,伙计们。我正试图在MVC5多租户应用程序中实现这种方法,其中所有IOC依赖项都是每个请求范围。事件处理程序是从IContainer而不是MVC DependencyResolver解析的。然后,事件处理程序尝试解析构造函数注入,该构造函数注入引发以下错误:错误:从请求实例的作用域中看不到标记与“AutofacWebRequest”匹配的作用域。这通常表示根据HTTP请求注册的组件正由SingleInstance()组件(或类似场景)请求。在web集成下,始终从DependencyResolver.Current或ILifetimeScopeProvider.RequestLifetime请求依赖项,而不是从容器本身。您好,我尝试了此操作,但EventDispatcher没有解析。builder.RegisterType();RegisterAssemblyTypes(typeof(Repository.Assembly).AsClosedTypesOf(ty