2

在这段代码中:

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

当容器被请求时IEnumerable<ISession>,它会得到一个包含EntityFrameworkSession,但没有应用装饰器。我怎样才能让它在上面的代码中应用装饰器?

我相信这是因为没有要求容器IEnumerable<IDataHoldingSession<T>>。我将 XML 文档解释RegisterAll为暗示在这种情况下将要求容器提供一个实例IDataHoldingSession<DbContext>,我认为这应该导致应用装饰器。但是,在这种情况下,装饰器似乎被绕过了,因为RegisterAll它是用ISession服务类型调用的。

4

2 回答 2

3

我能够通过提供Registrations 来解决这个问题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);
}
于 2013-10-29T00:26:23.660 回答
2

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

  1. 一个InstanceProducer。这是对象产生实例并负责拦截和装饰实例。InstanceProducer不知道TImplementation注册的,只知道TService.
  2. InstanceProducer包裹一个Registration对象。此对象负责构建创建实例的表达式,执行构造函数注入、属性注入、自定义初始化,并将生活方式应用于表达式。(Registration仅)知道TImplementation.

进行RegisterAll注册时,您提供引用容器中进行的其他注册的类型。Register<IDataHoldingSession<DbContext>>您可以通过在注册中同时使用该接口类型来做到这一点RegisterAll

幕后RegisterAll的工作是查询容器以获取给定类型的注册(在您的情况下IDataHoldingSession<DbContext>)。由于请求的类型可能与集合的服务类型不同(它通常会,并且在您的情况下也会如此),因此容器会Registration从找到的对象中获取它,并根据集合的实际服务类型InstanceProducer创建一个新的类型。这在 Simple Injector 源代码中如下所示(in ):InstanceProducerRegistrationContainerControlledCollection

return new InstanceProducer(typeof(TService), instanceProducer.Registration);

但是由于装饰器是由 应用的InstanceProducer,我们失去了你应用的装饰器IDataHoldingSession<T>

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

我会尝试对此进行调查,看看是否可以为 v2.4 提出修复,但我只能在不引入重大更改的情况下这样做。同时,我认为您发现自己的解决方法非常好。如果我进行修复,我可能会像您现在所做的那样在内部实现它。

很抱歉,Simple Injector 没有按您预期的方式工作。

更新:

我刚刚签入了修复此问题的主分支中的错误修复。v2.4 版本包含此修复程序。

于 2013-10-29T10:05:31.683 回答