装饰器未应用于RegisterAll中指定的实现类型

时间:2013-10-28 23:23:17

标签: .net simple-injector

在此代码中:

container.Register<IDataHoldingSession<DbContext>, EntityFrameworkSession>();
container.RegisterAll<ISession>(typeof(IDataHoldingSession<DbContext>));
container.RegisterDecorator(typeof(IDataHoldingSession<>), typeof(ValidatingSession<>));

当要求容器IEnumerable<ISession>时,会给它一个包含EntityFrameworkSession的集合,但不会应用装饰器。如何在上面的代码中应用装饰器?

我认为这是因为没有要求容器IEnumerable<IDataHoldingSession<T>>。我将RegisterAll的XML文档解释为暗示在这种情况下将要求容器提供IDataHoldingSession<DbContext>的实例,我认为这应该会导致应用装饰器。但是,由于使用RegisterAll服务类型调用ISession,因此可能会绕过装饰器。

2 个答案:

答案 0 :(得分:3)

我能够通过向Registration提供RegisterAll来解决此问题。我将每个注册的服务类型设置为其特定的服务类型,而不是ISession

这是一个演示此内容的扩展方法:

/// <summary>
/// Same as <see cref="Container.RegisterAll"/>, except each implementation service
/// is individually resolved from the container for compatibility with decorators.
/// </summary>
public static void RegisterAllBugFixed<TService>(this Container container, 
    params Type[] serviceTypes)
{
    var registrations = 
        from serviceType in serviceTypes
        select Lifestyle.Transient.CreateRegistration(
            serviceType,
            () => container.GetInstance(serviceType), 
            container);

    container.RegisterAll(typeof(TService), registrations);
}

答案 1 :(得分:2)

Simple Injector中的注册包含两部分:

  1. InstanceProducer。这是对象生成实例并负责拦截和装饰实例。 InstanceProducer不知道注册的TImplementation,只知道TService
  2. InstanceProducer包裹Registration个对象。该对象负责构建一个创建实例的Expression,构造函数注入,属性注入,自定义初始化,并将生活方式应用于表达式。 Registration(仅)知道TImplementation
  3. 当您进行RegisterAll注册时,您提供的类型会引用容器中的其他注册。您是通过Register<IDataHoldingSession<DbContext>>同时在RegisterAll注册中使用该接口类型来实现此目的。

    RegisterAll所涵盖的内容是查询容器以获取给定类型的注册(在您的情况下为IDataHoldingSession<DbContext>)。由于请求的类型可能与集合的服务类型不同(通常是这样,并且在您的情况下),容器从找到的Registration中抓取InstanceProducer并创建新的{{1}基于该InstanceProducer的集合的实际服务类型。这在Simple Injector源代码(Registration)中如下所示:

    ContainerControlledCollection

    但是由于装饰器由return new InstanceProducer(typeof(TService), instanceProducer.Registration); 应用,我们会丢失您应用于InstanceProducer的装饰器。

    坦率地说,我不确定为什么我们实现了这样的行为,因为最直观的行为会让IDataHoldingSession<T>的装饰器仍然被应用。我想我们试图阻止装饰器被施加两次;这是Simple Injector早期版本中的一个问题。

    我会试着调查一下,看看我是否可以为v2.4找到一个修复程序,但是如果我不引入一个重大变化,我只能这样做。与此同时,我认为您发现自己的解决方法非常好。如果我做了修复,我可能会在内部实现它,就像你现在做的那样。

    我很遗憾Simple Injector没有按照你预期的方式工作。

    <强>更新

    我刚刚检查了修复this issue的主分支中的错误修复程序。 v2.4 release包含此修复程序。