Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Примечание.
Это не последняя версия этой статьи. В текущей версии см. версию .NET 10 этой статьи.
Предупреждение
Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core. В текущей версии см. версию .NET 10 этой статьи.
Настроенный WebApplication поддерживает Map{Verb} и MapMethods, где {Verb} — это метод HTTP с использованным регистром Pascal, например, Get, Post, Put или Delete.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "This is a GET");
app.MapPost("/", () => "This is a POST");
app.MapPut("/", () => "This is a PUT");
app.MapDelete("/", () => "This is a DELETE");
app.MapMethods("/options-or-head", new[] { "OPTIONS", "HEAD" },
() => "This is an options or head request ");
app.Run();
Аргументы Delegate , передаваемые этим методам, называются обработчиками маршрутов.
В этой статье описывается использование обработчиков маршрутов, включая примеры, параметры, группы маршрутов и ограничения маршрутов.
Работа с обработчиками маршрутов
Обработчики маршрутов — это методы, которые выполняются, когда маршрут совпадает. Обработчики маршрутов могут быть лямбда-выражением, локальной функцией, методом экземпляра или статическим методом. Обработчики маршрутов могут быть синхронными или асинхронными.
В следующих разделах приведены примеры различных обработчиков маршрутов.
Лямбда-выражение
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/inline", () => "This is an inline lambda");
var handler = () => "This is a lambda variable";
app.MapGet("/", handler);
app.Run();
Локальная функция
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
string LocalFunction() => "This is local function";
app.MapGet("/", LocalFunction);
app.Run();
Метод экземпляра
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
var handler = new HelloHandler();
app.MapGet("/", handler.Hello);
app.Run();
class HelloHandler
{
public string Hello()
{
return "Hello Instance method";
}
}
Статический метод
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", HelloHandler.Hello);
app.Run();
class HelloHandler
{
public static string Hello()
{
return "Hello static method";
}
}
Конечная точка, определяемая вне Program.cs
Минимальные API не должны находиться в файле Program.cs . Например, можно настроить структуру в файле Program.cs и определить конечную точку в отдельном файле:
Program.cs
using MinAPISeparateFile;
var builder = WebApplication.CreateSlimBuilder(args);
var app = builder.Build();
TodoEndpoints.Map(app);
app.Run();
TodoEndpoints.cs
namespace MinAPISeparateFile;
public static class TodoEndpoints
{
public static void Map(WebApplication app)
{
app.MapGet("/", async context =>
{
// Get all todo items
await context.Response.WriteAsJsonAsync(new { Message = "All todo items" });
});
app.MapGet("/{id}", async context =>
{
// Get one todo item
await context.Response.WriteAsJsonAsync(new { Message = "One todo item" });
});
}
}
Дополнительные сведения см. в разделе "Группы маршрутов " далее в этой статье.
Именованные конечные точки и создание ссылок
Вы можете указать имя конечных точек для создания URL-адресов, предназначенных для конечной точки. Использование именованной конечной точки позволяет избежать сложных путей кода в приложении:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/hello", () => "Hello named route")
.WithName("hi");
app.MapGet("/", (LinkGenerator linker) =>
$"The link to the hello route is {linker.GetPathByName("hi", values: null)}");
app.Run();
В предыдущем коде отображается сообщение The link to the hello route is /hello из конечной точки / (косая черта).
Критерии для имен конечных точек
Имена конечных точек должны соответствовать следующим критериям:
- Имена конечных точек чувствительны к регистру.
- Имена конечных точек должны быть глобально уникальными.
- Имена конечных точек используются в качестве идентификатора операции OpenAPI при включенной поддержке OpenAPI. Дополнительные сведения см. в разделе "Создание документов OpenAPI".
Параметры маршрута
Параметры маршрута могут быть захвачены в составе определения шаблона маршрута:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/users/{userId}/books/{bookId}",
(int userId, int bookId) => $"The user id is {userId} and book id is {bookId}");
app.Run();
Предыдущий код возвращает сообщение Идентификатор пользователя равен 3, а идентификатор книги — 7 из URI /users/3/books/7.
Обработчик маршрута может объявлять параметры, которые нужно захватывать. Когда запрос посылается на маршрут с параметрами, объявленными для захвата, параметры анализируются и передаются обработчику. Такой подход упрощает захват значений в типобезопасном способе. В приведенном выше коде параметры userId и bookId оба имеют тип int.
В приведенном выше коде, если любое значение маршрута не может быть преобразовано в int, создается исключение. Запрос GET /users/hello/books/3 вызывает следующее исключение:
BadHttpRequestException: Failed to bind parameter "int userId" from "hello".
Использование подстановочных знаков и перехват всех маршрутов
Следующий перехват всех маршрутов возвращает маршрутизацию для приветствия из конечной /posts/hello точки:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/posts/{*rest}", (string rest) => $"Routing to {rest}");
app.Run();
Ограничения маршрута
Ограничения маршрутов определяют правила соответствия маршрута.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/todos/{id:int}", (int id) => db.Todos.Find(id));
app.MapGet("/todos/{text}", (string text) => db.Todos.Where(t => t.Text.Contains(text));
app.MapGet("/posts/{slug:regex(^[a-z0-9_-]+$)}", (string slug) => $"Post {slug}");
app.Run();
В приведенной ниже таблице перечислены представленные выше примеры шаблонов маршрутов и их поведение.
| Шаблон маршрута | Пример сопоставления URI |
|---|---|
/todos/{id:int} |
/todos/1 |
/todos/{text} |
/todos/something |
/posts/{slug:regex(^[a-z0-9_-]+$)} |
/posts/mypost |
Дополнительные сведения см. в разделе Справочник по ограничениям маршрутов в статье Маршрутизация в ASP.NET Core.
Группы маршрутов
Метод MapGroup расширения помогает упорядочивать группы конечных точек с общим префиксом и уменьшает повторяющийся код. Используйте этот метод для настройки целых групп конечных точек с одним вызовом таких методов RequireAuthorization и WithMetadata добавления метаданных конечной точки.
Например, следующий код создает две аналогичные группы конечных точек:
app.MapGroup("/public/todos")
.MapTodosApi()
.WithTags("Public");
app.MapGroup("/private/todos")
.MapTodosApi()
.WithTags("Private")
.AddEndpointFilterFactory(QueryPrivateTodos)
.RequireAuthorization();
EndpointFilterDelegate QueryPrivateTodos(EndpointFilterFactoryContext factoryContext, EndpointFilterDelegate next)
{
var dbContextIndex = -1;
foreach (var argument in factoryContext.MethodInfo.GetParameters())
{
if (argument.ParameterType == typeof(TodoDb))
{
dbContextIndex = argument.Position;
break;
}
}
// Skip filter if the method doesn't have a TodoDb parameter.
if (dbContextIndex < 0)
{
return next;
}
return async invocationContext =>
{
var dbContext = invocationContext.GetArgument<TodoDb>(dbContextIndex);
dbContext.IsPrivate = true;
try
{
return await next(invocationContext);
}
finally
{
// This should only be relevant if you're pooling or otherwise reusing the DbContext instance.
dbContext.IsPrivate = false;
}
};
}
public static RouteGroupBuilder MapTodosApi(this RouteGroupBuilder group)
{
group.MapGet("/", GetAllTodos);
group.MapGet("/{id}", GetTodo);
group.MapPost("/", CreateTodo);
group.MapPut("/{id}", UpdateTodo);
group.MapDelete("/{id}", DeleteTodo);
return group;
}
В этом сценарии можно использовать относительный адрес для Location заголовка в 201 Created результате:
public static async Task<Created<Todo>> CreateTodo(Todo todo, TodoDb database)
{
await database.AddAsync(todo);
await database.SaveChangesAsync();
return TypedResults.Created($"{todo.Id}", todo);
}
Первой группе конечных точек соответствуют только запросы с префиксом /public/todos, и они доступные без какой-либо проверки подлинности. Вторая группа конечных точек соответствует только запросам, которые начинаются с /private/todos, и требуют проверки подлинности.
QueryPrivateTodos — это локальная функция, которая изменяет TodoDb параметры обработчика маршрутов, чтобы разрешить им доступ к частным данным todo и хранить их.
QueryPrivateTodos служит фабрикой фильтров конечных точек.
Группы маршрутов также поддерживают вложенные группы и сложные шаблоны префикса с параметрами маршрута и ограничениями. В следующем примере обработчик маршрутов, сопоставленный с user группой, может захватывать параметры маршрута {org} и {group}, определенные во внешних префиксах группы.
Префикс также может быть пустым. Этот подход может быть полезен для добавления метаданных конечной точки или фильтров в группу конечных точек без изменения шаблона маршрута.
var all = app.MapGroup("").WithOpenApi();
var org = all.MapGroup("{org}");
var user = org.MapGroup("{user}");
user.MapGet("", (string org, string user) => $"{org}/{user}");
Добавление фильтров или метаданных в группу приводит к тому же поведению, что и их добавление в каждую конечную точку (перед добавлением дополнительных фильтров или метаданных, которые могут существовать во внутренней группе или конкретной конечной точке).
var outer = app.MapGroup("/outer");
var inner = outer.MapGroup("/inner");
inner.AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation("/inner group filter");
return next(context);
});
outer.AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation("/outer group filter");
return next(context);
});
inner.MapGet("/", () => "Hi!").AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation("MapGet filter");
return next(context);
});
В предыдущем примере внешний фильтр регистрирует входящий запрос раньше внутреннего фильтра, хотя он добавляется позже. Так как фильтры применяются к разным группам, порядок их добавления относительно друг друга не имеет значения. Порядок, в котором добавляются фильтры, имеет значение при применении к одной и той же группе или конкретной конечной точке.
Запрос к /outer/inner/ регистрирует следующие данные:
/outer group filter
/inner group filter
MapGet filter
Привязка параметров в обработчике маршрутов
Привязка параметров в приложениях Minimal API подробно описывает правила заполнения параметров обработчика маршрутов.
Обработайте ответ от маршрутизатора
Создание ответов в приложениях Minimal API подробно описывает, как значения, возвращаемые обработчиками маршрутов, преобразуются в ответы.
Связанный контент
ASP.NET Core