Как маршрутизировать древовидные URL с помощью ASP.NET Routing? - PullRequest
6 голосов
/ 23 мая 2010

Я хотел бы добиться чего-то очень похожего на этот вопрос , с некоторыми улучшениями.

Есть веб-приложение ASP.NET MVC.

У меня естьдерево сущностей.
Например, класс Page, который имеет свойство Children с типом IList<Page>.(Экземпляр класса Page соответствует строке в базе данных.)

Обратите внимание, что владельцы сайта могут добавлять новые страницы в любое время или удалять существующие, и URL-адреса должны отражать эти изменения.а также.

Я хотел бы назначить уникальный URL-адрес каждому Page в базе данных.
Я обрабатываю Page объекты с помощью контроллера с именем PageController.

Примеры URL:

http://mysite.com/Page1/
http://mysite.com/Page1/SubPage/
http://mysite.com/Page/ChildPage/GrandChildPage/

Вы получаете изображение.
Итак, я бы хотел, чтобы у каждого объекта Page был свой собственный URL, равный URL его родительского элемента плюсего собственное имя.
В дополнение к этому, мне также хотелось бы иметь возможность сопоставить один Page с / (корневым) URL.

Я хотел бы применить этиправила:

  1. Если URL-адрес может быть обработан любым другим маршрутом или файл существует в файловой системе по указанному URL-адресу, разрешите сопоставление URL-адреса по умолчанию
  2. ЕслиURL может быть обработан поставщиком виртуального пути, пусть это обрабатывает
  3. Если нет другого,сопоставьте другие URL-адреса с PageController классом

Я также нашел этот вопрос , также этот и этот , но они не очень помогли, так как не дают объяснения о моих первых двух пунктах.

Я вижу следующие возможные решения:

  • Отображение маршрута для каждой страницы индивидуально.
    Для этого требуется, чтобы я прошел по всему дереву при запуске приложения и добавил маршрут с точным соответствием в конец таблицы маршрутов.
  • Я мог бы добавитьмаршрут с {*path} и написать пользовательский IRouteHandler, который его обрабатывает, но я не вижу, как я мог тогда справиться с первыми двумя правилами, так как этот обработчик мог бы обрабатывать все.

Пока что первое решение кажется правильным, потому что оно также самое простое.Но, тем не менее, даже в этом случае я не уверен, как можно заставить PageController обрабатывать запросы.

Буду очень признателен за ваши мысли по этому поводу.

Заранее спасибо!

РЕДАКТИРОВАТЬ: Теперь у меня было время изучить все аспекты каждого ответа, который я получил.Я принял ответ Нила, так как он дает лучшее объяснение того, как все работает.Я также проголосовал за все остальные ответы, так как они дают хорошие идеи.

Ответы [ 4 ]

3 голосов
/ 31 мая 2010

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

По умолчанию маршрутизация MVC будет направлять к существующим файлам до применения любых маршрутов, хранящихся в коллекции маршрутов; см. http://msdn.microsoft.com/en-us/library/system.web.routing.routecollection.routeexistingfiles.aspx. (подсказка Павлу - см. комментарии).

Чтобы направить запросы на контроллер страницы, просто создайте пользовательский маршрут, который проверяет виртуальный путь, и, если он соответствует шаблону для страницы в базе данных, возвращает RouteData. Настройте RouteData с соответствующими значениями, извлеченными из виртуального пути (например, установите ключ Path в / Parent / Child / Grandchild), установите ключ контроллера в качестве имени контроллера вашей страницы (например, Page), а в качестве действия - имя действие, которое вы хотите выполнить (например, Показать). RouteData должен быть создан с MvcRouteHandler (не уверен, что это правильное имя класса).

Чтобы обеспечить правильное возвращение URL-адресов на страницы, управляемые вашей базой данных, переопределите метод GetVirtualPath( RequestContext, RouteValueDictionary ) для RouteBase и используйте переданные значения маршрута, чтобы определить, является ли это страницей, управляемой базой данных, и создает ли она виртуальный путь. данные требуются (или возвращают ноль в противном случае).

Для получения справки по переопределению GetRouteData и GetVirtualPath посмотрите на отраженный исходный код System.Web.Routing.RouteBase и System.Web.Routing.Route; после этого Google твой друг.

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

1 голос
/ 07 июня 2010

Вы можете использовать шаблон "Page/{*path}". Затем вы можете либо разложить путь, разделив строку на ‘/’ и пройтись по ней, либо вы можете использовать предложение Раруша о сохранении [сгенерированного] пути в БД и выполнить прямой поиск.

Если вы используете метод Rarouš, вам придется обновлять записи пути в вашей таблице для всех дочерних элементов при изменении родительского пути. Это можно сделать достаточно просто с помощью одного запроса на обновление.

Я предполагаю, что вы отображаете страницу, которую хотите использовать для домашней страницы, где-то в файле конфигурации или записи таблицы. Вы можете попросить контроллер домашней страницы выполнить поиск и вернуть содержимое для представления домашней страницы для визуализации (вы можете использовать общее представление, частичное представление или вызов в контроллер страницы, чтобы не дублировать поведение), или Вы можете перенаправить его на эту страницу.

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

Ваш путь будет выглядеть так:

http://mysite.com/Page/Page1/ 
http://mysite.com/Page/Page1/SubPage/ 
http://mysite.com/Page/Page/ChildPage/GrandChildPage/ 

Конечно, вы можете использовать префикс, отличный от "Page".

1 голос
/ 05 июня 2010

Вы знаете структуру своих страниц при сохранении страницы. Таким образом, вы можете сгенерировать URL для каждой страницы и сохранить его в записи базы данных. Тогда вы можете использовать {*path} правило и найти точное совпадение в базе данных. Это правило должно быть последним в определении правил, чтобы вы могли сопоставлять другие маршруты.

Например, у вашего Page1 нет родительской страницы, это URL Page1. Ваш SubPage знает, что является его родителем, поэтому он может преобразовать URL Page1/SubPage и т. Д.

1 голос
/ 23 мая 2010

Еще одна идея - использовать T4 (Text Template Transformation Toolkit), чтобы один раз прочитать «Дети» и сгенерировать содержимое файла Global.asax.

РЕДАКТИРОВАТЬ: В основном с T4 вы можете автоматизировать генерацию текстовых файлов. Например, вместо того, чтобы вручную копировать элементы некоторой огромной коллекции и вставлять их с определенным контекстом в текстовый файл (например, INSERT INTO [MyTable] (Text) VALUES (@ItemText)), вы можете заставить механизм T4 читать коллекцию и генерировать эти операторы вставки для вас. Он статичен и не предназначен для времени выполнения.

Я считаю, что очень хорошее введение доступно из Pro Entity Framework 4.0 книги.

Но если вы говорите, что вам нужно сделать это динамически, это может быть не для вас инструментом.

...