每个Web请求和上下文的简单注入器注册。

6

RegisterPerWebRequestRegisterWithContext(后者最初并未随simple injector一起提供,然而在其高级场景部分提供)。这两种方法单独工作得很好,但我需要将它们结合起来。

我发现RegisterPerWebRequest中使用了new WebRequestLifestyle()生命周期(在那里发现它)。因此,我用new WebRequestLifestyle()代替了Lifestyle.TransientRegisterWithContext中,但是问题在于DependencyContext.ImplementationTypeDependencyContext.ServiceType都为空。

这是什么问题?

更新1。

所以我想像RegisterPerWebRequest一样注册类型,但也能够使实例创建器访问注入已注册类型的类型。

我修改了RegisterWithContext(将生命周期作为参数提取),如下:

public static void RegisterWithContext<TService>(
    this Container container,
    Func<DependencyContext, TService> contextBasedFactory, Lifestyle lifestyle)
    where TService : class
{
    //original code

    container.Register<TService>(rootFactory, lifestyle);

    //original code
}

而对于“每个 Web 请求和上下文”注册,我希望能够使用以下内容:
container.RegisterWithContext<IUnitOfWork>(dependencyContext =>
{
      var implementationType = dependencyContext.ImplementationType;
      //do some stuff and return preconfigured UnitOfWork
}, new WebRequestLifestyle());

正如我已经提到的,dependencyContext.ImplementationTypeNULL

我正在使用SimpleInjector 2.3.0.0


1
你能具体说明一下吗?你想以什么方式混合它们?你能给出一个需要的代码示例吗?你正在使用哪个版本的Simple Injector? - Steven
亲爱的@Steven,我已经更新了我的问题。总的来说,我试图在某些特殊情况下为一些选定的存储库提供不同的连接字符串。希望这能帮到你。 - Vladimirs
1个回答

8
RegisterWithContext扩展方法会将提供的委托显式注册为Transient。这样做是因为用其他任何生命周期方式注册类型都没有意义。
诸如WebRequestLifestyle之类的生命周期的想法是在整个对象图中(甚至可能在更远的地方)缓存和重复使用同一实例。然而,在处理基于上下文的注册时,这个概念并不适用,因为我们期望基于上下文的实例每次注入时都是不同的。换句话说,向每个消费者提供唯一的实例与重用相同实例的概念冲突。
例如,看以下对象图:
new HomeController(
    new Logger("HomeController"),
    new LoggingRepositoryDecorator<User>(
        new Logger("LoggingRepositoryDecorator<User>"),
        new SqlRepository<User>(
            new DbContext())),
    new LoggingCommandHandlerDecorator<ShipOrder>(
        new Logger("LoggingCommandHandlerDecorator<ShipOrder>"),
        new ShipOrderCommandHandler(
            new DbContext())));

在这个对象图中,我们创建了一个带有其依赖项的HomeController。显然,Logger组件是一个基于上下文的组件,因为它每次都是根据其父级进行不同的初始化。以下是Logger的注册信息:
container.RegisterWithContext<ILogger>(context =>
    new Logger(context.ImplementationType.Name));

如果我们允许使用WebRequestLifestyle注册ILogger,那么每次都会应用相同的实例,可能会导致以下对象图:

ILogger logger = new Logger(typeName: "HomeController");

new HomeController(
    logger,
    new LoggingRepositoryDecorator<User>(
        logger,
        new SqlRepository<User>(
            new DbContext())),
    new LoggingCommandHandlerDecorator<ShipOrder>(
        logger,
        new ShipOrderCommandHandler(
            new DbContext())));

在这个对象图中,注入了相同的Logger("HomeController"),这显然不是我们想要的。此外,行为变得非常不可预测,因为先创建消费者的那个对象将决定在整个对象图中重复使用的记录器的typeName。但是没有人会预料到从HomeController的构造函数中删除ILogger会导致LoggingCommandHandlerDecorator<ShipOrder>的记录器发生更改。
这就是为什么RegisterWithContext扩展方法中没有Lifestyle参数的原因。

1
非常感谢您提供如此详细的答案,我对Simple Injector中的一些原则有了深入的理解。同时也要感谢您为Simple Injector的发展所做出的所有努力和贡献。谢谢! - Vladimirs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接