web-dev-qa-db-ja.com

.NET Core例外:タイプのサービスの循環依存関係が検出されました

最近ソフトウェアアーキテクチャについて質問しました

サービスは別のサービスまたはリポジトリを直接呼び出す必要がありますか?

その答えの後、私は自分のアプリケーションを再編成してリファクタリングしました。簡単な方法で、私のサービスは互いに呼び出し、StudentServiceはClassService(クラスの平均スコアを取得するなど)を必要とし、ClassServiceはStudentService(クラスに生徒を割り当てるため)を必要とします。クラス(簡略化された)を以下に示します。

public class StudentService : IStudentService
{
    protected readonly IClassService ClassService;
    public StudentService(IClassService classService)
    {
        ClassService = classService;
    }
}

public class ClassService : IClassService
{
    protected readonly IStudentService StudentService;
    public ClassService(IStudentService studentService)
    {
        StudentService = studentService;
    }
}

サービスは.NET CoreのDIコンテナーに登録されています

services.AddTransient<IStudentService, StudentService>();
services.AddTransient<IClassService, ClassService>();

解決中

var studentService = app.ApplicationServices.GetService<IStudentService>();

例外が発生しましたタイプのサービスの循環依存関係が検出されました...

ここでは実装の問題を理解していますが、ここではアーキテクチャの問題を修正する方法がわかりません。

何か提案はありますか?

編集:OK、もっと現実的なケースがあります。従業員、サービス、会社。抽象汎用CRUDリポジトリを持つリポジトリレイヤーがあります。次に、派生クラス:EmployeesRepository ServicesRepositoryおよびCompaniesRepositoryがあります。 EmployeesRepository実装メソッド:GetTopEmployeesOfTheMonth ServicesRepository実装メソッド:GetTopServicesForEmployees CompaniesRepository実装メソッド:GetCompaniesWithTopIncome

上のレイヤー(ビジネスレイヤーと呼びましょう)にも同じ構造があります。抽象的な汎用CRUDヘルパーです。ユーザー権限をチェックし、CRUDリポジトリからメソッドを呼び出します。次に、EmployeesHelper、ServicesHerlper、およびCompaniesHelperを派生させました。それらのすべてがユーザー特権をチェックし、適切なリポジトリからのメソッドを呼び出します(EmployeesRepositoryからのEmployeesHelperなど)。さらに、このレイヤーには、より「複雑な」オブジェクト(多くのエンティティから構成されるオブジェクト)を作成するためのメソッドがあります。たとえば、CompanyHelperには、販売されたサービスが最も多い上位5社を表示するメソッドがあります。データは1つの画面に表示されるため、1つのAPIリクエストによって生成され、JSONとして返される必要があります。 CompaniesHelperメソッドのShowCompaniesWithServicesは、CompanyHelperメソッドとEmployeesHelperメソッドを呼び出します。 2番目の側面では、今月のトップの従業員、彼らのトップのサービス、会社が従事する複雑なオブジェクトを返すメソッドを実装するEmployeesHelperがあるため、Comapniesヘルパーが必要です。

この循環依存関係を解決するにはどうすればよいですか?それを解決するためのデザインパターンはありますか?

5
Piotr Trojan

したがって、サービスに他のサービスを挿入する必要があるとは思いません。

各サービスは独立して、責任のあるデータだけを提供できる必要があると思います。 IStudentServiceのコンシューマーは、両方のソースからのデータが必要な場合、IClassServiceのコンシューマーになることもできます。

1
Gary Stewart

私がこれを回避した方法が非常にきれいであるかどうかは完全にはわかりませんが、私にとってはうまくいきます。その循環依存関係の問題に遭遇したとき、サービスを依存性注入から削除し、サービスをパラメーターとして、それを必要とする関数に単に渡しました。

したがって、メソッドを呼び出すと、次のようになります。

// Inside the Student service
var result = _classService.GetClassStudents(classId, this)

誰にとってもうまくいくとは限らないかもしれませんが、私の場合、私はかなりシンプルなセットアップをしていたので、深く掘り下げることはしませんでした。

お役に立てれば。

0