Исключение ядра .NET: обнаружена циклическая зависимость для службы типа - PullRequest
0 голосов
/ 05 декабря 2018

Недавно я задал вопрос об архитектуре программного обеспечения

Должна ли служба вызывать другую службу или хранилище напрямую?

После этого ответа я реорганизовала и реорганизовала свое приложение.Проще говоря, мои службы вызывают друг друга, 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;
    }
}

Службы регистрируются в контейнере DI в .NET Core

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

Во время разрешения

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

Я получаюИсключение Была обнаружена циклическая зависимость для службы типа ...

Я понимаю проблему реализации здесь, но я не знаю, как решить проблему архитектуры здесь.

Не могли бы выпредоставить какое-нибудь предложение?

Редактировать: Хорошо, у меня есть более реалистичный пример, например, сотрудники, услуги и компании.У нас есть слой репозитория с абстрактным универсальным репозиторием CRUD.Затем мы получили производные классы: EmployeesRepository ServicesRepository и CompaniesRepository.EmployeesRepository реализует методы: GetTopEmployeesOfTheMonth ServicesRepository реализует методы: GetTopServicesForEmployees CompaniesRepository реализует методы: GetCompaniesWithTopIncome

На вышеприведенном уровне (давайте назовем его Business Layer) у нас есть такая же структура: абстрактные универсальные вызовы пользователя и абстрактные привилегии CRUD,методы из хранилища CRUD.Затем мы получили сотрудники EmployeesHelper, ServicesHerlper и CompaniesHelper.Все они проверяют пользовательские привилегии и вызывают методы из надлежащего репозитория (EmployeesHelper из EmployeesRepository и т. Д.).Более того, на этом уровне у нас есть методы для создания более «сложных» объектов - объектов, состоящих из множества объектов.Например, CompaniesHelper имеет метод, чтобы показать топ-5 компаний с наиболее продаваемыми услугами.Данные будут показаны на одном экране, поэтому они должны быть сгенерированы одним запросом API и возвращены в виде JSON.Метод ShowCompaniesWithServices from CompaniesHelper вызывает методы CompaniesHelper и методы EmployeesHelper.С другой стороны, у нас есть EmployeesHelper, который реализует метод для возврата сложного объекта с лучшими сотрудниками месяца, их лучшими службами и компаниями, с которыми они работают, поэтому ему нужен Comapnies Helper.

Как решить эту круговую зависимость?Есть ли шаблон проектирования для его решения?

Ответы [ 3 ]

0 голосов
/ 15 августа 2019

Я не совсем уверен, что способ, которым я обошел это, очень чистый, но он прекрасно работает для меня.Когда я столкнулся с этой проблемой циклической зависимости, я удалил службу из внедрения зависимостей и просто передал службу в качестве параметра функции, которая нуждалась в ней.

Поэтому, когда вы вызываете метод, он выглядит следующим образом:

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

Может работать не для всех, но в моем случае у меня была довольно простая установка, поэтому я не копал глубже.

Надеюсь, это поможет.

0 голосов
/ 15 августа 2019

Итак, я не верю, что сервисам следует вводить другие сервисы.

Я думаю, что каждая служба должна быть в состоянии стоять самостоятельно и предоставлять только те данные, за которые она несет ответственность.Потребитель IStudentService также может быть потребителем IClassService, если ему нужны данные из обоих источников.

0 голосов
/ 05 декабря 2018

У вас есть два способа:

  1. Написать код, чтобы не вызывать ClassService из StudentService (или StudentService из ClassService)

  2. Создать третий класс:

    public class StudentService: IStudentService
    {
        private readonly IClassSharedSerive _classSharedService;
        ...
    }
    
    public class ClassService: IClassService
    {
        private readonly IClassSharedSerive _classSharedService;
        private readonly IStudentService _studentService;
        ...
    }
    
    public class ClassSharedService: IClassSharesService
    {
        ... without references to IClassService and IStudentService
    }
    

Но в большинстве случаев необходимо правильно написать StudentService и ClassService (путь 1)

...