ASP.NET MVC - перехватывать все маршруты и маршруты по умолчанию
Пытаясь заставить мое приложение корректно выдавать 404 ошибки, я реализовал перехват всех маршрутов в конце таблицы маршрутов, как показано ниже:
routes.MapRoute(
"NotFound", _
"{*url}", _
New With {.controller = "Error", .action = "PageNotFound"} _
)
Однако, чтобы это работало, мне пришлось удалить маршрут по умолчанию:
{controller}/action/{id}
Но теперь, когда значение по умолчанию было удалено, большинство моих ссылок действий больше не работают, и я нашел единственный способ заставить их работать снова, это добавить индивидуальные маршруты для каждого контроллера / действия.
Есть ли более простой способ сделать это, вместо добавления маршрута для каждого контроллера / действия?
Можно ли создать маршрут по умолчанию, который все еще позволяет перехватывать весь маршрут, если пользователь пытается перейти к неизвестному маршруту?
9 ответов
Используйте ограничения маршрута
В вашем случае вы должны определить маршрут по умолчанию {controller}/{action}/{id}
и наложить на это ограничение. Вероятно, связано с именами контроллеров или, возможно, даже действиями. Затем поместите защелку один за другим, и она должна работать нормально.
Поэтому, когда кто-то запрашивает ресурс, который не соответствует ограничению, маршрут перехвата будет соответствовать запросу.
Так. Сначала определите маршрут по умолчанию с ограничениями маршрута, а затем перехватите весь маршрут после него:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { controller = "Home|Settings|General|..." } // this is basically a regular expression
);
routes.MapRoute(
"NotFound",
"{*url}",
new { controller = "Error", action = "PageNotFound" }
);
//this catches all requests
routes.MapRoute(
"Error",
"{*.}",
new { controller = "PublicDisplay", action = "Error404" }
);
добавить этот маршрут в конец таблицы маршрутов
Ах, проблема в том, что ваш маршрут по умолчанию перехватывает все 3 сегмента URL. Проблема здесь в том, что маршрутизация выполняется до того, как мы определим, кто будет обрабатывать запрос. Таким образом, любой трехсегментный URL будет соответствовать маршруту по умолчанию, даже если позже он закончится тем, что нет контроллера, который мог бы обработать его.
Одна вещь, которую вы можете сделать, это переопределить ваш метод HandleMissingAction на вашем контроллере. Вы также должны использовать тег, чтобы поймать все 404 проблемы.
Ну, я обнаружил, что нет хорошего способа сделать это. Я установил redirectMode
собственность customErrors
в ResponseRewrite
,
<customErrors mode="On" defaultRedirect="~/Shared/Error" redirectMode="ResponseRewrite">
<error statusCode="404" redirect="~/Shared/PageNotFound"/>
</customErrors>
Это дает мне требуемое поведение, но не отображает отформатированную страницу.
Для меня это плохо сделано, насколько SEO идет. Тем не менее, я чувствую, что есть решение, которое мне не хватает, так как SO делает именно то, что я хочу достичь. URL остается на сбойной странице и выдает 404. Проверьте stackru.com/fail в Firebug.
Мое решение - 2 шага.
Первоначально я решил эту проблему, добавив эту функцию в мой файл Global.asax.cs:
protected void Application_Error(Object sender, EventArgs e)
Где я попытался привести Server.GetLastError() к HttpException, а затем проверил GetHttpCode. Это решение подробно описано здесь:
Обработка пользовательских ошибок ASP.NET MVC Application_Error Global.asax?
Это не оригинальный источник, где я получил код. Однако это ловит только 404 ошибки, которые уже были маршрутизированы. В моем случае это любой двухуровневый URL.
например, эти URL будут отображать страницу 404:
www.site.com/blah
www.site.com/blah/blah
однако, www.site.com/blah/blah/blah просто сказал бы, что страница не может быть найдена. Добавление вашего улова на весь маршрут ПОСЛЕ всех моих других маршрутов решило это:
routes.MapRoute(
"NotFound",
"{*url}",
new { controller = "Errors", action = "Http404" }
);
Однако маршрут NotFound, по-видимому, не направляет запросы с расширениями файлов. Это работает, когда они захвачены разными маршрутами.
Я бы порекомендовал это как наиболее читаемую версию. Это необходимо в вашем RouteConfig.cs и контроллере ErrorController.cs, содержащем действие "PageNotFound". Это может вернуть вид. Создайте PageNotFound.cshtml, и он будет возвращен в ответ на 404:
routes.MapRoute(
name: "PageNotFound",
url: "{*url}",
defaults: new { controller = "Error", action = "PageNotFound" }
);
Как читать это:
name: "PageNotFound"
= создать новый шаблон маршрута с произвольным именем "PageNotFound"
url:"{*url}"
= использовать этот шаблон для сопоставления всех необработанных маршрутов
defaults: new { controller = "Error", action = "PageNotFound" }
= определить действие, которому будет соответствовать неверный путь (метод действия PageNotFound в контроллере ошибок). Это необходимо, поскольку неверно введенный путь, очевидно, не будет сопоставлен ни с каким методом действия.
Я попробовал все вышеперечисленные шаблоны безуспешно, но в конце концов обнаружил, что ASP.NET рассматривает URL-адрес, который я использовал, как статический файл, поэтому ни один из моих запросов не скрывал конечную точку с одним контроллером. Я закончил тем, что добавил этот снайпер в web.config
<modules runAllManagedModulesForAllRequests="true"/>
А затем используйте приведенный ниже шаблон сопоставления маршрутов, и он решил проблему:
routes.MapRoute(
name: "RouteForAnyRequest",
url: "{*url}",
defaults: new { controller = "RouteForAnyRequest", action = "PageNotFound" }
);
Если вы ищете ASP.NET Core поймать все маршруты и искать в Google asp.net core catch all route
приводит вас сюда:
Ядро ASP.net MVC ловит весь маршрут обслуживает статический файл
Возможно, вам лучше настроить документ об ошибке 404 в разделе конфигурации, а затем восстановить маршрут по умолчанию.
FWIW, я думаю, что требование маршрута по умолчанию тоже задерживается.