AspNet Core Autofac 处理我的 DbContext 即使它注册为 SingleInstance [英] AspNet Core Autofac disposing my DbContext even if its registered as SingleInstance

查看:27
本文介绍了AspNet Core Autofac 处理我的 DbContext 即使它注册为 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().AsSelf().SingleInstance().As().IfNotRegistered(typeof(TDbContext));

之后

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

第二次注册不会有任何影响.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆