Pull to refresh

Обработка запросов в ASP.NET MVC

Reading time 7 min
Views 21K
Попробую внести свою лепту в освоение относительно неосвоенного фреймворка ASP.NET MVC и предлагаю вашему вниманию перевод отрывка из книги "Pro ASP.NET MVC Framework" под названием «The Request Processing Pipeline».

***

Давайте рассмотрим, что происходит в режиме runtime, когда ASP.NET MVC обрабатывает входящий запрос.

Конвейер обработки запросов в ASP.NET MVC сравним с жизненным циклом страницы в ASP.NET WebForms в том, что он отображает анатомию системы. Понимание этого процесса необходимо для выполнения каких-либо нестандартных задач. В отличие от традиционного жизненного цикла страницы в ASP.NET, конвейер обработки запросов в MVC очень гибок – можно изменить любую его часть так, как вам хочется, и даже перераспределить или заменить некоторые компоненты. Хотя обычно не приходится расширять или изменять конвейер, можно сделать это в любой момент, потому как расширяемость лежит в основе ASP.NET MVC.


На рисунке представлена схема конвейера обработки запросов. Центральная ось – стандартный конвейер (для запросов, которые рендерят представление); ответвления – главные точки расширения. Для упрощения схема не содержит абсолютно все этапы и точки расширения. Наиболее значимое упущение – фильтры, которые можно встраивать до или после выполнения методов действий, или до или после выполнения результатов действий.

image

ЭТАП 1: IIS


Internet Information Services (IIS), веб-сервер от Microsoft, начинает работу в первую очередь. При поступлении HTTP запроса, до того, как в дело вступает ASP.NET, драйвер HTTP.SYS ядра Windows анализирует комбинацию URL/port number/IP address, сопоставляет их и перенаправляет зарегистрированному приложению (которое может быть как веб-сайтом IIS, так и виртуальным каталогом внутри веб-сайта IIS).

Поскольку приложения ASP.NET MVC основаны на ASP.NET, необходимо включить ASP.NET для пула приложений (каждое приложение IIS сопоставлено с каким-либо пулом приложений). ASP.NET можно включить в двух управляемых конвейерных режимах (managed pipeline modes):

• В режиме ISAPI (классический режим) ASP.NET активизируется с помощью расширения ISAPI (aspnet_isapi.dll), ассоциированного с определенными расширениями файлов из URL адреса (например, .aspx, .ashx, .mvc). В IIS 6 можно использовать подстановочные знаки, и тогда aspnet_isapi.dll будет обрабатывать все запросы, несмотря на расширение файлов.

• В интегрированном режиме (поддерживается только в IIS 7+) .NET является нативной частью конвейера обработки запросов, поэтому не нужно использовать расширение ISAPI, ассоциированное с расширениями файлов. Именно это делает легким использование маршрутизации с «красивыми» URL адресами (без расширений файлов).

В любом случае, как только система ASP.NET принимает входящий запрос, она оповещает все зарегистрированные модули HTTP о том, что пришел новый запрос. (Модуль HTTP – это класс .NET, реализующий интерфейс IHttpModule, который можно «встроить» в конвейер обработки запросов). Один особенно важный модуль HTTP, зарегистрированный по умолчанию во всех приложениях ASP.NET MVC – UrlRoutingModule. Этот модуль является начальной точкой всей системы маршрутизации (core routing system). Для IIS 6 модуль UrlRoutingModule регистрируется в файле web.config.

В случае IIS 7 можно использовать Modules GUI (для этого откройте Internet Information Services (IIS) Manager из Administrative Tools, выберите веб-сайт и дважды кликните Modules).

ЭТАП 2: МАРШРУТИЗАЦИЯ (CORE ROUTING)


Когда модуль UrlRoutingModule вступает в обработку запроса, он запускает систему маршрутизации System.Web.Routing. Задача маршрутизации состоит в том, чтобы распознать и проанализировать входящий URL и заполнить контекст запроса (request context), который могут использовать последующие компоненты (например, ASP.NET MVC использует его для передачи управления соответствующему контроллеру MVC и заполнения параметров методов действий).

На схеме видно, что система маршрутизации в первую очередь проверяет, соответствует ли входящий URL файлу на диске. Если да, тогда система маршрутизации заканчивает свою работу и IIS продолжает обработку запроса. Для статичных файлов (например, .gif, .jpeg, .png, .css или .js) это значит, что IIS будет обрабатывать их стандартным способом (поскольку они существуют на диске), что очень эффективно. Подобно этому, традиционные страницы ASP.NET WebForms (.aspx) будут обработаны обычным способом.

Однако, если входящий URL не соответствует файлу на диске (например, запросы к контроллерам MVC, которые являются классами .NET, а не файлами), тогда система маршрутизации исследует текущую конфигурацию для того, чтобы определить как обработать входящий URL.

ТАБЛИЦА МАРШРУТИЗАЦИИ

Таблица маршрутизации хранится в статичной коллекции System.Web.Routing.RouteTable.Routes. Каждая запись в коллекции представляет собой шаблон для допустимых URL адресов. В шаблон могут опционально входить заполнители (placeholders) (например, /blog/{year}/{entry}) и ограничения (constraints), которые ограничивают диапазон допустимых значений для каждого из параметров. Каждая запись указывает на обработчик маршрута (route handler) – объект, реализующий интерфейс IRouteHandler, который принимает и обрабатывает запрос. Для того, чтобы заполнить коллекцию RouteTable.Routes, нужно добавить соответствующий код в метод RegisterRoutes() файла Global.asax.cs.

Для поиска соответствия запроса HTTP конкретному маршруту из RouteTable.Routes, система маршрутизации начинает сканировать коллекцию RouteTable.Routes сверху вниз и выбирает первый найденный маршрут, соответствующий входящему запросу. Найдя его, система маршрутизации передает управление обработчику маршрута, обеспечивая его контекстом запроса, описывающим выбранный маршрут и все параметры URL адреса.

ЭТАП 3: КОНТРОЛЛЕРЫ И ДЕЙСТВИЯ (CONTROLLERS AND ACTIONS)


К этому моменту система маршрутизации выбрала маршрут из коллекции RouteTable.Routes и проанализировала параметры URL адреса. Вся эта информация помещена в контекст запроса. Итак, в каком месте на сцену вступают контроллеры и действия?

ПОИСК И ЗАПУСК КОНТРОЛЛЕРОВ

Для приложений ASP.NET MVC большинство маршрутов из RouteTable.Routes соответствуют одному обработчику – обработчику MvcRouteHandler, это стандартный обработчик, встроенный в ASP.NET MVC. MvcRouteHandler знает, как с помощью контекста запроса вызвать соответствующий контроллер.

Как видно на схеме, он делает это, используя фабрику контроллеров (controller factory). По умолчанию он использует невероятно оригинально названную фабрику DefaultControllerFactory, которая использует определенное соглашение именования контроллеров для того, чтобы выбрать правильный контроллер для входящего запроса.

Однако, если вы заменяете встроенную фабрику DefaultControllerFactory какой-либо другой реализацией интерфейса IControllerFactory или наследником класса DefaultControllerFactory, тогда вы должны изменить эту логику.

ЧТО ДОЛЖНЫ ДЕЛАТЬ КОНТРОЛЛЕРЫ

Минимальное требование к классу контроллера состоит в том, что он должен реализовывать интерфейс IController:

public interface IController
{
   void Execute(RequestContext requestContext);
}

Как вы можете убедиться, это очень простой интерфейс! Он не определяет ничего, кроме того, что контроллер должен что-то сделать в методе Execute(). Заметьте, что параметр requestContext хранит полную информацию о контексте запроса, сформированном системой маршрутизации, включая параметры URL адреса, и, кроме того, обеспечивает доступ к объектам Request и Response.

ЧТО КОНТРОЛЛЕРЫ ДЕЛАЮТ ОБЫЧНО

Чаще всего нет необходимости реализовывать IController напрямую – можно наследовать контроллеры от класса System.Web.Mvc.Controller. Это стандартный базовый контроллер ASP.NET MVC, который добавляет необходимую инфраструктуру для обработки запросов. Что наиболее важно, он вводит в систему методы действий (action methods). Это значит, что все public методы контроллера достижимы через URL (такие методы и называются «методы действий») и, кроме того, это значит, что не нужно самостоятельно реализовывать метод Execute().

Хотя методы действий могут выводить результат прямо в HTTP response, так не рекомендуется делать. По причинам удобства тестирования и повторного использования кода в методах действий лучше возвращать результат действий (action result) (объект, наследованный от ActionResult), который описывает результат выполнения действия. Например, если вы хотите отрендерить представление, следует вернуть ViewResult. Или для перенаправления HTTP запроса к другому методу действия следует вернуть RedirectToRouteResult. ASP.NET MVC позаботится о выполнении результата в нужный момент конвейера обработки запросов.

Кроме того, существует очень гибка система фильтром (filters). Это атрибуты .NET (например, [Authorize]), которыми вы можете помечать классы контролеров или методы действий, встраивая какую-либо логику до или после выполнения методов действий, или до или после запуска результатов действий. Существуют несколько встроенных фильтров, например фильтры исключений и фильтры авторизации. Фильтры могут применяться в стольких различных местах, что им не нашлось места на схеме!

Контроллеры и действия (и связанные с ними возможности) – главные понятия в ASP.NET MVC.

ЭТАП 4: РЕЗУЛЬТАТЫ ДЕЙСТВИЙ И ПРЕДСТАВЛЕНИЯ (ACTION RESULTS AND VIEWS)


Ок, да, уже достаточно много всего произошло! Давайте повторим:

• Система маршрутизации сопоставила входящий URL с конкретным маршрутом и подготовила объект, содержащий контекст запроса. Выбранный из RouteTable.Routes маршрут обозначил обработчик MvcRouteHandler для обработки запроса.

• MvcRouteHandler использовал контекст запроса и фабрику контроллеров для того, чтобы выбрать и вызвать соответствующий контроллер.

• Контроллер вызвал один из своих методов действий.

• Метод действия вернул объект ActionResult.
В этот момент, ASP.NET MVC выполняет запуск результата ActionResult.

РЕНДЕРИНГ ПРЕДСТАВЛЕНИЯ

Уделим особое внимание одному особенному классу, наследованному от ActionResult – ViewResult. Этот класс способен найти и отрендерить соответствующий шаблон представления, передав ему что-либо в коллекции ViewData, сформированном в методе действия. Это и есть то, что называется «движок отображения» («view engine») (класс .NET, реализующий интерфейс IViewEngine).

Стандартный движок – это WebFormViewEngine. Его шаблоны представления являются страницами WebForms (.aspx) (то есть серверные страницы, используюшиеся в традиционной технологии ASP.NET WebForms). Страницы WebForms имеют свой собственный конвейер обработки, начинающийся с компиляции ASPX/ASCX «на лету» и проходящий через серию событий, называющийся жизненным циклом страницы. В отличие от традиционного ASP.NET, в ASP.NET MVC эти страницы должны быть максимально простыми, поскольку, согласно принципам MVC, представления могут отвечать только за генерацию HTML кода. Это значит что, вам не требуется детально понимать жизненный цикл страниц WebForms. С соблюдением принципов разделения ролей приходят простота и удобство сопровождения кода.

***

От себя хотел бы добавить, что непосредственно по данной теме может быть полезна статья "13 ASP.NET MVC extensibility points you have to know".
Tags:
Hubs:
+8
Comments 20
Comments Comments 20

Articles