wordpress知名站點seo咨詢茂名
????????構建最小 API,以創(chuàng)建具有最小依賴項的 HTTP API。 它們非常適合需要在 ASP.NET Core 中僅包括最少文件、功能和依賴項的微服務和應用。
????????本教程介紹使用 ASP.NET Core 生成最小 API 的基礎知識。 在 ASP.NET Core 中創(chuàng)建 API 的另一種方法是使用控制器。 有關在最小 API 和基于控制器的 API 之間進行選擇的幫助,請參閱 API 概述。 有關基于包含更多功能的控制器創(chuàng)建 API 項目的教程,請參閱創(chuàng)建 Web API。
概述
本教程將創(chuàng)建以下 API:?
API | 描述 | 請求正文 | 響應正文 |
---|---|---|---|
GET /todoitems | 獲取所有待辦事項 | None | 待辦事項的數(shù)組 |
GET /todoitems/complete | 獲取已完成的待辦事項 | None | 待辦事項的數(shù)組 |
GET /todoitems/{id} | 按 ID 獲取項 | None | 待辦事項 |
POST /todoitems | 添加新項 | 待辦事項 | 待辦事項 |
PUT /todoitems/{id} | 更新現(xiàn)有項 | 待辦事項 | None |
DELETE /todoitems/{id} ?? ? | 刪除項 | None | 無 |
先決條件
帶有 ASP.NET 和 Web 開發(fā)工作負載的 Visual Studio 2022?
創(chuàng)建 API 項目?
啟動 Visual Studio 2022 并選擇“創(chuàng)建新項目”。
在“創(chuàng)建新項目”對話框中:
?? ?在“搜索模板”搜索框中輸入 Empty。
?? ?選擇“ASP.NET Core 空”模板,然后選擇“下一步”。
將項目命名為 TodoApi,然后選擇“下一步”。
在“其他信息”對話框中:
?? ?選擇“.NET 8.0 (長期支持)”
?? ?取消選中“不使用頂級語句”
?? ?選擇“創(chuàng)建”
檢查代碼
Program.cs 文件包含以下代碼:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
前面的代碼:
?? ?創(chuàng)建具有預配置默認值的 WebApplicationBuilder 和 WebApplication。
?? ?創(chuàng)建返回 Hello World! 的 HTTP GET 終結點 /:
運行應用
按 Ctrl+F5 以在不使用調試程序的情況下運行。
Visual Studio 會顯示以下對話框:
如果信任 IIS Express SSL 證書,請選擇“是”。
將顯示以下對話框:
如果你同意信任開發(fā)證書,請選擇“是”。
有關信任 Firefox 瀏覽器的信息,請參閱 Firefox SEC_ERROR_INADEQUATE_KEY_USAGE 證書錯誤。
Visual Studio 啟動 Kestrel Web 服務器,然后打開瀏覽器窗口。
Hello World! 將顯示在瀏覽器中。 Program.cs 文件包含一個最小但完整的應用。
關閉瀏覽器窗口。
添加 NuGet 包
必須添加 NuGet 包以支持本教程中使用的數(shù)據庫和診斷。
?? ?在“工具”菜單中,選擇“NuGet 包管理器”>“管理解決方案的 NuGet 包”。
?? ?選擇“瀏覽”選項卡。
?? ?在搜索框中輸入“Microsoft.EntityFrameworkCore.InMemory”,然后選擇 Microsoft.EntityFrameworkCore.InMemory。
?? ?選中右窗格中的“項目”復選框,然后選擇“安裝” 。
?? ?按照上述說明添加 Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore 包。
模型和數(shù)據庫上下文類
在項目文件夾中,創(chuàng)建名為 Todo.cs 的文件,包含以下代碼:
public class Todo
{
? ? public int Id { get; set; }
? ? public string? Name { get; set; }
? ? public bool IsComplete { get; set; }
}
前面的代碼為此應用創(chuàng)建模型。 模型是一個表示應用管理的數(shù)據的類。
?? ?使用以下代碼創(chuàng)建名為 TodoDb.cs 的文件:
?? ?
using Microsoft.EntityFrameworkCore;
class TodoDb : DbContext
{
? ? public TodoDb(DbContextOptions<TodoDb> options)
? ? ? ? : base(options) { }
? ? public DbSet<Todo> Todos => Set<Todo>();
}
前面的代碼定義了數(shù)據庫上下文,它是為數(shù)據模型協(xié)調實體框架功能的主類。 此類從 Microsoft.EntityFrameworkCore.DbContext 類派生。
添加 API 代碼
將 Program.cs 文件的內容替換為以下代碼:
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();
以下突出顯示的代碼將數(shù)據庫上下文添加到依賴關系注入 (DI) 容器,并且允許顯示與數(shù)據庫相關的異常:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();
DI 容器提供對數(shù)據庫上下文和其他服務的訪問權限。
?? ?本教程使用終結點資源管理器和 .http 文件來測試 API。
測試發(fā)布數(shù)據
Program.cs 中的以下代碼創(chuàng)建 HTTP POST 終結點 /todoitems 以將數(shù)據添加到內存中數(shù)據庫:
app.MapPost("/todoitems", async (Todo todo, TodoDb db) =>
{
? ? db.Todos.Add(todo);
? ? await db.SaveChangesAsync();
? ? return Results.Created($"/todoitems/{todo.Id}", todo);
});
運行應用。 瀏覽器顯示 404 錯誤,因為不再存在 / 終結點。
POST 終結點將用于向應用添加數(shù)據。
?? ?選擇“查看”>“其他 Windows”>“終結點資源管理器”。
?? ?右鍵單擊“POST”終結點,然后選擇“生成請求”。
?
在名為 TodoApi.http 的項目文件夾中創(chuàng)建一個新文件,其內容類似于以下示例:
@TodoApi_HostAddress = https://localhost:7031
Post {{TodoApi_HostAddress}}/todoitems
###
?? ?第一行創(chuàng)建了一個變量,該變量適用于所有終結點。
?? ?下一行定義了 POST 請求。
?? ?三重井號標簽 (###) 行是請求分隔符:對于不同的請求,該標簽之后的內容屬于另一個請求。
POST 請求需要標頭和正文。 若要定義請求的這些部分,請緊隨 POST 請求行之后添加以下行:
Content-Type: application/json
{
? "name":"walk dog",
? "isComplete":true
}
前面的代碼會添加 Content-Type 標頭和 JSON 請求正文。 TodoApi.http 文件現(xiàn)在應如以下示例所示,但帶有端口號:
@TodoApi_HostAddress = https://localhost:7057
Post {{TodoApi_HostAddress}}/todoitems
Content-Type: application/json
{
? "name":"walk dog",
? "isComplete":true
}
###
運行應用。
選擇 POST 請求行上方的“發(fā)送請求”鏈接。
POST 請求將發(fā)送到應用,響應將顯示在“響應”窗格中。?
檢查 GET 終結點
示例應用通過調用 MapGet 實現(xiàn)多個 GET 終結點:?
API | 描述 | 請求正文 | 響應正文 |
---|---|---|---|
GET /todoitems | 獲取所有待辦事項 | None | 待辦事項的數(shù)組 |
GET /todoitems/complete | 獲取所有已完成的待辦事項 | None | 待辦事項的數(shù)組 |
GET /todoitems/{id} | 按 ID 獲取項 | None | 待辦事項 |
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());
測試 GET 終結點
通過從瀏覽器或使用終結點資源管理器調用 GET 終結點來測試應用。 以下步驟適用于終結點資源管理器。
?? ?在“終結點資源管理器”中,右鍵單擊第一個 GET 終結點,然后選擇“生成請求”。
?? ?將以下內容添加到 TodoApi.http 文件中:
?? ?
Get {{TodoApi_HostAddress}}/todoitems
###
選擇新的 GET 請求行上方的“發(fā)送請求”鏈接。
GET 請求將發(fā)送到應用,響應將顯示在“響應”窗格中。
響應正文與以下 JSON 類似:
[
? {
? ? "id": 1,
? ? "name": "walk dog",
? ? "isComplete": true
? }
]
在“終結點資源管理器”中,右鍵單擊“/todoitems/{id} GET”終結點,然后選擇“生成請求”。 將以下內容添加到 TodoApi.http 文件中:
GET {{TodoApi_HostAddress}}/todoitems/{id}
###
將 {id} 替換為 1。
選擇新的 GET 請求行上方的“發(fā)送請求”鏈接。
GET 請求將發(fā)送到應用,響應將顯示在“響應”窗格中。
響應正文與以下 JSON 類似:
{
? "id": 1,
? "name": "walk dog",
? "isComplete": true
}
此應用使用內存中數(shù)據庫。 如果已重新啟動應用,GET 請求不會返回任何數(shù)據。 如果未返回任何數(shù)據,請將數(shù)據 POST 到應用,然后重新嘗試 GET 請求。
返回值
ASP.NET Core 自動將對象序列化為 JSON,并將 JSON 寫入響應消息的正文中。 此返回類型的響應代碼為 200 OK(假設沒有未處理的異常)。 未經處理的異常將轉換為 5xx 錯誤。
返回類型可以表示大范圍的 HTTP 狀態(tài)代碼。 例如,GET /todoitems/{id} 可以返回兩個不同的狀態(tài)值:
?? ?如果沒有任何項與請求的 ID 匹配,該方法將返回 404 狀態(tài) NotFound 錯誤代碼。
?? ?否則,此方法將返回具有 JSON 響應正文的 200。 返回 item 則產生 HTTP 200 響應。
檢查 PUT 終結點
示例應用使用 MapPut 實現(xiàn)單個 PUT 終結點:
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();
});
????????此方法類似于 MapPost 方法,但它使用 HTTP PUT。 成功響應返回 204 (無內容)。 根據 HTTP 規(guī)范,PUT 請求需要客戶端發(fā)送整個更新的實體,而不僅僅是更改。 若要支持部分更新,請使用 HTTP PATCH。
測試 PUT 終結點
本示例使用內存內、數(shù)據庫,每次啟動應用時都必須對其進行初始化。 在進行 PUT 調用之前,數(shù)據庫中必須有一個項。 調用 GET,以確保在調用 PUT 之前數(shù)據庫中存在項。
更新具有 Id = 1 的 to-do 項,并將其名稱設置為 "feed fish"。
?? ?在“終結點資源管理器”中,右鍵單擊 PUT 終結點,然后選擇“生成請求”。
?? ?
?? ?將以下內容添加到 TodoApi.http 文件中:
?? ?
?? ?Put {{TodoApi_HostAddress}}/todoitems/{id}
?? ?
?? ?###
?? ?
?? ?在 PUT 請求行中,將 {id} 替換為 1。
?? ?
?? ?緊隨 PUT 請求行之后添加以下行:
?? ?
?? ?Content-Type: application/json
?? ?
?? ?{
?? ?"name": "feed fish",
?? ?"isComplete": false
?? ?}
?? ?
?? ?前面的代碼會添加 Content-Type 標頭和 JSON 請求正文。
?? ?
?? ?選擇新的 PUT 請求行上方的“發(fā)送請求”鏈接。
?? ?
?? ?PUT 請求將發(fā)送到應用,響應將顯示在“響應”窗格中。 響應正文為空,狀態(tài)代碼為 204。
檢查并測試 DELETE 終結點
示例應用使用 MapDelete 實現(xiàn)單個 DELETE 終結點:
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();
});
在“終結點資源管理器”中,右鍵單擊 DELETE 終結點,然后選擇“生成請求”。
將 DELETE 請求添加到 TodoApi.http。
將 DELETE 請求行中的 {id} 替換為 1。 DELETE 請求應如以下示例所示:
DELETE {{TodoApi_HostAddress}}/todoitems/1
###
選擇 DELETE 請求的“發(fā)送請求”鏈接。
DELETE 請求將發(fā)送到應用,響應將顯示在“響應”窗格中。 響應正文為空,狀態(tài)代碼為 204。
使用 MapGroup API
????????示例應用代碼每次設置終結點時都會重復 todoitems URL 前綴。 API 通常具有帶常見 URL 前綴的終結點組,并且 MapGroup 方法可用于幫助組織此類組。 它減少了重復代碼,并允許通過對 RequireAuthorization 和 WithMetadata 等方法的單一調用來自定義整個終結點組。
將 Program.cs 的內容替換為以下代碼:
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();
前面的代碼執(zhí)行以下更改:
?? ?添加 var todoItems = app.MapGroup("/todoitems"); 以使用 URL 前綴 /todoitems 設置組。
?? ?將所有 app.Map<HttpVerb> 方法更改為 todoItems.Map<HttpVerb>。
?? ?從 Map<HttpVerb> 方法調用中移除 URL 前綴 /todoitems。
測試終結點以驗證它們的運行方式是否相同。
使用 TypedResults API
?? ?返回 TypedResults(而不是 Results)有幾個優(yōu)點,包括可測試性和自動返回 OpenAPI 的響應類型元數(shù)據來描述終結點。 有關詳細信息,請參閱 TypedResults 與 Results。
Map<HttpVerb> 方法可以調用路由處理程序方法,而不是使用 lambda。 若要查看示例,請使用以下代碼更新 Program.cs:
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();
}
Map<HttpVerb> 代碼現(xiàn)在調用方法,而不是 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);
這些方法返回實現(xiàn) IResult 并由 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();
}
單元測試可以調用這些方法并測試它們是否返回正確的類型。 例如,如果方法是 GetAllTodos:
static async Task<IResult> GetAllTodos(TodoDb db)
{
? ? return TypedResults.Ok(await db.Todos.ToArrayAsync());
}
單元測試代碼可以驗證是否從處理程序方法返回了 Ok<Todo[]>類型的對象。 例如:
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);
}
防止過度發(fā)布
????????目前,示例應用公開了整個 Todo 對象。 生產應用程序中的生產應用是模型的一個子集,通常用于限制可輸入和返回的數(shù)據。 這背后有多種原因,但安全性是主要原因。 模型的子集通常稱為數(shù)據傳輸對象 (DTO)、輸入模型或視圖模型。 本文使用的是 DTO。
DTO 可以用于:
?? ?防止過度發(fā)布。
?? ?隱藏客戶端不應查看的屬性。
?? ?省略某些屬性以減少有效負載大小。
?? ?平展包含嵌套對象的對象圖。 對客戶端而言,平展的對象圖可能更方便。
?? ?若要演示 DTO 方法,請更新 Todo 類,使其包含機密字段:
?? ?
?? ?public class Todo
?? ?{
?? ??? ?public int Id { get; set; }
?? ??? ?public string? Name { get; set; }
?? ??? ?public bool IsComplete { get; set; }
?? ??? ?public string? Secret { get; set; }
?? ?}
此應用需要隱藏機密字段,但管理應用可以選擇公開它。
確??梢园l(fā)布和獲取機密字段。
使用以下代碼創(chuàng)建名為 TodoItemDTO.cs 的文件:
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 文件的內容替換為以下代碼以使用此 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();
}
確??梢园l(fā)布和獲取除機密字段以外的所有字段。
用完成的示例進行故障排除
如果遇到無法解決的問題,請將你的代碼與完成的項目進行比較。 查看或下載已完成的項目(如何下載)
原文連接:教程:使用 ASP.NET Core 創(chuàng)建最小 API | Microsoft Learn