Таблица маршрутизации
Таблица маршрутизации определяет набор правил, на основании которых происходит анализ URL-запроса и вычленения из URL информации, определяющей имя контроллера и действия контроллера, а также сопоставление параметров запроса. В проекте-заготовке правила добавляются в методе RegisterRoutes, описанном в файле Global.asax (листинг 1.1).
Листинг 1.1. Метод RegisterRoutes
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute( "Default", // Название маршрута
"{controller}/{action}/{id}", // URL с параметрами
new { controller = "Home", action = "Index", id = "" }
// Значения по умолчанию
);
}
Таблица маршрутизации заполняется двумя типами маршрутов — теми, которые должны быть обработаны MVC Framework (метода MapRoute коллекции RouteCollection), и теми, обработка которых должна быть передана дальше инфраструктуре ASP.NET в обход механизмов MVC Framework (метод IgnoreRoute коллекции RouteCollection).
В случае с игнорируемыми маршрутами задается определенный адрес либо маска. Так, приведенный в листинге 1.1 маршрут исключает запросы к файлам с расширением axd (используются инфраструктурой ASP.NET для встроенных ресурсов).
Маршруты, обрабатываемые MVC Framework, задаются набором параметров: названием маршрута для идентификации в коллекции, описанием шаблона URL и набором значений по умолчанию. Среди всех параметров обязательными являются controller — указывающий имя контроллера, обрабатывающего запросы, удовлетворяющие маске, и action — указывающий действие контроллера, обрабатывающего запрос. Все остальные параметры задаются произвольно, и их имена используются для передачи значений при вызове методов контроллера.
Контроллер
Рассмотрим код контроллера HomeController, приведенный в листинге 1.2.
Листинг 1.2. Код контроллера HomeController ИЗ приложения-заготовки
[HandleError]
public class HomeController : Controller {
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
}
На примере этого кода можно рассмотреть несколько основных концепций. Прежде всего, все классы контроллеров наследуют тип Controller, предоставляющий инфраструктуру для обработки запросов.
Каждый из контроллеров содержит методы, возвращающие значения типа ActionResult. В приведенном примере используется вспомогательный метод View, возвращающий тип ViewResult, который наследует тип ActionResult и передает управление механизму представлений — если параметр "имя представления" не передан методу View, то используется имя действия в качестве имени представления.
Задачей контроллера является обработка параметров запроса (в примере параметров действия не принимают, что тоже может быть в реальных приложениях — для отображения страниц, не зависящих от параметров запроса), заполнение коллекции ViewData и передача управления движку представлений.
В данном случае, например, действие Index поместит в коллекцию ViewData элемент Message, после чего передаст управление представлению Index.aspx, расположенному в папке /Views/Home.
Кроме того, в листинге 1.2 проиллюстрирована еще одна важная концепция, касающаяся кода контроллеров, — использование атрибутов для управления поведением контроллеров. Так, для того чтобы управлять поведением всего контроллера, можно установить атрибуты на класс контроллера, а для того чтобы управлять поведением конкретного действия — на соответствующий метод класса контроллера. В приведенном в листинге 1.2 коде используется атрибут для всего класса контроллера HandleError, который инструктирует среду MVC Framework на предмет возникновения необработанного исключения в любом из методов контроллера HomeController, необходимо будет это исключение поймать и отобразить пользователю специальную страницу с сообщением об ошибке.
Представление
В MVC Framework используется представление на основе ASPX-файлов. Так, например, рассмотрим представление Index.aspx из примера выше. Этому представлению передается коллекция viewData с элементом Message, значение которого должно быть отображено на странице. В листинге 1.3 приведен код этого представления.
Листинг 1.3. Представление Index.aspx
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="indexTitle"
ContentPlaceHolderID="TitleContent" runat="server">
Home Page
</asp:Content>
<asp:Content ID="indexContent"
ContentPlaceHolderID="MainContent" runat="server">
<h2><%= Html.Encode(ViewData["Message"]) %></h2>
<p>To learn more about ASP.NET MVC visit
<a href="http://asp.net/mvc"
title="ASP.NET MVC Website">http://asp.net/mvc</a>.
</p>
</asp:Content>
Как видно из листинга 1.3, в представлении используется шаблон Site.Master и метки Content для определения содержимого блоков ContentPlaceHolder, определенных в Site.Master.
Для отображения данных из коллекции ViewData используется серверная вставка вида <%= %>, с помощью которой можно отобразить значение на странице.
Подробнее о работе с представлениями и создании сложных представлений можно узнать в главе 5.
Подход к разработке MVC-приложений
Исходя из внутреннего устройства MVC-приложений, процесс разработки удобно построить по следующей схеме:
1. Создать модель — создать схему базы данных, по схеме базы данных создать логические структуры данных, с которыми будет работать приложение.
2. Описать физическую структуру приложения — задать маршруты, которые будут определять взаимодействие пользователя с приложением.
3. Создать контроллеры и их действия — на основании структуры приложения.
4. Создать представления — для каждого из действий контроллеров создать представления, учитывая возможность вынесения повторяющихся элементов в частичные представления и шаблоны.
5. Разработать модульные тесты для тестирования логики представления, если планируется модификация логики в процессе поддержки и развития приложения.
Процесс разработки может быть несколько модифицирован, если разрабатываются веб-приложения с богатой клиентской функциональностью. В случае если создается страница, использующая асинхронные вызовы для обращения к серверу и обновления фрагментов страниц, то может быть удобным изначально создать лишь базовые действия контроллеров, отображающие страницы, после этого в процессе разработки клиентского интерфейса дорабатывать методы, отвечающие на асинхронные запросы. Этот подход будет рассмотрен в главе 7, посвященной клиентскому программированию в MVC Framework.
В любом случае, при разработке приложений, вне зависимости от используемой платформы, технологии и парадигмы разработки, необходимо тщательное проектирование и детальное планирование разработки задолго до начала проекта. Хорошее планирование зачастую позволяет существенно сократить сроки разработки проекта, исключив неприятные моменты вроде необходимости рефакторинга части написанного кода для полноценной реализации функциональности.