web-dev-qa-db-ja.com

依存性注入によるバックグラウンドタスクのDbContext

私はおそらく正しい方向に考えていません。 Dependency InjectionとASP.Net Coreはかなり新しいです。

ASP.NetコアWebサイトを持っています。タスクの1つは、Excelシートからユーザーがアップロードするデータベースにデータをインポートすることです。 Excelシートは巨大になる可能性があり、データ変換タスクには時間がかかるため、バックグラウンドで実行したいと考えています。つまり、ユーザーがシートをアップロードし、応答がすぐに送信され、バックグラウンドジョブ/スレッドがデータをインポートします。

私はバックグラウンドジョブを実行しようとしています:

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

私が遭遇する問題は、Process importメソッドが、Scopedとして追加されたASP.Net Dependency Injection Containerを介してAppDbContextにアクセスするリポジトリクラスを持つサービスを呼び出し、応答が返送されると、コンテキストが破棄されることです。破棄された後のコンテキストを使用できないというランタイム例外が発生します。

私の質問は、この状況を処理するための最良の方法は何ですか? AppDbContextをシングルトンにする必要がありますか? ProcessImportメソッドでAppDbContextの新しいインスタンスを作成して渡す必要がありますか? DbContextはスレッドセーフではないので、これは良いアプローチですか?

21
Saad Farooq

タスクにIServiceScopeFactoryインスタンス(シングルトン)を渡す必要があります。

タスク内で、データが到着したら、新しいCreateScope()を作成し、そのスコープからサービスを要求する必要があります。データ処理が終了したら、このスコープを破棄します(ただし、次の実行のためにIServiceScopeFactoryへの参照を保持します)。

たとえば this を参照してください。このライブラリを使用して、小さくて高速なタスクを実行します。

実行時間の長いタスクの場合、Gertが書いたように、タスクが常に最後まで実行されるとは限りません。再起動の準備をし、同じデータの再処理の準備をします。

25
Dmitry

質問を分類するには:

  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の使用に関する詳細なガイドについては、次のブログをチェックしてください。 http://mehdi.me/ambient-dbcontext-in-ef6/

4
alltej