C# 在运行时通过.Net Core DI容器更改服务是作为作用域注入还是作为瞬态注入?

C# 在运行时通过.Net Core DI容器更改服务是作为作用域注入还是作为瞬态注入?,c#,entity-framework,asp.net-core,dependency-injection,C#,Entity Framework,Asp.net Core,Dependency Injection,在我们的应用程序中,有几个类依赖于实体框架6。因此,我们将DbContext注入到各个领域。但是,某些模块实现多线程方法,需要将DbContext作为临时服务注入,以防止出现任何线程问题。通过对任何子模块或接收相同共享的DbContext的模块调用SaveChanges,其他模块可以串在一起并整体保存。但是,这种方法要求将DbContext添加为作用域服务 除了构建一些子类或接口,这些子类或接口只是从我的DbContext继承的,还有什么方法可以动态地确定类是获得给定服务的作用域版本还是瞬时版本

在我们的应用程序中,有几个类依赖于实体框架6。因此,我们将
DbContext
注入到各个领域。但是,某些模块实现多线程方法,需要将
DbContext
作为临时服务注入,以防止出现任何线程问题。通过对任何子模块或接收相同共享的
DbContext
的模块调用
SaveChanges
,其他模块可以串在一起并整体保存。但是,这种方法要求将
DbContext
添加为作用域服务

除了构建一些子类或接口,这些子类或接口只是从我的
DbContext
继承的,还有什么方法可以动态地确定类是获得给定服务的作用域版本还是瞬时版本

子类上下文的示例可能类似于

public类TransientDbContext:DbContext{}
公共类ScopedDbContext:DbContext{}
//在职
services.AddTransient();
services.addScope();
这是可行的,但我正在寻找一种更具动态性的方法,在这种方法中,我可以潜在地传递一个参数来指示类应该使用共享上下文

对于一些额外的上下文,我有以下接口

公共接口IRepository
{
无效添加(潜在实体);
Task SaveAsync(CancellationToken=默认值);
}
公共接口管理器
{
Task AddAsync(User-User,bool-commitChanges=true,CancellationToken=default);
}
公共接口IUserPhoneNumberManager
{
Task AddAsync(UserPhoneNumber,bool commitChanges,CancellationToken-token=default)
}
在幕后,我可能有以下具体的实现

公共类用户存储库:IRepository
{
私有只读dbcontextu DbContext;
公共用户存储库(DbContext DbContext)
{
_dbContext=dbContext;
}
公共作废添加(用户实体)
{
_dbContext.Users.Add(实体);
}
公共任务SaveAsync(CancellationToken=默认值)
{
返回_dbContext.saveChangesSync(令牌);
}
}
公共类UserPhoneNumberRepository:IRepository
{
私有只读dbcontextu DbContext;
公共用户存储库(DbContext DbContext)
{
_dbContext=dbContext;
}
公共无效添加(UserPhoneNumber实体)
{
_dbContext.UserPhoneNumbers.Add(实体);
}
公共任务SaveAsync(CancellationToken=默认值)
{
返回_dbContext.saveChangesSync(令牌);
}
}

现在,在某些情况下,我希望底层存储库被注入一个单一的作用域上下文,而在其他情况下,我需要一个临时上下文。这些临时上下文在使用时显然会提交它们自己的更改。但是作用域上下文将作为单个单元提交其更改。

我认为您的问题的核心在于以下观察结果:

某些模块实现多线程方法,这些方法要求将DbContext作为临时服务注入,以防止任何线程问题

这意味着应用程序代码本身负责处理多线程性;您可能正在开始新的线程或任务。这是你应该防止的

相反,只有您的团队成员才应该知道多头性,并且应该衍生出新的线程。这集中了关于线程安全的知识。但不仅如此,许多组件都不是线程安全的,只有组合根应该知道哪些组件是和哪些组件不是。组件本身应始终以顺序方式调用其依赖项,并假定该依赖项只有一个实例

这意味着,当您开始并行操作时,您应该返回到合成根目录,让它解析一个新的对象图。然后,组合根可以决定将组件的新实例注入到图中(例如
DbContext

当您应用这种工作方式时,您将不再需要使用
DbContext
的临时版本和作用域版本


有关详细信息,请参阅:。我的书中确实包含了一些材料来解释这一点。

子类上下文的示例可能看起来像
这样做有效吗?是的,但我正在寻找一种更具动态性的方法,在这种方法中,我可能会传递一个参数来指示类应该使用共享上下文。瞬态db上下文并不意味着它是线程安全的。最好让那些DAL方法以线程安全的方式使用db上下文,或者在db上下文类中使用内部同步。@swdon在某些情况下,我们执行完全独立于数据库的高度并发操作。(假设运行一个报表和报表上的每个小部件都是自动执行的、自包含的,并且是并行运行的)。我们有两个单独的用例,需要动态地加速数据库上下文。在一种情况下,我们执行的是高度并发的操作,需要将信息反复保存到
DbContext
。当共享单个上下文来执行此操作时,我们会遇到问题。第二种情况是不需要按任何特定顺序完成的多个并发异步保存。但是,如果这些调用没有单独等待(而不是作为一个批处理),我们会收到来自EF6的并发异常。除此之外,我们还有一些类实现了
IRepository
,其中包含
SaveAsync
方法。如果我们想执行多个操作,然后保存批处理,我们只需在一个存储库中调用
SaveAsync
,所有共享相同范围上下文的存储库都会被保存。我浏览了一下您的站点。在你看来,建立一个