Dela via


Routningshanterare i minimala API-appar

Anmärkning

Det här är inte den senaste versionen av den här artikeln. För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .

Varning

Den här versionen av ASP.NET Core stöds inte längre. Mer information finns i supportpolicyn för .NET och .NET Core. För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .

Viktigt!

Den här informationen gäller en förhandsversionsprodukt som kan ändras avsevärt innan den släpps kommersiellt. Microsoft lämnar inga garantier, uttryckliga eller underförstådda, med avseende på den information som tillhandahålls här.

För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .

En konfigurerad WebApplication stöder Map{Verb} och MapMethods där {Verb} är en Pascal-cased HTTP-metod som Get, Post, Put eller 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();

De Delegate argument som skickas till dessa metoder kallas "routningshanterare".

Routningshanterare

Routhanterare är metoder som körs när rutten matchar. Routningshanterare kan vara ett lambda-uttryck, en lokal funktion, en instansmetod eller en statisk metod. Routningshanterare kan vara synkrona eller asynkrona.

Lambda-uttryck

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

Lokal funktion

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

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

app.MapGet("/", LocalFunction);

app.Run();

Instansmetod

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

Statisk metod

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

Slutpunkt definierad utanför Program.cs

Minimala API:er behöver inte finnas i 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" });
        });
    }
}

Se även Ruttgrupper senare i den här artikeln.

Slutpunkter kan ges namn för att generera URL:er till slutpunkten. Om du använder en namngiven slutpunkt undviker du att behöva hårdkoda sökvägar i en app:

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

Den föregående koden visar The link to the hello route is /hello från slutpunkten /.

NOTE: Ändpunktsnamn är skiftlägeskänsliga.

Slutpunktsnamn:

  • Måste vara globalt unikt.
  • Används som OpenAPI-åtgärds-ID när OpenAPI-stöd är aktiverat. Mer information finns i OpenAPI-.

Routningsparametrar

Routningsparametrar kan samlas in som en del av routningsmönsterdefinitionen:

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

Föregående kod returnerar The user id is 3 and book id is 7 från URI-/users/3/books/7.

Routningshanteraren kan deklarera parametrarna som ska avbildas. När en begäran görs till en väg med parametrar som deklarerats för avbildning parsas parametrarna och skickas till hanteraren. Det gör det enkelt att samla in värdena på ett säkert sätt. I föregående kod är både userId och bookIdint.

Om något av routningsvärdena inte kan konverteras till en inti föregående kod genereras ett undantag. GET-begäran /users/hello/books/3 genererar följande undantag:

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

Jokertecken och fånga alla vägar

Följande catch all route returnerar Routing to hello från slutpunkten "/posts/hello":

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

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

app.Run();

Vägbegränsningar

Routningsbegränsningar begränsar matchningsbeteendet för en väg.

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

I följande tabell visas föregående vägmallar och deras beteende:

Routningsmall Exempel på matchande URI
/todos/{id:int} /todos/1
/todos/{text} /todos/something
/posts/{slug:regex(^[a-z0-9_-]+$)} /posts/mypost

Mer information finns i referens för routningsbegränsningar i Routning i ASP.NET Core.

Routtgrupper

Tilläggsmetoden MapGroup hjälper till att organisera grupper av slutpunkter med ett gemensamt prefix. Det minskar repetitiv kod och gör det möjligt att anpassa hela grupper av slutpunkter med ett enda anrop till metoder som RequireAuthorization och WithMetadata som lägger till slutpunktsmetadata.

Följande kod skapar till exempel två liknande grupper av slutpunkter:

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

I det här scenariot kan du använda en relativ adress för Location-rubriken i 201 Created-resultatet.

public static async Task<Created<Todo>> CreateTodo(Todo todo, TodoDb database)
{
    await database.AddAsync(todo);
    await database.SaveChangesAsync();

    return TypedResults.Created($"{todo.Id}", todo);
}

Den första gruppen med slutpunkter matchar endast begäranden som är prefix med /public/todos och är tillgängliga utan autentisering. Den andra gruppen med slutpunkter matchar endast begäranden som är prefix med /private/todos och kräver autentisering.

QueryPrivateTodos slutpunktfilterfabriken är en lokal funktion som ändrar rout-hanterarens TodoDb parametrar för att tillåta åtkomst till och lagring av privata data.

Routningsgrupper stöder också kapslade grupper och komplexa prefixmönster med vägparametrar och begränsningar. I följande exempel kan routhanteraren som mappas till gruppen user fånga de {org}- och {group}-routningsparametrar som definierats i de yttre gruppens prefix.

Prefixet kan också vara tomt. Detta kan vara användbart för att lägga till slutpunktsmetadata eller filter till en grupp slutpunkter utan att ändra vägmönstret.

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

Att lägga till filter eller metadata i en grupp fungerar på samma sätt som att lägga till dem individuellt i varje slutpunkt innan du lägger till extra filter eller metadata som kan ha lagts till i en inre grupp eller en specifik slutpunkt.

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

I exemplet ovan loggar det yttre filtret den inkommande begäran före det inre filtret trots att det lades till tvåa. Eftersom filtren tillämpades på olika grupper spelar det ingen roll vilken ordning de lades till i förhållande till varandra. Orderfiltren som läggs till spelar roll om de tillämpas på samma grupp eller specifika slutpunkt.

En begäran om att /outer/inner/ loggar följande:

/outer group filter
/inner group filter
MapGet filter

Parameterbindning

Parameterbindning i minimala API-program beskriver reglerna i detalj för hur routningshanterarparametrar fylls i.

Svaren

Skapa svar i minimala API-program beskriver i detalj hur värden som returneras från routningshanterare konverteras till svar.