C# AspNet Core Autofac处理我的DbContext,即使它注册为SingleInstance

C# AspNet Core Autofac处理我的DbContext,即使它注册为SingleInstance,c#,entity-framework,asp.net-core,.net-core,autofac,C#,Entity Framework,Asp.net Core,.net Core,Autofac,在我们的应用程序中,我们有一个将一些数据存储到数据库的api。我们使用的是实体框架核心3.1.1。存储此实体后,一条消息将发布到Azure Servicebus,消费者将读取此消息并将消息存储到同一DbContext中的另一个表中 据我所知,LifetimeScope是根据对api的请求定义的。LifetimeScope将在api请求点击ApiController时启动,并在端点处理完请求时结束 我们面临的问题与正在处理的DbContext有关,因此它不能在已处理的消费者中使用 从我们的代码来看

在我们的应用程序中,我们有一个将一些数据存储到数据库的api。我们使用的是
实体框架核心3.1.1
。存储此实体后,一条消息将发布到
Azure Servicebus
,消费者将读取此消息并将消息存储到同一
DbContext
中的另一个表中

据我所知,
LifetimeScope
是根据对api的请求定义的。
LifetimeScope
将在api请求点击
ApiController
时启动,并在端点处理完请求时结束

我们面临的问题与正在处理的
DbContext
有关,因此它不能在已处理的消费者中使用

从我们的代码来看,它失败的原因很明显。
DbContext
的注册方式如下:

containerBuilder.RegisterType<TDbContext>().AsSelf().InstancePerLifetimeScope().As<IDbContext>().IfNotRegistered(typeof(TDbContext));
containerBuilder.RegisterType<TDbContext>().AsSelf().SingleInstance().As<IDbContext>().IfNotRegistered(typeof(TDbContext));
但是当我们尝试在消费者中使用ObjectDisposedException时,它仍然抛出ObjectDisposedException

你知道为什么会发生这种情况,以及我们如何解决这个问题吗

编辑:


DbContext通过扩展方法注册,并作为泛型传入:

public static class ContainerBuilderExtensions 
{
    public static void RegisterDbContext<TDbContext>(this ContainerBuilder builder) 
    {
        containerBuilder.RegisterType<TDbContext>().AsSelf().InstancePerLifetimeScope().As<IDbContext>().IfNotRegistered(typeof(TDbContext));
    }
}
公共静态类ContainerBuilderExtensions
{
公共静态无效注册表dbContext(此ContainerBuilder生成器)
{
containerBuilder.RegisterType().AsSelf().InstancePerLifetimeScope().As().IfNotRegistered(typeof(TDbContext));
}
}

假设您正在调用此

containerBuilder.RegisterType().AsSelf().SingleInstance().As().IfNotRegistered(typeof(TDbContext))

此后

containerBuilder.RegisterType().AsSelf().InstancePerLifetimeScope().As().IfNotRegistered(typeof(TDbContext))

第二次注册无效

其次,将
DbContext
注册为单例不是一个好主意。它不是线程安全的

相反,您可以将
IServiceProvider
注入到注册servicebus使用者的类中,并在使用新消息时手动解析上下文

选项1:使用IServiceProvider

使用(var scope=\u serviceProvider.CreateScope())
{
使用(var context=scope.ServiceProvider.GetRequiredService())
{
//你在这里工作吗
}
}
选项2:使用
IServiceProvider
并使用自
Autofac.Extensions.Microsoft.DependencyInjection
版本5起提供的扩展名向下转换到
ILifetimeScope

使用(var lifetimeScope=\u serviceProvider.GetAutofacRoot().BeginLifetimeScope())
{
使用(var context=lifetimeScope.Resolve())
{
//你在这里工作吗
}
}
这将在每次需要时创建一个
IDbContext
实例并进行处理。虽然这可能需要更长的时间,但当消息在后台使用时,这不应该是一个问题

编辑:您还可以将
DbContext
注册为
Transient

containerBuilder.RegisterType().AsSelf().InstancePerDependency().As().IfNotRegistered(typeof(TDbContext));

假设您正在调用此

containerBuilder.RegisterType().AsSelf().SingleInstance().As().IfNotRegistered(typeof(TDbContext))

此后

containerBuilder.RegisterType().AsSelf().InstancePerLifetimeScope().As().IfNotRegistered(typeof(TDbContext))

第二次注册无效

其次,将
DbContext
注册为单例不是一个好主意。它不是线程安全的

相反,您可以将
IServiceProvider
注入到注册servicebus使用者的类中,并在使用新消息时手动解析上下文

选项1:使用IServiceProvider

使用(var scope=\u serviceProvider.CreateScope())
{
使用(var context=scope.ServiceProvider.GetRequiredService())
{
//你在这里工作吗
}
}
选项2:使用
IServiceProvider
并使用自
Autofac.Extensions.Microsoft.DependencyInjection
版本5起提供的扩展名向下转换到
ILifetimeScope

使用(var lifetimeScope=\u serviceProvider.GetAutofacRoot().BeginLifetimeScope())
{
使用(var context=lifetimeScope.Resolve())
{
//你在这里工作吗
}
}
这将在每次需要时创建一个
IDbContext
实例并进行处理。虽然这可能需要更长的时间,但当消息在后台使用时,这不应该是一个问题

编辑:您还可以将
DbContext
注册为
Transient

containerBuilder.RegisterType().AsSelf().InstancePerDependency().As().IfNotRegistered(typeof(TDbContext));

忘了提到我们没有两次注册dbContext。刚刚替换了代码。我会调查你的答案。谢谢这可能是
Autofac
中的一个错误。我将尝试准备一个示例并报告它,如果是这样的话。当创建一个新范围时,它似乎起作用。我接受你的回答。谢谢忘了提到我们没有两次注册dbContext。刚刚替换了代码。我会调查你的答案。谢谢这可能是
Autofac
中的一个错误。我将尝试准备一个示例并报告它,如果是这样的话。当创建一个新范围时,它似乎起作用。我接受你的回答。谢谢TDbContext的确切来源是什么?你介意把那部分也贴出来吗。正在尝试重现手头的问题。DbContext是通过扩展方法注册的。请看我的最新答案TDbContext到底来自哪里?你介意把那部分也贴出来吗。正在尝试重现手头的问题。DbContext是通过扩展方法注册的。请看我的最新答案