ASP.NET MVC 4
Адам Фриман
Роутовые запросы для дисковых файлов
Не все запросы для MVC приложения предназначены для контроллеров и действий. Нам по-прежнему нужен способ обрабатывать такой контент, как изображения, статические HTML файлы, JavaScript библиотеки и так далее. В качестве демонстрации мы создали файл StaticContent.html
в папке Content
нашего MVC приложения, используя HTML Page. Листинг 13-32 показывает содержимое этого файла.
Листинг 13-32: Файл StaticContent.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Static HTML Content</title></head>
<body>
This is the static html file (~/Content/StaticContent.html)
</body>
</html>
Система маршрутизации обеспечивает интегрированную поддержку для обслуживания такого содержания. Если вы запустите приложение и запросите URL /Content/StaticContent.html
, вы увидите содержимое этого простого HTML файла, отображенного в браузере, как показано на рисунке 13-14.
Рисунок 13-14: Запрос файла со статическим содержание
По умолчанию система маршрутизации проверяет URL на соответствие дисковому файлу перед оценкой роутов приложения, и именно поэтому нам не нужно было добавлять роут, чтобы получить результат, показанный на рисунке 13-14.
Если есть соответствие между запрашиваемым URL и дисковым файлом, то будет обработан дисковый файл, а роуты, определенные приложением, никогда не будут использованы. Мы можем изменить это поведение так, чтобы наши роуты оценивались раньше дисковых файлов, если мы установим свойство RouteExistingFiles
RouteCollection
на true
, как показано в листинге 13-33.
Листинг 13-33: Включение оценки роутов до проверки файлов
public static void RegisterRoutes(RouteCollection routes) {
routes.RouteExistingFiles = true;
routes.MapRoute("ChromeRoute", "{*catchall}",
new { controller = "Home", action = "Index" },
new {
customConstraint = new UserAgentConstraint("Chrome")
},
new[] { "UrlsAndRoutes.AdditionalControllers" });
routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
new { controller = "Home", action = "Index",
id = UrlParameter.Optional },
new[] { "URLsAndRoutes.Controllers" });
}
По соглашению это выражение размещается в верхней части метода RegisterRoutes
, хотя все будет работать, даже если вы разместите его после определения роутов.
Конфигурация сервера приложения
Visual Studio 2012 использует IIS Express в качестве сервера приложений для MVC проектов. Мы не только должны установить свойство RouteExistingFiles
в методе RegisterRoutes
на true
, мы также должны сказать IIS Express не перехватывать запросы для дисковых, прежде чем они попадут в систему маршрутизации MVC.
Прежде всего, запустите IIS Express. Самый простой способ сделать это – это запустить MVC приложение из Visual Studio, которое покажет иконку IIS Express на панели задач. Щелкните правой кнопкой мыши по иконке и выберите из всплывающего меню Show All Applications
. Нажмите на UrlsAndRoutes
в столбце Site Name
для отображения информации о конфигурации IIS, как показано на рисунке 13-15.
Рисунок 13-15: Информация о конфигурации IIS Express
Нажмите на ссылку Config
в нижней части окна, чтобы открыть конфигурационный файл IIS Express в Visual Studio. Теперь нажмите Ctrl + F
и найдите UrlRoutingModule-4.0
. Там будет запись, найденная в разделе modules
конфигурационного файла, и нам нужно установить для атрибута preCondition
пустую строку:
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule"
preCondition="" />
Теперь перезапустите приложение в Visual Studio, чтобы измененные настройки вступили в силу, и перейдите по URL /Content/StaticContent.html
. Вместо того чтобы увидеть содержимое файла, вы увидите сообщение об ошибке, показанное на рисунке 13-16. Эта ошибка возникла потому, поскольку запрос для HTML файла был передан системе маршрутизации MVC, но роут, совпадающий с URL, направляет запрос к контроллеру Content
, который не существует.
Рисунок 13-16: Запрос файла со статическим контентом, который обрабатывается роутинговой системой
Совет
Альтернативным подходом является использование сервера разработки Visual Studio, который вы можете активировать в разделе Web конфигурации проекта, если вы выберете при выборе пункт
UrlsAndRoutes Properties
из Visual Studio менюProject
. Сервер разработки довольно прост и не является урезанной версией IIS, как IIS Express, и поэтому он не перехватывает запросы таким же образом.
Определение роутов для дисковых файлов
Как только свойство было установлено на true
, мы можем определить роуты, подходящие URL, которые соответствуют дисковым файлам, как показано в листинге 13-34.
Листинг 13-34: Роут, чей URL паттерн соответствует дисковому файлу
public static void RegisterRoutes(RouteCollection routes) {
routes.RouteExistingFiles = true;
routes.MapRoute("DiskFile", "Content/StaticContent.html",
new {
controller = "Customer",
action = "List",
});
routes.MapRoute("ChromeRoute", "{*catchall}",
new { controller = "Home", action = "Index" },
new {
customConstraint = new UserAgentConstraint("Chrome")
},
new[] { "UrlsAndRoutes.AdditionalControllers" });
routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
new { controller = "Home", action = "Index",
id = UrlParameter.Optional },
new[] { "URLsAndRoutes.Controllers" });
}
Этот роут направляет запросы для URL Content/StaticContent.html
действию List
контроллера Customer
. Вы можете увидеть, как это работает на рисунке 13-17, которые мы создали, запустив приложение и перейдя снова по URL /Content/StaticContent.html
.
Рисунок 13-17: Перехват запроса для дискового файла при помощи роута
Роутинговые запросы, предназначенные для файлов на диске, требуют тщательного анализа, не в последнюю очередь потому, что URL паттерны будут соответствовать этим видам URL так же хорошо, как и любым другим. Например, как было показано в предыдущем разделе, для /Content/StaticContent.html
будет соответствовать URL паттерн {controller}/{action}
. Если вы не будете осторожны, вы можете в конечном итоге получить исключительно странные результаты и снижение производительности. Эту опцию стоит включать только в крайнем случае.