Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7
В прошлой теме были рассмотрены базовые моменты работы с маршрутов. Теперь рассмотрим различные способы определения маршрутов.
Для добавления маршрута в прошлой теме использовался метод MapRoute()
. Он имеет ряд перегруженных версий, которые позволяют установить различные параметры:
MapRoute(string template, RequestDelegate handler)
: устанавливает маршрут с шаблоном template, который будет обрабатываться делегатом handler
MapRoute(string name, string template)
: устанавливает маршрут с именем name и шаблоном template
MapRoute(string name, string template, object defaults)
: добавляет значения по умолчанию в виде объекта defaults
MapRoute(string name, string template, object defaults, object constraints)
: добавляет ограничения к маршруту в виде объекта constraints
MapRoute(string name, string template, object defaults, object constraints, object dataTokens)
: добавляет токены в виде объекта dataTokens
Так первая версия позволяет сразу задать обработчик маршрута для определенного шаблона. Например, применим первую версию метода MapRoute:
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; namespace RoutingApp { public class Startup { public void Configure(IApplicationBuilder app) { var routeBuilder = new RouteBuilder(app); routeBuilder.MapRoute("{controller}/{action}", async context => { context.Response.ContentType = "text/html; charset=utf-8"; await context.Response.WriteAsync("двухсегментный запрос"); }); routeBuilder.MapRoute("{controller}/{action}/{id}", async context => { context.Response.ContentType = "text/html; charset=utf-8"; await context.Response.WriteAsync("трехсегментный запрос"); }); app.UseRouter(routeBuilder.Build()); app.Run(async (context) => { await context.Response.WriteAsync("Hello World!"); }); } } }
Здесь определено два маршрута, причем каждый из них имеет свой обработчик. Первый маршрут соответствует запросу с двумя сегментами, а второй - с тремя сегментами. Эта версия метода MapRoute тем и удобна, что мы можем легко повесить на каждый маршрут свой обработчик.
Ранее в предыдущей теме использовалась вторая версия:
routeBuilder.MapRoute("default", "{controller}/{action}");
Такая версия определяет маршрут с именем "default" и шаблоном URL "{controller}/{action}", который состоит из двух сегментов. С этим шаблоном затем сопоставляется запрошенный адрес URL. При удачном сопоставлении запускается обработчик маршрута, который обрабатывает запрос.
Но важно заметить, что здесь в шаблоне URL используются параметры маршрута
. Каждый параметр заключается в фигурные скобки. Когда приходит запрос,
система маршрутизации при удачном сопоставлении запроса с маршрутом будет выделять из запроса значения для этих параметров.
Например, при запросе http://localhost:xxxx/Home/Index значения для параметров распределятся так:
controller | action |
Home | Index |
Или запрос http://localhost:xxxx/Book/Order сформирует следующие значения:
controller | action |
Book | Order |
Однако сегменты шаблона необязательно должны представлять параметры URL, это также могут быть константные значения. Например, пусть у нас будет определен следующий маршрут:
routeBuilder.MapRoute("default", "store/{action}");
Шаблон опять же состоит из двух сегментов, но первый сегмент представляет константное значение "store", поэтому такой маршрут будет соответствовать, например, такому запросу http://localhost:xxxx/Store/Order или любому другому запросу, который состоит из двух сегментов, и первым сегментов обязательно идет "Store", а второй сегмент по-прежнему может представлять любое значение для параметра "action".
Или к примеру маршрут:
routeBuilder.MapRoute("default", "api/{controller}/{action}/{id?}");
Этот маршрут определяет в шаблоне статический сегмент "api", поэтому запрос в качестве первого сегмента обязательно должен иметь строку "api". И подобному маршруту будет соответствовать, например, следующий запрос:
http://localhost:56130/api/Home/Index/1
При использовании параметров в шаблоне URL мы можем их помечать как необязательные с помощью знака вопроса. Например, определим следующий маршрут:
routeBuilder.MapRoute("default", "{controller}/{action?}/{id?}");
Здесь шаблон состоит из трех сегментов, и последний сегмент id помечен как необязательный. А это значит, что мы можем в запросе игнорировать значение для этого сегмента. Например, данный шаблон будет соответствовать двум следующим url:
localhost:56130/Home/Index/ localhost:56130/Home/Index/2
Но при определении необязательных параметров надо учитывать одну вещь: мы можем определять необязательные параметры, начиная с конца, как в случае с параметром id. То есть шаблон {controller}/{action?}/{id} будет некорректным. А вот шаблон {controller}/{action?}/{id?} будет работать нормально.
Выше были рассмотрены версии метода MapRoute()
, одна из которых позволяет задавать для параметров значения по умолчанию, если
вдруг в запрошенный адрес url не содержит нужных значений:
routeBuilder.MapRoute("default", "{controller}/{action}/{id?}", new { controller = "home", action = "index" });
Третий параметр устанавливает значения по умолчанию. В итоге при различных запросах у нас получатся следующие значения:
Запрос | Параметры запроса |
http://localhost:56130/ | controller=Home action=Index |
http://localhost:56130/Book | controller=Book action=Index |
http://localhost:56130/Book/Show | controller=Book action=Show |
http://localhost:56130/Book/Show/2 | controller=Book action=Show id=2 |
В качестве альтернативы мы можем задать значения по умолчанию сразу же при определении параметров:
routeBuilder.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
Мы можем обозначить любое количество сегментов в запросе, чтобы не быть жестко привязанным к числу сегментов с помощью параметра со знаком * ("звездочка"):
routeBuilder.MapRoute("default", "{controller=Home}/{action=Index}/{id?}/{*catchall}");
Параметр catchall
будет соответствовать всем тем сегментам строки запроса, которые будут идти после id. То есть, например, при
запросе http://localhost:56130/Home/Index/1/name/book/order значения распределятся следующим образом:
controller | Home |
action | Index |
id | 1 |
catchall | name/book/order |
Сегменты строки запроса необязательно полностью должны нести только значения для параметров или констант, определенных в шаблоне маршруте. Можно также использовать различные префиксы в строке запроса и соответствующим образом настроить маршрут для обработки подобных запросов. Например, мы можем определить следующий маршрут:
routeBuilder.MapRoute("default", "Ru{controller=Home}/{action=Index}-en/{id?}");
Первый сегмент обязательно должен начинаться с префикса "Ru", а вся остальная часть сегмента считается параметром "controller". Аналогично второй сегмент обязательно должен оканчиваться на "-en", а вся остальная часть считается значением для параметра "action". И такому шаблону будет соответствовать, к примеру, следующий запрос:
http://localhost:56130/RuHome/Index-en/1
И также в одном сегменте может быть несколько параметров. Например, определим следующий маршрут:
routeBuilder.MapRoute("default", "{controller=Home}/{action=Index}/{name}-{year}");
Здесь последний сегмент включает два параметра name и year, которые разделены дефисом. И такому шаблону соответствует следующий запрос:
http://localhost:56130/Store/Order/lumia-2015
Распределение параметров:
controller | Store |
action | Order |
name | lumia |
year | 2015 |
Кроме метода MapRoute()
для создания маршрута мы можем использовать еще ряд методов, которые предназначены для создания маршрутов
для определенных типов запросов: GET, POST, PUT, DELETE. Это методы:
MapGet
MapDelete
MapPost
MapPut
MapVerb
По окончанию названия уже можно предположить, для какого типа запроса данный метод предназначен. Все они, кроме MapVerb, имеют следующие две формы:
MapGet(string template, RequestDelegate handler) MapGet(string template, Func<HttpRequest, HttpResponse, RouteDate, Task> handler)
Например:
routeBuilder.MapGet("{controller}/{action}", async (context) => { await context.Response.WriteAsync("Hello From MapGet!"); });
А метод MapVerb()
добавляет в качестве первого параметра название типа запроса http, например, "GET" или "POST":
MapVerb(string verb, string template, RequestDelegate handler) MapVerb(string verb, string template, Func<HttpRequest, HttpResponse, RouteDate, Task> handler)
Еще ряд методов позволяют установить для обработки запросов middleware в виде делегата Action<IApplicationBuilder app>. Это:
MapMiddlewareGet
MapMiddlewareDelete
MapMiddlewarePost
MapMiddlewarePut
MapMiddlewareRoute
MapMiddlewareVerb
Суффикс Get/Delete/Post/Put на конце имени метода указывает, какой именно тип запроса обрабатывается методом. MapMiddlewareRoute является универсальным, а MapMiddlewareVerb позволяет указать тип запроса в качестве первого параметра.
Например, применим MapMiddlewareGet:
public class Startup { public void Configure(IApplicationBuilder app) { var routeBuilder = new RouteBuilder(app); routeBuilder.MapMiddlewareGet("{controller}/{action}", app => { app.Run(async context => { await context.Response.WriteAsync("Hello from MapMiddlewareGet"); }); }); app.UseRouter(routeBuilder.Build()); app.Run(async (context) => { await context.Response.WriteAsync("Hello World!"); }); } }
Все методы, за исключением MapMiddlewareVerb, принимают те же параметры, что и MapMiddlewareGet:
MapMiddlewareGet()
MapMiddlewareVerb дополнительно в качестве первого параметра принимает тип запроса.