【问题标题】:Dependency Injection with NHibernate Event ListenersNHibernate 事件监听器的依赖注入
【发布时间】:2017-01-16 03:20:59
【问题描述】:

我正在尝试使用 NHibernate 事件列表器进行简单的构造函数注入,这是一个示例:

    public class FormGeneratorUpdate : IPostUpdateEventListener
{
    private readonly IHostingEnvironment _env;

    public FormGeneratorUpdate(IHostingEnvironment env)
    {
        _env = env;
    }

    public void OnPostUpdate(PostUpdateEvent @event)
    {
        string typeName = @event.Entity.GetType().Name;
        dynamic entity = @event.Entity;
        string filePath =
            $"{_env.ContentRootPath}\\App_Data\\FormGenerator\\{typeName}\\{entity.Id}.json";

        File.Delete(filePath);

        string json = JsonConvert.SerializeObject(entity);
        using (FileStream fs = File.Create(filePath))
        {
            // Add some text to file
            Byte[] content = new UTF8Encoding(true).GetBytes(json);
            fs.Write(content, 0, content.Length);
        }
    }
}

我目前将 NHibernate bytecodeProvider 设置为 autofac 实现,如下所示:

    NHibernate.Cfg.Environment.BytecodeProvider =
            new AutofacBytecodeProvider(_container, new ProxyFactoryFactory(), new DefaultCollectionTypeFactory());

在构建会话工厂时这似乎工作得很好,但我的问题是如何在不首先实例化的情况下使用 NHibernate 配置注册事件侦听器?我可以注册它的每一种方式都需要我首先实例化对象,如下所示:

cfg.SetListener(ListenerType.Update, new FormGeneratorUpdate());

由于构造函数不是空的,因此会引发错误...我尝试仅使用 Autofac 注册事件侦听器,但这似乎也不起作用,我相信我也必须在配置中进行设置一些方法。

【问题讨论】:

    标签: c# nhibernate autofac


    【解决方案1】:

    您似乎走在了正确的道路上,因为 official Autofac documentation 指向 this blog post,其中唯一的步骤是用 Autofac 提供的 BytecodeProvider 覆盖默认值。

    我认为您不需要使用 cfg.SetListener 自己设置侦听器。

    编辑:根据 The Pax Bisonica 的回答,我的以下假设是错误的,因为它通过将 Autofac 容器中的事件处理程序注册为其具体类而不是关联的接口来工作

    当您向 Autofac 注册事件侦听器时,您是否确保将它们注册为关联接口?类似:

    builder
        .RegisterType<FormGeneratorUpdate>()
        .As<IPostUpdateEventListener>();
    

    我之所以这么问,是因为我确信 NHibernate 会尝试解决这些接口。

    【讨论】:

    • 我已经删除了 setlistener 调用,并确保该类型已使用 autofac 注册,而不是破坏它只是不会触发事件
    【解决方案2】:

    想通了!!

    对于那些想要将依赖注入与事件侦听器一起使用的人,autofac 会通过具体类型而不是接口来解析它们。最初我是这样注册所有事件监听器的:

             builder.RegisterAssemblyTypes(assemblies)
                      .AssignableTo<IPostUpdateEventListener>()
                      .AsImplementedInterfaces()
                      .InstancePerLifetimeScope();
    

    我需要做的是像这样注册它们:

                builder.RegisterAssemblyTypes(assemblies)
                      .AssignableTo<IPostUpdateEventListener>()
                      .AsSelf()
                      .InstancePerLifetimeScope();
    

    当 AutofacObjectsFactory 调用 CreateInstance 时,它​​会尝试使用事件侦听器的具体类型而不是接口类型来解决它..

    对于那些感兴趣的人,我最终使用 xml 配置注册了侦听器,以避免在事件侦听器上创建默认构造函数...

        <?xml version='1.0' encoding='utf-8'?>
    <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    
      <!-- an ISessionFactory instance -->
      <session-factory>
        <event type="post-insert">
          <listener class="FastTrack.FormGenerator.Listeners.FormGeneratorCreate, FastTrack"/>
        </event>
        <event type="post-delete">
          <listener class="FastTrack.FormGenerator.Listeners.FormGeneratorDelete, FastTrack"/>
        </event>
        <event type="post-update">
          <listener class="FastTrack.FormGenerator.Listeners.FormGeneratorUpdate, FastTrack"/>
        </event>
      </session-factory>
    
    </hibernate-configuration>
    

    然后在您构建会话工厂之前,只需在您的 NHibernate.Cfg.Configuration 对象上调用 .Configure("path-to-xml-file")。

    编辑:看起来我们实际上可以使用此方法注册侦听器而无需实例化它:

    config.SetListeners(ListenerType.PostUpdate, new[] { typeof(FormGeneratorUpdate).AssemblyQualifiedName });
    

    【讨论】:

    • 我建议您将答案设置为已接受的答案 - 分数下方的小勾号。我更新了我的指定注册作为接口不是要走的路,但如果你的答案首先出现,它会更明显。
    • 另外,您可能希望通过使用_container.ResolveOptional() 而不是_container.ResolveOptional() 来更正最后一句
    • 好吧,它说我必须等待才能接受我的答案。不过感谢您的发帖,通常很难获得有关 NHibernate 的反馈
    • 您介意通过删除任何敏感信息来发布完整的代码示例吗?我尝试创建一个示例,但无论我将侦听器注册为它们自己还是关联的接口,我都无法让它工作。
    • 现在说得通了。我试图在没有配置文件的情况下以编程方式 100% 做某事。事实证明,您仍然可以实现它,因为 SetListeners 方法接受包含程序集限定类型名称的 string 数组。在你的情况下,它就像config.SetListeners(ListenerType.PostUpdate, new[] { typeof(FormGeneratorUpdate).AssemblyQualifiedName });。另请注意,监听器的单个实例由 NHibernate 创建,然后被重复使用,因此您不能在监听器中获取生命周期范围的依赖项。
    猜你喜欢
    • 2011-08-05
    • 2011-07-27
    • 2011-04-25
    • 2011-07-05
    • 1970-01-01
    • 1970-01-01
    • 2021-11-28
    • 2010-12-30
    • 1970-01-01
    相关资源
    最近更新 更多