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

时间:2018-03-20 16:03:18

标签: c# dependency-injection ioc-container simple-injector

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

container.Register<MyDbContext>(Lifestyle.Scoped);

其他类会注入此MyDbContext。例如,请参阅以下存储库:

ApplicationsRepository是:

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);
    }
}

但是有无数其他类要么依赖MyDbContext。其他类可能不直接依赖MyDbContext,但会注入一个依赖于MyDbContext的类。

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

1 个答案:

答案 0 :(得分:2)

有三种基本的生活方式可供选择,Transient,Scoped和Singleton,正如您已经通过阅读this学到的那样。

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

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

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

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

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

然而,依赖性使组件的生活方式选择复杂化,因为组件的生活方式永远不会比其任何依赖项更长。如果不遵守此规则,会导致Captive DependenciesLifestyle Mismatches为Simple Injector调用它们。

这意味着即使您确定某个组件有资格成为Singleton,它也只能与其最短的依赖关系一样长。换句话说,如果组件具有Scoped Dependency,它本身只能是Scoped或Transient。简单的注入器will detect如果你错误配置它。

但这确实意味着您为组件做出的选择确实会将调用堆栈向上传播到组件的使用者。

通常,这会产生一个结构,其中应用程序对象图中的叶组件是Scoped和Singleton,而根类型是Transients。