Внедрение зависимости (dependency injection) в контроллерах ASP.NET MVC

| Четверг, 28 марта, 2013

Метки: ASP.NET MVC Комментарии: 0

Как ASP.NET MVC создает контроллеры?

Перед описанием процесса внедрения объекта DefaultLogger в контроллер HomeController, получим ясную картину, о том как MVC-фреймворк создает объекты контроллеров. Интерфейс IControllerFactory отвечает за создание контроллеров. Класс DefaultControllerFactory является стандартной реализацией этого интерфейса, которую предлагает ASP.NET MVC. Данный класс реализует методы Create, GetControllerInstance, CreateController, которые играть важную роль в создании контроллеров. Так как ASP.NET MVC поставляется с открытым кодом, то можно очень подробно изучить реализацию этих методов. ASP.NET MVC предлагает шаблон абстрактной фабрики для создания контроллеров. Добавив строку получения текущей фабрики можно увидеть что тип этой фабрики DefaultControllerFactory.

Зачем нужна собственная реализация фабрики контроллеров?

Итак, выше было описано, что встроенная фабрика контроллеров создает контроллеры через конструктор без параметров. Но вообще-то все таки можно внедрять объекты через такие конструкторы. Например так:

public class HomeController : Controller
{
    private readonly ILogger _logger;
    public HomeController():this(new DefaultLogger())
    {
    } 
    public HomeController(ILogger logger)
    {
        _logger = logger;
    }
}    

Но это не является внедрением зависимости, так как данный подход нарушает главный принцип: "Верхний уровень модуля не должен зависеть от нижнего, оба уровня должны зависеть от абстракции, а абстракция зависит от деталей". В коде выше HomeController сам создает объект DefaultLogger, и из-за этого зависит от реализации интерфейса ILogger (DefaulLogger). Если в дальнейшем потребуется применить другую реализацию интерфейса ILogger, то придется вносить изменения в код контроллера. Это нехороший способ, гораздо лучше использовать конструктор с параметрами, в который передадим интерфейс ILogger, но реализация DefaultControllerFactory не сможет работать с таким конструктором, поэтому нужна собственная реализация фабрики.

Создание собственной фабрики контроллеров

Новую фабрику можно реализовать в в виде класса, который наследует интерфейс IControllerFactory. Предположим мы написали такую фабрику и назвали ее CustomControllerFactory. Реализация может быть такой:

public class CustomControllerFactory : IControllerFactory
{
    public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
    {
        ILogger logger = new DefaultLogger();
        var controller = new HomeController(logger);
        return controller;
    }
    public System.Web.SessionState.SessionStateBehavior GetControllerSessionBehavior(
       System.Web.Routing.RequestContext requestContext, string controllerName)
    {
        return SessionStateBehavior.Default;
    }
    public void ReleaseController(IController controller)
    {
        IDisposable disposable = controller as IDisposable;
        if (disposable != null)
            disposable.Dispose();
    }
} 

Первое, что нужно сделать – это зарегистрировать эту фабрику в MVC-фреймворке. Это делается в событии Application_Start:

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
	RegisterCustomControllerFactory ();
    }
}
private void RegisterCustomControllerFactory ()
{
    IControllerFactory factory = new CustomControllerFactory();
    ControllerBuilder.Current.SetControllerFactory(factory);
} 

Запускаем приложение и в режиме отладки видим, что вызвался конструктор с параметром HomeController(ILogger logger). Проблема решена.

Комментарии
Никто еще не оставил здесь комментарий.
Войдите, чтобы написать комментарий , или воспользуйтесь формой ниже.
 

Copyright © CodeHint.ru 2013-2019