Настройка маршрутизации ASP.NET Dynamic Data

122

Система динамических данных ASP.NET использует функцию маршрутов ASP.NET для отображения запросов на шаблоны страниц. Это средство можно применять для настройки ряда аспектов своего управляемого данными сайта. Маршруты способны внести серьезную путаницу. В действительности на их освоение уйдет некоторое время. В последующих разделах будет показано, как они работают, и продемонстрированы виды настройки, которые можно выполнить с их помощью.

Что собой представляют маршруты

Маршруты позволяют определять URL-адреса, которые приложения динамических данных будут поддерживать, и условия, при которых они будут использоваться. Ниже приведен пример маршрута:

routes.Add(new DynamicDataRoute("AllRows.aspx") 
{
    Action = PageAction.List, 
    ViewName = "List", 
    Model = DefaultModel
});

Маршруты (Routes) - это отображения между URL-адресами, вызываемыми клиентами, и шаблонами страниц. Аргумент конструктора класса DynamicDataRoute указывает URL-адрес клиента, который требуется отобразить на относительный URL-адрес приложения (в данном случае AllRows.aspx). Это означает, что любой URL-адрес, который обращается к приложению динамических данных и заканчивается на AllRows.aspx, должен использовать это отображение. Свойства, устанавливаемые в DynamicDataRoute, указывают ASP.NET, для чего предназначено отображение, и когда оно должно применяться.

Свойство Action, выраженное значением из перечисления PageAction, определяет назначение маршрута. В перечислении доступны следующие значения: Details, Edit, Insert и List. Установка свойства Action в PageAction.List указывает системе динамических данных ASP.NET, что она может использовать данный URL-адрес для вывода списка строк таблицы.

Свойство ViewName - имя шаблона страницы, на который требуется отобразить URL-адрес. В коде указан шаблон List, который отображается на шаблон List.aspx в папке PageTemplates или, если был предоставлен специальный шаблон для конкретной страницы, на соответствующий шаблону List.aspx в папке CustomTemplates.

Свойство Model определяет модель данных, к которой должен применяться этот URL-адрес. В этой статье используется только одна модель данных, хотя система динамических данных ASP.NET может работать и с более чем одной моделью. Во всех примерах для этого значения должно быть указано DefaultModel.

В приложении динамических данных ASP.NET маршруты определяются в методе RegisterRoutes() внутри файла Global.asax. При этом вызывается метод Add() на экземпляре RouteCollection, который передан методу RegisterRoutes в качестве аргумента по имени routes.

Когда система динамических данных ASP.NET создает шаблон для приложения, она пытается найти маршрут, который может использоваться для каждого действия CRUD в отношении каждой таблицы в используемой модели данных. Если она обнаруживает маршрут, то знает, что может активизировать заданное действие CRUD для конкретной таблицы. Отсутствие такого маршрута означает, что действие для этой таблицы недоступно.

Проще всего пояснить это на примере.

Откройте файл Global.asax и выполните прокрутку вниз, пока не увидите метод RegisterRoutes(). Закомментируйте определение маршрута, которое начинается с routes.Add (определяющее URL-адрес {table}/{action}.aspx). Удостоверьтесь, что закомментировали все четыре строки кода. Скопируйте показанный ранее пример определения маршрута в метод RegisterRoutes(), чтобы выглядел так, так показано ниже:

public static void RegisterRoutes(RouteCollection routes) {
        // ВАЖНО: РЕГИСТРАЦИЯ МОДЕЛИ ДАННЫХ
        // Удалите символы комментария из этой строки, чтобы зарегистрировать 
        // модель LINQ to SQL для динамических данных ASP.NET. 
        // Установите ScaffoldAllTables = true, только если уверены,
        // что все таблицы в модели данных должны поддерживать формирование шаблонов. 
        // Чтобы управлять поддержкой отдельных таблиц, создайте частичный класс 
        // для таблицы и примените атрибут [ScaffoldTable(true)] к частичному классу. 
        // Примечание. Не забудьте изменить YourDataContextType на имя класса 
        // контекста данных своего приложения.
        DefaultModel.RegisterContext(typeof(NorthwindDataContext),
            new ContextConfiguration() { ScaffoldAllTables = true });
        
        routes.Add(new DynamicDataRoute("AllRows.aspx")
        {
            Action = PageAction.List,
            ViewName = "List",
            Model = DefaultModel
        });

        // Следующий оператор поддерживает режим отдельных страниц, в котором
        // задачи List, Detail, Insert и Update выполняются за счет использования
        // отдельных страниц. Чтобы активизировать этот режим, удалите комментарий со
        // следующего определения маршрута и закомментируйте определения маршрутов
        // в следующем за ним разделе режима объединенной страницы.
        /* routes.Add(new DynamicDataRoute("{table}/{action}.aspx") {
            Constraints = new RouteValueDictionary(new { action = "List|Details|Edit|Insert" }),
            Model = DefaultModel
        }); */

        // Следующие операторы поддерживают режим объединенной страницы, в котором
        // задачи List, Detail, Insert и Update выполняются за счет использования
        // одной и той же страницы. Чтобы активизировать этот режим, удалите
        // комментарий со следующих определений маршрутов и закомментируйте
        // определение маршрута в предыдущем разделе режима отдельной страницы.
        //routes.Add(new DynamicDataRoute("{table}/ListDetails.aspx") {
        //    Action = PageAction.List,
        //    ViewName = "ListDetails",
        //    Model = DefaultModel
        //});

        //routes.Add(new DynamicDataRoute("{table}/ListDetails.aspx") {
        //    Action = PageAction.Details,
        //    ViewName = "ListDetails",
        //    Model = DefaultModel
        //});
}

Сохраните изменения и выберите пункт Start Without Debugging в меню Debug. Задержите курсор мыши над именами таблиц в списке. Отображаемый при этом URL-адрес должен выглядеть примерно так:

http://localhost:8090/AllRows.aspx?Table=Orders

Это тот URL-адрес, на который отображается маршрут в файле Global.asax. Система динамических данных ASP.NET выполнила поиск маршрутов, отображающих URL-адреса с действием PageAction.List, и нашла определенный нами маршрут. Щелкните на ссылке для таблицы Customers. Хотя отображение списка может выглядеть знакомым, в нем имеется существенное изменение. Попробуйте щелкнуть на ссылке Edit или Details для одной из строк. Они никуда не ведут, поскольку для них не определены маршруты, которые обеспечивают доступ к шаблонам страницы для редактирования или просмотра сведений строк данных.

Изменение формата URL-адреса

Одной из настроек, которую можно выполнять с помощью маршрутов, является изменение формата URL-адреса. Приведенный выше пример маршрута вел к ранее показанному URL-адресу. При этом система динамических данных ASP.NET предоставляет имя таблицы, с которой нужно работать, в виде параметра URL-адреса. Измените маршрут в Global.asax так, чтобы он выглядел следующим образом:

routes.Add(new DynamicDataRoute("{table}/{action}/AllRows.aspx")
{
    Action = PageAction.List,
    ViewName = "List",
    Model = DefaultModel
});

Сохраните изменения и снова запустите приложение. Теперь при наведении курсора мыши на имена таблиц формат URL-адреса будет подобен такому:

http://localhost:8090/Products/List/AllRows.aspx

Дескрипторы {table} и {action} используются для создания URL-адреса. Как только имя таблицы включено в URL-адрес, системе динамических данных ASP.NET больше не нужно включать его в качестве параметра. Если все сказанное и кажется несколько странным, то только потому, что способ представления маршрутов в тексте кода создает впечатление, будто мы определяем действие, которое должно быть выполнено, с помощью URL-адреса. В действительности маршрут определяет URL-адрес, который может использоваться для получения доступа к одному или более шаблонов, а система динамических данных ASP.NET просматривает все определенные нами маршруты, чтобы выяснить, какие из них нужно вызвать для выполнения действий, требуемых для формирования шаблона.

Ограничение маршрута

Можно также применять маршруты только к одной таблице, предоставляя значение для свойства Table класса DynamicDataRoute. Измените маршрут в Global.asax следующим образом:

routes.Add(new DynamicDataRoute("AllRows.aspx")
{
    Action = PageAction.List,
    ViewName = "List",
    Model = DefaultModel,
    Table = "Products"
});

Выберите пункт Start Without Debugging в меню Debug. Результат должен быть похож на показанный на рисунке ниже:

Эффект ограничения единственного маршрута единственной таблицей

Показана только таблица Products. Это связано с тем, что единственный созданный маршрут теперь ограничивается таблицей Products. Вспомните, что система динамических данных ASP.NET ищет маршруты для каждого из действий CRUD в отношении каждой таблицы. В данном случае она нашла маршрут, который поддерживает действие List (чтение (read) в терминах CRUD) для таблицы Products. Поскольку никаких маршрутов не доступно для действий с другими таблицами, эти таблицы не могут быть показаны.

Если требуется создать маршрут, который применяется к нескольким действиям или таблицам, должно использоваться свойство Constraints, которое требует экземпляра класса RouteValueDictionary. Чтобы заставить маршрут работать для действий List и Details в отношении таблиц Products и Orders, понадобится воспользоваться свойством Constraints, как показано в следующем примере:

routes.Add(new DynamicDataRoute("{table}/{action}.aspx")
{
    Model = DefaultModel,
    Constraints = new RouteValueDictionary(
        new {
            action = "List|Details",
            table = "Products|Orders"
        })
});

Конструктору передается новый анонимный тип RouteValueDictionary, содержащий строковые свойства с именами свойств DynamicDataRoute, которые нужно установить. В отличие от свойств DynamicDataRoute, в RouteValueDictionary можно определять несколько значений, используя символ вертикальной черты в качестве разделителя. Созданный объект RouteValueDictionary присваивается свойству DynamicDataRoute.Constraints.

Этот маршрут представляет шаблоны List и Details для таблиц Products и Orders. Работать этот маршрут заставляют два небольших приема. Во-первых, при использовании подобных ограничений в формате URL-адреса нужно применять дескрипторы {table} и {action}; в противном случае система динамических данных ASP.NET не сможет правильно сформировать URL-адреса. Во-вторых, если свойство ViewName (определяющее имя шаблона страницы, который должен использоваться) опущено, по умолчанию имя шаблона устанавливается соответствующим имени действия. Таким образом, в этом маршруте действие List отображается на шаблон List.aspx, что и требуется.

Если сделать этот маршрут единственным в файле Global.asax и выбрать пункт Start Without Debugging в меню Debug, можно убедиться, что новый маршрут вступил в действие. Обе таблицы Orders и Products появятся в главном списке, а ссылки Details в списке строк будут работать.

Теперь вы знаете о маршрутах достаточно, чтобы понять маршрут по умолчанию, который был закомментирован в начале этой статьи:

routes.Add(new DynamicDataRoute("{table}/{action}.aspx") {
	Constraints = new RouteValueDictionary(
    	new { 
        	action = "List|Details|Edit|Insert" 
    }),
	Model = DefaultModel
});

Этот маршрут применяется ко всем таблицам (поскольку не существует никакого свойства Table или ограничения) и может использоваться для действий List, Details, Edit и Insert. Эти действия будут отображены на стандартные имена шаблонов страниц, и формат поддерживаемого маршрутом URL-адреса включает в себя как действие, так и имя таблицы, к которой он применяется.

Итак, теперь известно, как работают маршруты. Если что-либо осталось не совсем понятным, не беспокойтесь. Далее будут продемонстрированы другие примеры возможного применения маршрутов, которые помогут лучше понять их функционирование.

Переключение на режим одностраничного редактирования

При создании нового проекта динамических данных использовался файл Global.asax, содержащий три маршрута, два из которых закомментированы. В этом разделе мы изменим два маршрута по умолчанию, чтобы сменить режим редактирования сайта. Закомментируйте все маршруты в файле Global.asax, за исключением двух приведенных ниже, и сохраните изменения:

routes.Add(new DynamicDataRoute("{table}/ListDetails.aspx") {
    Action = PageAction.List,
    ViewName = "ListDetails",
    Model = DefaultModel
});

routes.Add(new DynamicDataRoute("{table}/ListDetails.aspx") {
    Action = PageAction.Details,
    ViewName = "ListDetails",
    Model = DefaultModel
});

Первый маршрут предоставляет шаблон ListDetails.aspx для использования с действием List в отношении всех таблиц. Второй маршрут предоставляет этот же шаблон для применения с действием Details, также в отношении всех таблиц. (Вспомните, что эти маршруты применяются ко всем таблицам, поскольку для свойств Table и Constraint значения не установлены.)

Эти маршруты могут показаться несколько странными. В конце концов, они указывают на один и тот же шаблон страницы, но поддерживают различные действия. А что происходит с другими действиями? Ответ полностью содержится в шаблоне. Шаблон страницы ListDetails.aspx обрабатывает все действия в рамках единственной страницы. Выберите пункт Start Without Debugging в меню Debug и удостоверьтесь в этом.

Щелкните на одном из имен таблиц, и отобразится знакомый список записей. Но достаточно щелкнуть на ссылке Edit, чтобы увидеть первое изменение. Теперь редактирование выполняется непосредственно в тексте, а не посредством обработки другим шаблоном страницы. Это же относится и к ссылке Select (Выбор); щелкните на ссылке Select в строке данных и прокрутите страницу вниз. Сведения о записи отобразятся в поле, расположенном под строками таблицы.

Причина использования двумя маршрутами одного и того же шаблона страницы заключается в том, что этот шаблон разработан для поддержки выполнения нескольких действий непосредственно в тексте. Причина того, что маршруты требуются только для действий Details и List, состоит в том, что остальные действия обрабатываются кодом Ajax в шаблоне страницы ListDetails. Приведенный пример наглядно демонстрирует, как можно сочетать функциональные возможности шаблона страницы и маршруты динамических данных.

Использование различных шаблонов для таблиц

Когда система динамических данных ASP.NET обрабатывает маршруты, она просматривает каждое из действий страницы для каждой из таблиц и прекращает поиск, найдя соответствие каждому из них. Это означает, что будет использоваться первый найденный маршрут, который поддерживает данное действие для конкретной таблицы. Эту особенность можно применять для точного управления использованием шаблонов. Измените содержимое файла Global.asax так, чтобы метод RegisterRoutes() выглядел следующим образом:

public static void RegisterRoutes(RouteCollection routes)
{
        DefaultModel.RegisterContext(typeof(NorthwindDataContext),
            new ContextConfiguration() { ScaffoldAllTables = true });

        // Маршрут 1
        routes.Add(
            new DynamicDataRoute("Products/{action}.aspx")
            {
                Constraints = new RouteValueDictionary(
                    new { action = "List|Details|Edit|Insert" }),
                Model = DefaultModel,
                Table = "Products"
            });

        // Маршрут 2
        routes.Add(
            new DynamicDataRoute("{table}/ListDetails.aspx")
            {
                Action = PageAction.List,
                ViewName = "ListDetails",
                Model = DefaultModel
            });

        // Маршрут 3
        routes.Add(
            new DynamicDataRoute("{table}/ListDetails.aspx")
            {
                Action = PageAction.Details,
                ViewName = "ListDetails",
                Model = DefaultModel
            });
}

Чтобы понять, какое влияние окажут эти маршруты, повторите процесс поиска, выполняемый системой динамических данных ASP.NET, просматривая каждое из действий для каждой таблицы в модели данных. Маршруты пронумерованы в комментариях внутри листинга.

Начнем с таблицы Customers. Просматривая список маршрутов, постарайтесь найти соответствие для действий Details, Edit, Insert и List. Маршрут 1 применяется только к таблице Products, поэтому в нем какое-либо соответствие отсутствует. Маршрут 2 применяется ко всем таблицам и поддерживает действие List - соответствие присутствует. Маршрут 3 применяется ко всем таблицам и поддерживает действие Details - еще одно соответствие. Для действий Edit и Insert никаких соответствий не существует.

Повторение процесса для таблиц Orders и Order_Details приводит к такому же результату. Маршрут 1 не имеет соответствий, но каждый из маршрутов 2 и 3 поддерживает одно из искомых действий.

Для таблицы Products получается другой результат. Маршрут 1 применяется к этой таблице (согласно значению свойства Table), и для каждого из четырех действий обнаруживается соответствие (благодаря значениям в RouteValueDictionary). Результаты этого просмотра приведены в таблице ниже:

Соответствие маршрутов по таблицам
Таблицы Действие Маршрут Шаблон страницы
Customers, Orders, Order_Details List 2 ListDetails.aspx
Customers, Orders, Order_Details Details 3 ListDetails.aspx
Customers, Orders, Order_Details Edit Соответствие отсутствует
Customers, Orders, Order_Details Insert Соответствие отсутствует
Products List 1 List.aspx
Products Details 1 Details.aspx
Products Edit 1 Edit.aspx
Products Insert 1 Insert.aspx

Выберите пункт Start Without Debugging в меню Debug и проанализируйте результаты. Если щелкнуть на таблице Products, она отобразится с применением многостраничных шаблонов, в результате чего редактирование или просмотр сведений о записях дает разные страницы. Другие таблицы используют одностраничный шаблон с поддержкой Ajax.

Использование маршрутов для сопоставления таблиц с шаблонами совместимо с созданием специальных шаблонов страниц. Маршруты определяют имя применяемого шаблона, но папка CustomTemplates по-прежнему проверяется на предмет существования специального шаблона. Для демонстрации этого создадим специальный шаблон для таблицы Orders.

Щелкните правой кнопкой мыши на папке DynamicData\CustomPages в окне Solution Explorer, выберите пункт New Folder (Новая папка) в контекстном меню и измените имя папки на Orders. Скопируйте файл List.aspx из папки DynamicData\PageTemplates и вставьте его в только что созданную папку Orders, чтобы окно Solution Explorer выглядело как на рисунке ниже:

Копирование шаблона страницы List.aspx

Отредактируйте скопированный шаблон так, чтобы он явно отличался от стандартного; мы добавили в него текстовое сообщение, как показано на рисунке ниже:

Изменение специального шаблона страницы

Теперь, имея специальный шаблон, можно определить маршруты. Замените метод RegisterRoutes() в файле Global.asax приведенным ниже кодом. Мы изменили маршрут 1, чтобы он поддерживал обе таблицы Products и Orders. Для этого потребовалось изменить также формат URL-адреса, на который отображается маршрут, чтобы система динамических данных ASP.NET могла использовать как имя таблицы, так и действие, не вступая в конфликт с форматами, на которые отображаются другие маршруты:

public static void RegisterRoutes(RouteCollection routes)
{
        DefaultModel.RegisterContext(typeof(NorthwindDataContext),
            new ContextConfiguration() { ScaffoldAllTables = true });

        // Маршрут 1
        routes.Add(
            new DynamicDataRoute("{table}/{action}.aspx")
            {
                Constraints = new RouteValueDictionary(
                    new { 
                        action = "List|Details|Edit|Insert",
                        table = "Products|Orders"
                    }),
                Model = DefaultModel
            });

        // ...
}

Выберите пункт Start Without Debugging в меню Debug. Если щелкнуть на таблице Customers или Order_Details, будет применяться одностраничный шаблон ListDetails.aspx. Щелчок на таблице Products приводит к использованию стандартного многостраничного шаблона List.aspx. Если же щелкнуть на таблице Orders, будет применяться недавно созданный специальный шаблон List.aspx:

Проверка использования специального шаблона страницы
Пройди тесты
Лучший чат для C# программистов