Poznámka
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Poznámka:
Toto není nejnovější verze tohoto článku. Aktuální vydání naleznete v článku ve verzi .NET 9.
Varování
Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Aktuální vydání naleznete v č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í vydání naleznete v článku ve verzi .NET 9.
Autor: Rick Anderson a Tom Dykstra
Minimální rozhraní API jsou navržena tak, aby vytvářela rozhraní HTTP API s minimálními závislostmi. Jsou ideální pro mikroslužby a aplikace, které chtějí do ASP.NET Core zahrnout jenom minimální soubory, funkce a závislosti.
V tomto kurzu se naučíte základy vytváření minimálního rozhraní API pomocí ASP.NET Core. Dalším přístupem k vytváření rozhraní API v ASP.NET Core je použití kontrolerů. Nápovědu k výběru mezi minimálními rozhraními API a rozhraními API založenými na kontroleru najdete v přehledu rozhraní API. Kurz vytvoření projektu rozhraní API na základě kontrolerů , které obsahují další funkce, najdete v tématu Vytvoření webového rozhraní API.
Přehled
Tento kurz vytvoří následující rozhraní API:
API (rozhraní pro programování aplikací) | Popis | Text požadavku | Tělo odpovědi |
---|---|---|---|
GET /todoitems |
Získání všech položek úkolů | Nic | Pole položek úkolů |
GET /todoitems/complete |
Získejte dokončené úkoly | Nic | Pole položek úkolů |
GET /todoitems/{id} |
Získejte položku podle ID | Nic | Úkol k vyřízení |
POST /todoitems |
Přidání nové položky | Úkol k vyřízení | Úkol k vyřízení |
PUT /todoitems/{id} |
Aktualizace existující položky | Úkol k vyřízení | Nic |
DELETE /todoitems/{id} |
Odstranění položky | Nic | Nic |
Požadavky
Visual Studio 2022 s pracovním zatížením ASP.NET a vývoje webu
Vytvoření projektu rozhraní API
Spusťte Visual Studio 2022 a vyberte Vytvořit nový projekt.
V dialogovém okně Vytvořit nový projekt :
- Zadejte
Empty
do vyhledávacího pole Hledat šablony . - Vyberte šablonu ASP.NET Core Empty a vyberte Další.
- Zadejte
Pojmenujte projekt TodoApi a vyberte Další.
V dialogovém okně Další informace :
- Vyberte .NET 9.0
- Zrušte zaškrtnutí políčka Nepoužívat příkazy nejvyšší úrovně
- Vyberte příkaz Vytvořit.
Kontrola kódu
Soubor Program.cs
obsahuje následující kód:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
Předchozí kód:
- Vytvoří WebApplicationBuilder a WebApplication s předkonfigurovanými výchozími nastaveními.
- Vytvoří koncový bod
/
HTTP GET, který vrátíHello World!
:
Spustit aplikaci
Stisknutím kombinace kláves Ctrl+F5 spusťte bez debuggeru.
Visual Studio zobrazí následující dialogové okno:
Pokud důvěřujete certifikátu SSL služby IIS Express, vyberte Ano .
Zobrazí se následující dialogové okno:
Pokud souhlasíte s tím, že se má důvěřovat vývojovému certifikátu, vyberte Ano.
Informace o tom, jak důvěřovat prohlížeči Firefox, naleznete v části k chybě certifikátu Firefox SEC_ERROR_INADEQUATE_KEY_USAGE.
Visual Studio spustí Kestrel webový server a otevře okno prohlížeče.
Hello World!
se zobrazí v prohlížeči. Soubor Program.cs
obsahuje minimální, ale kompletní aplikaci.
Zavřete okno prohlížeče.
Přidání balíčků NuGet
Pro podporu databáze a diagnostiky používané v tomto kurzu je potřeba přidat balíčky NuGet.
- V nabídce Nástroje vyberte NuGet Správce balíčků > Spravovat balíčky NuGet pro řešení.
- Vyberte kartu Procházet.
- Vyberte Zahrnout předběžné vydání.
- Do vyhledávacího pole zadejte Microsoft.EntityFrameworkCore.InMemory a pak vyberte
Microsoft.EntityFrameworkCore.InMemory
. - V pravém podokně zaškrtněte políčko Projekt a pak vyberte Nainstalovat.
- Podle předchozích pokynů přidejte
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
balíček.
Třídy kontextu modelu a databáze
- Ve složce projektu vytvořte soubor s názvem
Todo.cs
s následujícím kódem:
public class Todo
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Předchozí kód vytvoří model pro tuto aplikaci. Model je třída, která představuje data, která aplikace spravuje.
- Vytvořte soubor s názvem
TodoDb.cs
s následujícím kódem:
using Microsoft.EntityFrameworkCore;
class TodoDb : DbContext
{
public TodoDb(DbContextOptions<TodoDb> options)
: base(options) { }
public DbSet<Todo> Todos => Set<Todo>();
}
Předchozí kód definuje kontext databáze, což je hlavní třída, která koordinuje funkce Entity Framework pro datový model. Tato třída je odvozena od Microsoft.EntityFrameworkCore.DbContext třídy.
Přidání kódu rozhraní API
- Obsah souboru
Program.cs
nahraďte následujícím kódem:
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();
app.MapGet("/todoitems", async (TodoDb db) =>
await db.Todos.ToListAsync());
app.MapGet("/todoitems/complete", async (TodoDb db) =>
await db.Todos.Where(t => t.IsComplete).ToListAsync());
app.MapGet("/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound());
app.MapPost("/todoitems", async (Todo todo, TodoDb db) =>
{
db.Todos.Add(todo);
await db.SaveChangesAsync();
return Results.Created($"/todoitems/{todo.Id}", todo);
});
app.MapPut("/todoitems/{id}", async (int id, Todo inputTodo, TodoDb db) =>
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return Results.NotFound();
todo.Name = inputTodo.Name;
todo.IsComplete = inputTodo.IsComplete;
await db.SaveChangesAsync();
return Results.NoContent();
});
app.MapDelete("/todoitems/{id}", async (int id, TodoDb db) =>
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return Results.NoContent();
}
return Results.NotFound();
});
app.Run();
Následující zvýrazněný kód přidá kontext databáze do kontejneru injektáže závislostí (DI) a povolí zobrazení výjimek souvisejících s databází:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();
Kontejner DI poskytuje přístup k kontextu databáze a dalším službám.
V tomto kurzu se k otestování rozhraní API používá Průzkumník koncových bodů a soubory .http.
Testování zveřejňování dat
Následující kód v Program.cs
vytvoří HTTP POST koncový bod /todoitems
, který přidá data do paměťové databáze:
app.MapPost("/todoitems", async (Todo todo, TodoDb db) =>
{
db.Todos.Add(todo);
await db.SaveChangesAsync();
return Results.Created($"/todoitems/{todo.Id}", todo);
});
Spustit aplikaci. Prohlížeč zobrazí chybu 404, protože /
koncový bod již neexistuje.
Koncový bod POST se použije k přidání dat do aplikace.
Vyberte Zobrazit>Další okna>Průzkumník koncových bodů.
Klikněte pravým tlačítkem na koncový bod POST a vyberte Vygenerovat požadavek.
Ve složce projektu s názvem
TodoApi.http
se vytvoří nový soubor s podobným obsahem jako v následujícím příkladu:@TodoApi_HostAddress = https://localhost:7031 POST {{TodoApi_HostAddress}}/todoitems ###
- První řádek vytvoří proměnnou, která se použije pro všechny koncové body.
- Další řádek definuje požadavek POST.
- Řádek s trojitým hashtagem (
###
) je značka oddělující požadavek: co následuje za ní, je určené pro jiný požadavek.
Požadavek POST potřebuje hlavičky a text. Pokud chcete definovat tyto části požadavku, přidejte následující řádky bezprostředně za řádek požadavku POST:
Content-Type: application/json { "name":"walk dog", "isComplete":true }
Předchozí kód přidá hlavičku Content-Type a text požadavku JSON. Soubor TodoApi.http by teď měl vypadat jako v následujícím příkladu, ale s číslem portu:
@TodoApi_HostAddress = https://localhost:7057 POST {{TodoApi_HostAddress}}/todoitems Content-Type: application/json { "name":"walk dog", "isComplete":true } ###
Spustit aplikaci.
Vyberte odkaz Odeslat žádost, který je nad řádkem
POST
žádosti.Požadavek POST se odešle do aplikace a odpověď se zobrazí v podokně Odpovědi .
Prozkoumání koncových bodů GET
Ukázková aplikace implementuje několik koncových bodů GET voláním MapGet
:
API (rozhraní pro programování aplikací) | Popis | Text požadavku | Tělo odpovědi |
---|---|---|---|
GET /todoitems |
Získání všech položek úkolů | Nic | Pole položek úkolů |
GET /todoitems/complete |
Získání všech dokončených položek úkolů | Nic | Pole položek úkolů |
GET /todoitems/{id} |
Získejte položku podle ID | Nic | Úkol k vyřízení |
app.MapGet("/todoitems", async (TodoDb db) =>
await db.Todos.ToListAsync());
app.MapGet("/todoitems/complete", async (TodoDb db) =>
await db.Todos.Where(t => t.IsComplete).ToListAsync());
app.MapGet("/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound());
Testování koncových bodů GET
Otestujte aplikaci voláním GET
koncových bodů z prohlížeče nebo pomocí Průzkumníka koncových bodů. Následující kroky jsou určené pro Průzkumníka koncových bodů.
V Průzkumníku koncových bodů klikněte pravým tlačítkem na první koncový bod GET a vyberte Vygenerovat požadavek.
Do souboru
TodoApi.http
byl přidán následující obsah:GET {{TodoApi_HostAddress}}/todoitems ###
Vyberte odkaz Odeslat žádost, který je nad novým
GET
řádkem žádosti.Požadavek GET se odešle do aplikace a odpověď se zobrazí v podokně Odpovědi .
Text odpovědi je podobný následujícímu formátu JSON:
[ { "id": 1, "name": "walk dog", "isComplete": true } ]
V Průzkumníku koncových bodů klikněte pravým tlačítkem na
/todoitems/{id}
koncový bod GET a vyberte Vygenerovat požadavek. Do souboruTodoApi.http
byl přidán následující obsah:GET {{TodoApi_HostAddress}}/todoitems/{id} ###
Nahraďte
{id}
s1
.Vyberte odkaz Odeslat požadavek, který je nad novým řádkem požadavku GET.
Požadavek GET se odešle do aplikace a odpověď se zobrazí v podokně Odpovědi .
Text odpovědi je podobný následujícímu formátu JSON:
{ "id": 1, "name": "walk dog", "isComplete": true }
Tato aplikace používá databázi v paměti. Pokud se aplikace restartuje, požadavek GET nevrací žádná data. Pokud se nevrátí žádná data, post data do aplikace a zkuste požadavek GET zopakovat.
Vrácené hodnoty
ASP.NET Core automaticky serializuje objekt do formátu JSON a zapíše json do textu zprávy odpovědi. Kód odpovědi pro tento návratový typ je 200 OK, za předpokladu, že neexistují žádné neošetřené výjimky. Neošetřené výjimky se překládají do chyb 5xx.
Návratové typy mohou představovat širokou škálu stavových kódů HTTP. Může například GET /todoitems/{id}
vrátit dvě různé hodnoty stavu:
- Pokud žádná položka neodpovídá požadovanému ID, vrátí metoda kód chyby stavuNotFound 404.
- V opačném případě metoda vrátí hodnotu 200 s textem odpovědi JSON. Vrácení
item
vede k odpovědi HTTP 200.
Prozkoumání koncového bodu PUT
Ukázková aplikace implementuje jeden koncový bod PUT pomocí MapPut
:
app.MapPut("/todoitems/{id}", async (int id, Todo inputTodo, TodoDb db) =>
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return Results.NotFound();
todo.Name = inputTodo.Name;
todo.IsComplete = inputTodo.IsComplete;
await db.SaveChangesAsync();
return Results.NoContent();
});
Tato metoda je podobná MapPost
metodě, s výjimkou použití HTTP PUT. Úspěšná odpověď vrátí hodnotu 204 (bez obsahu). Podle specifikace HTTP požadavek PUT vyžaduje, aby klient odeslal celou aktualizovanou entitu, nejen změny. Pokud chcete podporovat částečné aktualizace, použijte HTTP PATCH.
Testování koncového bodu PUT
Tato ukázka používá databázi v paměti, která se musí inicializovat při každém spuštění aplikace. Před voláním PUT musí být v databázi položka. Před voláním metody PUT zavolejte get a ujistěte se, že je v databázi položka.
Aktualizujte položku úkolu, která má Id = 1
, a nastavte její název na "feed fish"
.
V Průzkumníku koncových bodů klikněte pravým tlačítkem myši na koncový bod PUT a vyberte Vygenerovat požadavek.
Do souboru
TodoApi.http
byl přidán následující obsah:PUT {{TodoApi_HostAddress}}/todoitems/{id} ###
Na řádku požadavku PUT nahraďte
{id}
s1
.Přidejte následující řádky bezprostředně za řádek požadavku PUT:
Content-Type: application/json { "id": 1, "name": "feed fish", "isComplete": false }
Předchozí kód přidá hlavičku Content-Type a text požadavku JSON.
Vyberte odkaz Odeslat žádost, který je nad novým řádkem požadavku PUT.
Požadavek PUT se odešle do aplikace a odpověď se zobrazí v podokně Odpovědi . Tělo odpovědi je prázdné a stavový kód je 204.
Prozkoumání a otestování koncového bodu DELETE
Ukázková aplikace implementuje jeden koncový bod DELETE pomocí MapDelete
:
app.MapDelete("/todoitems/{id}", async (int id, TodoDb db) =>
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return Results.NoContent();
}
return Results.NotFound();
});
V Průzkumníku koncových bodů klikněte pravým tlačítkem na koncový bod DELETE a vyberte Vygenerovat požadavek.
Přidá se DELETE požadavek k
TodoApi.http
.Nahraďte
{id}
v řádku žádosti DELETE textem1
. Požadavek DELETE by měl vypadat jako v následujícím příkladu:DELETE {{TodoApi_HostAddress}}/todoitems/1 ###
Vyberte odkaz Odeslat žádost pro požadavek DELETE.
Požadavek DELETE se odešle do aplikace a odpověď se zobrazí v podokně Odpovědi . Tělo odpovědi je prázdné a stavový kód je 204.
Použití rozhraní MapGroup API
Vzorový kód aplikace opakuje předponu todoitems
adresy URL pokaždé, když nastaví koncový bod. Rozhraní API často obsahují skupiny koncových bodů se společnou předponou adresy URL a metoda MapGroup je k dispozici k uspořádání takových skupin. Redukuje opakující se kód a umožňuje přizpůsobit celé skupiny koncových bodů jediným voláním metod, jako RequireAuthorization a WithMetadata.
Program.cs
Obsah nahraďte následujícím kódem:
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();
var todoItems = app.MapGroup("/todoitems");
todoItems.MapGet("/", async (TodoDb db) =>
await db.Todos.ToListAsync());
todoItems.MapGet("/complete", async (TodoDb db) =>
await db.Todos.Where(t => t.IsComplete).ToListAsync());
todoItems.MapGet("/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound());
todoItems.MapPost("/", async (Todo todo, TodoDb db) =>
{
db.Todos.Add(todo);
await db.SaveChangesAsync();
return Results.Created($"/todoitems/{todo.Id}", todo);
});
todoItems.MapPut("/{id}", async (int id, Todo inputTodo, TodoDb db) =>
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return Results.NotFound();
todo.Name = inputTodo.Name;
todo.IsComplete = inputTodo.IsComplete;
await db.SaveChangesAsync();
return Results.NoContent();
});
todoItems.MapDelete("/{id}", async (int id, TodoDb db) =>
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return Results.NoContent();
}
return Results.NotFound();
});
app.Run();
Předchozí kód má následující změny:
- Přidá
var todoItems = app.MapGroup("/todoitems");
k nastavení skupiny pomocí předpony adresy URL/todoitems
. - Změní všechny
app.Map<HttpVerb>
metody natodoItems.Map<HttpVerb>
. - Odebere předponu
/todoitems
adresy URL zMap<HttpVerb>
volání metod.
Otestujte koncové body a ověřte, že fungují stejně.
Použití rozhraní TypedResults API
Vracení TypedResults místo Results má několik výhod, včetně testovatelnosti a automatického vracení metadat typu odpovědi pro OpenAPI k popisu koncového bodu. Další informace naleznete v tématu TypedResults vs Results.
Metody Map<HttpVerb>
mohou místo lambda volat metody obslužné rutiny trasy. Pokud chcete zobrazit příklad, aktualizujte Program.cs následujícím kódem:
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();
var todoItems = app.MapGroup("/todoitems");
todoItems.MapGet("/", GetAllTodos);
todoItems.MapGet("/complete", GetCompleteTodos);
todoItems.MapGet("/{id}", GetTodo);
todoItems.MapPost("/", CreateTodo);
todoItems.MapPut("/{id}", UpdateTodo);
todoItems.MapDelete("/{id}", DeleteTodo);
app.Run();
static async Task<IResult> GetAllTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.ToArrayAsync());
}
static async Task<IResult> GetCompleteTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.Where(t => t.IsComplete).ToListAsync());
}
static async Task<IResult> GetTodo(int id, TodoDb db)
{
return await db.Todos.FindAsync(id)
is Todo todo
? TypedResults.Ok(todo)
: TypedResults.NotFound();
}
static async Task<IResult> CreateTodo(Todo todo, TodoDb db)
{
db.Todos.Add(todo);
await db.SaveChangesAsync();
return TypedResults.Created($"/todoitems/{todo.Id}", todo);
}
static async Task<IResult> UpdateTodo(int id, Todo inputTodo, TodoDb db)
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return TypedResults.NotFound();
todo.Name = inputTodo.Name;
todo.IsComplete = inputTodo.IsComplete;
await db.SaveChangesAsync();
return TypedResults.NoContent();
}
static async Task<IResult> DeleteTodo(int id, TodoDb db)
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return TypedResults.NoContent();
}
return TypedResults.NotFound();
}
Kód Map<HttpVerb>
teď volá metody místo lambda:
var todoItems = app.MapGroup("/todoitems");
todoItems.MapGet("/", GetAllTodos);
todoItems.MapGet("/complete", GetCompleteTodos);
todoItems.MapGet("/{id}", GetTodo);
todoItems.MapPost("/", CreateTodo);
todoItems.MapPut("/{id}", UpdateTodo);
todoItems.MapDelete("/{id}", DeleteTodo);
Tyto metody vracejí objekty, které implementují IResult a jsou definovány TypedResults:
static async Task<IResult> GetAllTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.ToArrayAsync());
}
static async Task<IResult> GetCompleteTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.Where(t => t.IsComplete).ToListAsync());
}
static async Task<IResult> GetTodo(int id, TodoDb db)
{
return await db.Todos.FindAsync(id)
is Todo todo
? TypedResults.Ok(todo)
: TypedResults.NotFound();
}
static async Task<IResult> CreateTodo(Todo todo, TodoDb db)
{
db.Todos.Add(todo);
await db.SaveChangesAsync();
return TypedResults.Created($"/todoitems/{todo.Id}", todo);
}
static async Task<IResult> UpdateTodo(int id, Todo inputTodo, TodoDb db)
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return TypedResults.NotFound();
todo.Name = inputTodo.Name;
todo.IsComplete = inputTodo.IsComplete;
await db.SaveChangesAsync();
return TypedResults.NoContent();
}
static async Task<IResult> DeleteTodo(int id, TodoDb db)
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return TypedResults.NoContent();
}
return TypedResults.NotFound();
}
Testy jednotek mohou volat tyto metody a testovat, že vracejí správný datový typ. Například pokud je metoda GetAllTodos
:
static async Task<IResult> GetAllTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.ToArrayAsync());
}
Kód unit testu může ověřit, že objekt typu Ok<Todo[]> je vrácen z metody obslužné rutiny. Příklad:
public async Task GetAllTodos_ReturnsOkOfTodosResult()
{
// Arrange
var db = CreateDbContext();
// Act
var result = await TodosApi.GetAllTodos(db);
// Assert: Check for the correct returned type
Assert.IsType<Ok<Todo[]>>(result);
}
Zamezte nadměrnému zveřejňování
V současné době ukázková aplikace zveřejňuje celý Todo
objekt. V produkčních aplikacích se podmnožina modelu často používá k omezení dat, která mohou být vstupní a vrácená. Z tohoto důvodu existuje několik důvodů a zabezpečení je hlavním důvodem. Podmnožina modelu se obvykle označuje jako objekt pro přenos dat (DTO), vstupní model nebo model zobrazení.
DTO se používá v tomto článku.
DTO lze použít k:
- Zabránit nadměrnému příspěvkování.
- Skryjte vlastnosti, které klienti nemají zobrazit.
- Vynechejte některé vlastnosti pro zmenšení velikosti datové části.
- Zplošťujte grafy objektů, které obsahují vnořené objekty. Grafy plochých objektů můžou být pro klienty pohodlnější.
Pokud chcete předvést přístup DTO, aktualizujte Todo
třídu tak, aby obsahovala pole tajného kódu:
public class Todo
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public string? Secret { get; set; }
}
Pole tajného kódu musí být v této aplikaci skryté, ale aplikace pro správu by se mohla rozhodnout, že ho zveřejní.
Ověřte, že můžete publikovat a získat tajné pole.
Vytvořte soubor s názvem TodoItemDTO.cs
s následujícím kódem:
public class TodoItemDTO
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public TodoItemDTO() { }
public TodoItemDTO(Todo todoItem) =>
(Id, Name, IsComplete) = (todoItem.Id, todoItem.Name, todoItem.IsComplete);
}
Program.cs
Obsah souboru nahraďte následujícím kódem, který použije tento model DTO:
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();
RouteGroupBuilder todoItems = app.MapGroup("/todoitems");
todoItems.MapGet("/", GetAllTodos);
todoItems.MapGet("/complete", GetCompleteTodos);
todoItems.MapGet("/{id}", GetTodo);
todoItems.MapPost("/", CreateTodo);
todoItems.MapPut("/{id}", UpdateTodo);
todoItems.MapDelete("/{id}", DeleteTodo);
app.Run();
static async Task<IResult> GetAllTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.Select(x => new TodoItemDTO(x)).ToArrayAsync());
}
static async Task<IResult> GetCompleteTodos(TodoDb db) {
return TypedResults.Ok(await db.Todos.Where(t => t.IsComplete).Select(x => new TodoItemDTO(x)).ToListAsync());
}
static async Task<IResult> GetTodo(int id, TodoDb db)
{
return await db.Todos.FindAsync(id)
is Todo todo
? TypedResults.Ok(new TodoItemDTO(todo))
: TypedResults.NotFound();
}
static async Task<IResult> CreateTodo(TodoItemDTO todoItemDTO, TodoDb db)
{
var todoItem = new Todo
{
IsComplete = todoItemDTO.IsComplete,
Name = todoItemDTO.Name
};
db.Todos.Add(todoItem);
await db.SaveChangesAsync();
todoItemDTO = new TodoItemDTO(todoItem);
return TypedResults.Created($"/todoitems/{todoItem.Id}", todoItemDTO);
}
static async Task<IResult> UpdateTodo(int id, TodoItemDTO todoItemDTO, TodoDb db)
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return TypedResults.NotFound();
todo.Name = todoItemDTO.Name;
todo.IsComplete = todoItemDTO.IsComplete;
await db.SaveChangesAsync();
return TypedResults.NoContent();
}
static async Task<IResult> DeleteTodo(int id, TodoDb db)
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return TypedResults.NoContent();
}
return TypedResults.NotFound();
}
Ověřte, že můžete publikovat a získat všechna pole kromě tajného pole.
Řešení potíží s dokončeným příkladem
Pokud narazíte na problém, který nemůžete vyřešit, porovnejte kód s dokončeným projektem. Zobrazit nebo stáhnout dokončený projekt (jak stáhnout)
Další kroky
- Nakonfigurujte možnosti serializace JSON.
- Zpracování chyb a výjimek: Stránka vývojářských výjimek je ve výchozím nastavení povolena ve vývojovém prostředí pro minimalistické API aplikace. Informace o zpracování chyb a výjimek najdete v tématu Zpracování chyb v rozhraních ASP.NET Core API.
- Příklad testování minimální aplikace API najdete v této ukázce GitHubu.
- Podpora OpenAPI pro minimální rozhraní
- Rychlý start: Publikování do Azure
- Uspořádání minimalních rozhraní API ASP.NET Core
Další informace
Stručné referenční informace k minimálním rozhraním API
Minimální rozhraní API jsou navržena tak, aby vytvářela rozhraní HTTP API s minimálními závislostmi. Jsou ideální pro mikroslužby a aplikace, které chtějí do ASP.NET Core zahrnout jenom minimální soubory, funkce a závislosti.
V tomto kurzu se naučíte základy vytváření minimálního rozhraní API pomocí ASP.NET Core. Dalším přístupem k vytváření rozhraní API v ASP.NET Core je použití kontrolerů. Nápovědu k výběru mezi minimálními rozhraními API a rozhraními API založenými na kontroleru najdete v přehledu rozhraní API. Kurz vytvoření projektu rozhraní API na základě kontrolerů , které obsahují další funkce, najdete v tématu Vytvoření webového rozhraní API.
Přehled
Tento kurz vytvoří následující rozhraní API:
API (rozhraní pro programování aplikací) | Popis | Text požadavku | Tělo odpovědi |
---|---|---|---|
GET /todoitems |
Získání všech položek úkolů | Nic | Pole položek úkolů |
GET /todoitems/complete |
Získejte dokončené úkoly | Nic | Pole položek úkolů |
GET /todoitems/{id} |
Získejte položku podle ID | Nic | Úkol k vyřízení |
POST /todoitems |
Přidání nové položky | Úkol k vyřízení | Úkol k vyřízení |
PUT /todoitems/{id} |
Aktualizace existující položky | Úkol k vyřízení | Nic |
DELETE /todoitems/{id} |
Odstranění položky | Nic | Nic |
Požadavky
Visual Studio 2022 s pracovním zatížením ASP.NET a vývoje webu
Vytvoření projektu rozhraní API
Spusťte Visual Studio 2022 a vyberte Vytvořit nový projekt.
V dialogovém okně Vytvořit nový projekt :
- Zadejte
Empty
do vyhledávacího pole Hledat šablony . - Vyberte šablonu ASP.NET Core Empty a vyberte Další.
- Zadejte
Pojmenujte projekt TodoApi a vyberte Další.
V dialogovém okně Další informace :
- Vyberte .NET 7.0.
- Zrušte zaškrtnutí políčka Nepoužívat příkazy nejvyšší úrovně
- Vyberte příkaz Vytvořit.
Kontrola kódu
Soubor Program.cs
obsahuje následující kód:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
Předchozí kód:
- Vytvoří WebApplicationBuilder a WebApplication s předkonfigurovanými výchozími nastaveními.
- Vytvoří koncový bod
/
HTTP GET, který vrátíHello World!
:
Spustit aplikaci
Stisknutím kombinace kláves Ctrl+F5 spusťte bez debuggeru.
Visual Studio zobrazí následující dialogové okno:
Pokud důvěřujete certifikátu SSL služby IIS Express, vyberte Ano .
Zobrazí se následující dialogové okno:
Pokud souhlasíte s tím, že se má důvěřovat vývojovému certifikátu, vyberte Ano.
Informace o tom, jak důvěřovat prohlížeči Firefox, naleznete v části k chybě certifikátu Firefox SEC_ERROR_INADEQUATE_KEY_USAGE.
Visual Studio spustí Kestrel webový server a otevře okno prohlížeče.
Hello World!
se zobrazí v prohlížeči. Soubor Program.cs
obsahuje minimální, ale kompletní aplikaci.
Přidání balíčků NuGet
Pro podporu databáze a diagnostiky používané v tomto kurzu je potřeba přidat balíčky NuGet.
- V nabídce Nástroje vyberte NuGet Správce balíčků > Spravovat balíčky NuGet pro řešení.
- Vyberte kartu Procházet.
- Do vyhledávacího pole zadejte Microsoft.EntityFrameworkCore.InMemory a pak vyberte
Microsoft.EntityFrameworkCore.InMemory
. - Zaškrtněte políčko Project v pravém podokně.
- V rozevíracím seznamu Verze vyberte nejnovější dostupnou verzi 7, například
7.0.17
a pak vyberte Nainstalovat. - Podle předchozích pokynů přidejte balíček s nejnovější dostupnou
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
verzí 7.
Třídy kontextu modelu a databáze
Ve složce projektu vytvořte soubor s názvem Todo.cs
s následujícím kódem:
public class Todo
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Předchozí kód vytvoří model pro tuto aplikaci. Model je třída, která představuje data, která aplikace spravuje.
Vytvořte soubor s názvem TodoDb.cs
s následujícím kódem:
using Microsoft.EntityFrameworkCore;
class TodoDb : DbContext
{
public TodoDb(DbContextOptions<TodoDb> options)
: base(options) { }
public DbSet<Todo> Todos => Set<Todo>();
}
Předchozí kód definuje kontext databáze, což je hlavní třída, která koordinuje funkce Entity Framework pro datový model. Tato třída je odvozena od Microsoft.EntityFrameworkCore.DbContext třídy.
Přidání kódu rozhraní API
Obsah souboru Program.cs
nahraďte následujícím kódem:
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();
app.MapGet("/todoitems", async (TodoDb db) =>
await db.Todos.ToListAsync());
app.MapGet("/todoitems/complete", async (TodoDb db) =>
await db.Todos.Where(t => t.IsComplete).ToListAsync());
app.MapGet("/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound());
app.MapPost("/todoitems", async (Todo todo, TodoDb db) =>
{
db.Todos.Add(todo);
await db.SaveChangesAsync();
return Results.Created($"/todoitems/{todo.Id}", todo);
});
app.MapPut("/todoitems/{id}", async (int id, Todo inputTodo, TodoDb db) =>
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return Results.NotFound();
todo.Name = inputTodo.Name;
todo.IsComplete = inputTodo.IsComplete;
await db.SaveChangesAsync();
return Results.NoContent();
});
app.MapDelete("/todoitems/{id}", async (int id, TodoDb db) =>
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return Results.NoContent();
}
return Results.NotFound();
});
app.Run();
Následující zvýrazněný kód přidá kontext databáze do kontejneru injektáže závislostí (DI) a povolí zobrazení výjimek souvisejících s databází:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();
Kontejner DI poskytuje přístup k kontextu databáze a dalším službám.
Vytvoření uživatelského rozhraní api pro testování pomocí Swaggeru
Můžete si vybrat z mnoha dostupných testovacích nástrojů webového rozhraní API a můžete postupovat podle úvodních testovacích kroků tohoto kurzu pomocí vlastního preferovaného nástroje.
Tento kurz využívá balíček .NET NSwag.AspNetCore, který integruje nástroje Swaggeru pro generování testovacího uživatelského rozhraní, které dodržuje specifikaci OpenAPI:
- NSwag: Knihovna .NET, která integruje Swagger přímo do aplikací ASP.NET Core a poskytuje middleware a konfiguraci.
- Swagger: Sada opensourcových nástrojů, jako jsou OpenAPIGenerator a SwaggerUI, které generují stránky testování rozhraní API, které se řídí specifikací OpenAPI.
- Specifikace OpenAPI: Dokument, který popisuje možnosti rozhraní API na základě anotací XML a atributů v rámci kontrolerů a modelů.
Další informace o používání OpenAPI a NSwag s ASP.NET najdete v dokumentaci k webovému rozhraní API pro ASP.NET Core pomocí Swaggeru nebo OpenAPI.
Instalace nástrojů Swagger
Spusťte následující příkaz:
dotnet add package NSwag.AspNetCore
Předchozí příkaz přidá balíček NSwag.AspNetCore , který obsahuje nástroje pro generování dokumentů a uživatelského rozhraní Swagger.
Konfigurace middlewaru Swaggeru
Před tím, než je
app
definován na řádkuvar app = builder.Build();
, přidejte následující zvýrazněný kód.using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList")); builder.Services.AddDatabaseDeveloperPageExceptionFilter(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddOpenApiDocument(config => { config.DocumentName = "TodoAPI"; config.Title = "TodoAPI v1"; config.Version = "v1"; }); var app = builder.Build();
V předchozím kódu:
builder.Services.AddEndpointsApiExplorer();
: Povolí Průzkumníka rozhraní API, což je služba, která poskytuje metadata o rozhraní HTTP API. Swagger používá Průzkumník rozhraní API k vygenerování dokumentu Swagger.builder.Services.AddOpenApiDocument(config => {...});
: Přidá generátor dokumentů Swagger OpenAPI do aplikačních služeb a nakonfiguruje ho tak, aby poskytoval další informace o rozhraní API, jako je jeho název a verze. Informace o poskytování robustnějších podrobností rozhraní API najdete v tématu Začínáme se službou NSwag a ASP.NET Core.Přidejte následující zvýrazněný kód na další řádek za definici
app
na řádkuvar app = builder.Build();
.var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseOpenApi(); app.UseSwaggerUi(config => { config.DocumentTitle = "TodoAPI"; config.Path = "/swagger"; config.DocumentPath = "/swagger/{documentName}/swagger.json"; config.DocExpansion = "list"; }); }
Předchozí kód umožňuje middleware Swagger pro obsluhu generovaného dokumentu JSON a uživatelského rozhraní Swagger. Swagger je povolený jenom ve vývojovém prostředí. Povolení Swaggeru v produkčním prostředí by mohlo vystavit potenciálně citlivé podrobnosti o struktuře a implementaci rozhraní API.
Testování zveřejňování dat
Následující kód v Program.cs
vytvoří HTTP POST koncový bod /todoitems
, který přidá data do paměťové databáze:
app.MapPost("/todoitems", async (Todo todo, TodoDb db) =>
{
db.Todos.Add(todo);
await db.SaveChangesAsync();
return Results.Created($"/todoitems/{todo.Id}", todo);
});
Spustit aplikaci. Prohlížeč zobrazí chybu 404, protože /
koncový bod již neexistuje.
Koncový bod POST se použije k přidání dat do aplikace.
Když aplikace stále běží, v prohlížeči přejděte na
https://localhost:<port>/swagger
, abyste zobrazili stránku testování rozhraní API vygenerovanou Swaggerem.Na stránce pro testování rozhraní Swagger API vyberte Post /todoitems>.
Všimněte si, že pole Text požadavku obsahuje vygenerovaný ukázkový formát, který odráží parametry rozhraní API.
V textu požadavku zadejte JSON pro položku úkolu bez zadání volitelné
id
položky:{ "name":"walk dog", "isComplete":true }
Vyberte Provést.
Swagger poskytuje podokno Odpovědi pod tlačítkem Spustit.
Poznamenejte si několik užitečných podrobností:
- cURL: Swagger poskytuje příklad příkazu cURL v syntaxi systému Unix/Linux, který se dá spustit na příkazovém řádku s libovolným prostředím Bash, které používá syntaxi systému Unix/Linux, včetně Git Bashu z Gitu pro Windows.
- Adresa URL požadavku: Zjednodušená reprezentace požadavku HTTP vytvořeného kódem JavaScript uživatelského rozhraní Swagger pro volání rozhraní API. Skutečné požadavky můžou obsahovat podrobnosti, jako jsou hlavičky a parametry dotazu a text požadavku.
- Odpověď serveru: Obsahuje text odpovědi a hlavičky. Tělo odpovědi ukazuje, že
id
byla nastavena na1
. - Kód odpovědi: Vrátil se stavový kód 201
HTTP
, který indikoval, že požadavek byl úspěšně zpracován a způsobil vytvoření nového prostředku.
Prozkoumání koncových bodů GET
Ukázková aplikace implementuje několik koncových bodů GET voláním MapGet
:
API (rozhraní pro programování aplikací) | Popis | Text požadavku | Tělo odpovědi |
---|---|---|---|
GET /todoitems |
Získání všech položek úkolů | Nic | Pole položek úkolů |
GET /todoitems/complete |
Získání všech dokončených položek úkolů | Nic | Pole položek úkolů |
GET /todoitems/{id} |
Získejte položku podle ID | Nic | Úkol k vyřízení |
app.MapGet("/todoitems", async (TodoDb db) =>
await db.Todos.ToListAsync());
app.MapGet("/todoitems/complete", async (TodoDb db) =>
await db.Todos.Where(t => t.IsComplete).ToListAsync());
app.MapGet("/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound());
Testování koncových bodů GET
Otestujte aplikaci voláním koncových bodů z prohlížeče nebo Swaggeru.
V Swaggeru vyberte GET /todoitems>Vyzkoušejte to>Spustit.
Alternativně volejte GET /todoitems v prohlížeči zadáním adresy URI
http://localhost:<port>/todoitems
. Napříkladhttp://localhost:5001/todoitems
Volání na GET /todoitems
vytvoří odpověď podobnou následující:
[
{
"id": 1,
"name": "walk dog",
"isComplete": true
}
]
Zavolejte GET /todoitems/{id} ve Swaggeru pro získání dat pro konkrétní ID.
- Vyberte GET /todoitems>Vyzkoušet.
-
Nastavte pole ID na
1
a vyberte Spustit.
Alternativně volejte GET /todoitems v prohlížeči zadáním adresy URI
https://localhost:<port>/todoitems/1
. Napříkladhttps://localhost:5001/todoitems/1
Odpověď je podobná následující:
{ "id": 1, "name": "walk dog", "isComplete": true }
Tato aplikace používá databázi v paměti. Pokud se aplikace restartuje, požadavek GET nevrací žádná data. Pokud se nevrátí žádná data, post data do aplikace a zkuste požadavek GET zopakovat.
Vrácené hodnoty
ASP.NET Core automaticky serializuje objekt do formátu JSON a zapíše json do textu zprávy odpovědi. Kód odpovědi pro tento návratový typ je 200 OK, za předpokladu, že neexistují žádné neošetřené výjimky. Neošetřené výjimky se překládají do chyb 5xx.
Návratové typy mohou představovat širokou škálu stavových kódů HTTP. Může například GET /todoitems/{id}
vrátit dvě různé hodnoty stavu:
- Pokud žádná položka neodpovídá požadovanému ID, vrátí metoda kód chyby stavuNotFound 404.
- V opačném případě metoda vrátí hodnotu 200 s textem odpovědi JSON. Vrácení
item
vede k odpovědi HTTP 200.
Prozkoumání koncového bodu PUT
Ukázková aplikace implementuje jeden koncový bod PUT pomocí MapPut
:
app.MapPut("/todoitems/{id}", async (int id, Todo inputTodo, TodoDb db) =>
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return Results.NotFound();
todo.Name = inputTodo.Name;
todo.IsComplete = inputTodo.IsComplete;
await db.SaveChangesAsync();
return Results.NoContent();
});
Tato metoda je podobná MapPost
metodě, s výjimkou použití HTTP PUT. Úspěšná odpověď vrátí hodnotu 204 (bez obsahu). Podle specifikace HTTP požadavek PUT vyžaduje, aby klient odeslal celou aktualizovanou entitu, nejen změny. Pokud chcete podporovat částečné aktualizace, použijte HTTP PATCH.
Testování koncového bodu PUT
Tato ukázka používá databázi v paměti, která se musí inicializovat při každém spuštění aplikace. Před voláním PUT musí být v databázi položka. Před voláním metody PUT zavolejte get a ujistěte se, že je v databázi položka.
Aktualizujte položku úkolu, která má Id = 1
, a nastavte její název na "feed fish"
.
Odeslání požadavku PUT pomocí Swaggeru:
Vyberte Put /todoitems/{id}>Vyzkoušet.
Nastavte pole ID na hodnotu
1
.Nastavte text požadavku na následující JSON:
{ "name": "feed fish", "isComplete": false }
Vyberte Provést.
Prozkoumání a otestování koncového bodu DELETE
Ukázková aplikace implementuje jeden koncový bod DELETE pomocí MapDelete
:
app.MapDelete("/todoitems/{id}", async (int id, TodoDb db) =>
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return Results.NoContent();
}
return Results.NotFound();
});
K odeslání požadavku DELETE použijte Swagger:
Vyberte DELETE /todoitems/{id}>Vyzkoušet.
Nastavte pole ID na
1
a vyberte Spustit.Požadavek DELETE se odešle do aplikace a odpověď se zobrazí v podokně Odpovědi . Tělo odpovědi je prázdné a stavový kód odpovědi serveru je 204.
Použití rozhraní MapGroup API
Vzorový kód aplikace opakuje předponu todoitems
adresy URL pokaždé, když nastaví koncový bod. Rozhraní API často obsahují skupiny koncových bodů se společnou předponou adresy URL a metoda MapGroup je k dispozici k uspořádání takových skupin. Redukuje opakující se kód a umožňuje přizpůsobit celé skupiny koncových bodů jediným voláním metod, jako RequireAuthorization a WithMetadata.
Program.cs
Obsah nahraďte následujícím kódem:
using NSwag.AspNetCore;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddOpenApiDocument(config =>
{
config.DocumentName = "TodoAPI";
config.Title = "TodoAPI v1";
config.Version = "v1";
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseOpenApi();
app.UseSwaggerUi(config =>
{
config.DocumentTitle = "TodoAPI";
config.Path = "/swagger";
config.DocumentPath = "/swagger/{documentName}/swagger.json";
config.DocExpansion = "list";
});
}
var todoItems = app.MapGroup("/todoitems");
todoItems.MapGet("/", async (TodoDb db) =>
await db.Todos.ToListAsync());
todoItems.MapGet("/complete", async (TodoDb db) =>
await db.Todos.Where(t => t.IsComplete).ToListAsync());
todoItems.MapGet("/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound());
todoItems.MapPost("/", async (Todo todo, TodoDb db) =>
{
db.Todos.Add(todo);
await db.SaveChangesAsync();
return Results.Created($"/todoitems/{todo.Id}", todo);
});
todoItems.MapPut("/{id}", async (int id, Todo inputTodo, TodoDb db) =>
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return Results.NotFound();
todo.Name = inputTodo.Name;
todo.IsComplete = inputTodo.IsComplete;
await db.SaveChangesAsync();
return Results.NoContent();
});
todoItems.MapDelete("/{id}", async (int id, TodoDb db) =>
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return Results.NoContent();
}
return Results.NotFound();
});
app.Run();
Předchozí kód má následující změny:
- Přidá
var todoItems = app.MapGroup("/todoitems");
k nastavení skupiny pomocí předpony adresy URL/todoitems
. - Změní všechny
app.Map<HttpVerb>
metody natodoItems.Map<HttpVerb>
. - Odebere předponu
/todoitems
adresy URL zMap<HttpVerb>
volání metod.
Otestujte koncové body a ověřte, že fungují stejně.
Použití rozhraní TypedResults API
Vracení TypedResults místo Results má několik výhod, včetně testovatelnosti a automatického vracení metadat typu odpovědi pro OpenAPI k popisu koncového bodu. Další informace naleznete v tématu TypedResults vs Results.
Metody Map<HttpVerb>
mohou místo lambda volat metody obslužné rutiny trasy. Pokud chcete zobrazit příklad, aktualizujte Program.cs následujícím kódem:
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();
var todoItems = app.MapGroup("/todoitems");
todoItems.MapGet("/", GetAllTodos);
todoItems.MapGet("/complete", GetCompleteTodos);
todoItems.MapGet("/{id}", GetTodo);
todoItems.MapPost("/", CreateTodo);
todoItems.MapPut("/{id}", UpdateTodo);
todoItems.MapDelete("/{id}", DeleteTodo);
app.Run();
static async Task<IResult> GetAllTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.ToArrayAsync());
}
static async Task<IResult> GetCompleteTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.Where(t => t.IsComplete).ToListAsync());
}
static async Task<IResult> GetTodo(int id, TodoDb db)
{
return await db.Todos.FindAsync(id)
is Todo todo
? TypedResults.Ok(todo)
: TypedResults.NotFound();
}
static async Task<IResult> CreateTodo(Todo todo, TodoDb db)
{
db.Todos.Add(todo);
await db.SaveChangesAsync();
return TypedResults.Created($"/todoitems/{todo.Id}", todo);
}
static async Task<IResult> UpdateTodo(int id, Todo inputTodo, TodoDb db)
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return TypedResults.NotFound();
todo.Name = inputTodo.Name;
todo.IsComplete = inputTodo.IsComplete;
await db.SaveChangesAsync();
return TypedResults.NoContent();
}
static async Task<IResult> DeleteTodo(int id, TodoDb db)
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return TypedResults.NoContent();
}
return TypedResults.NotFound();
}
Kód Map<HttpVerb>
teď volá metody místo lambda:
var todoItems = app.MapGroup("/todoitems");
todoItems.MapGet("/", GetAllTodos);
todoItems.MapGet("/complete", GetCompleteTodos);
todoItems.MapGet("/{id}", GetTodo);
todoItems.MapPost("/", CreateTodo);
todoItems.MapPut("/{id}", UpdateTodo);
todoItems.MapDelete("/{id}", DeleteTodo);
Tyto metody vracejí objekty, které implementují IResult a jsou definovány TypedResults:
static async Task<IResult> GetAllTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.ToArrayAsync());
}
static async Task<IResult> GetCompleteTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.Where(t => t.IsComplete).ToListAsync());
}
static async Task<IResult> GetTodo(int id, TodoDb db)
{
return await db.Todos.FindAsync(id)
is Todo todo
? TypedResults.Ok(todo)
: TypedResults.NotFound();
}
static async Task<IResult> CreateTodo(Todo todo, TodoDb db)
{
db.Todos.Add(todo);
await db.SaveChangesAsync();
return TypedResults.Created($"/todoitems/{todo.Id}", todo);
}
static async Task<IResult> UpdateTodo(int id, Todo inputTodo, TodoDb db)
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return TypedResults.NotFound();
todo.Name = inputTodo.Name;
todo.IsComplete = inputTodo.IsComplete;
await db.SaveChangesAsync();
return TypedResults.NoContent();
}
static async Task<IResult> DeleteTodo(int id, TodoDb db)
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return TypedResults.NoContent();
}
return TypedResults.NotFound();
}
Testy jednotek mohou volat tyto metody a testovat, že vracejí správný datový typ. Například pokud je metoda GetAllTodos
:
static async Task<IResult> GetAllTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.ToArrayAsync());
}
Kód unit testu může ověřit, že objekt typu Ok<Todo[]> je vrácen z metody obslužné rutiny. Příklad:
public async Task GetAllTodos_ReturnsOkOfTodosResult()
{
// Arrange
var db = CreateDbContext();
// Act
var result = await TodosApi.GetAllTodos(db);
// Assert: Check for the correct returned type
Assert.IsType<Ok<Todo[]>>(result);
}
Zamezte nadměrnému zveřejňování
V současné době ukázková aplikace zveřejňuje celý Todo
objekt. Produkční aplikace V produkčních aplikacích se podmnožina modelu často používá k omezení dat, která mohou být vstupní a vrácená. Z tohoto důvodu existuje několik důvodů a zabezpečení je hlavním důvodem. Podmnožina modelu se obvykle označuje jako objekt pro přenos dat (DTO), vstupní model nebo model zobrazení.
DTO se používá v tomto článku.
DTO lze použít k:
- Zabránit nadměrnému příspěvkování.
- Skryjte vlastnosti, které klienti nemají zobrazit.
- Vynechejte některé vlastnosti pro zmenšení velikosti datové části.
- Zplošťujte grafy objektů, které obsahují vnořené objekty. Grafy plochých objektů můžou být pro klienty pohodlnější.
Pokud chcete předvést přístup DTO, aktualizujte Todo
třídu tak, aby obsahovala pole tajného kódu:
public class Todo
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public string? Secret { get; set; }
}
Pole tajného kódu musí být v této aplikaci skryté, ale aplikace pro správu by se mohla rozhodnout, že ho zveřejní.
Ověřte, že můžete publikovat a získat tajné pole.
Vytvořte soubor s názvem TodoItemDTO.cs
s následujícím kódem:
public class TodoItemDTO
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public TodoItemDTO() { }
public TodoItemDTO(Todo todoItem) =>
(Id, Name, IsComplete) = (todoItem.Id, todoItem.Name, todoItem.IsComplete);
}
Program.cs
Obsah souboru nahraďte následujícím kódem, který použije tento model DTO:
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
var app = builder.Build();
app.MapGet("/todoitems", async (TodoDb db) =>
await db.Todos.Select(x => new TodoItemDTO(x)).ToListAsync());
app.MapGet("/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(new TodoItemDTO(todo))
: Results.NotFound());
app.MapPost("/todoitems", async (TodoItemDTO todoItemDTO, TodoDb db) =>
{
var todoItem = new Todo
{
IsComplete = todoItemDTO.IsComplete,
Name = todoItemDTO.Name
};
db.Todos.Add(todoItem);
await db.SaveChangesAsync();
return Results.Created($"/todoitems/{todoItem.Id}", new TodoItemDTO(todoItem));
});
app.MapPut("/todoitems/{id}", async (int id, TodoItemDTO todoItemDTO, TodoDb db) =>
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return Results.NotFound();
todo.Name = todoItemDTO.Name;
todo.IsComplete = todoItemDTO.IsComplete;
await db.SaveChangesAsync();
return Results.NoContent();
});
app.MapDelete("/todoitems/{id}", async (int id, TodoDb db) =>
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return Results.NoContent();
}
return Results.NotFound();
});
app.Run();
public class Todo
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public string? Secret { get; set; }
}
public class TodoItemDTO
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public TodoItemDTO() { }
public TodoItemDTO(Todo todoItem) =>
(Id, Name, IsComplete) = (todoItem.Id, todoItem.Name, todoItem.IsComplete);
}
class TodoDb : DbContext
{
public TodoDb(DbContextOptions<TodoDb> options)
: base(options) { }
public DbSet<Todo> Todos => Set<Todo>();
}
Ověřte, že můžete publikovat a získat všechna pole kromě tajného pole.
Řešení potíží s dokončeným příkladem
Pokud narazíte na problém, který nemůžete vyřešit, porovnejte kód s dokončeným projektem. Zobrazit nebo stáhnout dokončený projekt (jak stáhnout)
Další kroky
- Nakonfigurujte možnosti serializace JSON.
- Zpracování chyb a výjimek: Stránka vývojářských výjimek je ve výchozím nastavení povolena ve vývojovém prostředí pro minimalistické API aplikace. Informace o zpracování chyb a výjimek najdete v tématu Zpracování chyb v rozhraních ASP.NET Core API.
- Příklad testování minimální aplikace API najdete v této ukázce GitHubu.
- Podpora OpenAPI pro minimální rozhraní
- Rychlý start: Publikování do Azure
- Uspořádání minimalních rozhraní API ASP.NET Core
Další informace
Stručné referenční informace k minimálním rozhraním API
Minimální rozhraní API jsou navržena tak, aby vytvářela rozhraní HTTP API s minimálními závislostmi. Jsou ideální pro mikroslužby a aplikace, které chtějí do ASP.NET Core zahrnout jenom minimální soubory, funkce a závislosti.
V tomto kurzu se naučíte základy vytváření minimálního rozhraní API pomocí ASP.NET Core. Dalším přístupem k vytváření rozhraní API v ASP.NET Core je použití kontrolerů. Nápovědu k výběru mezi minimálními rozhraními API a rozhraními API založenými na kontroleru najdete v přehledu rozhraní API. Kurz vytvoření projektu rozhraní API na základě kontrolerů , které obsahují další funkce, najdete v tématu Vytvoření webového rozhraní API.
Přehled
Tento kurz vytvoří následující rozhraní API:
API (rozhraní pro programování aplikací) | Popis | Text požadavku | Tělo odpovědi |
---|---|---|---|
GET /todoitems |
Získání všech položek úkolů | Nic | Pole položek úkolů |
GET /todoitems/complete |
Získejte dokončené úkoly | Nic | Pole položek úkolů |
GET /todoitems/{id} |
Získejte položku podle ID | Nic | Úkol k vyřízení |
POST /todoitems |
Přidání nové položky | Úkol k vyřízení | Úkol k vyřízení |
PUT /todoitems/{id} |
Aktualizace existující položky | Úkol k vyřízení | Nic |
DELETE /todoitems/{id} |
Odstranění položky | Nic | Nic |
Požadavky
- Visual Studio 2022 s pracovním zatížením ASP.NET a vývoje webu
- Sada .NET 6 SDK
Vytvoření projektu rozhraní API
Spusťte Visual Studio 2022 a vyberte Vytvořit nový projekt.
V dialogovém okně Vytvořit nový projekt :
- Zadejte
Empty
do vyhledávacího pole Hledat šablony . - Vyberte šablonu ASP.NET Core Empty a vyberte Další.
- Zadejte
Pojmenujte projekt TodoApi a vyberte Další.
V dialogovém okně Další informace :
- Vyberte .NET 6.0
- Zrušte zaškrtnutí políčka Nepoužívat příkazy nejvyšší úrovně
- Vyberte příkaz Vytvořit.
Kontrola kódu
Soubor Program.cs
obsahuje následující kód:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
Předchozí kód:
- Vytvoří WebApplicationBuilder a WebApplication s předkonfigurovanými výchozími nastaveními.
- Vytvoří koncový bod
/
HTTP GET, který vrátíHello World!
:
Spustit aplikaci
Stisknutím kombinace kláves Ctrl+F5 spusťte bez debuggeru.
Visual Studio zobrazí následující dialogové okno:
Pokud důvěřujete certifikátu SSL služby IIS Express, vyberte Ano .
Zobrazí se následující dialogové okno:
Pokud souhlasíte s tím, že se má důvěřovat vývojovému certifikátu, vyberte Ano.
Informace o tom, jak důvěřovat prohlížeči Firefox, naleznete v části k chybě certifikátu Firefox SEC_ERROR_INADEQUATE_KEY_USAGE.
Visual Studio spustí Kestrel webový server a otevře okno prohlížeče.
Hello World!
se zobrazí v prohlížeči. Soubor Program.cs
obsahuje minimální, ale kompletní aplikaci.
Přidání balíčků NuGet
Pro podporu databáze a diagnostiky používané v tomto kurzu je potřeba přidat balíčky NuGet.
- V nabídce Nástroje vyberte NuGet Správce balíčků > Spravovat balíčky NuGet pro řešení.
- Vyberte kartu Procházet.
- Do vyhledávacího pole zadejte Microsoft.EntityFrameworkCore.InMemory a pak vyberte
Microsoft.EntityFrameworkCore.InMemory
. - Zaškrtněte políčko Project v pravém podokně.
- V rozevíracím seznamu Verze vyberte nejnovější dostupnou verzi 7, například
6.0.28
a pak vyberte Nainstalovat. - Podle předchozích pokynů přidejte balíček s nejnovější dostupnou
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
verzí 7.
Třídy kontextu modelu a databáze
Ve složce projektu vytvořte soubor s názvem Todo.cs
s následujícím kódem:
public class Todo
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Předchozí kód vytvoří model pro tuto aplikaci. Model je třída, která představuje data, která aplikace spravuje.
Vytvořte soubor s názvem TodoDb.cs
s následujícím kódem:
using Microsoft.EntityFrameworkCore;
class TodoDb : DbContext
{
public TodoDb(DbContextOptions<TodoDb> options)
: base(options) { }
public DbSet<Todo> Todos => Set<Todo>();
}
Předchozí kód definuje kontext databáze, což je hlavní třída, která koordinuje funkce Entity Framework pro datový model. Tato třída je odvozena od Microsoft.EntityFrameworkCore.DbContext třídy.
Přidání kódu rozhraní API
Obsah souboru Program.cs
nahraďte následujícím kódem:
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.MapGet("/todoitems", async (TodoDb db) =>
await db.Todos.ToListAsync());
app.MapGet("/todoitems/complete", async (TodoDb db) =>
await db.Todos.Where(t => t.IsComplete).ToListAsync());
app.MapGet("/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound());
app.MapPost("/todoitems", async (Todo todo, TodoDb db) =>
{
db.Todos.Add(todo);
await db.SaveChangesAsync();
return Results.Created($"/todoitems/{todo.Id}", todo);
});
app.MapPut("/todoitems/{id}", async (int id, Todo inputTodo, TodoDb db) =>
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return Results.NotFound();
todo.Name = inputTodo.Name;
todo.IsComplete = inputTodo.IsComplete;
await db.SaveChangesAsync();
return Results.NoContent();
});
app.MapDelete("/todoitems/{id}", async (int id, TodoDb db) =>
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return Results.NoContent();
}
return Results.NotFound();
});
app.Run();
Následující zvýrazněný kód přidá kontext databáze do kontejneru injektáže závislostí (DI) a povolí zobrazení výjimek souvisejících s databází:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();
Kontejner DI poskytuje přístup k kontextu databáze a dalším službám.
Vytvoření uživatelského rozhraní api pro testování pomocí Swaggeru
Můžete si vybrat z mnoha dostupných testovacích nástrojů webového rozhraní API a můžete postupovat podle úvodních testovacích kroků tohoto kurzu pomocí vlastního preferovaného nástroje.
Tento kurz využívá balíček .NET NSwag.AspNetCore, který integruje nástroje Swaggeru pro generování testovacího uživatelského rozhraní, které dodržuje specifikaci OpenAPI:
- NSwag: Knihovna .NET, která integruje Swagger přímo do aplikací ASP.NET Core a poskytuje middleware a konfiguraci.
- Swagger: Sada opensourcových nástrojů, jako jsou OpenAPIGenerator a SwaggerUI, které generují stránky testování rozhraní API, které se řídí specifikací OpenAPI.
- Specifikace OpenAPI: Dokument, který popisuje možnosti rozhraní API na základě anotací XML a atributů v rámci kontrolerů a modelů.
Další informace o používání OpenAPI a NSwag s ASP.NET najdete v dokumentaci k webovému rozhraní API pro ASP.NET Core pomocí Swaggeru nebo OpenAPI.
Instalace nástrojů Swagger
Spusťte následující příkaz:
dotnet add package NSwag.AspNetCore
Předchozí příkaz přidá balíček NSwag.AspNetCore , který obsahuje nástroje pro generování dokumentů a uživatelského rozhraní Swagger.
Konfigurace middlewaru Swaggeru
V Program.cs na začátek přidejte následující
using
příkazy:using NSwag.AspNetCore;
Před tím, než je
app
definován na řádkuvar app = builder.Build();
, přidejte následující zvýrazněný kód.using NSwag.AspNetCore; using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList")); builder.Services.AddDatabaseDeveloperPageExceptionFilter(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddOpenApiDocument(config => { config.DocumentName = "TodoAPI"; config.Title = "TodoAPI v1"; config.Version = "v1"; }); var app = builder.Build();
V předchozím kódu:
builder.Services.AddEndpointsApiExplorer();
: Povolí Průzkumníka rozhraní API, což je služba, která poskytuje metadata o rozhraní HTTP API. Swagger používá Průzkumník rozhraní API k vygenerování dokumentu Swagger.builder.Services.AddOpenApiDocument(config => {...});
: Přidá generátor dokumentů Swagger OpenAPI do aplikačních služeb a nakonfiguruje ho tak, aby poskytoval další informace o rozhraní API, jako je jeho název a verze. Informace o poskytování robustnějších podrobností rozhraní API najdete v tématu Začínáme se službou NSwag a ASP.NET Core.Přidejte následující zvýrazněný kód na další řádek za definici
app
na řádkuvar app = builder.Build();
.var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseOpenApi(); app.UseSwaggerUi(config => { config.DocumentTitle = "TodoAPI"; config.Path = "/swagger"; config.DocumentPath = "/swagger/{documentName}/swagger.json"; config.DocExpansion = "list"; }); }
Předchozí kód umožňuje middleware Swagger pro obsluhu generovaného dokumentu JSON a uživatelského rozhraní Swagger. Swagger je povolený jenom ve vývojovém prostředí. Povolení Swaggeru v produkčním prostředí by mohlo vystavit potenciálně citlivé podrobnosti o struktuře a implementaci rozhraní API.
Testování zveřejňování dat
Následující kód v Program.cs
vytvoří HTTP POST koncový bod /todoitems
, který přidá data do paměťové databáze:
app.MapPost("/todoitems", async (Todo todo, TodoDb db) =>
{
db.Todos.Add(todo);
await db.SaveChangesAsync();
return Results.Created($"/todoitems/{todo.Id}", todo);
});
Spustit aplikaci. Prohlížeč zobrazí chybu 404, protože /
koncový bod již neexistuje.
Koncový bod POST se použije k přidání dat do aplikace.
Když aplikace stále běží, v prohlížeči přejděte na
https://localhost:<port>/swagger
, abyste zobrazili stránku testování rozhraní API vygenerovanou Swaggerem.Na stránce pro testování rozhraní Swagger API vyberte Post /todoitems>.
Všimněte si, že pole Text požadavku obsahuje vygenerovaný ukázkový formát, který odráží parametry rozhraní API.
V textu požadavku zadejte JSON pro položku úkolu bez zadání volitelné
id
položky:{ "name":"walk dog", "isComplete":true }
Vyberte Provést.
Swagger poskytuje podokno Odpovědi pod tlačítkem Spustit.
Poznamenejte si několik užitečných podrobností:
- cURL: Swagger poskytuje příklad příkazu cURL v syntaxi systému Unix/Linux, který se dá spustit na příkazovém řádku s libovolným prostředím Bash, které používá syntaxi systému Unix/Linux, včetně Git Bashu z Gitu pro Windows.
- Adresa URL požadavku: Zjednodušená reprezentace požadavku HTTP vytvořeného kódem JavaScript uživatelského rozhraní Swagger pro volání rozhraní API. Skutečné požadavky můžou obsahovat podrobnosti, jako jsou hlavičky a parametry dotazu a text požadavku.
- Odpověď serveru: Obsahuje text odpovědi a hlavičky. Tělo odpovědi ukazuje, že
id
byla nastavena na1
. - Kód odpovědi: Vrátil se stavový kód 201
HTTP
, který indikoval, že požadavek byl úspěšně zpracován a způsobil vytvoření nového prostředku.
Prozkoumání koncových bodů GET
Ukázková aplikace implementuje několik koncových bodů GET voláním MapGet
:
API (rozhraní pro programování aplikací) | Popis | Text požadavku | Tělo odpovědi |
---|---|---|---|
GET /todoitems |
Získání všech položek úkolů | Nic | Pole položek úkolů |
GET /todoitems/complete |
Získání všech dokončených položek úkolů | Nic | Pole položek úkolů |
GET /todoitems/{id} |
Získejte položku podle ID | Nic | Úkol k vyřízení |
app.MapGet("/", () => "Hello World!");
app.MapGet("/todoitems", async (TodoDb db) =>
await db.Todos.ToListAsync());
app.MapGet("/todoitems/complete", async (TodoDb db) =>
await db.Todos.Where(t => t.IsComplete).ToListAsync());
app.MapGet("/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound());
Testování koncových bodů GET
Otestujte aplikaci voláním koncových bodů z prohlížeče nebo Swaggeru.
V Swaggeru vyberte GET /todoitems>Vyzkoušejte to>Spustit.
Alternativně volejte GET /todoitems v prohlížeči zadáním adresy URI
http://localhost:<port>/todoitems
. Napříkladhttp://localhost:5001/todoitems
Volání na GET /todoitems
vytvoří odpověď podobnou následující:
[
{
"id": 1,
"name": "walk dog",
"isComplete": true
}
]
Zavolejte GET /todoitems/{id} ve Swaggeru pro získání dat pro konkrétní ID.
- Vyberte GET /todoitems>Vyzkoušet.
-
Nastavte pole ID na
1
a vyberte Spustit.
Alternativně volejte GET /todoitems v prohlížeči zadáním adresy URI
https://localhost:<port>/todoitems/1
. Příklad:https://localhost:5001/todoitems/1
Odpověď je podobná následující:
{ "id": 1, "name": "walk dog", "isComplete": true }
Tato aplikace používá databázi v paměti. Pokud se aplikace restartuje, požadavek GET nevrací žádná data. Pokud se nevrátí žádná data, post data do aplikace a zkuste požadavek GET zopakovat.
Vrácené hodnoty
ASP.NET Core automaticky serializuje objekt do formátu JSON a zapíše json do textu zprávy odpovědi. Kód odpovědi pro tento návratový typ je 200 OK, za předpokladu, že neexistují žádné neošetřené výjimky. Neošetřené výjimky se překládají do chyb 5xx.
Návratové typy mohou představovat širokou škálu stavových kódů HTTP. Může například GET /todoitems/{id}
vrátit dvě různé hodnoty stavu:
- Pokud žádná položka neodpovídá požadovanému ID, vrátí metoda kód chyby stavuNotFound 404.
- V opačném případě metoda vrátí hodnotu 200 s textem odpovědi JSON. Vrácení
item
vede k odpovědi HTTP 200.
Prozkoumání koncového bodu PUT
Ukázková aplikace implementuje jeden koncový bod PUT pomocí MapPut
:
app.MapPut("/todoitems/{id}", async (int id, Todo inputTodo, TodoDb db) =>
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return Results.NotFound();
todo.Name = inputTodo.Name;
todo.IsComplete = inputTodo.IsComplete;
await db.SaveChangesAsync();
return Results.NoContent();
});
Tato metoda je podobná MapPost
metodě, s výjimkou použití HTTP PUT. Úspěšná odpověď vrátí hodnotu 204 (bez obsahu). Podle specifikace HTTP požadavek PUT vyžaduje, aby klient odeslal celou aktualizovanou entitu, nejen změny. Pokud chcete podporovat částečné aktualizace, použijte HTTP PATCH.
Testování koncového bodu PUT
Tato ukázka používá databázi v paměti, která se musí inicializovat při každém spuštění aplikace. Před voláním PUT musí být v databázi položka. Před voláním metody PUT zavolejte get a ujistěte se, že je v databázi položka.
Aktualizujte položku úkolu, která má Id = 1
, a nastavte její název na "feed fish"
.
Odeslání požadavku PUT pomocí Swaggeru:
Vyberte Put /todoitems/{id}>Vyzkoušet.
Nastavte pole ID na hodnotu
1
.Nastavte text požadavku na následující JSON:
{ "name": "feed fish", "isComplete": false }
Vyberte Provést.
Prozkoumání a otestování koncového bodu DELETE
Ukázková aplikace implementuje jeden koncový bod DELETE pomocí MapDelete
:
app.MapDelete("/todoitems/{id}", async (int id, TodoDb db) =>
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return Results.NoContent();
}
return Results.NotFound();
});
K odeslání požadavku DELETE použijte Swagger:
Vyberte DELETE /todoitems/{id}>Vyzkoušet.
Nastavte pole ID na
1
a vyberte Spustit.Požadavek DELETE se odešle do aplikace a odpověď se zobrazí v podokně Odpovědi . Tělo odpovědi je prázdné a stavový kód odpovědi serveru je 204.
Zamezte nadměrnému zveřejňování
V současné době ukázková aplikace zveřejňuje celý Todo
objekt. Produkční aplikace V produkčních aplikacích se podmnožina modelu často používá k omezení dat, která mohou být vstupní a vrácená. Z tohoto důvodu existuje několik důvodů a zabezpečení je hlavním důvodem. Podmnožina modelu se obvykle označuje jako objekt pro přenos dat (DTO), vstupní model nebo model zobrazení.
DTO se používá v tomto článku.
DTO lze použít k:
- Zabránit nadměrnému příspěvkování.
- Skryjte vlastnosti, které klienti nemají zobrazit.
- Vynechejte některé vlastnosti pro zmenšení velikosti datové části.
- Zplošťujte grafy objektů, které obsahují vnořené objekty. Grafy plochých objektů můžou být pro klienty pohodlnější.
Pokud chcete předvést přístup DTO, aktualizujte Todo
třídu tak, aby obsahovala pole tajného kódu:
public class Todo
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public string? Secret { get; set; }
}
Pole tajného kódu musí být v této aplikaci skryté, ale aplikace pro správu by se mohla rozhodnout, že ho zveřejní.
Ověřte, že můžete publikovat a získat tajné pole.
Vytvořte soubor s názvem TodoItemDTO.cs
s následujícím kódem:
public class TodoItemDTO
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public TodoItemDTO() { }
public TodoItemDTO(Todo todoItem) =>
(Id, Name, IsComplete) = (todoItem.Id, todoItem.Name, todoItem.IsComplete);
}
Program.cs
Obsah souboru nahraďte následujícím kódem, který použije tento model DTO:
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
var app = builder.Build();
app.MapGet("/todoitems", async (TodoDb db) =>
await db.Todos.Select(x => new TodoItemDTO(x)).ToListAsync());
app.MapGet("/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(new TodoItemDTO(todo))
: Results.NotFound());
app.MapPost("/todoitems", async (TodoItemDTO todoItemDTO, TodoDb db) =>
{
var todoItem = new Todo
{
IsComplete = todoItemDTO.IsComplete,
Name = todoItemDTO.Name
};
db.Todos.Add(todoItem);
await db.SaveChangesAsync();
return Results.Created($"/todoitems/{todoItem.Id}", new TodoItemDTO(todoItem));
});
app.MapPut("/todoitems/{id}", async (int id, TodoItemDTO todoItemDTO, TodoDb db) =>
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return Results.NotFound();
todo.Name = todoItemDTO.Name;
todo.IsComplete = todoItemDTO.IsComplete;
await db.SaveChangesAsync();
return Results.NoContent();
});
app.MapDelete("/todoitems/{id}", async (int id, TodoDb db) =>
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return Results.NoContent();
}
return Results.NotFound();
});
app.Run();
public class Todo
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public string? Secret { get; set; }
}
public class TodoItemDTO
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public TodoItemDTO() { }
public TodoItemDTO(Todo todoItem) =>
(Id, Name, IsComplete) = (todoItem.Id, todoItem.Name, todoItem.IsComplete);
}
class TodoDb : DbContext
{
public TodoDb(DbContextOptions<TodoDb> options)
: base(options) { }
public DbSet<Todo> Todos => Set<Todo>();
}
Ověřte, že můžete publikovat a získat všechna pole kromě tajného pole.
Testování minimálního rozhraní API
Příklad testování minimální aplikace API najdete v této ukázce GitHubu.
Publikování do Azure
Informace o nasazení do Azure najdete v tématu Rychlý start: Nasazení webové aplikace ASP.NET.
Další materiály
Minimální rozhraní API jsou navržena tak, aby vytvářela rozhraní HTTP API s minimálními závislostmi. Jsou ideální pro mikroslužby a aplikace, které chtějí do ASP.NET Core zahrnout jenom minimální soubory, funkce a závislosti.
V tomto kurzu se naučíte základy vytváření minimálního rozhraní API pomocí ASP.NET Core. Dalším přístupem k vytváření rozhraní API v ASP.NET Core je použití kontrolerů. Nápovědu k výběru mezi minimálními rozhraními API a rozhraními API založenými na kontroleru najdete v přehledu rozhraní API. Kurz vytvoření projektu rozhraní API na základě kontrolerů , které obsahují další funkce, najdete v tématu Vytvoření webového rozhraní API.
Přehled
Tento kurz vytvoří následující rozhraní API:
API (rozhraní pro programování aplikací) | Popis | Text požadavku | Tělo odpovědi |
---|---|---|---|
GET /todoitems |
Získání všech položek úkolů | Nic | Pole položek úkolů |
GET /todoitems/complete |
Získejte dokončené úkoly | Nic | Pole položek úkolů |
GET /todoitems/{id} |
Získejte položku podle ID | Nic | Úkol k vyřízení |
POST /todoitems |
Přidání nové položky | Úkol k vyřízení | Úkol k vyřízení |
PUT /todoitems/{id} |
Aktualizace existující položky | Úkol k vyřízení | Nic |
DELETE /todoitems/{id} |
Odstranění položky | Nic | Nic |
Požadavky
Visual Studio 2022 s pracovním zatížením ASP.NET a vývoje webu
Vytvoření projektu rozhraní API
Spusťte Visual Studio 2022 a vyberte Vytvořit nový projekt.
V dialogovém okně Vytvořit nový projekt :
- Zadejte
Empty
do vyhledávacího pole Hledat šablony . - Vyberte šablonu ASP.NET Core Empty a vyberte Další.
- Zadejte
Pojmenujte projekt TodoApi a vyberte Další.
V dialogovém okně Další informace :
- Vyberte .NET 8.0 (dlouhodobá podpora)
- Zrušte zaškrtnutí políčka Nepoužívat příkazy nejvyšší úrovně
- Vyberte příkaz Vytvořit.
Kontrola kódu
Soubor Program.cs
obsahuje následující kód:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
Předchozí kód:
- Vytvoří WebApplicationBuilder a WebApplication s předkonfigurovanými výchozími nastaveními.
- Vytvoří koncový bod
/
HTTP GET, který vrátíHello World!
:
Spustit aplikaci
Stisknutím kombinace kláves Ctrl+F5 spusťte bez debuggeru.
Visual Studio zobrazí následující dialogové okno:
Pokud důvěřujete certifikátu SSL služby IIS Express, vyberte Ano .
Zobrazí se následující dialogové okno:
Pokud souhlasíte s tím, že se má důvěřovat vývojovému certifikátu, vyberte Ano.
Informace o tom, jak důvěřovat prohlížeči Firefox, naleznete v části k chybě certifikátu Firefox SEC_ERROR_INADEQUATE_KEY_USAGE.
Visual Studio spustí Kestrel webový server a otevře okno prohlížeče.
Hello World!
se zobrazí v prohlížeči. Soubor Program.cs
obsahuje minimální, ale kompletní aplikaci.
Zavřete okno prohlížeče.
Přidání balíčků NuGet
Pro podporu databáze a diagnostiky používané v tomto kurzu je potřeba přidat balíčky NuGet.
- V nabídce Nástroje vyberte NuGet Správce balíčků > Spravovat balíčky NuGet pro řešení.
- Vyberte kartu Procházet.
- Do vyhledávacího pole zadejte Microsoft.EntityFrameworkCore.InMemory a pak vyberte
Microsoft.EntityFrameworkCore.InMemory
. - V pravém podokně zaškrtněte políčko Projekt a pak vyberte Nainstalovat.
- Podle předchozích pokynů přidejte
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
balíček.
Třídy kontextu modelu a databáze
- Ve složce projektu vytvořte soubor s názvem
Todo.cs
s následujícím kódem:
public class Todo
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Předchozí kód vytvoří model pro tuto aplikaci. Model je třída, která představuje data, která aplikace spravuje.
- Vytvořte soubor s názvem
TodoDb.cs
s následujícím kódem:
using Microsoft.EntityFrameworkCore;
class TodoDb : DbContext
{
public TodoDb(DbContextOptions<TodoDb> options)
: base(options) { }
public DbSet<Todo> Todos => Set<Todo>();
}
Předchozí kód definuje kontext databáze, což je hlavní třída, která koordinuje funkce Entity Framework pro datový model. Tato třída je odvozena od Microsoft.EntityFrameworkCore.DbContext třídy.
Přidání kódu rozhraní API
- Obsah souboru
Program.cs
nahraďte následujícím kódem:
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();
app.MapGet("/todoitems", async (TodoDb db) =>
await db.Todos.ToListAsync());
app.MapGet("/todoitems/complete", async (TodoDb db) =>
await db.Todos.Where(t => t.IsComplete).ToListAsync());
app.MapGet("/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound());
app.MapPost("/todoitems", async (Todo todo, TodoDb db) =>
{
db.Todos.Add(todo);
await db.SaveChangesAsync();
return Results.Created($"/todoitems/{todo.Id}", todo);
});
app.MapPut("/todoitems/{id}", async (int id, Todo inputTodo, TodoDb db) =>
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return Results.NotFound();
todo.Name = inputTodo.Name;
todo.IsComplete = inputTodo.IsComplete;
await db.SaveChangesAsync();
return Results.NoContent();
});
app.MapDelete("/todoitems/{id}", async (int id, TodoDb db) =>
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return Results.NoContent();
}
return Results.NotFound();
});
app.Run();
Následující zvýrazněný kód přidá kontext databáze do kontejneru injektáže závislostí (DI) a povolí zobrazení výjimek souvisejících s databází:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();
Kontejner DI poskytuje přístup k kontextu databáze a dalším službám.
V tomto kurzu se k otestování rozhraní API používá Průzkumník koncových bodů a soubory .http.
Testování zveřejňování dat
Následující kód v Program.cs
vytvoří HTTP POST koncový bod /todoitems
, který přidá data do paměťové databáze:
app.MapPost("/todoitems", async (Todo todo, TodoDb db) =>
{
db.Todos.Add(todo);
await db.SaveChangesAsync();
return Results.Created($"/todoitems/{todo.Id}", todo);
});
Spustit aplikaci. Prohlížeč zobrazí chybu 404, protože /
koncový bod již neexistuje.
Koncový bod POST se použije k přidání dat do aplikace.
Vyberte Zobrazit>Další okna>Průzkumník koncových bodů.
Klikněte pravým tlačítkem na koncový bod POST a vyberte Vygenerovat požadavek.
Ve složce projektu s názvem
TodoApi.http
se vytvoří nový soubor s podobným obsahem jako v následujícím příkladu:@TodoApi_HostAddress = https://localhost:7031 Post {{TodoApi_HostAddress}}/todoitems ###
- První řádek vytvoří proměnnou, která se použije pro všechny koncové body.
- Další řádek definuje požadavek POST.
- Řádek s trojitým hashtagem (
###
) je značka oddělující požadavek: co následuje za ní, je určené pro jiný požadavek.
Požadavek POST potřebuje hlavičky a text. Pokud chcete definovat tyto části požadavku, přidejte následující řádky bezprostředně za řádek požadavku POST:
Content-Type: application/json { "name":"walk dog", "isComplete":true }
Předchozí kód přidá hlavičku Content-Type a text požadavku JSON. Soubor TodoApi.http by teď měl vypadat jako v následujícím příkladu, ale s číslem portu:
@TodoApi_HostAddress = https://localhost:7057 Post {{TodoApi_HostAddress}}/todoitems Content-Type: application/json { "name":"walk dog", "isComplete":true } ###
Spustit aplikaci.
Vyberte odkaz Odeslat žádost, který je nad řádkem
POST
žádosti.Požadavek POST se odešle do aplikace a odpověď se zobrazí v podokně Odpovědi .
Prozkoumání koncových bodů GET
Ukázková aplikace implementuje několik koncových bodů GET voláním MapGet
:
API (rozhraní pro programování aplikací) | Popis | Text požadavku | Tělo odpovědi |
---|---|---|---|
GET /todoitems |
Získání všech položek úkolů | Nic | Pole položek úkolů |
GET /todoitems/complete |
Získání všech dokončených položek úkolů | Nic | Pole položek úkolů |
GET /todoitems/{id} |
Získejte položku podle ID | Nic | Úkol k vyřízení |
app.MapGet("/todoitems", async (TodoDb db) =>
await db.Todos.ToListAsync());
app.MapGet("/todoitems/complete", async (TodoDb db) =>
await db.Todos.Where(t => t.IsComplete).ToListAsync());
app.MapGet("/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound());
Testování koncových bodů GET
Otestujte aplikaci voláním GET
koncových bodů z prohlížeče nebo pomocí Průzkumníka koncových bodů. Následující kroky jsou určené pro Průzkumníka koncových bodů.
V Průzkumníku koncových bodů klikněte pravým tlačítkem na první koncový bod GET a vyberte Vygenerovat požadavek.
Do souboru
TodoApi.http
byl přidán následující obsah:Get {{TodoApi_HostAddress}}/todoitems ###
Vyberte odkaz Odeslat žádost, který je nad novým
GET
řádkem žádosti.Požadavek GET se odešle do aplikace a odpověď se zobrazí v podokně Odpovědi .
Text odpovědi je podobný následujícímu formátu JSON:
[ { "id": 1, "name": "walk dog", "isComplete": true } ]
V Průzkumníku koncových bodů klikněte pravým tlačítkem na
/todoitems/{id}
koncový bod GET a vyberte Vygenerovat požadavek. Do souboruTodoApi.http
byl přidán následující obsah:GET {{TodoApi_HostAddress}}/todoitems/{id} ###
Nahraďte
{id}
s1
.Vyberte odkaz Odeslat požadavek, který je nad novým řádkem požadavku GET.
Požadavek GET se odešle do aplikace a odpověď se zobrazí v podokně Odpovědi .
Text odpovědi je podobný následujícímu formátu JSON:
{ "id": 1, "name": "walk dog", "isComplete": true }
Tato aplikace používá databázi v paměti. Pokud se aplikace restartuje, požadavek GET nevrací žádná data. Pokud se nevrátí žádná data, post data do aplikace a zkuste požadavek GET zopakovat.
Vrácené hodnoty
ASP.NET Core automaticky serializuje objekt do formátu JSON a zapíše json do textu zprávy odpovědi. Kód odpovědi pro tento návratový typ je 200 OK, za předpokladu, že neexistují žádné neošetřené výjimky. Neošetřené výjimky se překládají do chyb 5xx.
Návratové typy mohou představovat širokou škálu stavových kódů HTTP. Může například GET /todoitems/{id}
vrátit dvě různé hodnoty stavu:
- Pokud žádná položka neodpovídá požadovanému ID, vrátí metoda kód chyby stavuNotFound 404.
- V opačném případě metoda vrátí hodnotu 200 s textem odpovědi JSON. Vrácení
item
vede k odpovědi HTTP 200.
Prozkoumání koncového bodu PUT
Ukázková aplikace implementuje jeden koncový bod PUT pomocí MapPut
:
app.MapPut("/todoitems/{id}", async (int id, Todo inputTodo, TodoDb db) =>
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return Results.NotFound();
todo.Name = inputTodo.Name;
todo.IsComplete = inputTodo.IsComplete;
await db.SaveChangesAsync();
return Results.NoContent();
});
Tato metoda je podobná MapPost
metodě, s výjimkou použití HTTP PUT. Úspěšná odpověď vrátí hodnotu 204 (bez obsahu). Podle specifikace HTTP požadavek PUT vyžaduje, aby klient odeslal celou aktualizovanou entitu, nejen změny. Pokud chcete podporovat částečné aktualizace, použijte HTTP PATCH.
Testování koncového bodu PUT
Tato ukázka používá databázi v paměti, která se musí inicializovat při každém spuštění aplikace. Před voláním PUT musí být v databázi položka. Před voláním metody PUT zavolejte get a ujistěte se, že je v databázi položka.
Aktualizujte položku úkolu, která má Id = 1
, a nastavte její název na "feed fish"
.
V Průzkumníku koncových bodů klikněte pravým tlačítkem myši na koncový bod PUT a vyberte Vygenerovat požadavek.
Do souboru
TodoApi.http
byl přidán následující obsah:Put {{TodoApi_HostAddress}}/todoitems/{id} ###
Na řádku požadavku PUT nahraďte
{id}
s1
.Přidejte následující řádky bezprostředně za řádek požadavku PUT:
Content-Type: application/json { "name": "feed fish", "isComplete": false }
Předchozí kód přidá hlavičku Content-Type a text požadavku JSON.
Vyberte odkaz Odeslat žádost, který je nad novým řádkem požadavku PUT.
Požadavek PUT se odešle do aplikace a odpověď se zobrazí v podokně Odpovědi . Tělo odpovědi je prázdné a stavový kód je 204.
Prozkoumání a otestování koncového bodu DELETE
Ukázková aplikace implementuje jeden koncový bod DELETE pomocí MapDelete
:
app.MapDelete("/todoitems/{id}", async (int id, TodoDb db) =>
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return Results.NoContent();
}
return Results.NotFound();
});
V Průzkumníku koncových bodů klikněte pravým tlačítkem na koncový bod DELETE a vyberte Vygenerovat požadavek.
Přidá se DELETE požadavek k
TodoApi.http
.Nahraďte
{id}
v řádku žádosti DELETE textem1
. Požadavek DELETE by měl vypadat jako v následujícím příkladu:DELETE {{TodoApi_HostAddress}}/todoitems/1 ###
Vyberte odkaz Odeslat žádost pro požadavek DELETE.
Požadavek DELETE se odešle do aplikace a odpověď se zobrazí v podokně Odpovědi . Tělo odpovědi je prázdné a stavový kód je 204.
Použití rozhraní MapGroup API
Vzorový kód aplikace opakuje předponu todoitems
adresy URL pokaždé, když nastaví koncový bod. Rozhraní API často obsahují skupiny koncových bodů se společnou předponou adresy URL a metoda MapGroup je k dispozici k uspořádání takových skupin. Redukuje opakující se kód a umožňuje přizpůsobit celé skupiny koncových bodů jediným voláním metod, jako RequireAuthorization a WithMetadata.
Program.cs
Obsah nahraďte následujícím kódem:
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();
var todoItems = app.MapGroup("/todoitems");
todoItems.MapGet("/", async (TodoDb db) =>
await db.Todos.ToListAsync());
todoItems.MapGet("/complete", async (TodoDb db) =>
await db.Todos.Where(t => t.IsComplete).ToListAsync());
todoItems.MapGet("/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound());
todoItems.MapPost("/", async (Todo todo, TodoDb db) =>
{
db.Todos.Add(todo);
await db.SaveChangesAsync();
return Results.Created($"/todoitems/{todo.Id}", todo);
});
todoItems.MapPut("/{id}", async (int id, Todo inputTodo, TodoDb db) =>
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return Results.NotFound();
todo.Name = inputTodo.Name;
todo.IsComplete = inputTodo.IsComplete;
await db.SaveChangesAsync();
return Results.NoContent();
});
todoItems.MapDelete("/{id}", async (int id, TodoDb db) =>
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return Results.NoContent();
}
return Results.NotFound();
});
app.Run();
Předchozí kód má následující změny:
- Přidá
var todoItems = app.MapGroup("/todoitems");
k nastavení skupiny pomocí předpony adresy URL/todoitems
. - Změní všechny
app.Map<HttpVerb>
metody natodoItems.Map<HttpVerb>
. - Odebere předponu
/todoitems
adresy URL zMap<HttpVerb>
volání metod.
Otestujte koncové body a ověřte, že fungují stejně.
Použití rozhraní TypedResults API
Vracení TypedResults místo Results má několik výhod, včetně testovatelnosti a automatického vracení metadat typu odpovědi pro OpenAPI k popisu koncového bodu. Další informace naleznete v tématu TypedResults vs Results.
Metody Map<HttpVerb>
mohou místo lambda volat metody obslužné rutiny trasy. Pokud chcete zobrazit příklad, aktualizujte Program.cs následujícím kódem:
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();
var todoItems = app.MapGroup("/todoitems");
todoItems.MapGet("/", GetAllTodos);
todoItems.MapGet("/complete", GetCompleteTodos);
todoItems.MapGet("/{id}", GetTodo);
todoItems.MapPost("/", CreateTodo);
todoItems.MapPut("/{id}", UpdateTodo);
todoItems.MapDelete("/{id}", DeleteTodo);
app.Run();
static async Task<IResult> GetAllTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.ToArrayAsync());
}
static async Task<IResult> GetCompleteTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.Where(t => t.IsComplete).ToListAsync());
}
static async Task<IResult> GetTodo(int id, TodoDb db)
{
return await db.Todos.FindAsync(id)
is Todo todo
? TypedResults.Ok(todo)
: TypedResults.NotFound();
}
static async Task<IResult> CreateTodo(Todo todo, TodoDb db)
{
db.Todos.Add(todo);
await db.SaveChangesAsync();
return TypedResults.Created($"/todoitems/{todo.Id}", todo);
}
static async Task<IResult> UpdateTodo(int id, Todo inputTodo, TodoDb db)
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return TypedResults.NotFound();
todo.Name = inputTodo.Name;
todo.IsComplete = inputTodo.IsComplete;
await db.SaveChangesAsync();
return TypedResults.NoContent();
}
static async Task<IResult> DeleteTodo(int id, TodoDb db)
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return TypedResults.NoContent();
}
return TypedResults.NotFound();
}
Kód Map<HttpVerb>
teď volá metody místo lambda:
var todoItems = app.MapGroup("/todoitems");
todoItems.MapGet("/", GetAllTodos);
todoItems.MapGet("/complete", GetCompleteTodos);
todoItems.MapGet("/{id}", GetTodo);
todoItems.MapPost("/", CreateTodo);
todoItems.MapPut("/{id}", UpdateTodo);
todoItems.MapDelete("/{id}", DeleteTodo);
Tyto metody vracejí objekty, které implementují IResult a jsou definovány TypedResults:
static async Task<IResult> GetAllTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.ToArrayAsync());
}
static async Task<IResult> GetCompleteTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.Where(t => t.IsComplete).ToListAsync());
}
static async Task<IResult> GetTodo(int id, TodoDb db)
{
return await db.Todos.FindAsync(id)
is Todo todo
? TypedResults.Ok(todo)
: TypedResults.NotFound();
}
static async Task<IResult> CreateTodo(Todo todo, TodoDb db)
{
db.Todos.Add(todo);
await db.SaveChangesAsync();
return TypedResults.Created($"/todoitems/{todo.Id}", todo);
}
static async Task<IResult> UpdateTodo(int id, Todo inputTodo, TodoDb db)
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return TypedResults.NotFound();
todo.Name = inputTodo.Name;
todo.IsComplete = inputTodo.IsComplete;
await db.SaveChangesAsync();
return TypedResults.NoContent();
}
static async Task<IResult> DeleteTodo(int id, TodoDb db)
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return TypedResults.NoContent();
}
return TypedResults.NotFound();
}
Testy jednotek mohou volat tyto metody a testovat, že vracejí správný datový typ. Například pokud je metoda GetAllTodos
:
static async Task<IResult> GetAllTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.ToArrayAsync());
}
Kód unit testu může ověřit, že objekt typu Ok<Todo[]> je vrácen z metody obslužné rutiny. Příklad:
public async Task GetAllTodos_ReturnsOkOfTodosResult()
{
// Arrange
var db = CreateDbContext();
// Act
var result = await TodosApi.GetAllTodos(db);
// Assert: Check for the correct returned type
Assert.IsType<Ok<Todo[]>>(result);
}
Zamezte nadměrnému zveřejňování
V současné době ukázková aplikace zveřejňuje celý Todo
objekt. Produkční aplikace V produkčních aplikacích se podmnožina modelu často používá k omezení dat, která mohou být vstupní a vrácená. Z tohoto důvodu existuje několik důvodů a zabezpečení je hlavním důvodem. Podmnožina modelu se obvykle označuje jako objekt pro přenos dat (DTO), vstupní model nebo model zobrazení.
DTO se používá v tomto článku.
DTO lze použít k:
- Zabránit nadměrnému příspěvkování.
- Skryjte vlastnosti, které klienti nemají zobrazit.
- Vynechejte některé vlastnosti pro zmenšení velikosti datové části.
- Zplošťujte grafy objektů, které obsahují vnořené objekty. Grafy plochých objektů můžou být pro klienty pohodlnější.
Pokud chcete předvést přístup DTO, aktualizujte Todo
třídu tak, aby obsahovala pole tajného kódu:
public class Todo
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public string? Secret { get; set; }
}
Pole tajného kódu musí být v této aplikaci skryté, ale aplikace pro správu by se mohla rozhodnout, že ho zveřejní.
Ověřte, že můžete publikovat a získat tajné pole.
Vytvořte soubor s názvem TodoItemDTO.cs
s následujícím kódem:
public class TodoItemDTO
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public TodoItemDTO() { }
public TodoItemDTO(Todo todoItem) =>
(Id, Name, IsComplete) = (todoItem.Id, todoItem.Name, todoItem.IsComplete);
}
Program.cs
Obsah souboru nahraďte následujícím kódem, který použije tento model DTO:
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();
RouteGroupBuilder todoItems = app.MapGroup("/todoitems");
todoItems.MapGet("/", GetAllTodos);
todoItems.MapGet("/complete", GetCompleteTodos);
todoItems.MapGet("/{id}", GetTodo);
todoItems.MapPost("/", CreateTodo);
todoItems.MapPut("/{id}", UpdateTodo);
todoItems.MapDelete("/{id}", DeleteTodo);
app.Run();
static async Task<IResult> GetAllTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.Select(x => new TodoItemDTO(x)).ToArrayAsync());
}
static async Task<IResult> GetCompleteTodos(TodoDb db) {
return TypedResults.Ok(await db.Todos.Where(t => t.IsComplete).Select(x => new TodoItemDTO(x)).ToListAsync());
}
static async Task<IResult> GetTodo(int id, TodoDb db)
{
return await db.Todos.FindAsync(id)
is Todo todo
? TypedResults.Ok(new TodoItemDTO(todo))
: TypedResults.NotFound();
}
static async Task<IResult> CreateTodo(TodoItemDTO todoItemDTO, TodoDb db)
{
var todoItem = new Todo
{
IsComplete = todoItemDTO.IsComplete,
Name = todoItemDTO.Name
};
db.Todos.Add(todoItem);
await db.SaveChangesAsync();
todoItemDTO = new TodoItemDTO(todoItem);
return TypedResults.Created($"/todoitems/{todoItem.Id}", todoItemDTO);
}
static async Task<IResult> UpdateTodo(int id, TodoItemDTO todoItemDTO, TodoDb db)
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return TypedResults.NotFound();
todo.Name = todoItemDTO.Name;
todo.IsComplete = todoItemDTO.IsComplete;
await db.SaveChangesAsync();
return TypedResults.NoContent();
}
static async Task<IResult> DeleteTodo(int id, TodoDb db)
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return TypedResults.NoContent();
}
return TypedResults.NotFound();
}
Ověřte, že můžete publikovat a získat všechna pole kromě tajného pole.
Řešení potíží s dokončeným příkladem
Pokud narazíte na problém, který nemůžete vyřešit, porovnejte kód s dokončeným projektem. Zobrazit nebo stáhnout dokončený projekt (jak stáhnout)
Další kroky
- Nakonfigurujte možnosti serializace JSON.
- Zpracování chyb a výjimek: Stránka vývojářských výjimek je ve výchozím nastavení povolena ve vývojovém prostředí pro minimalistické API aplikace. Informace o zpracování chyb a výjimek najdete v tématu Zpracování chyb v rozhraních ASP.NET Core API.
- Příklad testování minimální aplikace API najdete v této ukázce GitHubu.
- Podpora OpenAPI pro minimální rozhraní
- Rychlý start: Publikování do Azure
- Uspořádání minimalních rozhraní API ASP.NET Core
Další informace
Stručné referenční informace k minimálním rozhraním API