[英]Autofac.Core.Registration.ComponentNotRegisteredException even the interface seems to be registered
[英]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 請求命中ApiController
時ApiController
,並在端點處理完請求時結束。
我們面臨的問題與正在處理的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.