Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core
Итак, мы объявили зависимость контроллера от объекта IRepository. Теперь необходимо внедрить зависимость в контроллер.
Для внедрения зависимостей, как правило, используются IoC-контейнеры. Существует множество IoC-контейнеров: Castle Windsor, Spring.Net, Autofac, Ninject, Unity. Используем Ninject.
Для этого вначале все необходимые библиотеки в проект. Установить необходимый пакет можно через NuGet:
Нужный нам пакет: Ninject.MVC5, вместе с которым устанавливается ряд зависимых пакетов.
После установки пакета мы уже можем использовать Ninject в проекте. Например, изменим конструктор контроллера следующим образом:
using Ninject; //..................... public class HomeController : Controller { IRepository repo; public HomeController() { IKernel ninjectKernel = new StandardKernel(); ninjectKernel.Bind<IRepository>().To<BookRepository>(); repo = ninjectKernel.Get<IRepository>(); } public ActionResult Index() { return View(repo.List()); } }
Чтобы управлять зависимостями через Ninject, вначале надо создать объект Ninject.IKernel
с помощью встроенной реализации этого интерфейса -
класса StandardKernel:
IKernel ninjectKernel = new StandardKernel();
Далее нужно установить отношения между интерфейсами и их реализациями:
ninjectKernel.Bind<IRepository>().To<BookRepository>();
Данное выражение указывает, что объекты IRepository должны будут рассматриваться как BookRepository.
И в конце создается объект интерфейса через метод Get:
repo = ninjectKernel.Get<IRepository>();
Поскольку выше мы установили сопоставление между IRepository и BookRepository, то метод ninjectKernel.Get<IRepository>()
будет создавать экземпляр класса
BookRepository.
Зарегистрируем зависимости глобально для всех контроллеров и для этого создадим в проекте новую папку Util и поместим в нее новый класс NinjectRegistrations:
using IoSApp.Models; using Ninject.Modules; namespace IoSApp.Util { public class NinjectRegistrations : NinjectModule { public override void Load() { Bind<IRepository>().To<BookRepository>(); } } }
Класс NinjectRegistrations наследуется от класса NinjectModule и фактически представляет модуль Ninject. Он переопределяет метод
Load()
, который вызывается при загрузке модуля. И с помощью вызова Bind<IRepository>().To<BookRepository>();
собственно устанавливается сопоставление между интерфейсом-зависимостью и конкретным классом этого интерфейса.
И в конце необходимо инициализировать сопоставление зависимостей происходило при запуске приложения. Для этого перейдем к файлу Global.asax.cs, который запускается при старте приложения. Изменим его содержимое следующим образом:
using Ninject; using Ninject.Modules; using Ninject.Web.Mvc; using IoSApp.Models; using IoSApp.Util; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; namespace IoSApp { public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); // внедрение зависимостей NinjectModule registrations = new NinjectRegistrations(); var kernel = new StandardKernel(registrations); DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel)); } } }
Этот класс вызывается при запуске приложения. В конце метода создается модуль Ninject - объект NinjectRegistrations.
И затем с помощью метода DependencyResolver.SetResolver()
регистрируется ранее созданный сопоставитель зависимостей.
И теперь изменим контроллер:
public class HomeController : Controller { IRepository repo; public HomeController(IRepository r) { repo = r; } public ActionResult Index() { return View(repo.List()); } }
Несмотря на то, что в конструктор контроллера не передается никакой конкретной реализации, но все будет работать. Рассмотрим поэтапно, как происходит в данном случае внедрение зависимостей:
Фреймворк MVC получает запрос и обращается к контроллеру HomeController
Фреймворк MVC обращается к классу сопоставления зависимостей (в данном случае класс NinjectDependencyResolver), чтобы тот создал новый объект HomeController, передавая параметр Type в метод GetService (в класс NinjectDependencyResolver)
Сопоставитель зависимостей вызывает инфраструктуру Ninject для создания нового объекта HomeController, передавая тип создаваемого объекта в метод TryGet
Ninject смотрит на конструктор HomeController и видит, что там используется зависимость от интерфейса IRepository, для которого он устанавливает сопоставление с конкретной реализацией
Ninject создает экземпляр класса BookRepository и затем использует его для создания контроллера HomeController
Ninject передает созданный объект HomeController сопоставителю зависимостей, который, в свою очередь, передает его фреймворку MVC. И далее происходит обработка запроса.
Таким образом, мы избегаем использования конкретных реализаций и работаем с объектами на уровне интерфейсов. А сопоставление интерфейсов с конкретными реализациями перекладывается на класс NinjectDependencyResolver.