Pull to refresh

Comments 20

Можно поинтересоваться, что вас толкнуло к переезду на WebForms? К слову, у меня была тоже заметка про настройку кастомного роутинга, правда тогда была версия 1.0, да и я уже забыл практически все, что связано с ASP .NET MVC. Но, возможно, кому-нибудь пригодится.
Как раз таки наоборот — с WebForms переехали на MVC.
В большинстве случаев ни один менеджер не даст добро на перевозку работающего сайта на новые рельсы, а у нас просто настала глобальная перестройка проекта. И новую часть решили сделать с новыми технологиями.
Лично я не пожалел ни разу: MVC — рай для ленивых разработчиков.:)
Можите привести пример «нашего дружественного url», а то немного не понятна какую вы проблему решали.
В самом начале статьи привел — www.site.com/helloworld
Т.е. friendly-url, идущий сразу же за доменным именем, без возможности явного указания контроллера, что подразумевается в стандартном роутинге.
простите, но зачем огород городить?
вы в курсе, что можете добавлять свои правила роутинга? и вашу проблему «friendly ulr» можно решить, написав что-нибудь в стиле:
routes.MapRoute("YourHelloWorldRoute", "helloworld", new { controller = "Home", action = "Index" })
ага, насколько я помню, там просто нужно прописать ее в таблице рутов раньше дефолтного, чтобы он первым обрабатывал этот маршрут, как-то так…
С таким подходом придется создавать правило для каждой ссылки, не правда ли?
У меня их не одна и даже не десять.
ниже правильно пишут, что основная ваша проблема — это лишний запрос к базе данных при любом обращении к сайту, все правила нужно прописывать один раз. извините, но прежде чем подобным образом решать задачи, и тем более писать статью, нужно хотя бы немного ознакомиться с соответствующей литературой — вы в любой книжке по MVC найдете рассмотрения этого вопроса.
Ниже ответил, что у меня не каждый раз запрос к базе, а только когда ссылка не подходит под стандартный роутинг. Писать >50 правил в таблицу роутинга я считаю неприемлемым, а вы мне предлагаете именно это. Надо пользоваться более гибкими методами, мне кажется.

Я умею признавать свои ошибки, но для этого нужно указать более удачное решение.
Более удачное решение — таблицу роутинга в кэш и считывать из него, а не из БД
Велосипед с квадратными колесами. Автор не очень хорошо знаком с гибкостью роутинга в ASP.NET.
Можно начать с этого: www.asp.net/mvc/tutorials#Routing
Можете привести более удачное решение?
Есть, скажем, пятьдесят ссылок, каждая без возможности указать контроллер. Какие правила вы создадите в таблице роутинга?
Что значит «без возможности указать контроллер»?
Если это 50 ссылок на разные контроллеры/действия, то надо сделать 50 правил.
Вы просто переносите те же правила в БД. И у вас каждый раз будет лишний запрос к БД.
Не проще ли задать все правила при старте приложения, как это и предполагается?

routes.MapRoute(
    "helloworld",
    "helloworld",
    new { controller = "hello", action = "world" }
);

routes.MapRoute(
    "foobar",
    "foobar",
    new { controller = "foo", action = "bar" }
);

//...ваши 50 правил

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



А еще я против дефолтного правила. Оно позволяет, при желании, вызывать любые действия любых контроллеров, зная их названия. Даже если для этих действий предназначены совсем другие урлы. Этого допускать нельзя.
То есть вы считаете, что указать пятьдесят правил в глобал.асакс — это хорошее решение?
При таком подходе мы получаем необходимость править этот файл при малейшем изменении — это раз. И я не уверен, что такая дикая таблица роутинга хорошо скажется на производительности — прежде чем добраться до дефолтного правила, надо пройти другие 50. Не могу утверждать, но есть мнение, что времени процессору придется потратить не меньше, чем на запрос к базе.
А рассмотренное решение — гораздо более гибкое.

Проблемы с доступом к экшнам — совсем другая тема. Надо рассматривать детально, навскидку вспоминается NonActionAttribute — хотя всё зависит от того, что и как вы хотите ограничить.

И наконец самое главное — у меня не каждый раз лишний запрос к БД, а только тогда, когда ссылка не подходит под дефолтное правило. Я об этом также написал.
>То есть вы считаете, что указать пятьдесят правил в глобал.асакс — это хорошее решение?
>При таком подходе мы получаем необходимость править этот файл при малейшем изменении — это раз.

Не обязательно в global.asax. Вы можете придумать удобную абстракцию для заполнения RouteTable.
Смысл в том, чтобы таблица заполнилась правилами во время запуска приложения.
Если вам надо часто менять роутинг без релиза (в чем я очень сомневаюсь), вы можете вынести класс, заполняющий таблицу, в отдельную сборку, чтобы легко ее заменять на продакшн сервере.

>И я не уверен, что такая дикая таблица роутинга хорошо скажется на производительности —
>прежде чем добраться до дефолтного правила, надо пройти другие 50. Не могу утверждать, но
>есть мнение, что времени процессору придется потратить не меньше, чем на запрос к базе.

Могу утверждать, что запрос к БД медленнее, чем работа с памятью приложения. А еще при проблемах с доступом к БД ваше приложение даже не сможет узнать какое действие вызвать. Значит вы не сможете реализовать разную логику обработки этого исключения для разных действий.

>А рассмотренное решение — гораздо более гибкое.

Оно менее гибкое потому, что позволяет задать только контроллер, фильтр и один параметр.
В реальной жизни в урлах бывает больше параметров.

>Проблемы с доступом к экшнам — совсем другая тема. Надо рассматривать детально, навскидку
>вспоминается NonActionAttribute — хотя всё зависит от того, что и как вы хотите ограничить.

routes.MapRoute(
    "helloworld",
    "helloworld",
    new { controller = "hello", action = "world" }
);

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

/*
* имеем два урла для одного действия:
*  /helloworld
*  /hello/world
*/

Если для каждой ссылки я буду прописывать правило (опустим детали реализации), то при обращении к MVC-урлам придется пройти все 50 правил, потому что они будут выше в таблице — и мне это видится не очень хорошим подходом.

Возможность работы в базе мне изначально нужна для CMS-ности — контент я также беру из базы, поэтому при проблемах доступа к ней я так и так не получу содержимого.
Таким образом, я могу сделать админку для отдела маркетинга, который сможет насиловать эти ссылки, как им заблагорассудится, без релиза и вообще моего участия. В этом и гибкость, о которой я говорил.
Даже если сделать вытягивание правил из базы при старте приложения, каждое изменение будет требовать рестарта приложения, а этого ответственный за контент делать не умеет.

> В реальной жизни в урлах бывает больше параметров.
Request.Param тоже не запретили, поэтому можно и их продолжать использовать. Более того, можно расширить это решение под конкретные проблемы, я не утверждал, что приведенный подход универсальный — наоборот, для вполне конкретных задач.

Собственно, мы с вами говорим о разных степенях гибкости — я хочу, чтобы сайтом можно было управлять без моего участия как программиста. В этом прелесть CMS и для этого данное решение очень подходит.
Пройти 50 правил быстрее, чем сделать запрос к БД. Количество должно быть гораздо больше, чтобы издержки на запрос к базе стали меньшими, чем цикл по объектам в памяти. Едва ли у вас будет столько страниц.

Вы можете легко обновлять роутинг без перезапуска приложения.
RouteCollection реализует ICollection.
Есть сомнения, но нет времени проверить. Единственное, что нашел по поводу изменения роутинга на лету, а не в Application_Start:

Hmm, I'm starting to think this might be true — debugging through the code, it looks like RouteTable.Routes.Add() successfully increases the number of routes, but apparently only for that Request cycle. It doesn't seem to persist it to the RouteTable that's used throughout the app.


Так что если это действительно так, и формирование таблицы роутинга доступно только при старте приложения, предложенный вами вариант всё же не подходит для CMS, управляемой не-программистами.
Стивен Сандерсон предлагает следующее в своей книге:

routes.MapRoute(null,
«Page{page}», // Matches /Page2, /Page123, but not /PageXYZ
new { controller = «Product», action = «List», category = (string)null },
new { page = @"\d+" } // Constraints: page must be numerical
);

routes.MapRoute(null,
"{category}", // Matches /Football or /AnythingWithNoSlash
new { controller = «Product», action = «List», page = 1 }
);

Смысл думаю понятен, выглядит гораздо проще в реализации… У Вас не будет указания страниц и параметром будет строка.
Хорошее решение, но опять не подошло в данной ситуации.
Дело в том, что мне необходимо оставить дефолтный роутинг для остальных контроллеров.
В связи с этим возникает загвоздка: варианты со значением по умолчанию получаются по формату такими же, как и friendly — не обязательно же вводить /Home/Index — можно ввести только /Home и это должно оставаться валидной ссылкой.

Как бы то ни было, возможность указать регулярное выражение в роутинге — замечательная опция. Спасибо.
Sign up to leave a comment.

Articles