Определение маршрутов

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7

Последнее обновление: 15.11.2019

В прошлой теме были рассмотрены базовые моменты работы с маршрутов. Теперь рассмотрим различные способы определения маршрутов.

Для добавления маршрута в прошлой теме использовался метод 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 и определение маршрутов в ASP.NET Core

URL matching

Ранее в предыдущей теме использовалась вторая версия:

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 для обработки запросов

Еще ряд методов позволяют установить для обработки запросов 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 дополнительно в качестве первого параметра принимает тип запроса.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850