IoC-контейнер Ninject

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 28.10.2017

Итак, мы объявили зависимость контроллера от объекта IRepository. Теперь необходимо внедрить зависимость в контроллер.

Для внедрения зависимостей, как правило, используются IoC-контейнеры. Существует множество IoC-контейнеров: Castle Windsor, Spring.Net, Autofac, Ninject, Unity. Используем Ninject.

Для этого вначале все необходимые библиотеки в проект. Установить необходимый пакет можно через NuGet:

Ninject in ASP.NET MVC 5

Нужный нам пакет: 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());
    }
}

Несмотря на то, что в конструктор контроллера не передается никакой конкретной реализации, но все будет работать. Рассмотрим поэтапно, как происходит в данном случае внедрение зависимостей:

  1. Фреймворк MVC получает запрос и обращается к контроллеру HomeController

  2. Фреймворк MVC обращается к классу сопоставления зависимостей (в данном случае класс NinjectDependencyResolver), чтобы тот создал новый объект HomeController, передавая параметр Type в метод GetService (в класс NinjectDependencyResolver)

  3. Сопоставитель зависимостей вызывает инфраструктуру Ninject для создания нового объекта HomeController, передавая тип создаваемого объекта в метод TryGet

  4. Ninject смотрит на конструктор HomeController и видит, что там используется зависимость от интерфейса IRepository, для которого он устанавливает сопоставление с конкретной реализацией

  5. Ninject создает экземпляр класса BookRepository и затем использует его для создания контроллера HomeController

  6. Ninject передает созданный объект HomeController сопоставителю зависимостей, который, в свою очередь, передает его фреймворку MVC. И далее происходит обработка запроса.

Таким образом, мы избегаем использования конкретных реализаций и работаем с объектами на уровне интерфейсов. А сопоставление интерфейсов с конкретными реализациями перекладывается на класс NinjectDependencyResolver.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850