Комментарии 11
А в чем преимущество такого собственного контейнера, перед тем чтобы взять один из многих доступных вариантов, например Unity, Ninject и т.д? Вроде все предоставляют широкий набор где конфигурировать зависимости, в коде, в библиотеке, в xml, комбинацию вариантов и т.д.?
Собственная обертка нужна не просто для того, чтобы распихать регистрацию зависимостей по блокам, но и для предоставления полного функционала конфигурирования модулей: и регистрацию зависимостей, и и использование этих зависимостей после регистрации в рамках модуля. Ну и в меньшей степени это нужно для поддержки модулей для любого IoC-контейнера(хоть и во многих популярных контейнерах эта функциональность есть)
А какой именно функциональности не хватает в широко используемых IoC контейнерах?
Насколько я знаю практика удаления зависимостей (RemoveDependency) после конфигурации считается плохой нарушающей целый ряд принципов, основной из которых в том что контейнер создается только один раз в application root точке одной строчкой кода. Если нужно несколько комбинаций зависимостей тогда используется например контекстуальные зависимости.
Или я что-то неправильно понял из целей?
Насколько я знаю практика удаления зависимостей (RemoveDependency) после конфигурации считается плохой нарушающей целый ряд принципов, основной из которых в том что контейнер создается только один раз в application root точке одной строчкой кода. Если нужно несколько комбинаций зависимостей тогда используется например контекстуальные зависимости.
Или я что-то неправильно понял из целей?
Во-первых, удаление(RemoveDependency) не пересоздает контейнер и никаким образом не удаляет зависимости из него. Просто на этапе сборки(Build) некий модуль не будет зарегистрирован(и его зависимости).
По поводу функциональности IoC-контейнеров. Приведу пример:
Нам нужно сконфигурировать в asp.net приложении часть asp.net mvc-фреймворка: роутинги, конвертеры, биндеры, фильтры, в том числе фильтры авторизации. Фильтр авторизации нам надо зарегистрировать в IoC-контейнере. А после регистрации всех зависимостей нам надо на этапе настройки mvc добавить сей фильтр в коллекцию фильтров. Подход с созданием settings-модуля позволяет объединить в рамках одного класса как регистрацию фильтра так и его получение с последующим добавлением в коллекцию фильтров(причем в рамках данного класса мы не знаем, когда все зависимости будут зарегистрированы и проверены). Стандартные же функции IoC-контейнера способны оперировать только уровнем регистрации, но не пост-обработки.
По поводу функциональности IoC-контейнеров. Приведу пример:
Нам нужно сконфигурировать в asp.net приложении часть asp.net mvc-фреймворка: роутинги, конвертеры, биндеры, фильтры, в том числе фильтры авторизации. Фильтр авторизации нам надо зарегистрировать в IoC-контейнере. А после регистрации всех зависимостей нам надо на этапе настройки mvc добавить сей фильтр в коллекцию фильтров. Подход с созданием settings-модуля позволяет объединить в рамках одного класса как регистрацию фильтра так и его получение с последующим добавлением в коллекцию фильтров(причем в рамках данного класса мы не знаем, когда все зависимости будут зарегистрированы и проверены). Стандартные же функции IoC-контейнера способны оперировать только уровнем регистрации, но не пост-обработки.
Фильтры поддерживаются, в том числе какие угодно сложные типа Select(Func<Type, bool> filter) пример из Ninject документации. Реализуется это не ядром а расширением, Ninject.Extensions.Conventions но функционал этот есть. В других контейнерах есть аналоги. Это не тоже самое?
Так. Насколько я понимаю, вы думаете, что я написал свой IoC-контейнер. Это не так. С помощью моего подхода можно использовать любой существующий контейнер(тот же Unity или Autofac). А мой пример поясню кодом(под фильтрами я подразумевал фильтры asp.net mvc: FilterAttribute):
Код максимально упрощен, но он показывает назначение подхода: в одном классе мы и регистрируем фильтр, и получаем его для сохранение в коллекции фильтров.
public class MvcSettings: ISettings<Container>
{
public void Init(IDependencyResolver resolver)
{
GlobalFilters.Filters.Add(resolver.GetService<CustomAuthorizeFilter>())
}
public virtual void Register(Container container)
{
container.Register(() => new CustomAuthorizeFilter("params"))
}
}
Код максимально упрощен, но он показывает назначение подхода: в одном классе мы и регистрируем фильтр, и получаем его для сохранение в коллекции фильтров.
Да, мне казалось что это свой контейнер, видимо плохо разобрался.
Но понятно пока не до конца. Т.е. проблема в том, что на момент инициализации веб приложения не известно какие типы надо будет использовать и их надо динамически подгружать откуда-то (как плагины)? Кажется маловероятным для веб приложения.
Просто если набор зависимостей конечен и известен их можно зарегистрировать и уже какая-нибудь фабрика будет нужные типы подбирать? Или фактически это и есть такая фабрика?
Я просто не очень понимаю зачем надо динамически регистрировать зависимости если набор зависимостей известен на момент компиляции (а в случае mvc инициализации) приложения. Я всегда видел рекомендации не делать регистрацию нигде кроме как в одной корневой точке.
Но понятно пока не до конца. Т.е. проблема в том, что на момент инициализации веб приложения не известно какие типы надо будет использовать и их надо динамически подгружать откуда-то (как плагины)? Кажется маловероятным для веб приложения.
Просто если набор зависимостей конечен и известен их можно зарегистрировать и уже какая-нибудь фабрика будет нужные типы подбирать? Или фактически это и есть такая фабрика?
Я просто не очень понимаю зачем надо динамически регистрировать зависимости если набор зависимостей известен на момент компиляции (а в случае mvc инициализации) приложения. Я всегда видел рекомендации не делать регистрацию нигде кроме как в одной корневой точке.
Основная проблема возникает, когда с одной стороны зависимостей реально много(хоть и конечное количество), а с другой стороны кроме регистрации зависимостей есть ещё дополнительный код инициализации(как в моем примере). Попытка делать всё в единой точке(с чего мы и начинали) с ростом проекта приводит к тому, что контролировать код в этой единой точке становится сильно неудобно + надо как-то контролировать этот пост-регистрационный код. Цель — легкое управление модулями(все их регистрации, настройки, записи в глобальные коллекция типа коллекции фильтров), чтобы можно было очень просто найти модуль, изменить его настройки или вовсе удалить, не разбираясь в куче не относящегося к нему кода. Именно для этого всё и сделано.
Теперь вроде понятно. Всегда интересно было узнать другие подходы.
Хотя мне все — равно кажется что было бы удобнее разбивать и структурировать модули в регистрации до тех пор пока код не станет удобным для поддержки.
Хотя мне все — равно кажется что было бы удобнее разбивать и структурировать модули в регистрации до тех пор пока код не станет удобным для поддержки.
[del]
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
DI в сложных приложениях. Как не утонуть в зависимостях