Ninject: контекст сущности для контроллера - PullRequest
5 голосов
/ 12 февраля 2012

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

Я всегда создавал свой контекст сущности, как я видел в учебниках по MS, например:

public class UserController : Controller
{
    private DbEntities db = new DbEntities();

}

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

Это должно выглядеть так, когда я закончу, верно?

public class UserController : Controller
{
    private DbEntities db;

    public UserController(DbEntities context)
    {
        db = context;
    }
}

Документация начинается с «На предыдущем шаге мы уже подготовили все, что необходимо для введения контроллера».что чертовски запутанно, так как предыдущий шаг был установкой.Я использовал метод Nuget для установки, но я не знаю, что это значит, когда он говорит: «Теперь загрузите ваши модули или определите привязки в методе RegisterServices».Как мне это сделать, и является ли сущность модулем или привязкой?Документация кажется такой скудной.

Извините, если я пропустил что-то критическое в документах, я часами прыгал между форумами, пытаясь выяснить этот один шаг.

Ответы [ 3 ]

4 голосов
/ 12 февраля 2012

Я использовал метод Nuget для установки, но я не знаю, что это значит, когда он говорит: «Теперь загрузите ваши модули или определите привязки в методе RegisterServices».Как мне это сделать, и является ли entity модулем или привязкой?

Установка Nuget на самом деле уже многое для вас делает.Самое главное, что он устанавливает Ninject в качестве фабрики контроллеров, что означает, что Ninject создаст ваши контроллеры и сможет передавать все зарегистрированные вами зависимости.

Если вы проверите папку App_Start, вы будетенайти файл NinjectMVC3.cs.Уже есть пустой метод RegisterServices(), который вы можете использовать для регистрации ваших зависимостей.

Для вашего примера вы должны быть в состоянии разрешить DbEntities.Самый простой и простой способ сделать это:

kernel.Bind<DbEntities>().ToSelf();

При этом вы действительно должны передать интерфейс к контроллеру, чтобы контроллер не зависел от Entity Framework, используя абстракции и регистрируя конкретный класс для использования.в контейнере IoC это одна из основных причин внедрения зависимостей.

Это должно дать вам начало - документация, на которую вы ссылаетесь, кажется немного устаревшей.Я бы порекомендовал посмотреть на образец Ninject MVC3 на github.

1 голос
/ 12 февраля 2012

Внедрение зависимостей на первый взгляд может показаться запутанным, но на самом деле все довольно просто.

«Контейнер» внедрения зависимостей - это в основном универсальная фабрика с различными функциями управления временем жизни объектов. В частности, Ninject использует синтаксис kernel.Bind() для настройки этой фабрики. Когда вы говорите kernel.Bind<DbEntities>().ToSelf(), это означает, что Ninject будет создавать экземпляр связанного типа (в данном случае DbEntities) всякий раз, когда запрашивается этот тип. Этот запрос обычно выглядит так:

var entities = kernel.Get<DbEntities>();  // Note: don't do this, just an example

По сути, это и есть инъекция зависимости. Универсальная фабрика, которая может создавать экземпляры произвольных типов.

Однако в этом есть нечто гораздо большее. Одна приятная особенность внедрения зависимостей заключается в том, что он также будет создавать экземпляры любых зависимых типов в процессе. Итак, предположим, у вас есть контроллер, и этот контроллер зависит от DbEntities. Хорошо, когда контроллер создается в DI Framework, он также создает экземпляры зависимых DbEntities. Смотрите код ниже. Когда создается экземпляр MyController, создаются экземпляры DbEntities автоматически (при условии, что вы связали класс DbEntities с self в конфигурации DI)

var controller = kernel.Get<MyController>();

public class MyController : Controller {
    private DbEntities _entities;
    public MyController(DbEntities entities) {
        _entities = entities;
    }
}

Это рекурсивно. Любой класс, для которого создается экземпляр, который имеет любые объекты, от которых он сам может зависеть, также получает экземпляр, и так далее, и так далее, пока, наконец, у всего не будет того, что ему нужно для своей работы.

Теперь, что самое замечательное в MVC, это то, что он имеет встроенный способ автоматического использования любого DI-контейнера. Вам не нужно вызывать kernel.Get, потому что инфраструктура делает это за вас, когда создает контроллеры при поступлении запроса. Эта функция называется IDependencyResolver и представляет собой интерфейс, который использует инфраструктура MVC, чтобы разрешить сторонний DI контейнеры для использования каркасом.

Если вы устанавливаете Ninject с помощью пакета Nuget Ninject.MVC3, он автоматически настроит все это для вас, и вам нужно только добавить свои привязки в раздел RegisterServices () в NinjectMVC3.cs

Это намного больше, чем это, но это должно дать вам базовое понимание. Внедрение зависимостей позволяет вам забыть о деталях управления созданием и уничтожением объектов, вы просто указываете в конструкторе, какие зависимости вам нужны, и, предполагая, что у вас есть привязки к ним в вашей конфигурации, MVC позаботится о их создании и уничтожении для вы. Вы просто используете их.

EDIT:

Для ясности, я не рекомендую вам использовать примеры, которые я привел выше. Они просто простые иллюстрации того, как работает DI. В частности, синтаксис Get () известен как «Расположение службы» и считается плохим. Однако, в конечном счете, некоторый код, который где-то должен вызывать Get (), просто скрыт глубоко в фреймворке.

Как упоминает Адам, связывание напрямую с контекстом сущностей данных не является хорошей идеей, и в конечном итоге вам следует перейти к использованию подхода, основанного на интерфейсе.

0 голосов
/ 12 февраля 2012

Я бы никогда не внедрил конкретный тип здесь - вы напрямую связаны с реализацией доступа к данным.

Вместо этого привязывайте к IDbContext (или IUnitOfWork) - это интерфейсы, которые вы определяете с помощью конкретной реализации DbContext, таким образом вы можете легко абстрагироваться от используемой вами технологии, делая ее более удобной в использовании, тестируемой, поддерживаемой и т. Д.

Например: http://blogs.planetcloud.co.uk/mygreatdiscovery/post/EF-Code-First-Common-Practices.aspx#disqus_thread

...