Penangan Rute di aplikasi API Minimal
Catatan
Ini bukan versi terbaru dari artikel ini. Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.
Peringatan
Versi ASP.NET Core ini tidak lagi didukung. Untuk informasi selengkapnya, lihat Kebijakan Dukungan .NET dan .NET Core. Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.
Penting
Informasi ini berkaitan dengan produk pra-rilis yang mungkin dimodifikasi secara substansial sebelum dirilis secara komersial. Microsoft tidak memberikan jaminan, tersirat maupun tersurat, sehubungan dengan informasi yang diberikan di sini.
Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.
Dukungan yang dikonfigurasi WebApplication
dan MapMethods di mana {Verb}
adalah metode HTTP berkode Pascal seperti Get
, , Post
Put
atau Delete
:Map{Verb}
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();
Argumen Delegate yang diteruskan ke metode ini disebut "penangan rute".
Penangan rute
Penangan rute adalah metode yang dijalankan saat rute cocok. Penangan rute dapat berupa ekspresi lambda, fungsi lokal, metode instans, atau metode statis. Penangan rute bisa sinkron atau asinkron.
Ekspresi 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();
Fungsi lokal
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
string LocalFunction() => "This is local function";
app.MapGet("/", LocalFunction);
app.Run();
Metode instans
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";
}
}
Metode statis
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";
}
}
Titik akhir yang ditentukan di luar Program.cs
API minimal tidak harus berada di 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" });
});
}
}
Lihat juga Merutekan grup nanti di artikel ini.
Titik akhir dan pembuatan tautan bernama
Titik akhir dapat diberikan nama untuk menghasilkan URL ke titik akhir. Menggunakan titik akhir bernama menghindari harus melakukan jalur kode keras di aplikasi:
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();
Kode sebelumnya ditampilkan The link to the hello route is /hello
dari /
titik akhir.
CATATAN: Nama titik akhir peka huruf besar/kecil.
Nama titik akhir:
- Harus unik secara global.
- Digunakan sebagai id operasi OpenAPI saat dukungan OpenAPI diaktifkan. Untuk informasi selengkapnya, lihat OpenAPI.
Parameter Rute
Parameter rute dapat ditangkap sebagai bagian dari definisi pola rute:
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();
Kode sebelumnya dikembalikan The user id is 3 and book id is 7
dari URI /users/3/books/7
.
Handler rute dapat mendeklarasikan parameter yang akan diambil. Ketika permintaan dibuat ke rute dengan parameter yang dinyatakan untuk diambil, parameter diurai dan diteruskan ke handler. Ini memudahkan untuk menangkap nilai dengan cara yang aman. Dalam kode sebelumnya, userId
dan bookId
keduanya int
.
Dalam kode sebelumnya, jika salah satu nilai rute tidak dapat dikonversi ke int
, pengecualian akan dilemparkan. Permintaan /users/hello/books/3
GET melemparkan pengecualian berikut:
BadHttpRequestException: Failed to bind parameter "int userId" from "hello".
Kartubebas dan tangkap semua rute
Berikut ini menangkap semua rute yang Routing to hello
dikembalikan dari titik akhir '/posts/hello':
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/posts/{*rest}", (string rest) => $"Routing to {rest}");
app.Run();
Batasan rute
Batasan rute membatasi perilaku pencocokan rute.
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();
Tabel berikut menunjukkan templat rute sebelumnya dan perilakunya:
Templat Rute | Contoh URI yang Cocok |
---|---|
/todos/{id:int} |
/todos/1 |
/todos/{text} |
/todos/something |
/posts/{slug:regex(^[a-z0-9_-]+$)} |
/posts/mypost |
Untuk informasi selengkapnya, lihat Referensi batasan rute dalam Perutean di ASP.NET Core.
Grup rute
Metode MapGroup ekstensi membantu mengatur grup titik akhir dengan awalan umum. Ini mengurangi kode berulang dan memungkinkan untuk menyesuaikan seluruh grup titik akhir dengan satu panggilan ke metode seperti RequireAuthorization dan WithMetadata yang menambahkan metadata titik akhir.
Misalnya, kode berikut membuat dua grup titik akhir serupa:
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;
}
Dalam skenario ini, Anda dapat menggunakan alamat relatif untuk Location
header dalam hasil 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);
}
Grup titik akhir pertama hanya akan cocok dengan permintaan yang diawali dan /public/todos
dapat diakses tanpa autentikasi apa pun. Grup titik akhir kedua hanya akan cocok dengan permintaan yang diawali dan /private/todos
memerlukan autentikasi.
Pabrik QueryPrivateTodos
filter titik akhir adalah fungsi lokal yang memodifikasi parameter handler TodoDb
rute untuk memungkinkan mengakses dan menyimpan data todo privat.
Grup rute juga mendukung grup berlapis dan pola awalan kompleks dengan parameter rute dan batasan. Dalam contoh berikut, dan handler rute yang dipetakan user
ke grup dapat menangkap {org}
parameter rute dan {group}
yang ditentukan dalam awalan grup luar.
Awalan juga dapat kosong. Ini dapat berguna untuk menambahkan metadata titik akhir atau filter ke sekelompok titik akhir tanpa mengubah pola rute.
var all = app.MapGroup("").WithOpenApi();
var org = all.MapGroup("{org}");
var user = org.MapGroup("{user}");
user.MapGet("", (string org, string user) => $"{org}/{user}");
Menambahkan filter atau metadata ke grup berulah dengan cara yang sama seperti menambahkannya satu per satu ke setiap titik akhir sebelum menambahkan filter atau metadata tambahan yang mungkin telah ditambahkan ke grup dalam atau titik akhir tertentu.
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);
});
Dalam contoh di atas, filter luar akan mencatat permintaan masuk sebelum filter dalam meskipun ditambahkan kedua. Karena filter diterapkan ke grup yang berbeda, urutan yang ditambahkan relatif satu sama lain tidak masalah. Filter pesanan ditambahkan tidak masalah jika diterapkan ke grup yang sama atau titik akhir tertentu.
Permintaan untuk /outer/inner/
mencatat hal berikut:
/outer group filter
/inner group filter
MapGet filter
Pengikatan parameter
Pengikatan parameter dalam aplikasi API Minimal menjelaskan aturan secara rinci tentang bagaimana parameter handler rute diisi.
Respons
Membuat respons dalam aplikasi API Minimal menjelaskan secara rinci bagaimana nilai yang dikembalikan dari handler rute dikonversi menjadi respons.
ASP.NET Core