Взятие моего MVC на следующий уровень: DI и блок работы

Я рассмотрел более простые приложения, такие как Nerddinner и ContactManager, а также более сложные, такие как Kigg. Я понимаю более простые, и теперь я хотел бы понять более сложные.

Обычно более простые приложения имеют классы и интерфейсы репозитория (так же слабо связаны, как они могут быть) поверх LINQtoSQL или Entity Framework. Репозитории вызываются из контроллеров для выполнения необходимых операций с данными.

Один общий шаблон, который я вижу, когда я рассматриваю более сложные приложения, такие как Kigg или Oxite, - это введение (я только царапаю поверхность здесь, но мне нужно что-то начинать):

  • IOC DI (в случае Kigg Unity)
  • Менеджер веб-запросов Lifetime
  • Единица работы

Вот мои вопросы:

Я понимаю, что для того, чтобы действительно иметь слабосвязанное приложение, вы должны использовать что-то вроде Unity. Но также кажется, что, как только вы внедряете Unity в микс, вам также нужно представить Web Lifetime Manager. Почему это? Почему в примерах приложений, таких как Nerddinner, нет диспетчера жизненных циклов веб-запросов? Что именно он делает? Это единственная особенность?

Вторая картина, которую я замечаю, - это введение Единицы работы. Опять же, тот же вопрос: почему Nerddinner или ContactManager не используют Единицу работы? Вместо этого эти приложения используют классы репозитория поверх Linq2Sql или Entity Framework для обработки данных. Никаких признаков какой-либо Единицы работы. Что именно это и зачем его использовать?

Спасибо

Ниже приведен пример DI в Nerddiner на уровне DinnersController:

    public DinnersController()
        : this(new DinnerRepository()) {
    }

    public DinnersController(IDinnerRepository repository) {
        dinnerRepository = repository;
    }

Итак, правильно ли предположить, что из-за первого конструктора контроллер "владеет" DinnerRepository, и поэтому он будет зависеть от времени жизни контроллера, поскольку он объявлен там?

Ответ 1

При использовании Linq-to-SQL напрямую, ваш контроллер владеет ссылкой на контекст данных. Это обычно частная ссылка внутри контроллера, и поэтому создается как часть ее построения. Нет необходимости в управлении жизненным циклом, поскольку он находится в одном месте.

Однако, когда вы используете контейнер IoC, ваш репозиторий данных создается вне вашего контроллера. Поскольку контейнер IoC, который создает его для вас, не знает, как и как долго вы собираетесь использовать созданный объект, вводится стратегия жизни.

Например, контекст данных (репозиторий) обычно создается в начале веб-запроса и уничтожается в конце. Однако для компонентов, которые работают с внешней веб-службой или какого-либо статического картографа (например, logger), нет необходимости создавать их каждый раз. Таким образом, вы можете сказать, чтобы создать их один раз (например, один стиль жизни).

Все это происходит потому, что контейнер IoC (например, Unity) предназначен для обработки многих ситуаций, и они не знают ваших конкретных потребностей. Например, некоторые приложения используют транзакции "беседы", в которых NHibernate (или Entity Framework) может продолжаться в течение нескольких страниц/веб-запросов. Контейнеры IoC позволяют настраивать срок службы объектов в соответствии с вашими потребностями. Но поскольку это говорит о цене, поскольку нет единой предопределенной стратегии, вы должны выбрать ее самостоятельно.

Почему NerdDinner и другие приложения не используют более сложные методы, просто потому, что они предназначены для демонстрации возможностей MVC, а не для продвинутых использования некоторых других библиотек. Я помню статью, написанную для демонстрации одной расширенной функциональности контейнера IoC. В этой статье были нарушены некоторые утвержденные шаблоны проектирования, такие как разделение проблем, но это было не так важно, потому что шаблоны проектирования не были целью статьи. То же самое с простыми демонстрационными приложениями MVC - они не хотят, чтобы вы, новичок MVC, терялись в лабиринтах IoC.

И я бы не рекомендовал рассматривать Oxite как пример ссылки на дизайн: http://codebetter.com/blogs/karlseguin/archive/2008/12/15/oxite-oh-dear-lord-why.aspx http://ayende.com/Blog/archive/2008/12/19/oxite-open-exchangable-informative-troubled-engine.aspx

Ответ 2

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

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

Наконец, я полагаю, вы имеете в виду Единицу работы. Единица работы - это, по сути, группа действий, которые вы хотите преуспеть или потерпите неудачу в качестве одной транзакции с атомными операциями. Для более формального описания взгляните на определение Мартина Фаулера . Это концепция, которая приобрела большую популярность в контексте Domain Driven Design. Единица работы отслеживает изменения, которые вы применяете в такой транзакции, и когда время подходит, оно совершает эти изменения в одной транзакции ACID. В NHibernate, например, сеанс поддерживает понятие единицы работы и, более конкретно, отслеживание изменений, тогда как в Linq2SQL это контекст...