+7 (495) 229-0436   shopadmin@itshop.ru 119334, г. Москва, ул. Бардина, д. 4, корп. 3
 
 
Вход
 
 
Каталог
 
 
Подписка на новости
Новости ITShop
Windows 7 и Office: Новости и советы
Обучение и сертификация Microsoft
Вопросы и ответы по MSSQLServer
Delphi - проблемы и решения
Adobe Photoshop: алхимия дизайна
 
Ваш отзыв
Оцените качество магазина ITShop.ru на Яндекс.Маркете. Если вам нравится наш магазин - скажите об этом Google!
 
 
Способы оплаты
 
Курс расчета
 
 1 у.е. = 91.78 руб.
 
 Цены показывать:
 
 
 
 
  
Новости, статьи, акции
 

"Классические" friendly url в ASP.NET MVC

18.11.2011 14:36

Речь пойдет о том, как сделать ссылки типа www.site.com/helloworld в ASP.NET MVC-приложении. Слышу возмущенные возгласы "зачем это надо?" и "чем тебя не устраивает нормальный человеческий роутинг?" и у меня по этому поводу заготовлен ответ.

 Дело в том, что наш проект переезжает на MVC с Web Forms, и контекстная реклама уже давно оплачена. Routing - прекрасная вещь, однако, учитывая, что сайт состоит не только из приземляющих страниц, мы не можем так по-хитрому его настроить, чтобы продолжали работать и обычные MVC-ссылки /Controller/Action, и наши невероятно дружественные URL'ы. Причина проста: дефолтный роутинг ("{controller}/{action}/{id}", new { controller = "Default", action = "Index", id = UrlParameter.Optional }) предполагает значения по умолчанию, поэтому при обращении к www.site.com/helloworld нас попытаются перекинуть на контроллер helloworld в экшн Index.
 Печаль.
 Придется что-то делать. Причем вариант с созданием контроллера для каждой ссылки нас явно не устроит - их тьма, да и в целом это порнография, правда?

 Мы пойдем другим путём.


Концепция

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

Модель

 

Вот так просто и незатейливо. ContentID здесь внешний ключ, однако при желании можно использовать VARCHAR(MAX) и писать контент сразу здесь. У нас такая реализация обусловлена тем, что контент поделен на куски (основной контент, title, мета-тег description...) - SEO, сами понимаете.


Реализация

 Основа реализации заключается вот в чем:


routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Default", action = "Index", id = UrlParameter.Optional }
).RouteHandler = new FriendlyUrlRouteHandler();

 К нашему роутеру мы приделываем хендлер (наследник MvcRouteHandler), который обрабатывает уже готовые значения. То есть сначала механизм роутинга разберется со ссылкой, заполнит значения по умолчанию, потом мы вступим в дело и при необходимости заменим значения на наши.

    public class FriendlyUrlRouteHandler : MvcRouteHandler
    {
        private static readonly Regex TypicalLink = new Regex("^.+/.+(/.*)?");

        protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            // Path для www.site.com/helloworld?id=1 будет равняться /helloworld
            // поэтому мы убираем начальный слэш
            var url = requestContext.HttpContext.Request.Path.TrimStart('/');

            if (!string.IsNullOrEmpty(url) && !TypicalLink.IsMatch(url))
            {
                PageItem page = RedirectManager.GetPageByFriendlyUrl(url);
                if (page != null)
                {
                    FillRequest(page.ControllerName,
                        page.ActionName ?? "GetStatic",
                        page.ID.ToString(),
                        requestContext);
                }
            }

            return base.GetHttpHandler(requestContext);
        }

        /// <summary> Заполнение request-контекста данными о контроллере, экшне и параметрах </summary>
        private static void FillRequest(string controller, string action, string id, RequestContext requestContext)
        {
            if (requestContext == null)
            {
                throw new ArgumentNullException("requestContext");
            }

            requestContext.RouteData.Values["controller"] = controller;
            requestContext.RouteData.Values["action"] = action;
            requestContext.RouteData.Values["id"] = id;
        }
    }


 Я использую в качестве параметра ID записи, и при загрузке страницы использую вьюху, которая состоит из join'а нескольких таблиц. Если не нужны подобные заморочки, можно просто передавать в качестве параметра ContentID, а не id всей записи.

 По умолчанию используется экшн GetStatic, который определен как виртуальный в нашем базовом классе для контроллеров. В конкретном контроллере он берет текст страницы из базы, и генерирует страничку с учетом особенностей и layout'ов раздела.


    public abstract class BaseController : Controller
    {
        /// <summary> Получение страницы из базы </summary>
        public virtual ActionResult GetStatic(int id)
        {
            return HttpNotFound();
        }
    }


 И наконец сам механизм редиректа. Признаться, уже не помню, почему я вынес его в отдельный класс. С другой стороны, почему бы и нет.
    public static class RedirectManager
    {
        public static PageItem GetPageByFriendlyUrl(string friendlyUrl)
        {
            PageItem page = null;

            using (var cmd = new SqlCommand())
            {
                cmd.Connection = new SqlConnection(/*YourConnectionString*/);
                cmd.CommandText = "select * from FriendlyUrl where FriendlyUrl = @FriendlyUrl";
                cmd.Parameters.Add("@FriendlyUrl", SqlDbType.NVarChar).Value = friendlyUrl.TrimEnd('/');

                cmd.Connection.Open();
                using (var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
                {
                    if (reader.Read())
                    {
                        page = new PageItem
                                   {
                                       ID = (int) reader["Id"],
                                       ControllerName = (string) reader["ControllerName"],
                                       ActionName = (string) reader["ActionName"],
                                       FriendlyUrl = (string) reader["FriendlyUrl"],
                                   };
                    }
                }

                return page;
            }
        }
    }

 

Результат

 В конечном итоге мы получили именно то, к чему стремились. После заполнения базы у нас заработал редирект на правильные страницы, причем в адресной строке ничего не меняется, и мы получаем 200 OK без дополнительных плясок.

 Конечно, ситуация в достаточной степени нетипичная - в большинстве случаев стандартного роутинга более чем достаточно: можно сделать контроллер, например, Static, который также по URL будет забирать данные из базы. Но если контекстная реклама уже оплачена, или просто есть дикое желание сделать ссылки, в которых ни одного лишнего слэша, описанный вариант, на мой взгляд, весьма пригодный.

 В конце концов, мы поставили задачу, и благополучно с ней справились.

Ссылки по теме

  
Помощь
Задать вопрос
 программы
 обучение
 экзамены
 компьютеры
Бесплатный звонок
ICQ-консультанты
Skype-консультанты

Общая справка
Как оформить заказ
Тарифы доставки
Способы оплаты
Прайс-лист
Карта сайта
 
Бестселлеры
Курсы обучения "Atlassian JIRA - система управления проектами и задачами на предприятии"
Microsoft Windows 10 Профессиональная 32-bit/64-bit. Все языки. Электронный ключ
Microsoft Office для Дома и Учебы 2019. Все языки. Электронный ключ
Курс "Oracle. Программирование на SQL и PL/SQL"
Курс "Основы TOGAF® 9"
Microsoft Office 365 Персональный 32-bit/x64. 1 ПК/MAC + 1 Планшет + 1 Телефон. Все языки. Подписка на 1 год. Электронный ключ
Курс "Нотация BPMN 2.0. Ее использование для моделирования бизнес-процессов и их регламентации"
 

О нас
Интернет-магазин ITShop.ru предлагает широкий спектр услуг информационных технологий и ПО.

На протяжении многих лет интернет-магазин предлагает товары и услуги, ориентированные на бизнес-пользователей и специалистов по информационным технологиям.

Хорошие отзывы постоянных клиентов и высокий уровень специалистов позволяет получить наивысший результат при совместной работе.

В нашем магазине вы можете приобрести лицензионное ПО выбрав необходимое из широкого спектра и ассортимента по самым доступным ценам. Наши менеджеры любезно помогут определиться с выбором ПО, которое необходимо именно вам. Также мы проводим учебные курсы. Мы приглашаем к сотрудничеству учебные центры, организаторов семинаров и бизнес-тренингов, преподавателей. Сфера сотрудничества - продвижение бизнес-тренингов и курсов обучения по информационным технологиям.



 

О нас

 
Главная
Каталог
Новинки
Акции
Вакансии
 

Помощь

 
Общая справка
Как оформить заказ
Тарифы доставки
Способы оплаты
Прайс-лист
Карта сайта
 

Способы оплаты

 

Проекты Interface Ltd.

 
Interface.ru   ITShop.ru   Interface.ru/training   Olap.ru   ITnews.ru  
 

119334, г. Москва, ул. Бардина, д. 4, корп. 3
+7 (495) 229-0436   shopadmin@itshop.ru
Проверить аттестат
© ООО "Interface Ltd."
Продаем программное обеспечение с 1990 года