Pull to refresh

Ставим точки в MVC Framework. Механизм работы, часть первая

Reading time 5 min
Views 7.1K
В этой и следующей статьях точки ставятся в ответе на вопрос “Как работает MVC Framework?”

imageЭто продолжение цикла заметок про ASP.NET MVC Framework. Начало было положено в предыдущей статье, в которой поднимался вопрос необходимости перехода на MVC Framework. После появления комментариев стало очевидно, что статья была написана не зря, так как определенная часть читателей не представляет значение и различие двух подходов: классического ASP.NET и MVC Framework. Надеюсь, что поднятые вопросы первой главы заставили кого-то задуматься.

В этот раз речь пойдет о том как устроен изнутри механизм MVC Framework. На Habrahabr уже была публикация по этому поводу, но я постараюсь дать более подробное описание и затронуть механизмы которые в той статье не были упомянуты.

Обработка запроса и маршрутизация


Механизм маршрутизации ASP.NET является важным элементом работы MVC Framework. В стандартном варианте, когда поступает первый запрос к приложению и приложение создается, в файле Global.asax посредством метода Application_Start производится инициализация маршрутов определенных разработчиком.

Строго говоря, обработкой запроса занимаются механизмы, которые нельзя назвать составной частью MVC Framework. Обработка запроса возложена на UrlRoutingModule — это класс реализующий IHttpModule, определенный в проектах MVC Framework как модуль обрабатывающий http-запросы. UrlRoutingModule, как механизм маршрутизации, это стандартная часть ASP.NET и вполне возможно ее использование вне MVC Framework. Если же рассматривать UrlRoutingModule в контексте MVC Framework, то его задачей становится создание и инициализация объекта типа RequestContext, который в свою очередь используется механизмом MVC.

В упрощенном виде схема обработки запроса представляет собой следующую последовательность действий:
  • UrlRoutingModule обрабатывает запрос и на его основании выбирает первый подходящий маршрут из определенной разработчиком коллекции маршрутов;
  • UrlRoutingModule, на основании маршрута, представленного объектом типа Route, создает объект типа RequestContext. RequestContext содержит данные о контексте выполнения запроса и данные касающиеся текущего маршрута;
  • в MVC Framework каждому маршруту по умолчанию сопоставлен обработчик маршрутов  в виде объекта MVCRouteHandler, который в общем случае создает и возвращает экземпляр класса MVCHandler, которому передается созданный ранее объект RequestContext;
  • MVCHandler делает последний шаг, он создает фабрику контроллеров и с помощью нее получает необходимый для продолжения обработки запроса объект контроллера MVC Framework.
Таким образом на запрос пользователя создается контроллер. Рассмотрим создание контроллеров подробнее.

Фабрика контроллеров


Фабрика контроллеров – это механизм, задачей которого является инстанцирование классов контроллеров на основании переданной информации в виде имени контроллера и объекта типа RequestContext. Фабрика контроллеров должна реализовывать интерфейс IControllerFactory. Но в общем случае нет нужды определять свою фабрику контроллеров, так как в MVC Framework существует класс DefaultFactoryController, который является фабрикой контроллеров используемой по умолчанию.

MVC Framework использует метод CreateController фабрики контроллеров для получения объекта типа IController. На этом этап создания контроллера завершается и у него вызывается метод Execute, которому передается параметр в виде RequestContext.

На этапе фабрики контроллеров существует замечательная возможность расширения функционала, которая показывает насколько расширяем MVC Framework. Вы можете определить свой собственный класс фабрики контроллеров наследовав его от класса DefaultFactoryController. Затем, переопределив в своем классе метод GetControllerInstance вы можете определить в нем свою логику по созданию контроллеров. Чтобы зарегистрировать свою фабрику контроллеров вы можете добавить следующий код в метод Application_Start файла Global.asax:

ControllerBuilder.Current.SetControllerFactory(new ControllerFactory());

Для чего может понадобиться создание своей фабрики контроллеров? Один из самых распространенных вариантов – это внедрение механизма IoC/DI для инстанцирования контроллеров с помощью DI-контейнера, например Unity Application Blocks.

Итак, контроллер создан и у него вызван метод Execute. Что дальше?

ActionInvoker


А дальше в дело вступает механизм ActionInvoker, цель которого выяснить, какой же метод класса контроллера нужно выполнить в ответ на пользовательский запрос. ActionInvoker – это свойство класса Controller, который обычно является производным для всех контроллеров в MVC Framework. ActionInvoker представляет собой объект класса ControllerActionInvoker. Его важной частью является метод InvokeAction, который и выполняет поиск необходимого метода класса контроллера, его вызов и исполнение результата.

Для работы метод InvokeAction принимает параметры контекста контроллера и имени действия которое нужно найти. Хотя поиск в классе метода по имени тривиален, существует несколько важных моментов которые влияют на результаты поиска. Следующие четыре группы атрибутов влияют на процесс исполнения действия и его результата:
  • атрибуты производные от ActionMethodSelectorAttribute могут повлиять на то, будет или нет выбран метод для исполнения в зависимости от контекста запроса. В MVC Framework есть два таких стандартных атрибута: AcceptVerbsAttribute и NonActionAttribute;
  • атрибуты производные от ActionNameSelectorAttribute могут повлиять на то, будет или нет выбран метод для исполнения в зависимости от имени действия, которое нужно исполнить. В MVC Framework есть один такой атрибут – ActionNameAttribute;
  • атрибуты производные от FilterAttribute представляют собой так называемый механизмы фильтров, которые позволяют более гибко управлять процессом исполнения действия. Эти фильтры призваны либо ограничить исполнение действия по какой-то причине, либо обработать возникающие при исполнении исключения. Стандартными реализациями эти фильтров являются атрибуты AuthorizeAttribute, HandleErrorAttibute, ValidateAntiForgeryTokenAttribute и ValidateInputAttribute;
  • еще один атрибут ActionFilterAttribute, производный от FilterAttribute, позволяет создать механизм который будет вызываться в четырех ключевых местах исполнения действия: перед исполнением, после исполнения, перед исполнением результата и после исполнения результата. Реализация этого атрибута позволит вам более гибко влиять на процесс исполнения действия и результата, отслеживать его и управлять им. В MVC Framework есть один атрибут производный от ActionFilterAttribute – это OutputCacheAttribute.
Если вы прочитали все это и ничего не поняли, то подождите немного, в следующих статьях я постараюсь описать каждый из атрибутов подробнее. А пока продолжим разбирать как работает механизм ActionInvoker.

Согласно архитектуре MVC Framework каждую его часть вы можете заменить на свою. Не обошел этот принцип стороной и ActionInvoker, а так же все описанные выше атрибуты. Вы можете определить свой ActionInvoker, для этого вам достаточно реализовать класс наследующий от класса ControllerActionInvoker и переопределить метод InvokeAction. Такое переопределение позволит вам создать свой механизм поиска метода, его исполнения и обработки результата. Для регистрации своего варианта ActionInvoker достаточно присвоить его экземпляр свойству контроллера:

public AccountController()
: this(null, null)
{
    ActionInvoker = new FastControllerActionInvoker();
}


После того, как ActionInvoker определил какой метод необходимо вызвать в дело вступает механизм Model Binding, который призван сопоставить параметры клиентского запроса с параметрами метода действия.

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

Progg it
Tags:
Hubs:
+20
Comments 12
Comments Comments 12

Articles