Устранение ошибки циклической зависимости с помощью DI в ядре .NET

Я столкнулся с проблемой, связанной с ошибкой ссылки на циклическую зависимость в основном веб-приложении .NET. Хотя я думаю, что понимаю проблему, я не могу придумать способ ее решения, я искал вокруг и, похоже, не нашел никого с такой же проблемой.

Вот логическая схема, которую я пытаюсь достичь: 1. Общий репозиторий, обрабатывающий операции db CRUD. 2. В этом репозитории есть служба, которая выполняет определенную задачу в зависимости от типа выполняемого действия с базой данных.

Пример 1 В пользовательскую таблицу вставляется новая запись, есть задача, которая отправляет пользователю приветственное письмо.

Пример 2 Лид вставлен в базу данных, есть задача, которая создает последующую задачу для системного администратора.

Причина, по которой все это обрабатывается таким универсальным способом, заключается в том, что я хочу предоставить администраторам приложений интерфейс для создания / обновления этих триггерных задач, поэтому в примере 1 я не просто жестко кодирую электронное письмо пользователю.

Я использую DI для решения различных услуг, и у меня возникла следующая проблема:

EntityFrameworkRepository реализует IRepository  введите описание изображения здесь

Конструктор TriggerService  введите описание изображения здесь

ITriggerService вводится в EntityFrameworkRepository, ошибка запускается, потому что я затем пытаюсь внедрить и разрешить IRepository в триггерной службе, даже без этой инъекции templateService также пытается разрешить IRepository в своем собственном конструкторе. На данный момент у меня только закодированы ITempalteService и IEmailerService, но будет много других «служб триггерных действий», которые также будут использоваться во всем коде и других службах, поэтому я действительно не хочу менять их дизайн.

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

Все предложения приветствуются!


person James    schedule 25.01.2018    source источник
comment
Зачем вам нужно свойство IRepository в TriggerService?   -  person Krishna Mohan    schedule 25.01.2018
comment
Он считывает действия триггера из базы данных, служба шаблонов также считывает шаблоны из базы данных для использования в службе электронной почты.   -  person James    schedule 25.01.2018
comment
Я думаю, что лучше вызывать triggerService из Controller / BusinessLayer (в соответствии со структурой вашего решения). Чтобы использовать EntityFrameworkRepository в TriggerService, вы можете DI в Startup.cs   -  person Krishna Mohan    schedule 25.01.2018
comment
Независимо от круговой зависимости, которую вы могли бы решить, например, с помощью событий (как объяснено в связанном вопросе): кажется неправильным, что репозиторий базы данных отвечает за запуск приветственных писем или других вещей. Единственной заботой репозитория должен быть доступ к базе данных. Если есть действие «создать пользователя и вызвать приветственное письмо», то оно должно быть выделено в отдельную службу, представляя другой уровень. Таким образом, вы должны использовать эту «службу пользователя», которая затем создала объект с использованием вашего репозитория, а затем инициировала приветственное письмо с помощью службы триггера.   -  person poke    schedule 25.01.2018


Ответы (1)


Вообще говоря, репозиторий должен выполнять только простые операции CRUD, без какой-либо бизнес-логики. Конечно, отправка письма и создание последующей задачи после вставки записи являются бизнес-логикой.

Представьте, что вам нужно разрешить вставку записи без отправки приветственного письма, потому что вводится новый вариант использования, и такой вариант использования не связан с первоначальным намерением. Простым примером может быть пользователь, которому не нужно получать уведомление. Другими словами, если вы закрепите какую-то бизнес-логику с операцией репозитория, вы не сможете отсоединить ее при необходимости.

Правильный способ подумать о своей проблеме - перефразировать ее, преобразовав смешанную бизнес-логику репо + в чистую бизнес-логику:

  1. В таблицу пользователя добавляется новая запись, есть задача, которая отправляет пользователю приветственное письмо. => Зарегистрирован новый пользователь, есть задача, которая отправляет пользователю приветственное письмо.
  2. Интерес вставлен в базу данных, есть задача, которая создает последующую задачу для системного администратора. => Лид создан, есть задача, которая создает последующую задачу для системного администратора.

Говоря о коде, я предлагаю добавить промежуточную службу, которая вызывает репозиторий для выполнения простого CRUD и вызывает службы, обеспечивающие желаемые побочные эффекты.

Рассматривая ваш 1-й пример (второй аналогичный), вместо прямого вызова IRepository для вставки пользовательской записи, введите в вызывающую программу новый IUserService, который, в свою очередь, получает IRepository и IEmailerService в своем конструкторе и вызывает их. Это позволяет без проблем вводить IRepository в IEmailerService.

Единственное, чего я не могу вам сказать, это то, можно ли применить мое предложение в соответствии с вашими потребностями в предоставлении общего интерфейса. В любом случае рефакторинг, необходимый для применения такого изменения, должен привести к минимуму, и, конечно же, проблема циклической зависимости (вызванная цикличностью в исходной формулировке) решена.

person FstTesla    schedule 25.01.2018