Есть эта структура, которую я помогаю разработать. Есть некоторые общие задачи, которые должны быть выполнены с использованием некоторых общих компонентов: журналирование, кеширование и повышение событий в частности.
Я не уверен, что лучше использовать внедрение зависимостей и вводить все эти компоненты для каждой службы (например, в качестве свойств), или мне нужно разместить какие-то метаданные над каждым методом моих служб и использовать перехват для выполнения этих общих задач ?
Вот пример обоих:
Раствор для инъекций:
public class MyService
{
public ILoggingService Logger { get; set; }
public IEventBroker EventBroker { get; set; }
public ICacheService Cache { get; set; }
public void DoSomething()
{
Logger.Log(myMessage);
EventBroker.Publish<EventType>();
Cache.Add(myObject);
}
}
и вот другая версия:
Перехват:
public class MyService
{
[Log("My message")]
[PublishEvent(typeof(EventType))]
public void DoSomething()
{
}
}
Вот мои вопросы:
- Какое решение лучше для сложных рамок?
- Если перехват выигрывает, каковы мои варианты взаимодействия с внутренними значениями метода (например, для использования со службой кэширования?)? Могу ли я использовать другие способы, а не атрибуты для реализации этого поведения?
- Или, может быть, могут быть другие решения для решения проблемы?
c#
dependency-injection
Beatles1692
источник
источник
Ответы:
Межсекторальные проблемы, такие как ведение журнала, кэширование и т. Д., Не являются зависимостями, поэтому их не следует вводить в службы. Однако, в то время как большинство людей тогда, кажется, достигают полного чередования AOP-фреймворков, для этого есть хороший шаблон проектирования: Decorator .
В приведенном выше примере позвольте MyService реализовать интерфейс IMyService:
Благодаря этому класс MyService полностью освобождается от сквозных проблем, что соответствует принципу единой ответственности (SRP).
Чтобы применить ведение журнала, вы можете добавить декоратор ведения журнала:
Вы можете реализовать кэширование, измерение, обработку событий и т. Д. Таким же образом. Каждый Декоратор делает только одно, поэтому они также следуют SRP, и вы можете составлять их произвольно сложными способами. Например
источник
Для небольшого числа сервисов я думаю, что ответ Марка хороший: вам не придется изучать или вводить какие-либо новые сторонние зависимости, и вы все равно будете следовать хорошим принципам SOLID.
Для большого количества сервисов я бы порекомендовал инструмент AOP, такой как PostSharp или Castle DynamicProxy. PostSharp имеет бесплатную (как в пиве) версию, и они только недавно выпустили PostSharp Toolkit for Diagnostics (бесплатно, как в пиве и речи), которая предоставит вам некоторые функции регистрации из коробки.
источник
Я считаю, что дизайн фреймворка в значительной степени ортогональн к этому вопросу - сначала вам следует сосредоточиться на интерфейсе вашей фреймворка, и, возможно, в качестве фонового ментального процесса подумайте, как кто-то на самом деле может его использовать. Вы не хотите делать что-то, что мешает использовать его хитроумными способами, но это должно быть только вкладом в дизайн вашей структуры; один из многих.
источник
Я сталкивался с этой проблемой много раз и думаю, что нашел простое решение.
Сначала я использовал шаблон декоратора и вручную реализовывал каждый метод, когда у вас есть сотни методов, это становится очень утомительным.
Затем я решил использовать PostSharp, но мне не понравилась идея включить целую библиотеку просто для того, чтобы сделать что-то, что я мог бы выполнить с помощью (большого количества) простого кода.
Затем я пошел по прозрачному прокси-маршруту, который был забавным, но включал динамическое излучение IL во время выполнения, и я не хотел бы заниматься этим в производственной среде.
Недавно я решил использовать шаблоны T4 для автоматической реализации шаблона декоратора во время разработки, оказалось, что с шаблонами T4 на самом деле довольно сложно работать, и мне нужно было сделать это быстро, поэтому я создал код ниже. Он быстрый и грязный (и не поддерживает свойства), но, надеюсь, кто-то найдет его полезным.
Вот код:
Вот пример:
Затем создайте класс с именем LoggingTestAdapter, который реализует ITestAdapter, получите Visual Studio для автоматической реализации всех методов и затем выполните его с помощью приведенного выше кода. Вы должны иметь что-то вроде этого:
Вот и все с кодом поддержки:
источник