Терминология из вопроса на самом деле не совпадает с примером кода. Это Ambient Context
шаблон, используемый для получения зависимости от любого класса в любом модуле настолько легко, насколько это возможно, не загрязняя каждый класс, чтобы принять интерфейс зависимости, но сохраняя идею инверсии управления. Такие зависимости обычно предназначены для ведения журналов, безопасности, управления сеансами, транзакций, кэширования, аудита, а также для любых сквозных задач в этом приложении. Это как - то раздражает добавить ILogging
, ISecurity
, ITimeProvider
конструкторам и большую часть времени не все классы нужно в одно и тоже время, поэтому я понимаю вашу потребность.
Что если время жизни ISession
экземпляра отличается от времени жизни ILogger
? Возможно, экземпляр ISession должен быть создан при каждом запросе, а ILogger - один раз. Поэтому все эти зависимости, управляемые одним объектом, который не является самим контейнером, не выглядят правильным выбором из-за всех этих проблем с управлением временем жизни и локализацией, а также с другими, описанными в этом потоке.
Этот IAmbientContext
вопрос не решает проблему не загрязнения каждого конструктора. Вы все еще должны использовать его в сигнатуре конструктора, конечно, только на этот раз.
Таким образом, самый простой способ - НЕ использовать инжекцию конструктора или любой другой механизм внедрения для решения сквозных зависимостей, а использовать статический вызов . На самом деле мы видим этот шаблон довольно часто, реализуемый самой платформой. Проверьте Thread.CurrentPrincipal, который является статическим свойством, которое возвращает реализацию IPrincipal
интерфейса. Это также настраивается, так что вы можете изменить реализацию, если хотите, таким образом, вы не связаны с ней.
MyCore
выглядит сейчас что-то вроде
public class MyCoreClass
{
public void BusinessFeature(string data)
{
LoggerContext.Current.Log(data);
_repository.SaveProcessedData();
SessionContext.Current.SetData(data);
...etc
}
}
Этот шаблон и возможные реализации были подробно описаны Марком Зееманом в этой статье . Могут быть реализации, основанные на самом контейнере IoC, который вы используете.
Вы хотите , чтобы избежать AmbientContext.Current.Logger
, AmbientContext.Current.Session
по тем же причинам , как описано выше.
Но у вас есть другие варианты решения этой проблемы: используйте декораторы, динамический перехват, если ваш контейнер имеет такую возможность, или AOP. Окружающий контекст должен быть последним средством, потому что его клиенты скрывают свои зависимости через него. Я бы по-прежнему использовал Ambient Context, если интерфейс действительно имитирует мой импульс использовать статическую зависимость, например DateTime.Now
или, ConfigurationManager.AppSettings
и эта потребность возникает довольно часто. Но, в конце концов, внедрение в конструктор может быть не такой уж плохой идеей для получения этих вездесущих зависимостей.
IService
используется для общения с другими службами»? ЕслиIService
представляет неопределенную зависимость от других сервисов, то это звучит как поиск сервисов и не должно существовать. Ваш класс должен зависеть от интерфейсов, которые явно описывают, что их потребитель будет делать с ними. Ни одному классу не нужна услуга для предоставления доступа к услуге. Классу нужна зависимость, которая делает что-то конкретное, что нужно классу.