Маршрутизация с ASP.NET Web Forms
До сих пор мы рассматривали маршрутизацию в рамках ASP.NET MVC. Хотя система маршрутизации действительно была впервые введена в MVC, впоследствии она была перемещена в ядро .NET Framework в .NET 3.5 SP1, и в .NET 4 она также полностью поддерживается в приложениях ASP.NET Web Forms. Это значит, что страницы Web Forms могут существовать бок о бок с контроллерами и представлениями MVC в рамках одного проекта, используя одни и те же схемы URL.
В этом разделе мы рассмотрим то, как страницы, разработанные в ASP.NET MVC, могут работать вместо со страницами, написанными в ASP.NET Web Forms, и как страницы Web Forms могут использовать инфраструктуру маршрутизации URL.
Добавляем роуты для страниц Web Forms
Продолжая работу с примером интернет-магазина, представьте, что у нас есть страница под названием ProductsByCategory.aspx
, первоначально написанная с помощью ASP.NET Web Forms, которая составляет перечни товаров, сгруппированных по категории, как показано на рисунке 9-4.
Эта страница также предоставляет возможность для фильтрации отображаемых категорий, для чего нужно указать название категории в строке запроса:
http://example.com/ProductsByCategory.aspx?category=Books
Рисунок 9-4 : Страница Web Forms ProductsByCategory

Вот код этой страницы.
Листинг 9-3: Код страницы ProductsByCategory
public partial class ProductsByCategory : Page
{
private ProductRepository _productRepository
= new ProductRepository();
protected void Page_Load(object sender, EventArgs e)
{
string category = Request.QueryString["category"];
var productsByCategory =
_productRepository
.GetProductsByCategory(category);
_groupedProductsRepeater.DataSource =
productsByCategory;
_groupedProductsRepeater.DataBind();
}
}
Строка 7: Получает категорию из строки запроса
Строки 8-10: Загружает продукты для категории
Строки 11-13: Связывает продукты с UI
Метод Page_Load
вызывается после того, как загружена веб-форма. Он сначала извлекает категорию из строки запроса (если она указана), а затем передает ее в метод GetProductsByCategory
в ProductRepository
. Этот метод возвращает список объектов Product
, сгруппированных по категориям (если категория не указана, метод GetProductsByCategory
возвращает все товары). Эти товары затем связываются со свойством DataSource Repeater
, которое используется для представления UI. Разметка страницы показана здесь.
Листинг 9-4: Разметка страницы Web Forms
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="ProductsByCategory.aspx.cs"
Inherits="RoutingSample.ProductsByCategory" %>
<!DOCTYPE html>
<html>
<head runat="server">
<title>Products by Category</title>
<link rel="Stylesheet"
href="~/content/site.css" type="text/css" />
</head>
<body>
<form runat="server">
<ul>
<asp:repeater runat="server"
id="_groupedProductsRepeater">
<ItemTemplate>
<li>
<strong><%# Eval("Category") %></strong>
<ul>
<asp:Repeater runat="server"
DataSource='<%# Eval("Products") %>'>
<ItemTemplate>
<li><%# Eval("Name") %></li>
</ItemTemplate>
</asp:Repeater>
</ul>
</li>
</ItemTemplate>
</asp:repeater>
</ul>
</form>
</body>
</html>
Строка 14:
Repeater
создает список категорий
Строка 18: Выводит имя категории
Строки 20-21: Дочерний
Repeater
для товаров
Строка 23: Выводит название товара
Страница содержит Repeater
, который выдает список категорий, где каждая категория содержит список товаров.
Если можно было бы переписать эту страницу в ASP.NET MVC, альтернативным вариантом было бы включить страницу в существующую схему URL с незначительными изменениями. Этот подход полезен, когда необходимо интегрировать большие страницы, где рерайт будет нецелесообразным.
В файле Global.asax
мы можем зарегистрировать другой роут, который соотнесет URL /Products-ByCategory
со страницей ProductsByCategory.aspx
, как показано в следующем листинге. Мы добавим его предпоследним (до catchall роута, который был определен ранее).
Листинг 9-5: Добавляем роут для страницы Web Forms
routes.MapPageRoute(
"ProductsByCategory",
"ProductsByCategory/{category}",
"~/ProductsByCategory.aspx",
checkPhysicalUrlAccess: true,
defaults: new RouteValueDictionary(new{category="All"})
);
Строка 1: Добавление роута для веб формы
Вместо того, чтобы использовать метод MapRoute
из предыдущих примеров, мы используем метод MapPageRoute
, который появился в .NET 4 для добавления роутов для страниц Web Forms. Этот метод принимает несколько аргументов. Как и в MapRoute
, первый – это имя роута, а второй - шаблон URL, который должен соответствовать роуту. Далее мы указать соответствующий приложению путь к странице Web Forms, которая должна обработать запрос. Четвертый аргумент указывает, следует ли ASP.NET проверять, имеет ли текущий пользователь доступ к физической странице ASPX. Наконец, мы предоставляем RouteValueDictionary
, содержащий значения по умолчанию. В этом случае мы указываем, что если параметр категории опущен, то по умолчанию должна использоваться строка All
.
Теперь, когда роут настроен, нам нужно изменить страницу так, чтобы извлечь параметр категории из RouteData
, а не из строки запроса, как показано ниже.
Листинг 9-6: Изменяем страницу Web Forms, чтобы использовать RouteData
protected void Page_Load(object sender, EventArgs e)
{
string category = (string)RouteData.Values["category"];
var productsByCategory =
_productRepository.GetProductsByCategory(category);
_groupedProductsRepeater.DataSource = productsByCategory;
_groupedProductsRepeater.DataBind();
}
Строка 3: Получает значение из данных роута
Метод Page_Load
остался почти таким же, как раньше. Единственное изменение заключается в том, что теперь он получает имя категории из RouteData.Values
, а не Request.QueryString
. Свойство RouteData
обеспечивает доступ ко всей информации о текущем роуте, и оно было включено в базовый класс Page
в Web Forms 4.
Запуск приложения в этой точке и посещение URL /ProductsByCategory
теперь будет иметь точно такой же результат, как на рисунке 9-4.
Маршрутизация запросов к страницам Web Forms - только часть работы, мы также хотим, чтобы страницы Web Forms могли ссылаться на действия контроллеров MVC для беспрепятственного перехода из одной части приложения в другую.
Вы сможете использовать инфраструктуру маршрутизации при работе со страницами Web Forms для генерации ссылок на другие роуты, в том числе и те, которые соответствуют действиям контроллера.
Например, мы можем изменить разметку из листинга 9-4 так, чтобы генерировать URL на страницу товара для каждого товара. Этого можно добиться с помощью метода GetRouteUrl
, как показано здесь.
Листинг 9-7: Генерируем URL с помощью GetRouteUrl
<asp:repeater runat="server" id="_groupedProductsRepeater">
<ItemTemplate>
<li>
<strong><%# Eval("Category") %></strong>
<ul>
<asp:Repeater runat="server"
DataSource='<%# Eval("Products") %>'>
<ItemTemplate>
<li>
<asp:HyperLink runat="server"
NavigateUrl='<%# GetRouteUrl(new{
controller = "Catalog",
action = "Show",
productCode=Eval("Code")
}) %>'
Text='<%# Eval("Name") %>' />
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
</li>
</ItemTemplate>
</asp:repeater>
Строки 11-14: Устанавливает URL
В разметке элемента Repeater
мы вызываем метод GetRouteUrl
и связываем его значение со свойством NavigateUrl
серверного элемента управленияasp:Hyperlink
. Этот метод принимает анонимный тип, в котором мы указываем контроллер и действие, на которые мы хотим получить ссылку, а также код продукта (который извлекается из контекста привязки данных с помощью функции Eval
). Есть другие перегруженные варианты для этого метода, которые могут использоваться с указанными роутами.
Теперь мы знаем, как можно определить роуты и для контроллеров, и страниц Web Forms. Далее мы рассмотрим, как отлаживать роуты, когда они работают не так, как ожидалось.