6

我可能沒有想到正確的方向。我對依賴注入和ASP.Net核心相當陌生。通過依賴注入進行後臺任務的DbContext

我有一個ASP.Net核心網站,其中一項任務是將數據從excel工作表導入用戶將要上傳的數據庫。 Excel工作表可能很龐大,數據轉換任務需要時間,因此我希望在後臺執行它們。即用戶將上傳表單,響應將立即發送,後臺作業/線程將導入數據。

我試圖運行在後臺作業:

Task.Run(() => ProcessImport(model)); 

我遇到的問題是,該進程導入方法通過ASP.Net依賴注入容器即調用有庫類來訪問AppDbContext服務作爲Scoped添加,並且一旦響應被髮回,上下文被處置。我得到一個運行時異常,你不能在處理它之後使用上下文。

我的問題是,處理這種情況的最佳方法是什麼?我應該創建AppDbContext單例嗎?我應該在ProcessImport方法中創建一個新的AppDbContext實例並傳遞給它?我讀過DbContext不是線程安全的,那麼這是一個好方法嗎?

+0

不要:https://stackoverflow.com/questions/3266295/net-entity-framework-and-transactions/3266481#3266481 – Steven

+0

你是對的,但如何處理在不同線程上運行的任務,需要訪問DbContext? –

+3

無論如何,這是一個危險的模式。您不應該使用ASP.Net應用程序[執行長時間運行的「忘記任務」)(http://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx)。如果你做得對,這個任務就會在自己的過程中運行,整個DI問題都消失了。 –

回答

10

您應該將IServiceScopeFactory實例(它是單例)傳遞給您的任務。

內部任務,當數據到達時,您應該創建新的CreateScope()並從該範圍請求服務。數據處理完成時 - 處理該範圍(但參考IServiceScopeFactory進行下一次運行)。

例如見this。我用這個庫運行小而快的任務。

對於沉重/長時間運行的任務,正如Gert寫道的,不要認爲你的任務總是運行完成。準備好重啓,準備好重新處理相同的數據。

+0

我不完全瞭解如何將其應用於我的場景。我有一個叫做ImportService的類,它從控制器中調用,在那裏我正在注入存儲庫類來訪問數據庫。我想在我的ProcessImport方法中使用這些存儲庫類。 如果正確地明白,如果我使用封閉方法的主體與 (VAR範圍= ServiceScopeFactory.CreateScope()) {} 將它使最後的塊的壽命的注入類,還是會注入這些類的新實例? –

+0

不,新範圍會給你新的db(和其他範圍 - 生命週期)類的實例。如果你不想讓用戶[請求]等待你的ProcessImport完成 - 你不應該與它共享scope-lifetime實例。當請求結束時,請求範圍被處置,它將所有可處理的內容都置於其中。 – Dmitry

3

擊穿您的問題:

  1. 什麼是處理這種情況的最好方法是什麼?

    這對於API來處理長時間運行的任務並不理想。你可以委託進程到後臺應用程序

  2. 我應該創建AppDbContext單例嗎?

    在Web應用程序場景中,dbContext不應該是單例,因爲它可能會導致管理事務等問題。

  3. 處理這種情況的最佳方法是什麼?

    擊穿的各種服務/過程:

    • ,將採取文件的API。理想情況下,API應該將文件作爲輸入並將其保存到磁盤或數據庫。
    • 將處理文件的服務。創建這個組件/服務作爲一個單獨的庫。然後從控制檯應用程序中使用此庫。這樣你可以分析性能。通過使其成爲異步方法來使它失火併忘記方法。這樣你可以靈活地重用你的代碼。
    • 如果您不希望大量文件上載,則可以在API控制器上重新使用該庫並使用QueueBackgroundWorkItem執行該方法。看到這裏供參考:http://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx
  4. 我應該在ProcessImport方法創建AppDbContext的新實例,並將其傳遞?

    由於它不是線程安全的,因此在每個線程中創建並使用您的dbContext類的單獨實例。

  5. 我看過DbContext不是線程安全的,那麼這是一個好方法嗎?

    對於使用EF的DbContext的深入指導,結賬這個博客:「我應該讓AppDbContext單」 http://mehdi.me/ambient-dbcontext-in-ef6/