![](/img/trans.png)
[英]How do I configure a DbContext with dependency injection with .Net Core 2.1?
[英].NET Core 2.1 DbContext ObjectDisposedException Dependency Injection
我正在使用 .NET Core 2.1 和 Entity Framework 制作一個 n 層 MVC 應用程序。 還有一個托管的 MQTT 隊列,我的應用程序作為客戶端偵聽該隊列。 我也使用依賴注入。 這完美地工作,直到將消息推送到隊列並且我想將該消息保存到數據庫。 一旦發生這種情況,我會收到以下ObjectDisposedException
錯誤消息:
無法訪問已處置的對象。 此錯誤的一個常見原因是處理從依賴注入解析的上下文,然后嘗試在應用程序的其他地方使用相同的上下文實例。 如果您在上下文上調用 Dispose() 或將上下文包裝在 using 語句中,則可能會發生這種情況。 如果你使用依賴注入,你應該讓依賴注入容器來處理上下文實例。 對象名稱:'xxxDbContext'。
我可以點擊繼續,之后應用程序繼續工作。 他只在從隊列收到的第一條消息上拋出異常。 控制器/管理器/存儲庫的所有其他操作都可以正常工作。 我的代碼如下:
啟動文件
public void ConfigureServices(IServiceCollection services)
{
services.AddDefaultIdentity<User>()
.AddEntityFrameworkStores<xxxDbContext>();
services.AddDbContext<xxxDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")
));
// Some identity configuration omitted here
services.AddScoped<IIdeationRepository, IdeationRepository>();
services.AddScoped<IIdeationManager, IdeationManager>();
// Some other DI configuration omitted as well.
}
public Configure(IApplicationBuilder app, IHostingEnvironment env,
IApplicationLifetime applicationLifetime, IServiceProvider serviceProvider)
{
// Start MQTT
var broker = new MqttBroker(serviceProvider.GetService<IIdeationManager>(),
serviceProvider.GetService<IConfiguration>());
// On application exit terminate MQTT to make sure the connection is ended properly
applicationLifetime.ApplicationStopping.Register(() => broker.Terminate());
// Some default http pipeline code omitted
}
MqttBroker.cs
public MqttBroker(
[FromServices] IIdeationManager ideationManage,
[FromServices] IConfiguration configuration)
{
_ideationManager = ideationManager;
_configuration = configuration;
Initialize();
}
// Some code where I just parse the message and on receive send it to the
// ideation manager, this just works so I omitted it.
}
管理器只是將它直接發送到存儲庫,在那里出現錯誤消息。
存儲庫.cs
private xxxDbContext ctx;
public IdeationRepository(xxxDbContext xxxDbContext)
{
this.ctx = xxxDbContext;
}
// This method crashes with the error
public IdeationReply ReadIdeationReply(int id)
{
return ctx
.IdeationReplies
.Include(r => r.Votes)
.FirstOrDefault(r => r.IdeationReplyId == id);
}
數據庫上下文
public class xxxDbContext : IdentityDbContext<User>
{
public DbSet<Ideation> Ideations { get; set; }
// Some more dbsets omitted
public CityOfIdeasDbContext(DbContextOptions<CityOfIdeasDbContext> options)
: base (options)
{
CityOfIdeasDbInitializer.Initialize(this, dropCreateDatabase: false);
}
// In configuring I just create a logger, nothing special
// In OnModelCreating I just setup some value converters for other tables
// than the ones I need here
internal int CommitChanges()
{
if (delaySave)
{
int infectedRecords = base.SaveChanges();
return infectedRecords;
}
throw new InvalidOperationException(
"No UnitOfWork present, use SaveChanges instead");
}
}
我讀過這篇文章,但這些情況似乎都不適用於我。 當我在Dispose()
打印堆棧跟蹤時,它發生在Main()
方法中,所以它並沒有真正幫助我。
任何人都知道如何解決或我可以在哪里搜索來解決這個問題?
提前致謝!
傳遞給Configure
的IServiceProvider
實例是scoped ,這意味着它在Configure
完成后由框架處理 - 它創建的任何作用域服務也在此過程中處理。
在您的示例中,您正在請求一個IIdeationManager
實例(它是scoped ),然后嘗試在您的MqttBroker
類(實際上是一個單例)中使用它。 到時候你試圖使用你的執行IIdeationManager
,的范圍的情況下CityOfIdeasDbContext
已創建並DI迷上了已處置等一個ObjectDisposedException
引發異常。
為了解決這個問題,您可以采用一種通用模式,當單例需要訪問范圍服務時使用該模式:創建范圍,解析服務,使用服務,然后處置范圍。 松散地,這看起來有點像這樣:
using (var scope = serviceProvider.CreateScope())
{
var ideationManager = scope.ServiceProvider.GetService<IIdeationManager>();
// Do something with ideationManager.
}
// scope and all created disposable services have been disposed.
當您請求IIdeationManager
的實現時,DI 系統看到(最終)它需要一個作用域CityOfIdeasDbContext
並為您創建一個。 一旦scope
被CityOfIdeasDbContext
,這個CityOfIdeasDbContext
實例也會被CityOfIdeasDbContext
。
為了使其在您的示例中工作,您的MqttBroker
可以將IServiceProvider
的實例帶入其構造函數,並使用它來創建我在上面顯示的范圍(它仍然可以采用IConfiguration
,因為它本身是一個單例) .
該IServiceProvider
應傳遞到實例MqttBroker
類不應該是IServiceProvider
傳遞到Configure
-這已經是作用域,正如我所描述,之后將被清理Configure
完成,這真的是你以前做的問題開始了。 為此,請使用app.ApplicationServices
,它是根提供程序並且沒有范圍。
我之前也遇到過同樣的問題,之前我也試圖處理 dbcontext 對象,如 .net 經典分層結構存儲庫設計模式案例,但在 .net 核心中足以使其作用域解決問題。 因為它為每個請求處理,所以您不需要手動處理 dbcontext。 此外, IServiceCollection 中的 adddbcontext 方法將其實現為默認范圍。 參考
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.