AspNet Core Autofac 处理我的 DbContext 即使它注册为 SingleInstance [英] AspNet Core Autofac disposing my DbContext even if its registered as SingleInstance
问题描述
在我们的应用程序中,我们有一个 api,它将一些数据存储到数据库中.我们正在使用 Entity Framework Core 3.1.1
.存储此实体后,将一条消息发布到 Azure Servicebus
,消费者将读取此消息并将消息存储到同一 DbContext
中的另一个表中.
In our application, we have an api which will store some data to a database. We are using Entity Framework Core 3.1.1
. After this entity has been stored, a message is posted to Azure Servicebus
and a consumer will read this message a store the message to another table in the same DbContext
.
据我所知,LifetimeScope
是针对每个 api 请求定义的.LifetimeScope
将在 api 请求命中 ApiController
时启动,并在端点处理完请求时结束.
As far as I understand, a LifetimeScope
is defined per request to the api. The LifetimeScope
will start when the api request hits the ApiController
and finishes when the endpoint is done processing the request.
我们面临的问题与被释放的 DbContext
相关,因此它不能在消费者中使用,因为它被释放了.
The issue we are facing is related to the DbContext
being disposed, so it cannot be used in the Consumer sinced its disposed.
从我们的代码可以很明显地看出它失败的原因.DbContext
是这样注册的:
From our code its pretty obvious why it fails. The DbContext
is registered this way:
containerBuilder.RegisterType<TDbContext>().AsSelf().InstancePerLifetimeScope().As<IDbContext>().IfNotRegistered(typeof(TDbContext));
我们在注册DbContext
时设置了InstancePerLifetimeScope
,导致DbContext
在api请求完成时被释放并抛出ObjectDisposedException
当我们尝试在消费者中使用它时.
We set the InstancePerLifetimeScope
when registering the DbContext
, resulting the DbContext
to be disposed when the api request is finished and throwing ObjectDisposedException
when we try to use it in the consumer.
作为一个实验,我尝试以这种方式将 DbContext
注册为 SingleInstance
:
Just as an experiment I tried registering the DbContext
as SingleInstance
this way:
containerBuilder.RegisterType<TDbContext>().AsSelf().SingleInstance().As<IDbContext>().IfNotRegistered(typeof(TDbContext));
但是当我们尝试在消费者中使用它时它仍然抛出 ObjectDisposedException.
But it still throws the ObjectDisposedException when we try using it in the Consumer.
知道为什么会发生这种情况以及我们如何解决这个问题吗?
Any ideas why this is happening and how we can solve this?
DbContext 通过扩展方法注册并作为泛型传入:
The DbContext is registered via an extension method and passed in as a generic:
public static class ContainerBuilderExtensions
{
public static void RegisterDbContext<TDbContext>(this ContainerBuilder builder)
{
containerBuilder.RegisterType<TDbContext>().AsSelf().InstancePerLifetimeScope().As<IDbContext>().IfNotRegistered(typeof(TDbContext));
}
}
推荐答案
假设你正在调用这个
containerBuilder.RegisterType
之后
containerBuilder.RegisterType
第二次注册不会有任何影响.
the second registration will not have any effect.
其次,将 DbContext
注册为单例并不是一个好主意.它不是线程安全的.
Secondly, registering the DbContext
as a singleton is not a very good idea. It's not thread-safe.
相反,您可以在注册服务总线使用者的类中注入 IServiceProvider
,并在消费新消息时手动解析上下文.
Instead, you can inject IServiceProvider
in the class where the consumer for the servicebus is registered and resolve the context manually when a new message is being consumed.
选项 1:使用 IServiceProvider
using (var scope = _serviceProvider.CreateScope())
{
using (var context = scope.ServiceProvider.GetRequiredService<IDbContext>())
{
// do work here
}
}
选项 2:使用 IServiceProvider
并使用 Autofac.Extensions.Microsoft.DependencyInjection
版本 5 后可用的扩展向下转换为 ILifetimeScope
.
Option 2: Using IServiceProvider
and casting down to ILifetimeScope
using the extension available since Autofac.Extensions.Microsoft.DependencyInjection
version 5.
using (var lifetimeScope = _serviceProvider.GetAutofacRoot().BeginLifetimeScope())
{
using (var context = lifetimeScope.Resolve<IDbContext>())
{
// do work here
}
}
这将在您每次需要并处理它时创建一个 IDbContext
实例.虽然这可能需要更长的时间,但在后台使用消息时应该不会有问题.
This will create an instance of IDbContext
everytime you need it and disposes it. While this might take a little longer, it shouldn't be a problem, when messages are consumed in the background.
EDIT:您还可以将 DbContext
注册为 Transient
EDIT: You can also register the DbContext
as Transient
containerBuilder.RegisterType<TDbContext>().AsSelf().InstancePerDependency().As<IDbContext>().IfNotRegistered(typeof(TDbContext));
这篇关于AspNet Core Autofac 处理我的 DbContext 即使它注册为 SingleInstance的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!