如何确定在 Simple Injector 中使用哪种生活方式
How to determine which lifestyle to use in Simple Injector
我的应用程序使用 Entity Framework。因为我希望我的 DbContext
在单个请求中重复使用,所以我将其注册为 Lifestyle.Scoped
,如下所示:
container.Register<MyDbContext>(Lifestyle.Scoped);
其他 classes 得到这个 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);
}
}
但是还有无数其他 class 依赖于 MyDbContext
。其他 classes 可能不直接依赖于 MyDbContext
,但确实注入了依赖于 MyDbContext
.
的 class
我的问题是:我应该对这些 class 使用什么样的生活方式管理以及如何实施它?
有 3 种基本生活方式可供选择,Transient、Scoped 和 Singleton,正如您在阅读 this 时学到的那样。
为特定组件选择哪种生活方式取决于几个因素:
- 组件是否可以跨 requests/threads
安全使用
- 组件是否包含需要跨线程共享的状态
- 组件依赖项的生活方式。
首先,您的组件所需的生活方式是您需要根据该组件的设计方式做出的选择。有些组件根本无法重复使用,并且在请求时应始终为 re-created。这通常适用于 MVC 控制器等框架类型。虽然每个请求通常有一个控制器,但也可以请求其他控制器,这需要创建新实例。这相当于短暂的生活方式。
您注册的其他组件或类需要重复使用。 Entity Framework 的 DbContext
等工作单元实现通常需要在整个请求期间重复使用。您可以阅读有关为什么要重用 DbContext here 的详细讨论。这相当于 Scoped 生活方式。
其他组件是完全无状态或不可变的,可以由应用程序中的所有线程并行重用而不会出现任何问题。其他组件可能是有状态的或可变的,但在设计时考虑到了 thread-safety。他们可能会实施需要更新的 application-wide 缓存,并且对组件的访问受锁保护。这意味着您在整个应用程序中只能重用一个实例。这相当于单身生活。
然而,依赖关系使组件的生活方式选择变得复杂,因为组件的生命周期应该永远不会长于它的任何依赖关系。不遵守此规则,会导致 Captive Dependencies, or Lifestyle Mismatches 简单注入器调用它们。
这意味着即使您确定一个组件有资格成为单例,它也只能与其最短的依赖项一样长。换句话说,如果组件具有 Scoped Dependency,它本身只能是 Scoped 或 Transient。简单注入器 will detect 如果你配置错误。
然而,这确实意味着您为组件所做的选择确实会向上传播调用堆栈到组件的使用者。
一般来说,这会产生一个结构,其中应用程序对象图中的叶组件是 Scoped 和 Singleton,而根类型是 Transients。如果您以这种方式构建对象图,则您遵循 Closure Composition Model.
还有一个选择DI Composition Model, and it is called the Ambient Composition Model. When practicing this model you, for the most part, keep state out of your components, and instead store state in Ambient State, which is controlled by the Composition Root. Both composition models have their advantages and disadvantages。
我的应用程序使用 Entity Framework。因为我希望我的 DbContext
在单个请求中重复使用,所以我将其注册为 Lifestyle.Scoped
,如下所示:
container.Register<MyDbContext>(Lifestyle.Scoped);
其他 classes 得到这个 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);
}
}
但是还有无数其他 class 依赖于 MyDbContext
。其他 classes 可能不直接依赖于 MyDbContext
,但确实注入了依赖于 MyDbContext
.
我的问题是:我应该对这些 class 使用什么样的生活方式管理以及如何实施它?
有 3 种基本生活方式可供选择,Transient、Scoped 和 Singleton,正如您在阅读 this 时学到的那样。
为特定组件选择哪种生活方式取决于几个因素:
- 组件是否可以跨 requests/threads 安全使用
- 组件是否包含需要跨线程共享的状态
- 组件依赖项的生活方式。
首先,您的组件所需的生活方式是您需要根据该组件的设计方式做出的选择。有些组件根本无法重复使用,并且在请求时应始终为 re-created。这通常适用于 MVC 控制器等框架类型。虽然每个请求通常有一个控制器,但也可以请求其他控制器,这需要创建新实例。这相当于短暂的生活方式。
您注册的其他组件或类需要重复使用。 Entity Framework 的 DbContext
等工作单元实现通常需要在整个请求期间重复使用。您可以阅读有关为什么要重用 DbContext here 的详细讨论。这相当于 Scoped 生活方式。
其他组件是完全无状态或不可变的,可以由应用程序中的所有线程并行重用而不会出现任何问题。其他组件可能是有状态的或可变的,但在设计时考虑到了 thread-safety。他们可能会实施需要更新的 application-wide 缓存,并且对组件的访问受锁保护。这意味着您在整个应用程序中只能重用一个实例。这相当于单身生活。
然而,依赖关系使组件的生活方式选择变得复杂,因为组件的生命周期应该永远不会长于它的任何依赖关系。不遵守此规则,会导致 Captive Dependencies, or Lifestyle Mismatches 简单注入器调用它们。
这意味着即使您确定一个组件有资格成为单例,它也只能与其最短的依赖项一样长。换句话说,如果组件具有 Scoped Dependency,它本身只能是 Scoped 或 Transient。简单注入器 will detect 如果你配置错误。
然而,这确实意味着您为组件所做的选择确实会向上传播调用堆栈到组件的使用者。
一般来说,这会产生一个结构,其中应用程序对象图中的叶组件是 Scoped 和 Singleton,而根类型是 Transients。如果您以这种方式构建对象图,则您遵循 Closure Composition Model.
还有一个选择DI Composition Model, and it is called the Ambient Composition Model. When practicing this model you, for the most part, keep state out of your components, and instead store state in Ambient State, which is controlled by the Composition Root. Both composition models have their advantages and disadvantages。