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 解析app

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

結果發現 IServiceProvider 也被 Disposed async

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

由此能夠推斷在 ASP.NET Core 中在新建的線程中沒法經過依賴注入的方式訪問實現了 IDisposable 接口的對象(單例對象除外,但實現 IDisposable 接口的類型一般不會註冊爲單例),也就是隻要請求一結束,實現 IDisposable 接口的對象的 Dispose 方法就會被調用。ide

那如何解決這個問題呢?函數

1)最下下策的解決方法是將 DbContext 註冊爲單例ui

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

它會帶來不少反作用,不考慮。this

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

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

實測有效。.net

相關文章
相關標籤/搜索