Sdílet prostřednictvím


Obslužné rutiny tras v minimálních aplikacích API

Poznámka:

Toto není nejnovější verze tohoto článku. Aktuální verzi najdete v tomto článku ve verzi .NET 9.

Upozorňující

Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Aktuální verzi najdete v tomto článku ve verzi .NET 9.

Důležité

Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.

Aktuální verzi najdete v tomto článku ve verzi .NET 9.

Nakonfigurovaná podpora a kde je metoda HTTP typu Pascal cased, například Get, Put Postnebo Delete:{Verb} MapMethods Map{Verb} WebApplication

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();

Argumenty Delegate předané těmto metodám se nazývají "obslužné rutiny tras".

Obslužné rutiny tras

Obslužné rutiny tras jsou metody, které se spouštějí, když se trasa shoduje. Obslužné rutiny tras mohou být výraz lambda, místní funkce, metoda instance nebo statická metoda. Obslužné rutiny tras můžou být synchronní nebo asynchronní.

Výraz lambda

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();

Místní funkce

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

string LocalFunction() => "This is local function";

app.MapGet("/", LocalFunction);

app.Run();

Instanční metoda

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";
    }
}

Statická metoda

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";
    }
}

Koncový bod definovaný mimo Program.cs

Minimální rozhraní API nemusí být umístěna v Program.csumístění .

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" });
        });
    }
}

Viz také skupiny Směrování dále v tomto článku.

Koncové body můžou mít názvy, aby se vygenerovaly adresy URL koncového bodu. Použitím pojmenovaného koncového bodu se v aplikaci nemusíte pevně zakódovat cesty:

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();

Předchozí kód se zobrazí The link to the hello route is /hello z koncového / bodu.

POZNÁMKA: V názvech koncových bodů se rozlišují malá a velká písmena.

Názvy koncových bodů:

  • Musí být globálně jedinečný.
  • Používají se jako ID operace OpenAPI, pokud je povolená podpora OpenAPI. Další informace najdete v tématu OpenAPI.

Parametry trasy

Parametry trasy je možné zachytit jako součást definice vzoru trasy:

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();

Předchozí kód vrátí The user id is 3 and book id is 7 z identifikátoru URI /users/3/books/7.

Obslužná rutina trasy může deklarovat parametry, které se mají zachytit. Při provedení požadavku na trasu s parametry deklarovanými k zachycení se parametry parsují a předávají obslužné rutině. To usnadňuje zachytávání hodnot v bezpečném typu. V předchozím kódu userId a bookId jsou oba int.

Pokud v předchozím kódu nelze převést intna některou hodnotu trasy , vyvolá se výjimka. Požadavek /users/hello/books/3 GET vyvolá následující výjimku:

BadHttpRequestException: Failed to bind parameter "int userId" from "hello".

Zástupný znak a zachycení všech tras

Následující zachytávání všech návratových tras Routing to hello z koncového bodu /posts/hello:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/posts/{*rest}", (string rest) => $"Routing to {rest}");

app.Run();

Omezení trasy

Omezení trasy omezují odpovídající chování trasy.

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();

Následující tabulka ukazuje předchozí šablony tras a jejich chování:

Šablona trasy Příklad odpovídajícího identifikátoru URI
/todos/{id:int} /todos/1
/todos/{text} /todos/something
/posts/{slug:regex(^[a-z0-9_-]+$)} /posts/mypost

Další informace najdete v tématu Referenční informace o omezení trasy ve směrování v ASP.NET Core.

Skupiny tras

Metoda MapGroup rozšíření pomáhá uspořádat skupiny koncových bodů s běžnou předponou. Snižuje opakující se kód a umožňuje přizpůsobit celé skupiny koncových bodů jediným voláním metod, jako RequireAuthorization jsou a WithMetadata které přidávají metadata koncového bodu.

Například následující kód vytvoří dvě podobné skupiny koncových bodů:

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;
}

V tomto scénáři můžete použít relativní adresu hlavičky Location ve výsledku 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);
}

První skupina koncových bodů se bude shodovat pouze s požadavky s předponou /public/todos a jsou přístupná bez ověřování. Druhá skupina koncových bodů bude odpovídat pouze požadavkům s předponou /private/todos a vyžaduje ověření.

Objekt QueryPrivateTodos pro filtrování koncových bodů je místní funkce, která upravuje parametry obslužné rutiny TodoDb trasy tak, aby umožňovala přístup k privátním datům úkolů a jejich ukládání.

Skupiny tras také podporují vnořené skupiny a složité vzory předpon s parametry trasy a omezeními. V následujícím příkladu a obslužná rutina trasy namapovaná na user skupinu může zachytit {org} parametry a {group} parametry trasy definované v předponách vnější skupiny.

Předpona může být také prázdná. To může být užitečné pro přidání metadat koncového bodu nebo filtrů do skupiny koncových bodů beze změny vzoru trasy.

var all = app.MapGroup("").WithOpenApi();
var org = all.MapGroup("{org}");
var user = org.MapGroup("{user}");
user.MapGet("", (string org, string user) => $"{org}/{user}");

Přidání filtrů nebo metadat do skupiny se chová stejně jako jejich individuální přidání do každého koncového bodu před přidáním dalších filtrů nebo metadat, které mohly být přidány do vnitřní skupiny nebo konkrétního koncového bodu.

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);
});

V předchozím příkladu vnější filtr zapíše příchozí požadavek před vnitřním filtrem, i když byl přidán druhý. Vzhledem k tomu, že filtry byly použity u různých skupin, pořadí, které byly přidány vzhledem k sobě, nezáleží. Přidají se filtry objednávek bez ohledu na to, jestli se použije na stejnou skupinu nebo konkrétní koncový bod.

Žádost o /outer/inner/ protokolování bude následující:

/outer group filter
/inner group filter
MapGet filter

Vazba parametru

Vazba parametrů v aplikacích s minimálním rozhraním API podrobně popisuje pravidla pro naplnění parametrů obslužné rutiny trasy.

Odpovědi

Vytváření odpovědí v aplikacích s minimálním rozhraním API podrobně popisuje, jak se hodnoty vrácené z obslužných rutin tras převedou na odpovědi.