ASP.NET MVC 4

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}. Если вы не будете осторожны, вы можете в конечном итоге получить исключительно странные результаты и снижение производительности. Эту опцию стоит включать только в крайнем случае.

или RSS канал: Что новенького на smarly.net