asp.net-mvc
маршрутизация
Поиск…
Вступление
Маршрутизация - это то, как ASP.NET MVC сопоставляет URI с действием. Модуль маршрутизации отвечает за сопоставление входящих запросов браузера с конкретными действиями контроллера MVC.
MVC 5 поддерживает новый тип маршрутизации, называемый маршрутизацией атрибутов. Как следует из названия, маршрутизация атрибутов использует атрибуты для определения маршрутов. Маршрутизация атрибутов дает вам больше контроля над URI в вашем веб-приложении.
Пользовательская маршрутизация
Пользовательская маршрутизация обеспечивает специализированную потребность в маршрутизации для обработки определенных входящих запросов.
Чтобы определить пользовательские маршруты, имейте в виду, что порядок маршрутов, который вы добавляете в таблицу маршрутов, важен.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// this is an advanced custom route
// you can define custom URL with custom parameter(s) point to certain action method
routes.MapRoute(
"CustomEntry", // Route name
"Custom/{entryId}", // Route pattern
new { controller = "Custom", action = "Entry" } // Default values for defined parameters above
);
// this is a basic custom route
// any custom routes take place on top before default route
routes.MapRoute(
"CustomRoute", // Route name
"Custom/{controller}/{action}/{id}", // Route pattern
new { controller = "Custom", action = "Index", id = UrlParameter.Optional } // Default values for defined parameters above
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // Route pattern
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Default values for defined parameters above
);
}
controller
и имена action
зарезервированы. По умолчанию MVC отображает {controller}
часть URL-адреса <controller>Controller
класса <controller>Controller
, а затем ищет метод с именем <action>
без добавления каких-либо суффиксов.
Хотя может возникнуть соблазн создать семейство маршрутов с использованием шаблона {controller}/{action}/{parameter}
подумайте, что, делая это, вы раскрываете структуру своего приложения и делаете URL-адреса несколько хрупкими, потому что изменение имени контроллера изменяет маршрут и разрывает ссылки, сохраненные пользователем.
Предпочитают явные настройки маршрута:
routes.MapRoute(
"CustomRoute", // Route name
"Custom/Index/{id}", // Route pattern
new { controller = "Custom", action = nameof(CustomController.Index), id = UrlParameter.Optional }
);
(вы не можете использовать оператор nameof
для имени контроллера, так как он будет иметь дополнительный суффикс- Controller
), который должен быть опущен при установке имени контроллера на маршруте.
Добавление настраиваемого маршрута в Mvc
Пользователь может добавить собственный маршрут, сопоставляя URL-адрес с определенным действием в контроллере. Это используется для оптимизации поисковой системы и чтения URL-адресов.
routes.MapRoute(
name: "AboutUsAspx", // Route name
url: "AboutUs.aspx", // URL with parameters
defaults: new { controller = "Home", action = "AboutUs", id = UrlParameter.Optional } // Parameter defaults
);
Маршрутизация атрибутов в MVC
Наряду с классическим способом определения маршрута MVC WEB API 2, а затем структуры MVC 5 ввели Attribute routing
:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// This enables attribute routing and must go before other routes are added to the routing table.
// This makes attribute routes have higher priority
routes.MapMvcAttributeRoutes();
}
}
Для маршрутов с одним и тем же префиксом внутри контроллера вы можете установить общий префикс для всех методов действий внутри контроллера, используя атрибут RoutePrefix
.
[RoutePrefix("Custom")]
public class CustomController : Controller
{
[Route("Index")]
public ActionResult Index()
{
...
}
}
RoutePrefix
является необязательным и определяет часть URL-адреса, которая имеет префикс для всех действий контроллера.
Если у вас несколько маршрутов, вы можете установить маршрут по умолчанию, выполнив действие как параметр, затем примените его для всего контроллера, если только определенный атрибут Route
определен для определенных методов (-ов) действия, которые переопределяют маршрут по умолчанию.
[RoutePrefix("Custom")]
[Route("{action=index}")]
public class CustomController : Controller
{
public ActionResult Index()
{
...
}
public ActionResult Detail()
{
...
}
}
Основы маршрутизации
Когда вы запрашиваете url yourSite/Home/Index
через браузер, модуль маршрутизации направляет запрос методу действия Index
класса HomeController
. Как известно, чтобы отправить запрос на конкретный метод этого конкретного класса? появляется RouteTable.
Каждое приложение имеет таблицу маршрутов, в которой хранится шаблон маршрута и информация о том, куда направлять запрос. Поэтому, когда вы создаете приложение mvc, в маршрутной таблице уже указан маршрут по умолчанию. Вы можете видеть это в классе RouteConfig.cs
.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("Default", "{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
}
Вы можете видеть, что запись имеет имя и шаблон. Шаблон - это шаблон маршрута, который нужно проверить при входе запроса. В шаблоне по умолчанию Home
как значение сегмента URL-адреса контроллера, а Index
как значение для сегмента действия. Это означает, что если вы явно не передаете имя контроллера и действие в свой запрос, оно будет использовать эти значения по умолчанию. Именно по этой причине вы получаете тот же результат, когда yourSite/Home/Index
доступ к yourSite/Home/Index
и yourSite
Возможно, вы заметили, что у нас есть параметр, называемый id, как последний сегмент нашего шаблона маршрута. Но в настройках по умолчанию мы указываем, что это необязательно. Именно по этой причине нам не нужно было указывать значение id, которое мы попробовали.
Теперь вернитесь к методу действия индекса в HomeController и добавьте параметр к этому
public ActionResult Index(int id)
{
return View();
}
Теперь поставьте контрольную точку визуальной студии в этом методе. Запустите проект и получите доступ к yourSite/Home/Index/999
в вашем браузере. Точка останова будет удалена, и вы сможете увидеть, что значение 999 теперь доступно в параметре id
.
Создание второго шаблона маршрута
Предположим, мы хотели бы настроить его таким образом, чтобы тот же метод действий был вызван для другого шаблона маршрута. Мы можем это сделать, добавив новое определение маршрута в таблицу маршрутов.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// New custom route definition added
routes.MapRoute("MySpecificRoute",
"Important/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
//Default catch all normal route definition
routes.MapRoute("Default", "{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
}
Новое определение, которое я добавил, имеет шаблон Important/{id}
где id снова является необязательным. Это означает, что при запросе yourSiteName\Important
или yourSiteName\Important\888
он будет отправлен в действие Index HomeController.
Порядок определения определения маршрута
Важен порядок регистрации маршрута. Вы должны всегда регистрировать определенные шаблоны маршрутов перед общим маршрутом по умолчанию.
Поймать весь маршрут
Предположим, мы хотим иметь маршрут, который позволяет несвязанное количество сегментов, например:
- http://example.com/Products/ (просмотреть все продукты)
- http://example.com/Products/IT
- http://example.com/Products/IT/Laptops
- http://example.com/Products/IT/Laptops/Ultrabook
- http://example.com/Products/IT/Laptops/Ultrabook/Asus
- и т.п.
Нам нужно будет добавить маршрут, обычно в конце таблицы маршрутов, потому что это, вероятно, поймает все запросы, например:
routes.MapRoute("Final", "Route/{*segments}",
new { controller = "Product", action = "View" });
В контроллере действие, которое может справиться с этим, может быть:
public void ActionResult View(string[] segments /* <- the name of the parameter must match the name of the route parameter */)
{
// use the segments to obtain information about the product or category and produce data to the user
// ...
}
Маршрут Catch-all для включения маршрутизации на стороне клиента
Хорошей практикой является кодирование состояния Single Page Application (SPA) в URL-адресе:
my-app.com/admin-spa/users/edit/id123
Это позволяет сохранять и совместно использовать состояние приложения.
Когда пользователь помещает URL-адрес в адресную строку браузера и попадает на сервер входа, он должен игнорировать клиентскую часть запрошенного URL-адреса. Если вы обслуживаете свой SPA как визуализированный вид Razor (результат действия контроллера вызова), а не статический html-файл, вы можете использовать весь маршрут:
public class AdminSpaController
{
[Route("~/admin-spa/{clienSidePart*}")]
ActionResult AdminSpa()
{
...
}
}
В этом случае сервер возвращает только SPA, а затем инициализирует себя в соответствии с маршрутом. Этот подход более гибкий, поскольку он не зависит от модуля url-rewrite .
Маршрутизация атрибутов в областях
Для использования маршрутизации атрибутов в областях [RouteArea(...)]
регионы регистрации и определения [RouteArea(...)]
.
В RouteConfig.cs
:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
AreaRegistration.RegisterAllAreas();
}
}
В определении маршрутизации атрибута области выборки:
[RouteArea("AreaName", AreaPrefix = "AreaName")]
[RoutePrefix("SampleAreaController")]
public class SampleAreaController : Controller
{
[Route("Index")]
public ActionResult Index()
{
return View();
}
}
Для использования ссылок Url.Action
в регионах:
@Url.Action("Index", "SampleAreaController", new { area = "AreaName" })