Комментарии 37
Только это не стандарт, а реализация. И что делать, если она не покрывает мои потребности?
И весь дот нет фреймворк состоит из реализаций и ничего, никто не пилит своей реализации вывода на консоль или работы http, разве только по крайней нужде.
Угу, и будет реализация, имеющая объединение всех фич — иными словами, зоопарк.
Кто будет определять "действительно нужные фичи"?
Куча реализаций одного и того же — это не зоопарк, а свобода выбора.
А когда вы видите массу по своей сути одинаковых решений, которые в целом равнозначны, делают одно и то же, но… слегка по-разному, это уже зоопарк
Нет, это все еще свобода выбора.
И лично я бы предпочел, чтобы фича, которая продвигается как «мастхэв» процесса разработки на платформе
Проблема в том, что когда DI-контейнер становится musthave для платформы — это не очень хорошо.
Стандартный контейнер определяет необходимый для .NET Core минимум способов регистрации зависимости: transient, singleton, scoped. Их реализует любой контейнер. Нужно ли было усложнить интерфейс добавления зависимостей и сделать его более богатым и совместимым со всеми фичами Simple Injector, Ninject, Castle Winsdor, Autofac и т.д?
Я считаю, что нет, это не принесло бы значительной пользы, но сильно усложнило бы написание адаптеров для сторонних библиотек. Это хорошая практика дизайна системы — делать точки расширения с простым и очевидным интерфейсом, без сложных внутренних инвариантов. Такие интерфейсы легко понять и реализовать.
Понять, запомнить и реализовать все инварианты регистрации любого из современных контейнеров очень и очень сложно, что привело бы к кучке реализаций, совместимых между собой на 90%, и порождающих такие баги, что обычные ошибки регистрации будут потом казаться ясными, как предупреждения компилятора.
В кои-то веки Майкрософт предпочла простоту универсальности.
Вопрос в том, нужно ли было вообще создавать интерфейс регистрации зависимостей.
Одна из удачных реализаций: помечать мета-данными конструкторы / сеттеры / поля, А конфигурация всех зависимостей остается на плечах имплементации.
В результате все контейнеры смогут выполнять свою функци и не будут ограничены в том, как организовывать свою конфигурацию, а значит и возможностей для развития у них будет больше.
Одна из удачных реализаций: помечать мета-данными конструкторы / сеттеры / поля, А конфигурация всех зависимостей остается на плечах имплементации.
Сейчас так и есть, конфигурация специфичная для каждого контейнера как была так и осталась, со всем фичами характерными для каждого контейнера.
http://docs.autofac.org/en/latest/integration/aspnetcore.html
Проблема, которая возникла у вендоров состоит совсем в другом — необходимость обеспечения совместимости для интерфейсов, которые МС использует для регистрации внутренних компонентов ASP.NET Core.
Я не думаю, что метаданные обеспечат необходимый уровень гибкости, в частности, подмену произвольного сервиса или использование scoped врапперов и т.п.
Я предпочел бы мыслить об этом не в терминах "как подключить сторонний контейнер" (потому что я могу вообще не хотеть пользоваться контейнерами), а "откуда asp.net берет сервисы", и в этом случае паттерны в WebAPI были, мне кажется, весьма неплохими.
http://www.asp.net/web-api/overview/advanced/configuring-aspnet-web-api#services
Все что спасало сторонних вендоров от текущих проблем, что не было одного DI зашаренного между компонентами фреймворка и зависимостями определяемыми разработчиками.
Был Resolver который где-то мог использоваться фреймворком где-то нет при содании клиентских типов. И набор сервис локатор для фреймворка.
В свою очередь это порождало другую боль для разработчиков:
1. Необходимость для вендоров, а иногда и самих разработчиков переопределять стандартные фабрики и провайдеры своими и прогонять обьект через сторонний контейнер.
2. Непонятный жизненный цикл компонентов — когда надо помнить, что вот у меня эти фильтры живут как синглтоны, а эти transient, а эти Handlers опять singltones.
Мне не совсем понятен отсыл к предыдущим реализациям 'DI' в Mvc и Web Api даже на фоне текущих проблем он выглядит мягко говоря странным.
А как без него? Раньше тоже был такой интерфейс —
http://www.asp.net/web-api/overview/advanced/configuring-aspnet-web-api#services
Это не "такой же" интерфейс. Это специфичный сервис-контейнер для WebAPI, а не обобщенный DI-контейнер для любого случая. Что более важно, он делегирует свои запросы на resolve в контейнер (если такой есть), но не делегирует туда register.
Непонятный жизненный цикл компонентов — когда надо помнить, что вот у меня эти фильтры живут как синглтоны, а эти transient, а эти Handlers опять singltones.
Эта проблема не решается унифицированным DI, она решается унифицированным Resolve.
Что более важно, он делегирует свои запросы на resolve в контейнер (если такой есть), но не делегирует туда register.
В таком случае, что вам мешает делать как прежде? Использовать контейнер от стороннего вендора вне Asp.Net Core фрейморка и написать UnityGlobalFilterProvider, AutofacFilterProvider, MyControllerFactory и подключить их в IServiceCollection не мешая два контейнера?
Хотите использовать два контейнера — используйте.
Новый дотнет модульный, тот же асп нет конфигурируется путем регистрации и использования зависимостей. Какая этому альтернатива?
Можно использовать специфичный интерфейс регистрации, а не обобщенный контейнер.
Конечно, нет. Никто не отменял дефолтные регистрации.
Кстати, вопрос: "These are consumed only when creating action descriptors, then they can be de-allocated". Описанное поведение — оно определено фреймворком?
Этот комментарий объясняет почему они зарегистрированы как transient, он относится к особенностям работы MVC, а не DI
Тогда я не очень понимаю, какой интерфейс регистрации должен использовать MVC?
А ему точно нужен интерфейс регистрации? Разве нельзя просто резолвить дефолтные сервисы без всякой регистрации?
Проблема в том, что регистрация — это не часть DI как паттерна, это часть конкретной контейнерной реализации DI-шаблона. Но кто-то ведь может делать DI иначе, вплоть до того, что просто иметь написанный руками composition root с конструкторами.
Этот комментарий объясняет почему они зарегистрированы как transient, он относится к особенностям работы MVC, а не DI
Да, я понимаю. И именно это и расстраивает: в итоге мы все равно должны знать, как именно работает потребляющий фреймворк (и мы не можем повлиять на то, как он работает), когда определяем жизненный цикл. Так зачем нам вообще здесь определение жизненного цикла компонента, на что оно повлияет?
Вы всегда должны знать как работает потребляющий фреймфорк, в данной модели вы можете повлиять на много больше вещей чем до этого, просто переопределяя нужные сервисы.
Если MVC будет использовать сервисы по умолчанию вы теряете возможность менять их поведение.
Конечно же, нет. По умолчанию — это когда есть способ переопределения. Как, собственно, и в MVC, и в WebAPI было сделано.
Вы всегда должны знать как работает потребляющий фреймфорк, в данной модели вы можете повлиять на много больше вещей чем до этого, просто переопределяя нужные сервисы.
Вы хотите сказать, что раньше нельзя было переопределить нужные сервисы? Или просто что теперь для переопределения доступно больше сервисов?
Что не так с DI абстракцией ASP.NET Core?