ASP.NET Core 新建線程中使用依賴注入的問題


問題來自博問的一個提問 .net core 多線程數據保存的時候DbContext被釋放 。

TCPService 通過構造函數注入了 ContentService , ContentService 的實例依賴了 AppDbContext (繼承自 EF Core 的 DbContext)。在 TCPService 中通過 Thread.Start 啟動了一個新的線程執行了 TCPService 中的 Receive 方法,在 Receive 方法中通過 ContentService 進行保存數據庫的操作,而在訪問 AppDbContext 的實例時出現對象已被 Disposed 的錯誤。

Object name: 'AppDbContext'. --->System.ObjectDisposedException: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.

針對這個問題,嘗試改為通過構造函數注入 IServiceProvider ,在 TCPService.Receive (在新線程中執行的方法)中通過 IServiceScope 解析

using (var scope = _serviceProvider.CreateScope())
{
    var contentService = scope.ServiceProvider.GetRequiredService<ContentService>();
    //...
}

結果發現 IServiceProvider 也被 Disposed 

System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'IServiceProvider'.

由此可以推斷在 ASP.NET Core 中在新建的線程中無法通過依賴注入的方式訪問實現了 IDisposable 接口的對象(單例對象除外,但實現 IDisposable 接口的類型通常不會注冊為單例),也就是只要請求一結束,實現 IDisposable 接口的對象的 Dispose 方法就會被調用。

那如何解決這個問題呢?

1)最下下策的解決方法是將 DbContext 注冊為單例

services.AddDbContext<AppDbContext>(options => { }, ServiceLifetime.Singleton);

它會帶來很多副作用,不考慮。

2)在保存數據至數據庫的實現方法中基於 DbContextOptions (它是單例)手工 new AppDbContext ,用這個 DbContext 實例進行保存操作。

public class ContentService : Repository<Content>
{
    private readonly DbContextOptions _options;

    public ContentService(AppDbContext Context, DbContextOptions options) : base(Context)
    {
        _options = options;
    }

    public override async Task<bool> SaveAsync(Content entity)
    {
        using (var context = new AppDbContext(_options))
        {
            context.Set<Content>().Add(entity);
            return await context.SaveChangesAsync() > 0;           
        }
    }
}

實測有效。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM