如何确定在 Simple Injector 中使用哪种生活方式

pam*_*a84 2 c# dependency-injection ioc-container simple-injector

我的应用程序使用实体框架。由于我希望DbContext在单个请求中重用my ,因此我将其注册为Lifestyle.Scoped,如下所示:

container.Register<MyDbContext>(Lifestyle.Scoped);
Run Code Online (Sandbox Code Playgroud)

其他类得到这个MyDbContext注入。例如,请参阅以下存储库:

应用程序库是:

public class ApplicationsRepository : IApplicationsRepository
{
    private readonly MyDbContext _dbContext;

    public ApplicationsRepository(MyDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public void Save()
    {
        _dbContext.Save();
    }

    public Application GetByName(string appName)
    {
        var dbApplication = _dbContext.APPLICATIONS.FirstOrDefault(a => a.NAME == appName);

        return ApplicationMapper.MapApplicationFromAPPLICATIONS(dbApplication);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是还有无数其他类依赖于MyDbContext. 其他类可能不MyDbContext直接依赖,但会注入一个依赖于MyDbContext.

我的问题是:我应该为这些课程使用什么样的生活方式管理以及如何实施?

Ste*_*ven 6

有 3 种基本生活方式可供选择,瞬态、范围和单例,正如您通过阅读本文所了解的。

为特定组件选择哪种生活方式取决于以下几个因素:

  • 组件是否可以跨请求/线程安全使用
  • 组件是否包含需要跨线程共享的状态
  • 组件依赖项的生活方式。

首先,您的组件需要的生活方式是您需要根据该组件的设计方式做出的选择。某些组件根本无法重用,应始终在需要时重新创建。这通常适用于框架类型,例如 MVC 控制器。尽管每个请求通常有一个控制器,但也可以请求其他控制器,这需要创建新实例。这相当于瞬态生活方式。

您注册的其他组件或类需要重用。实体框架等工作单元实现DbContext通常需要在完整请求期间重复使用。您可以在此处阅读有关为什么要重用 DbContext 的详细讨论。这相当于Scoped生活方式。

其他组件是完全无状态或不可变的,并且可以被应用程序中的所有线程并行重用,没有任何麻烦。其他组件可能是有状态的或可变的,但在设计时考虑了线程安全。他们可能会实现需要更新的应用程序范围的缓存,并且使用锁保护对组件的访问。这意味着您只有一个实例在整个应用程序中重复使用。这相当于单身人士的生活方式。

然而,依赖关系使组件的生活方式选择复杂化,因为组件的生活方式永远不应该长于它的任何依赖关系。不遵守此规则会导致Captive DependenciesLifestyle Mismatches ,正如 Simple Injector 所称的那样。

这意味着即使你确定一个组件有资格成为单例,它也只能是它最短的依赖项。换句话说,如果组件具有 Scoped Dependency,则它本身只能是 Scoped 或 Transient。Simple Injector将检测您是否配置错误。

然而,这确实意味着您为组件所做的选择确实会向上传播调用堆栈到组件的使用者。

通常,这会导致应用程序对象图中的叶组件为 Scoped 和 Singleton,而根类型为 Transient 的结构。如果您以这种方式构建对象图,您就是在遵循闭包组合模型

有一个替代的DI 组合模型,它被称为环境组合模型。在实践这个模型时,在大多数情况下,您将状态保留在组件之外,而是将状态存储在由Composition Root控制的 Ambient State 中。两种合成模型都有其优点和缺点