Kurz: Vytvoření minimálního rozhraní API pomocí ASP.NET Core
Poznámka:
Toto není nejnovější verze tohoto článku. Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Upozorňující
Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Důležité
Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.
Aktuální verzi najdete v tomto článku ve verzi .NET 9.
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 | Popis | Text požadavku | Text odpovědi |
---|---|---|---|
GET /todoitems |
Získání všech položek úkolů | Nic | Pole položek úkolů |
GET /todoitems/complete |
Dokončení položek úkolů | Nic | Pole položek úkolů |
GET /todoitems/{id} |
Získání položky podle ID | Nic | Položka úkolu |
POST /todoitems |
Přidání nové položky | Položka úkolu | Položka úkolu |
PUT /todoitems/{id} |
Aktualizace existující položky | Položka úkolu | Nic |
DELETE /todoitems/{id} |
Odstranění položky | Nic | Nic |
Požadavky
Sada Visual Studio 2022 se sadou funkcí Vývoj pro ASP.NET a web
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šení 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:
- WebApplicationBuilder Vytvoří 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 ladicího programu.
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 důvěřování prohlížeči Firefox naleznete v článku o chybě certifikátu aplikace 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é verze.
- 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í odúčtovacích dat
Následující kód vytvoří Program.cs
koncový bod /todoitems
HTTP POST, který přidá data do databáze v paměti:
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 už /
neexistuje koncový bod.
Koncový bod POST se použije k přidání dat do aplikace.
Vyberte Zobrazit>další průzkumníka koncových bodů Windows.>
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.
- Triple hashtag (
###
) line is a request delimiter: what comes after it is for a different request.
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 | Popis | Text požadavku | Text 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ískání položky podle ID | Nic | Položka úkolu |
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 se přidá
TodoApi.http
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 souboru se přidáTodoApi.http
následující obsah:GET {{TodoApi_HostAddress}}/todoitems/{id} ###
Nahraďte
{id}
1
.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.
item
Vrácení výsledků v 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 nastavila její název ."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 se přidá
TodoApi.http
následující obsah:Put {{TodoApi_HostAddress}}/todoitems/{id} ###
Na řádku požadavku PUT nahraďte
{id}
.1
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.
Do souboru se přidá
TodoApi.http
požadavek DELETE .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ů s běžnou předponou adresy URL a MapGroup tato metoda 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/todoitems
adresy URL . - Změní všechny
app.Map<HttpVerb>
metody natodoItems.Map<HttpVerb>
. - Odebere předponu
/todoitems
adresy URL zMap<HttpVerb>
volání metody.
Otestujte koncové body a ověřte, že fungují stejně.
Použití rozhraní TypedResults API
Vrácení TypedResults místo Results několika výhod, včetně testovatelnosti a automatického vrácení metadat typu odpovědi pro OpenAPI k popisu koncového bodu. Další informace naleznete v tématu TypedResults vs Výsledky.
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 vrací správný typ. Pokud je GetAllTodos
metoda například:
static async Task<IResult> GetAllTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.ToArrayAsync());
}
Kód testu jednotek 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);
}
Prevence nadměrného účtová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 účtování.
- Skryjte vlastnosti, které klienti nemají zobrazit.
- Vynecháte některé vlastnosti pro zmenšení velikosti datové části.
- Zploštěné 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čenou ukázkou
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ýjimky vývojáře je ve výchozím nastavení povolená ve vývojovém prostředí pro minimální aplikace API. 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 v minimálních rozhraních API
- Rychlý start: Publikování do Azure
- Uspořádání ASP.NET základních minimálních rozhraní API
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 | Popis | Text požadavku | Text odpovědi |
---|---|---|---|
GET /todoitems |
Získání všech položek úkolů | Nic | Pole položek úkolů |
GET /todoitems/complete |
Dokončení položek úkolů | Nic | Pole položek úkolů |
GET /todoitems/{id} |
Získání položky podle ID | Nic | Položka úkolu |
POST /todoitems |
Přidání nové položky | Položka úkolu | Položka úkolu |
PUT /todoitems/{id} |
Aktualizace existující položky | Položka úkolu | Nic |
DELETE /todoitems/{id} |
Odstranění položky | Nic | Nic |
Požadavky
Sada Visual Studio 2022 se sadou funkcí Vývoj pro ASP.NET a web
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šení 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:
- WebApplicationBuilder Vytvoří 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 ladicího programu.
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 důvěřování prohlížeči Firefox naleznete v článku o chybě certifikátu aplikace 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 definováním na řádku přidejte následující zvýrazněný kód
app
.var app = builder.Build();
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. Průzkumník rozhraní API používá Swagger 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 po
app
definování na řádku.var 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í odúčtovacích dat
Následující kód vytvoří Program.cs
koncový bod /todoitems
HTTP POST, který přidá data do databáze v paměti:
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 už /
neexistuje koncový bod.
Koncový bod POST se použije k přidání dat do aplikace.
Když je aplikace stále spuštěná, přejděte v prohlížeči a
https://localhost:<port>/swagger
zobrazte stránku testování rozhraní API vygenerovanou Swaggerem.Na stránce testování rozhraní API Swagger vyberte Post /todoitems>Vyzkoušet.
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 pod tlačítkem Spustit podokno Odpovědi.
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. Text odpovědi ukazuje, že
id
byla nastavena na1
hodnotu . - 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 | Popis | Text požadavku | Text 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ískání položky podle ID | Nic | Položka úkolu |
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šet spustit.>
Alternativně volání GET /todoitems z prohlížeče zadáním identifikátoru URI
http://localhost:<port>/todoitems
. Napříkladhttp://localhost:5001/todoitems
Volání, které GET /todoitems
vytvoří odpověď podobnou následující:
[
{
"id": 1,
"name": "walk dog",
"isComplete": true
}
]
Volání metody GET /todoitems/{id} ve Swaggeru pro vrácení dat z konkrétního ID:
- Vyberte GET /todoitems>Vyzkoušet.
-
Nastavte pole ID na
1
a vyberte Spustit.
Alternativně volání GET /todoitems z prohlížeče zadáním identifikátoru 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.
item
Vrácení výsledků v 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 nastavila její název ."feed fish"
Odeslání požadavku PUT pomocí Swaggeru:
Vyberte Put /todoitems/{id}>Vyzkoušet.
Nastavte pole ID na
1
hodnotu .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ů s běžnou předponou adresy URL a MapGroup tato metoda 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/todoitems
adresy URL . - Změní všechny
app.Map<HttpVerb>
metody natodoItems.Map<HttpVerb>
. - Odebere předponu
/todoitems
adresy URL zMap<HttpVerb>
volání metody.
Otestujte koncové body a ověřte, že fungují stejně.
Použití rozhraní TypedResults API
Vrácení TypedResults místo Results několika výhod, včetně testovatelnosti a automatického vrácení metadat typu odpovědi pro OpenAPI k popisu koncového bodu. Další informace naleznete v tématu TypedResults vs Výsledky.
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 vrací správný typ. Pokud je GetAllTodos
metoda například:
static async Task<IResult> GetAllTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.ToArrayAsync());
}
Kód testu jednotek 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);
}
Prevence nadměrného účtová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 účtování.
- Skryjte vlastnosti, které klienti nemají zobrazit.
- Vynecháte některé vlastnosti pro zmenšení velikosti datové části.
- Zploštěné 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čenou ukázkou
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ýjimky vývojáře je ve výchozím nastavení povolená ve vývojovém prostředí pro minimální aplikace API. 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 v minimálních rozhraních API
- Rychlý start: Publikování do Azure
- Uspořádání ASP.NET základních minimálních rozhraní API
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 | Popis | Text požadavku | Text odpovědi |
---|---|---|---|
GET /todoitems |
Získání všech položek úkolů | Nic | Pole položek úkolů |
GET /todoitems/complete |
Dokončení položek úkolů | Nic | Pole položek úkolů |
GET /todoitems/{id} |
Získání položky podle ID | Nic | Položka úkolu |
POST /todoitems |
Přidání nové položky | Položka úkolu | Položka úkolu |
PUT /todoitems/{id} |
Aktualizace existující položky | Položka úkolu | Nic |
DELETE /todoitems/{id} |
Odstranění položky | Nic | Nic |
Požadavky
- Sada Visual Studio 2022 se sadou funkcí Vývoj pro ASP.NET a web
- Sada .NET 6.0 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šení 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:
- WebApplicationBuilder Vytvoří 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 ladicího programu.
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 důvěřování prohlížeči Firefox naleznete v článku o chybě certifikátu aplikace 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 definováním na řádku přidejte následující zvýrazněný kód
app
.var app = builder.Build();
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. Průzkumník rozhraní API používá Swagger 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 po
app
definování na řádku.var 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í odúčtovacích dat
Následující kód vytvoří Program.cs
koncový bod /todoitems
HTTP POST, který přidá data do databáze v paměti:
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 už /
neexistuje koncový bod.
Koncový bod POST se použije k přidání dat do aplikace.
Když je aplikace stále spuštěná, přejděte v prohlížeči a
https://localhost:<port>/swagger
zobrazte stránku testování rozhraní API vygenerovanou Swaggerem.Na stránce testování rozhraní API Swagger vyberte Post /todoitems>Vyzkoušet.
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 pod tlačítkem Spustit podokno Odpovědi.
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. Text odpovědi ukazuje, že
id
byla nastavena na1
hodnotu . - 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 | Popis | Text požadavku | Text 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ískání položky podle ID | Nic | Položka úkolu |
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šet spustit.>
Alternativně volání GET /todoitems z prohlížeče zadáním identifikátoru URI
http://localhost:<port>/todoitems
. Napříkladhttp://localhost:5001/todoitems
Volání, které GET /todoitems
vytvoří odpověď podobnou následující:
[
{
"id": 1,
"name": "walk dog",
"isComplete": true
}
]
Volání metody GET /todoitems/{id} ve Swaggeru pro vrácení dat z konkrétního ID:
- Vyberte GET /todoitems>Vyzkoušet.
-
Nastavte pole ID na
1
a vyberte Spustit.
Alternativně volání GET /todoitems z prohlížeče zadáním identifikátoru 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.
item
Vrácení výsledků v 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 nastavila její název ."feed fish"
Odeslání požadavku PUT pomocí Swaggeru:
Vyberte Put /todoitems/{id}>Vyzkoušet.
Nastavte pole ID na
1
hodnotu .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.
Prevence nadměrného účtová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 účtování.
- Skryjte vlastnosti, které klienti nemají zobrazit.
- Vynecháte některé vlastnosti pro zmenšení velikosti datové části.
- Zploštěné 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 | Popis | Text požadavku | Text odpovědi |
---|---|---|---|
GET /todoitems |
Získání všech položek úkolů | Nic | Pole položek úkolů |
GET /todoitems/complete |
Dokončení položek úkolů | Nic | Pole položek úkolů |
GET /todoitems/{id} |
Získání položky podle ID | Nic | Položka úkolu |
POST /todoitems |
Přidání nové položky | Položka úkolu | Položka úkolu |
PUT /todoitems/{id} |
Aktualizace existující položky | Položka úkolu | Nic |
DELETE /todoitems/{id} |
Odstranění položky | Nic | Nic |
Požadavky
Sada Visual Studio 2022 se sadou funkcí Vývoj pro ASP.NET a web
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šení 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:
- WebApplicationBuilder Vytvoří 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 ladicího programu.
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 důvěřování prohlížeči Firefox naleznete v článku o chybě certifikátu aplikace 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í odúčtovacích dat
Následující kód vytvoří Program.cs
koncový bod /todoitems
HTTP POST, který přidá data do databáze v paměti:
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 už /
neexistuje koncový bod.
Koncový bod POST se použije k přidání dat do aplikace.
Vyberte Zobrazit>další průzkumníka koncových bodů Windows.>
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.
- Triple hashtag (
###
) line is a request delimiter: what comes after it is for a different request.
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 | Popis | Text požadavku | Text 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ískání položky podle ID | Nic | Položka úkolu |
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 se přidá
TodoApi.http
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 souboru se přidáTodoApi.http
následující obsah:GET {{TodoApi_HostAddress}}/todoitems/{id} ###
Nahraďte
{id}
1
.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.
item
Vrácení výsledků v 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 nastavila její název ."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 se přidá
TodoApi.http
následující obsah:Put {{TodoApi_HostAddress}}/todoitems/{id} ###
Na řádku požadavku PUT nahraďte
{id}
.1
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.
Do souboru se přidá
TodoApi.http
požadavek DELETE .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ů s běžnou předponou adresy URL a MapGroup tato metoda 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/todoitems
adresy URL . - Změní všechny
app.Map<HttpVerb>
metody natodoItems.Map<HttpVerb>
. - Odebere předponu
/todoitems
adresy URL zMap<HttpVerb>
volání metody.
Otestujte koncové body a ověřte, že fungují stejně.
Použití rozhraní TypedResults API
Vrácení TypedResults místo Results několika výhod, včetně testovatelnosti a automatického vrácení metadat typu odpovědi pro OpenAPI k popisu koncového bodu. Další informace naleznete v tématu TypedResults vs Výsledky.
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 vrací správný typ. Pokud je GetAllTodos
metoda například:
static async Task<IResult> GetAllTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.ToArrayAsync());
}
Kód testu jednotek 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);
}
Prevence nadměrného účtová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 účtování.
- Skryjte vlastnosti, které klienti nemají zobrazit.
- Vynecháte některé vlastnosti pro zmenšení velikosti datové části.
- Zploštěné 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čenou ukázkou
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ýjimky vývojáře je ve výchozím nastavení povolená ve vývojovém prostředí pro minimální aplikace API. 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 v minimálních rozhraních API
- Rychlý start: Publikování do Azure
- Uspořádání ASP.NET základních minimálních rozhraní API
Další informace
Stručné referenční informace k minimálním rozhraním API