簡體   English   中英

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中的另一個表。

據我了解, LifetimeScope是根據對 api 的請求定義的。 LifetimeScope將在 api 請求命中ApiControllerApiController ,並在端點處理完請求時結束。

我們面臨的問題與正在處理的DbContext相關,因此它不能在消費者中使用,因為它已被處理。

從我們的代碼中很明顯它失敗的原因。 DbContext是這樣注冊的:

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

我們在注冊DbContext時設置了InstancePerLifetimeScope ,導致在 api 請求完成時ObjectDisposedException DbContext並在我們嘗試在消費者中使用它時拋出ObjectDisposedException

作為一個實驗,我嘗試以這種方式將DbContext注冊為SingleInstance

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

但是當我們嘗試在消費者中使用它時,它仍然拋出 ObjectDisposedException。

任何想法為什么會發生這種情況以及我們如何解決這個問題?

編輯:

DbContext 通過擴展方法注冊並作為泛型傳入:

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注冊為單例並不是一個好主意。 它不是線程安全的。

相反,您可以在注冊服務總線使用者的類中注入IServiceProvider ,並在使用新消息時手動解析上下文。

選項 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

using (var lifetimeScope = _serviceProvider.GetAutofacRoot().BeginLifetimeScope())
{
   using (var context = lifetimeScope.Resolve<IDbContext>())
   {
      // do work here
   }
}

這將在IDbContext每次需要時創建一個IDbContext實例並處理它。 雖然這可能需要更長的時間,但在后台使用消息時應該不會有問題。

編輯:您還可以將DbContext注冊為Transient

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM