AspNet Core Autofac处置我的DbContext,即使其已注册为SingleInstance [英] AspNet Core Autofac disposing my DbContext even if its registered as SingleInstance

查看:68
本文介绍了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.

据我了解,每个对api的请求都定义了 LifetimeScope . 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 的处置有关,因此,由于其已处置,因此不能在Consumer中使用.

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));

但是当我们尝试在Consumer中使用它时,它仍然会抛出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< TDbContext>().AsSelf().SingleInstance().As< IDbContext>().IfNotRegistered(typeof(TDbContext));

在此之后

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

第二次注册将无效.

第二,将 DbContext 注册为单例并不是一个好主意.这不是线程安全的.

Secondly, registering the DbContext as a singleton is not a very good idea. It's not thread-safe.

相反,您可以在注册Servicebus使用者的类中插入 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 ./p>

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.

编辑:您还可以将 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天全站免登陆