由 蒂姆·德施里弗 和 里克·安德森

本教程介绍生成使用数据库的基于控制器的 Web API 的基础知识。 在 ASP.NET Core 中创建 API 的另一种方法是创建 最小 API 。 有关在最小 API 和基于控制器的 API 之间进行选择的帮助,请参阅 API 概述 。 有关创建最小 API 的教程,请参阅 教程:使用 ASP.NET Core 创建最小 API 。

Overview

本教程将创建以下 API:

Description .NET 9 SDK

可以按照 macOS、Linux 或 Windows 上的 Visual Studio Code 指南进行操作。 如果使用 Visual Studio Code 以外的集成开发环境(IDE),可能需要更改。

创建 Web API 项目

  • 在搜索框中输入 Web API 。
  • 选择“ASP.NET Core Web API” 模板,然后选择“下一步” 。
  • 在“配置新项目” 对话框中,将项目命名为“TodoApi” ,然后选择“下一步” 。
  • 在“其他信息” 对话框中:
    • 确认 Framework 为 .NET 9.0(标准期限支持) 。
    • 确认已选中“启用 OpenAPI 支持” 复选框。
    • 确认 “使用控制器” 复选框已选中(取消选中以使用最小 API)。
    • 选择 创建 。
    • 添加 NuGet 包

      必须添加 NuGet 包以支持本教程中使用的数据库。

    • 在“工具”菜单中,选择“NuGet 包管理器” “管理解决方案的 NuGet 包”。
    • 选择“浏览”选项卡。
    • 在搜索框中输入“Microsoft.EntityFrameworkCore.InMemory”,然后选择 。
    • 选中右窗格中的“项目”复选框,然后选择“安装” 。
    • dotnet new webapi --use-controllers -o TodoApi
      cd TodoApi
      dotnet add package Microsoft.EntityFrameworkCore.InMemory
      code -r .
      

      以下命令:

    • 创建新的 Web API 项目,并在 Visual Studio Code 中打开它。
    • 添加下一部分所需的 NuGet 包。
    • 在 Visual Studio Code 的当前实例中打开 TodoApi 文件夹。
    • Visual Studio Code 可能会显示一个对话框,询问:“你是否信任此文件夹中的文件作者?”

    • 如果你信任父文件夹中的所有文件,请选择“信任父文件夹中所有文件的作者”。
    • 选择“是,我信任所有作者”,因为项目文件夹包含 .NET 生成的文件。
    • 当 Visual Studio Code 请求添加资产以生成和调试项目时,请选择“ 是”。 如果 Visual Studio Code 不提供添加生成和调试资产,请选择 “查看>命令面板 ”,然后在搜索框中键入“.NET”。 从命令列表中选择 .NET: Generate Assets for Build and Debug 命令。
    • Visual Studio Code 添加一个包含生成的 .vscode 和 launch.json 文件的 tasks.json 文件夹。

      如果你同意信任开发证书,请选择“是”。

      有关信任 Firefox 浏览器的信息,请参阅 Firefox SEC_ERROR_INADEQUATE_KEY_USAGE 证书错误。

      Visual Studio 启动一个终端窗口,并显示正在运行的应用的 URL。 API 托管在 https://localhost:<port>,其中 <port> 是在项目创建时随机选择的端口号。

      info: Microsoft.Hosting.Lifetime[14] Now listening on: https://localhost:7260 info: Microsoft.Hosting.Lifetime[14] Now listening on: http://localhost:7261 info: Microsoft.Hosting.Lifetime[0] Application started. Press Ctrl+C to shut down. Ctrl+单击 输出中的 HTTPS URL 以在浏览器中测试 Web 应用。 https://localhost:<port> 没有终结点,因此浏览器返回 HTTP 404 未找到。

      将 /weatherforecast 附加到 URL,以测试 WeatherForecast API。 浏览器显示类似于以下示例的 JSON:

      "date": "2025-07-16", "temperatureC": 52, "temperatureF": 125, "summary": "Mild" "date": "2025-07-17", "temperatureC": 36, "temperatureF": 96, "summary": "Warm" "date": "2025-07-18", "temperatureC": 39, "temperatureF": 102, "summary": "Cool" "date": "2025-07-19", "temperatureC": 10, "temperatureF": 49, "summary": "Bracing" "date": "2025-07-20", "temperatureC": -1, "temperatureF": 31, "summary": "Chilly"

      上述命令需要 Linux 上的 .NET 9 或更高版本 SDK。 对于 .NET 8.0.401 或更早版本的 SDK 上的 Linux,请参阅 Linux 分发的文档来信任证书。

      如果证书以前不受信任,上述命令显示以下对话:

      Ctrl+单击 输出中的 HTTPS URL 以在浏览器中测试 Web 应用。

    • 默认浏览器会启动到 https://localhost:<port>,其中 <port> 是输出中显示的随机选择的端口号。 https://localhost:<port> 没有终结点,因此浏览器返回 HTTP 404 未找到。

    • 将 /weatherforecast 附加到 URL,以测试 WeatherForecast API。 浏览器显示类似于以下示例的 JSON:

      "date": "2025-07-16", "temperatureC": 52, "temperatureF": 125, "summary": "Mild" "date": "2025-07-17", "temperatureC": 36, "temperatureF": 96, "summary": "Warm" "date": "2025-07-18", "temperatureC": 39, "temperatureF": 102, "summary": "Cool" "date": "2025-07-19", "temperatureC": 10, "temperatureF": 49, "summary": "Bracing" "date": "2025-07-20", "temperatureC": -1, "temperatureF": 31, "summary": "Chilly"
    • 使用以下说明测试 Web 应用后,按集成终端中的 Ctrl+C 将其关闭。
    • 使用 Swagger 创建 API 测试 UI

      有许多可用的 Web API 测试工具可供选择,你可以使用首选工具遵循本教程介绍的 API 测试步骤。

      本教程利用 .NET 包 NSwag.AspNetCore,它集成了 Swagger 工具,可用于生成遵循 OpenAPI 规范的测试 UI:

    • NSwag:将 Swagger 直接集成到 ASP.NET Core 应用程序中的 .NET 库,提供了中间件和配置。
    • Swagger:一组开放源代码工具(如 OpenAPIGenerator 和 SwaggerUI),用于生成遵循 OpenAPI 规范的 API 测试页。
    • OpenAPI 规范:基于控制器和模型中的 XML 和属性注释,描述 API 功能的文档。
    • 有关将 OpenAPI 和 NSwag 与 ASP.NET 配合使用的详细信息,请参阅使用 Swagger / OpenAPI 的 ASP.NET Core Web API 文档。

      安装 Swagger 工具

    • 运行以下命令:

      dotnet add package NSwag.AspNetCore
      

      上一个命令添加了 NSwag.AspNetCore 包,其中包含用于生成 Swagger 文档和 UI 的工具。 因为我们的项目使用 OpenAPI,所以我们只使用 NSwag 包来生成 Swagger UI。

      配置 Swagger 中间件

    • 在 Program.cs 中,添加以下突出显示的代码:
    • var app = builder.Build();
      if (app.Environment.IsDevelopment())
          app.MapOpenApi();
          app.UseSwaggerUi(options =>
              options.DocumentPath = "/openapi/v1.json";
      

      前面的代码使 Swagger 中间件能够使用 Swagger UI 为生成的 JSON 文档提供服务。 Swagger 仅在开发环境中启用。 在生产环境中启用 Swagger 可能会公开有关 API 结构和实现的潜在敏感详细信息。

      该应用使用 OpenAPI 生成的 OpenAPI 文档(位于 /openapi/v1.json)来生成 UI。 在项目运行时,通过在浏览器中导航到 WeatherForecast,查看为 https://localhost:<port>/openapi/v1.json API 生成的 OpenAPI 规范。

      OpenAPI 规范是一个 JSON 格式的文档,它描述了 API 的结构和功能,包括终结点、请求/响应格式、参数等。 它本质上是 API 的蓝图,各种工具可以使用它来理解 API 并与之交互。

      添加模型类

      模型是一组类,表示应用管理的数据。 此应用的模型是 TodoItem 类。

    • 在 解决方案资源管理器中,右键单击项目。 选择“添加>新文件夹。 将该文件夹命名为 Models注册一个免费试用帐户。
    • 右键单击 Models 文件夹,然后选择“ 添加>类”。 将类命名 为 TodoItem ,然后选择“ 添加”。
    • 将模板代码替换为以下内容:
    • namespace TodoApi.Models;
      public class TodoItem
          public long Id { get; set; }
          public string? Name { get; set; }
          public bool IsComplete { get; set; }
          public long Id { get; set; }
          public string? Name { get; set; }
          public bool IsComplete { get; set; }
      public class TodoContext : DbContext
          public TodoContext(DbContextOptions<TodoContext> options)
              : base(options)
          public DbSet<TodoItem> TodoItems { get; set; } = null!;
      public class TodoContext : DbContext
          public TodoContext(DbContextOptions<TodoContext> options)
              : base(options)
          public DbSet<TodoItem> TodoItems { get; set; } = null!;
      builder.Services.AddControllers();
      builder.Services.AddOpenApi();
      builder.Services.AddDbContext<TodoContext>(opt =>
          opt.UseInMemoryDatabase("TodoList"));
      var app = builder.Build();
      if (app.Environment.IsDevelopment())
          app.MapOpenApi();
      app.UseHttpsRedirection();
      app.UseAuthorization();
      app.MapControllers();
      app.Run();
      
      using Microsoft.EntityFrameworkCore;
      using TodoApi.Models;
      var builder = WebApplication.CreateBuilder(args);
      builder.Services.AddControllers();
      builder.Services.AddOpenApi();
      builder.Services.AddDbContext<TodoContext>(opt =>
          opt.UseInMemoryDatabase("TodoList"));
      // <snippet_UseSwagger>
      var app = builder.Build();
      if (app.Environment.IsDevelopment())
          app.MapOpenApi();
          app.UseSwaggerUi(options =>
              options.DocumentPath = "/openapi/v1.json";
      // </snippet_UseSwagger>
      app.UseHttpsRedirection();
      app.UseAuthorization();
      app.MapControllers();
      app.Run();
      
    • 在 Model 类中选择 TodoItem (TodoApi.Models)。
    • 在数据上下文类中选择 TodoContext (TodoApi.Models)。
    • 选择 并添加。
    • 如果搭建基架失败,请选择添加以尝试第二次搭建。

      此步骤将 Microsoft.VisualStudio.Web.CodeGeneration.Design 和 Microsoft.EntityFrameworkCore.Tools NuGet 包添加到项目中。 这些包是基架所需的。

      请确保目前所有更改均已保存。

    • 右键单击(或命令单击 macOS) TodoAPI 项目,然后选择 “在终端中打开”。 终端将在 TodoAPI 项目文件夹中打开。 运行以下命令:
    • dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
      dotnet add package Microsoft.EntityFrameworkCore.Design
      dotnet add package Microsoft.EntityFrameworkCore.SqlServer
      dotnet add package Microsoft.EntityFrameworkCore.Tools
      dotnet tool uninstall -g dotnet-aspnet-codegenerator
      dotnet tool install -g dotnet-aspnet-codegenerator
      dotnet tool update -g dotnet-aspnet-codegenerator
      

      前面的命令:

    • 添加构建所需的 NuGet 包。
    • 卸载任何可能的早期版本后,安装基架引擎 (dotnet-aspnet-codegenerator)。
    • 对于 Linux,使用以下命令将 .NET 工具目录添加到系统路径:

      echo 'export PATH=$HOME/.dotnet/tools:$PATH' >> ~/.bashrc
      source ~/.bashrc
      

      默认情况下,要安装的.NET二进制文件的体系结构表示当前运行的操作系统体系结构。 若要指定其他架构,请参阅如何使用 dotnet tool install 命令并配合 '--arch' 选项。 有关详细信息,请参阅 GitHub dotnet/aspnetcore.docs 议题 #29262 - 在 Apple Silicon 上添加“-a arm64”。

      生成项目。

      运行以下命令:

      dotnet aspnet-codegenerator controller -name TodoItemsController -async -api -m TodoItem -dc TodoContext -outDir Controllers
      

      上述命令为 TodoItemsController 创建基架。

      生成的代码:

    • 使用 [ApiController] 属性标记类。 此属性指示控制器响应 Web API 请求。 有关该属性启用的特定行为的信息,请参阅使用 ASP.NET Core 创建 Web API。
    • 使用 DI 将数据库上下文 (TodoContext) 注入到控制器中。 数据库上下文用于控制器中的每个 CRUD 方法。
    • ASP.NET Core 模板:

    • 具有视图的控制器在路由模板中包含 [action]。
    • API 控制器不在路由模板中包含 [action]。
    • 如果[action]标记不在路由模板中,则终结点中不会包含操作名称(方法名称)。 也就是说,不会在匹配的路由中使用操作的关联方法名称。

      打开生成的 Controllers/TodoItemsController.cs 文件以查看基架代码。 基架生成完整的工作控制器,其中包含创建、读取、更新和删除 TodoItem 数据的操作方法:

      GetTodoItems:获取所有待办项。
    • GetTodoItem:通过 ID 获取待办事项。 PostTodoItem:创建待办事项。 PutTodoItem:更新现有待办事项。 DeleteTodoItem:删除待办事项。

      以下各节将考察这些生成的方法,并从 PostTodoItem 开始。

      检查 PostTodoItem 的创建方法

      检查构建的 PostTodoItem 方法。 生成的代码已正常工作。 return 语句使用 nameof 运算符,因此操作名称不会硬编码为字符串。 被注释掉的代码行显示了由 nameof 替代的等效硬编码形式:

      [HttpPost]
      public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
          _context.TodoItems.Add(todoItem);
          await _context.SaveChangesAsync();
          //    return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
          return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
      

      上述代码是 HTTP POST 方法,如 [HttpPost] 属性所指示。 此方法从 HTTP 请求正文获取 TodoItem 的值。

      有关详细信息,请参阅使用 Http [Verb] 特性的特性路由。

      CreatedAtAction 方法:

    • 如果成功,将返回 HTTP 201 状态代码。 HTTP 201 是在服务器上创建新资源的 HTTP POST 方法的标准响应。
    • 向响应添加 Location 标头。 标头 Location 指定新创建的 to-do 项的 URI 。 有关详细信息,请参阅创建的 10.2.2 201。
    • 引用 GetTodoItem 操作以创建 Location 标头的 URI。
    • 测试 PostTodoItem

      在名为 TodoApi.http 的项目文件夹中创建一个新文件,其内容类似于以下示例:

      @TodoApi_HostAddress = https://localhost:49738
      POST {{TodoApi_HostAddress}}/api/todoitems
      Content-Type: application/json
        //TodoItem
      
    • 第一行创建了一个变量,该变量适用于所有终结点。
    • 下一行定义了 POST 请求。
    • POST 请求行后面的行会定义标头以及请求正文的占位符。
    • 三重井号标签 (###) 行是请求分隔符:对于不同的请求,该标签之后的内容属于另一个请求。
    • POST 请求需要 TodoItem。 要定义待办事项,请将 //TodoItem 注释替换为以下 JSON:

      "name": "walk dog", "isComplete": true

      TodoApi.http 文件现在应如以下示例所示,但带有端口号:

      @TodoApi_HostAddress = https://localhost:7260
      Post {{TodoApi_HostAddress}}/api/todoitems
      Content-Type: application/json
        "name": "walk dog",
        "isComplete": true
      
    • 运行应用。

    • 选择 请求行上方的“发送请求”POST链接。

      请注意一些有用的详细信息:

    • cURL:Swagger 在 Unix/Linux 语法中提供了一个示例 cURL 命令,可以通过任何使用 Unix/Linux 语法的 bash shell(包括 Git for Windows 中的 Git Bash)在命令行上运行。
    • 请求 URL:Swagger UI 针对 API 调用的 JavaScript 代码发出的 HTTP 请求的简化表示形式。 实际请求可以包括标头和查询参数以及请求正文等详细信息。
    • 服务器响应:包括响应正文和标头。 响应正文显示 id 已设置为 1。
    • 响应代码:返回了 201 HTTP 状态代码,指示请求已成功处理并导致创建新资源。
    • 测试位置标头 URI

      通过从浏览器调用 GET 终结点或使用 终结点探查器来测试应用。 以下步骤适用于终结点资源管理器。

    • 在“终结点资源管理器”中,右键单击第一个 GET 终结点,然后选择“生成请求”。

      将以下内容添加到 TodoApi.http 文件中:

      GET {{TodoApi_HostAddress}}/api/todoitems
      
    • 选择新的 请求行上方的“发送请求”GET链接。

      GET 请求将发送到应用,响应将显示在“响应”窗格中。

    • 响应正文与以下 JSON 类似:

      "id": 1, "name": "walk dog", "isComplete": true
    • 在终结点资源管理器中,右键单击/api/todoitems/{id}GET终结点,然后选择生成请求。 将以下内容添加到 TodoApi.http 文件中:

      @id=0
      GET {{TodoApi_HostAddress}}/api/todoitems/{{id}}
      
    • 将 {@id} 分配给 1(而不是 0)。

    • 选择新的 GET 请求行上方的“发送请求”链接。

      GET 请求将发送到应用,响应将显示在“响应”窗格中。

    • 响应正文与以下 JSON 类似:

      "id": 1, "name": "walk dog", "isComplete": true
    • 在 Swagger 中,选择 “GET /api/todoitems>试用>执行”。

    • 或者,通过输入 URI 从浏览器调用 https://localhost:<port>/api/todoitems。 例如: https://localhost:7260/api/todoitems

      对 GET /api/todoitems 的调用生成如下响应:

      "id": 1, "name": "walk dog", "isComplete": true
    • 在 Swagger 中调用 GET /api/todoitems/{id} 以从特定 ID 返回数据:

    • 选择GET /api/todoitems>尝试一下。
    • 将 id 字段设置为1并选择执行。
    • 或者,通过输入 URI 从浏览器调用 https://localhost:<port>/api/todoitems/1。 例如: https://localhost:7260/api/todoitems/1

    • 响应类似于以下内容:

      "id": 1, "name": "walk dog", "isComplete": true

      上一节展示了 /api/todoitems/{id} 路由的示例。

      按照 POST 说明添加另一个待办事项,然后使用 Swagger 测试 /api/todoitems 路由。

      此应用使用内存中数据库。 如果停止并启动应用,则前面的 GET 请求不会返回任何数据。 如果未返回任何数据,则向应用程序发送 POST 数据。

      路由和 URL 路径

      [HttpGet] 属性表示响应 HTTP GET 请求的方法。 每个方法的 URL 路径构造如下所示:

    • 在控制器的 Route 属性中以模板字符串开头:

      [Route("api/[controller]")]
      [ApiController]
      public class TodoItemsController : ControllerBase
      
    • 将 [controller] 替换为控制器的名称,按照惯例,在控制器类名称中去掉“Controller”后缀。 对于此示例,控制器类名称为 TodoItems控制器,因此控制器名称为“TodoItems”。 ASP.NET 核心 路由 不区分大小写。

    • 如果 [HttpGet] 属性具有路由模板(例如 [HttpGet("products")]),则将它追加到路径。 此示例不使用模板。 有关详细信息,请参阅使用 Http [Verb] 特性的特性路由。

      在下面的 GetTodoItem 方法中,"{id}" 是待办事项的唯一标识符的占位符变量。 调用 GetTodoItem 时,URL 中 "{id}" 的值会在 id 参数中提供给方法。

      [HttpGet("{id}")]
      public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
          var todoItem = await _context.TodoItems.FindAsync(id);
          if (todoItem == null)
              return NotFound();
          return todoItem;
                    GetTodoItems 和 GetTodoItem 方法的返回类型是 ActionResult<T> 类型。 ASP.NET Core 自动将对象序列化为 JSON,并将 JSON 写入响应消息的正文中。 此返回类型的响应代码为 200 OK(假设没有未处理的异常)。 未经处理的异常将转换为 5xx 错误。

      ActionResult 返回类型可以表示大范围的 HTTP 状态代码。 例如,GetTodoItem 可以返回两个不同的状态值:

    • 如果没有任何项与请求的 ID 匹配,该方法将返回 404 状态NotFound 错误代码。
    • 否则,此方法将返回具有 JSON 响应正文的 200。 返回 item 则产生 HTTP 200 响应。
    • PutTodoItem 方法

      检查 PutTodoItem 方法:

      [HttpPut("{id}")]
      public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
          if (id != todoItem.Id)
              return BadRequest();
          _context.Entry(todoItem).State = EntityState.Modified;
              await _context.SaveChangesAsync();
          catch (DbUpdateConcurrencyException)
              if (!TodoItemExists(id))
                  return NotFound();
                  throw;
          return NoContent();
                    PutTodoItem 与 PostTodoItem 类似,但使用的是 HTTP PUT。 响应是 204(无内容)。 根据 HTTP 规范,PUT 请求需要客户端发送整个更新的实体,而不仅仅是更改。 若要支持部分更新,请使用 HTTP PATCH。

      测试 PutTodoItem 方法

      本示例使用内存内、数据库,每次启动应用时都必须对其进行初始化。 在进行 PUT 调用之前,数据库中必须有一个项。 调用 GET,以确保在调用 PUT 之前数据库中存在项。

      使用 PUT 方法更新 Id=1 的 TodoItem,并将其名称设置为 "feed fish"。 请注意,响应为 HTTP 204 No Content。

    • 在“终结点资源管理器”中,右键单击 PUT 终结点,然后选择“生成请求”。

      将以下内容添加到 TodoApi.http 文件中:

      PUT {{TodoApi_HostAddress}}/api/todoitems/{{id}}
      Content-Type: application/json
        //TodoItem
      
    • 在 PUT 请求行中,将 {{id}} 替换为 1。

    • 将 //TodoItem 占位符替换为以下行:

      PUT {{TodoApi_HostAddress}}/api/todoitems/1
      Content-Type: application/json
        "id": 1,
        "name": "feed fish",
        "isComplete": false
      
    • 选择新的 PUT 请求行上方的“发送请求”链接。

      PUT 请求将发送到应用,响应将显示在“响应”窗格中。 响应正文为空,状态代码为 204。

      检查 DeleteTodoItem 方法:

      [HttpDelete("{id}")]
      public async Task<IActionResult> DeleteTodoItem(long id)
          var todoItem = await _context.TodoItems.FindAsync(id);
          if (todoItem == null)
              return NotFound();
          _context.TodoItems.Remove(todoItem);
          await _context.SaveChangesAsync();
          return NoContent();
      

      测试 DeleteTodoItem 方法

      使用 DELETE 方法删除 Id = 1 的 TodoItem。 请注意,响应为 HTTP 204 No Content。

    • 将 DELETE 请求行中的 {{id}} 替换为 1。 DELETE 请求应如以下示例所示:

      DELETE {{TodoApi_HostAddress}}/api/todoitems/{{id}}
      
    • 选择 DELETE 请求的“发送请求”链接。

      DELETE 请求将发送到应用,响应将显示在“响应”窗格中。 响应正文为空,状态代码为 204。

      防止过度发布

      目前,示例应用公开了整个 TodoItem 对象。 生产应用通常使用模型的子集来限制输入和返回的数据。 这背后有多种原因,但安全性是主要原因。 模型的子集通常称为数据传输对象 (DTO)、输入模型或视图模型。 本教程使用 DTO。

      DTO 可用于:

    • 防止过度发布。
    • 隐藏客户端不应查看的属性。
    • 省略一些属性以缩减有效负载大小。
    • 平展包含嵌套对象的对象图。 对客户端而言,平展的对象图可能更方便。
    • 若要演示 DTO 方法,请更新 TodoItem 类,使其包含机密字段:

      namespace TodoApi.Models;
      public class TodoItem
          public long Id { get; set; }
          public string? Name { get; set; }
          public bool IsComplete { get; set; }
          public string? Secret { get; set; }
      

      此应用需要隐藏机密字段,但管理应用可以选择公开它。

      确保可以发布和获取机密字段。

      在 Models/TodoItemDTO.cs 文件中创建 DTO 模型:

      namespace TodoApi.Models;
      public class TodoItemDTO
          public long Id { get; set; }
          public string? Name { get; set; }
          public bool IsComplete { get; set; }
      

      更新 TodoItemsController 以使用 TodoItemDTO:

      using Microsoft.AspNetCore.Mvc;
      using Microsoft.EntityFrameworkCore;
      using TodoApi.Models;
      namespace TodoApi.Controllers;
      [Route("api/[controller]")]
      [ApiController]
      public class TodoItemsController : ControllerBase
          private readonly TodoContext _context;
          public TodoItemsController(TodoContext context)
              _context = context;
          // GET: api/TodoItems
          [HttpGet]
          public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
              return await _context.TodoItems
                  .Select(x => ItemToDTO(x))
                  .ToListAsync();
          // GET: api/TodoItems/5
          // <snippet_GetByID>
          [HttpGet("{id}")]
          public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
              var todoItem = await _context.TodoItems.FindAsync(id);
              if (todoItem == null)
                  return NotFound();
              return ItemToDTO(todoItem);
          // </snippet_GetByID>
          // PUT: api/TodoItems/5
          // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
          // <snippet_Update>
          [HttpPut("{id}")]
          public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
              if (id != todoDTO.Id)
                  return BadRequest();
              var todoItem = await _context.TodoItems.FindAsync(id);
              if (todoItem == null)
                  return NotFound();
              todoItem.Name = todoDTO.Name;
              todoItem.IsComplete = todoDTO.IsComplete;
                  await _context.SaveChangesAsync();
              catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
                  return NotFound();
              return NoContent();
          // </snippet_Update>
          // POST: api/TodoItems
          // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
          // <snippet_Create>
          [HttpPost]
          public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
              var todoItem = new TodoItem
                  IsComplete = todoDTO.IsComplete,
                  Name = todoDTO.Name
              _context.TodoItems.Add(todoItem);
              await _context.SaveChangesAsync();
              return CreatedAtAction(
                  nameof(GetTodoItem),
                  new { id = todoItem.Id },
                  ItemToDTO(todoItem));
          // </snippet_Create>
          // DELETE: api/TodoItems/5
          [HttpDelete("{id}")]
          public async Task<IActionResult> DeleteTodoItem(long id)
              var todoItem = await _context.TodoItems.FindAsync(id);
              if (todoItem == null)
                  return NotFound();
              _context.TodoItems.Remove(todoItem);
              await _context.SaveChangesAsync();
              return NoContent();
          private bool TodoItemExists(long id)
              return _context.TodoItems.Any(e => e.Id == id);
          private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
             new TodoItemDTO
                 Id = todoItem.Id,
                 Name = todoItem.Name,
                 IsComplete = todoItem.IsComplete
      

      确保无法发布或获取机密字段。

      使用 JavaScript 调用 Web API

      请参阅教程:使用 JavaScript 调用 ASP.NET Core Web API。

      Web API 视频系列

      请参阅视频:初学者系列:Web API。

      企业 Web 应用模式

      有关创建可靠、安全、高性能、可测试且可缩放的 ASP.NET Core 应用的指导,请参阅 企业 Web 应用模式。 提供了一个完整且具备生产质量的示例 Web 应用,该应用实现了这些模式。

      向 Web API 添加身份验证支持

      ASP.NET Core Identity 将用户界面 (UI) 登录功能添加到 ASP.NET Core Web 应用。 若要保护 Web API 和 SPA,请使用以下项之一:

      Microsoft Entra ID
    • Duende Identity Server
    • Duende Identity Server 是适用于 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 框架。 Duende Identity Server 支持以下安全功能:

    • 身份验证即服务 (AaaS)
    • 跨多个应用程序类型的单一登录/注销 (SSO)
    • API 的访问控制
    • Important

      Duende Software 可能会要求你为 Duende Identity Server 的生产使用支付许可证费用。 有关详细信息,请参阅 从 .NET 5 中的 ASP.NET Core 迁移到 .NET 6。

      有关详细信息,请参阅 Duende Identity Server 文档(Duende Software 网站)。

      发布到 Azure

      有关部署到 Azure 的信息,请参阅快速入门:部署 ASP.NET Web 应用。

      查看或下载本教程的示例代码。 请参阅如何下载。

      有关详细信息,请参阅以下资源:

      使用 ASP.NET Core 创建 Web API
    • 教程:使用 ASP.NET Core 创建最小 API
    • 使用生成的 OpenAPI 文档
    • 带有 Swagger/OpenAPI 的 ASP.NET Core Web API 文档
    • Razor ASP.NET Core 中带 Entity Framework Core 的页面 - 第 1 个教程(共 8 个)
    • 在 ASP.NET Core 中路由到控制器操作
    • ASP.NET Core Web API 中控制器操作的返回类型
    • 将 ASP.NET Core 应用部署到 Azure 应用程序服务 托管和部署 ASP.NET Core 使用 ASP.NET Core 创建 Web API

      本教程介绍生成使用数据库的基于控制器的 Web API 的基础知识。 在 ASP.NET Core 中创建 API 的另一种方法是创建 最小 API。 有关在最小 API 和基于控制器的 API 之间进行选择的帮助,请参阅 API 概述。 有关创建最小 API 的教程,请参阅 教程:使用 ASP.NET Core 创建最小 API。

      Overview

      本教程将创建以下 API:

      Description

      Important

      Microsoft 已宣布停用 Visual Studio for Mac。 从 2024 年 8 月 31 日起,将不再支持 Visual Studio for Mac。 替代方案包括:

    • 带有 C# 开发工具包 和相关扩展(如 .NET MAUI 和 Unity)的 Visual Studio Code。
    • 在 Mac 虚拟机中的 Windows 上运行的 Visual Studio IDE。
    • 在云虚拟机中的 Windows 上运行的 Visual Studio IDE。
    • 有关详细信息,请参阅 Visual Studio for Mac 停用公告。

    • 在搜索框中输入 Web API。
    • 选择“ASP.NET Core Web API”模板,然后选择“下一步”。
    • 在“配置新项目”对话框中,将项目命名为“TodoApi”,然后选择“下一步”。
    • 在“其他信息”对话框中:
      • 确认框架为 .NET 8.0(长期支持)。
      • 确认选中了“使用控制器”复选框(取消选中以使用最小 API)。
      • 确认已选中“启用 OpenAPI 支持”复选框。
      • 选择 创建。
      • 添加 NuGet 包

        必须添加 NuGet 包以支持本教程中使用的数据库。

      • 在“工具”菜单中,选择“NuGet 包管理器”“管理解决方案的 NuGet 包”。
      • 选择“浏览”选项卡。
      • 在搜索框中输入“Microsoft.EntityFrameworkCore.InMemory”,然后选择 。
      • 选中右窗格中的“项目”复选框,然后选择“安装” 。
      • dotnet new webapi --use-controllers -o TodoApi
        cd TodoApi
        dotnet add package Microsoft.EntityFrameworkCore.InMemory
        code -r ../TodoApi
        

        以下命令:

      • 创建新的 Web API 项目,并在 Visual Studio Code 中打开它。
      • 添加下一部分所需的 NuGet 包。
      • 在 Visual Studio Code 的当前实例中打开 TodoApi 文件夹。
      • Visual Studio Code 可能会显示一个对话框,询问:“你是否信任此文件夹中的文件作者?”

      • 如果你信任父文件夹中的所有文件,请选择“信任父文件夹中所有文件的作者”。
      • 选择“是,我信任所有作者”,因为项目文件夹包含 .NET 生成的文件。
      • 当 Visual Studio Code 请求添加资产以生成和调试项目时,请选择“ 是”。 如果 Visual Studio Code 不提供添加生成和调试资产,请选择 “查看>命令面板 ”,然后在搜索框中键入“.NET”。 从命令列表中选择 .NET: Generate Assets for Build and Debug 命令。
      • Visual Studio Code 添加一个包含生成的 .vscode 和 launch.json 文件的 tasks.json 文件夹。

      • 在 Visual Studio for Mac 2022 工具栏中,选择“ 项目>管理 NuGet 包...”。
      • 在搜索框中,输入 Microsoft.EntityFrameworkCore.InMemory。
      • 在结果窗口中,选中 Microsoft.EntityFrameworkCore.InMemory。
      • 选择添加包
      • 在 “选择项目 ”窗口中,选择“ 确定”。
      • 在 “许可协议 ”窗口中,选择“ 同意”。
      • 上述命令需要 Linux 上的 .NET 9 或更高版本 SDK。 对于 .NET 8.0.401 或更早版本的 SDK 上的 Linux,请参阅 Linux 分发的文档来信任证书。

        如果证书以前不受信任,上述命令显示以下对话:

        Ctrl+单击 输出中的 HTTPS URL 以在浏览器中测试 Web 应用。

      • 默认浏览器会启动到 https://localhost:<port>/swagger/index.html,其中 <port> 是输出中显示的随机选择的端口号。 https://localhost:<port> 没有终结点,因此浏览器返回 HTTP 404 未找到。 将 /swagger 附加到 URL https://localhost:<port>/swagger。

        按照以下说明测试 Web 应用后,按集成终端中的 Ctrl+C 将其关闭。

        选择 “调试>开始调试 ”以启动应用。 Visual Studio for Mac 将启动一个浏览器并导航到 https://localhost:<port>/swagger/index.html,其中 <port> 是在创建项目时设置的一个随机选择的端口号。

        随即显示 Swagger 页面 /swagger/index.html。 选择 "GET">尝试>执行。 页面将显示:

      • 用于测试 WeatherForecast API 的 Curl 命令。
      • 用于测试 WeatherForecast API 的 URL。
      • 响应代码、正文和标头。
      • 包含媒体类型、示例值和架构的下拉列表框。
      • 如果 Swagger 页面未显示,请参阅此 GitHub 问题。

        Swagger 用于为 Web API 生成有用的文档和帮助页面。 本教程使用 Swagger 测试应用。 有关 Swagger 的详细信息,请参阅包含 Swagger / OpenAPI 的 ASP.NET Core Web API 文档。

        在浏览器中复制并粘贴 请求 URL : https://localhost:<port>/weatherforecast

        返回类似于以下示例的 JSON:

        "date": "2019-07-16T19:04:05.7257911-06:00", "temperatureC": 52, "temperatureF": 125, "summary": "Mild" "date": "2019-07-17T19:04:05.7258461-06:00", "temperatureC": 36, "temperatureF": 96, "summary": "Warm" "date": "2019-07-18T19:04:05.7258467-06:00", "temperatureC": 39, "temperatureF": 102, "summary": "Cool" "date": "2019-07-19T19:04:05.7258471-06:00", "temperatureC": 10, "temperatureF": 49, "summary": "Bracing" "date": "2019-07-20T19:04:05.7258474-06:00", "temperatureC": -1, "temperatureF": 31, "summary": "Chilly"

        添加模型类

        模型是一组类,表示应用管理的数据。 此应用的模型是 TodoItem 类。

      • 在 解决方案资源管理器中,右键单击项目。 选择“添加>新文件夹。 将该文件夹命名为 Models注册一个免费试用帐户。
      • 右键单击 Models 文件夹,然后选择“ 添加>类”。 将类命名 为 TodoItem ,然后选择“ 添加”。
      • 将模板代码替换为以下内容:
      • 按住 Control 键单击 TodoAPI 项目,然后选择“ 添加新>文件夹”。 将该文件夹命名为 Models注册一个免费试用帐户。

      • 按住 Control 键点击Models文件夹,然后选择添加>新类...>常规>空类。

      • 将类命名 为 TodoItem,然后选择“ 创建”。

      • 将模板代码替换为以下内容:

        public long Id { get; set; } public string? Name { get; set; } public bool IsComplete { get; set; } Id 属性用作关系数据库中的唯一键。

        模型类可位于项目的任意位置,但按照惯例会使用 Models 文件夹。

        添加数据库上下文

        数据库上下文是协调数据模型的 Entity Framework 功能的主类。 此类由 Microsoft.EntityFrameworkCore.DbContext 类派生而来。

        public class TodoContext : DbContext public TodoContext(DbContextOptions<TodoContext> options) : base(options) public DbSet<TodoItem> TodoItems { get; set; } = null!;

        注册数据库上下文

        在 ASP.NET Core 中,服务(如数据库上下文)必须向依赖关系注入 (DI) 容器进行注册。 该容器向控制器提供服务。

        使用以下突出显示的代码更新 Program.cs:

        using Microsoft.EntityFrameworkCore;
        using TodoApi.Models;
        var builder = WebApplication.CreateBuilder(args);
        builder.Services.AddControllers();
        builder.Services.AddDbContext<TodoContext>(opt =>
            opt.UseInMemoryDatabase("TodoList"));
        builder.Services.AddEndpointsApiExplorer();
        builder.Services.AddSwaggerGen();
        var app = builder.Build();
        if (app.Environment.IsDevelopment())
            app.UseSwagger();
            app.UseSwaggerUI();
        app.UseHttpsRedirection();
        app.UseAuthorization();
        app.MapControllers();
        app.Run();
        

        前面的代码:

      • 添加 using 指令。
      • 将数据库上下文添加到 DI 容器。
      • 指定数据库上下文将使用内存中数据库。
      • 构建控制器

      • 在 Model 类中选择 TodoItem (TodoApi.Models)。
      • 在数据上下文类中选择 TodoContext (TodoApi.Models)。
      • 选择 并添加。
      • 如果搭建基架失败,请选择添加以尝试第二次搭建。

        dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
        dotnet add package Microsoft.EntityFrameworkCore.Design
        dotnet add package Microsoft.EntityFrameworkCore.SqlServer
        dotnet add package Microsoft.EntityFrameworkCore.Tools
        dotnet tool uninstall -g dotnet-aspnet-codegenerator
        dotnet tool install -g dotnet-aspnet-codegenerator
        dotnet tool update -g dotnet-aspnet-codegenerator
        

        前面的命令:

      • 添加构建所需的 NuGet 包。
      • 卸载任何可能的早期版本后,安装基架引擎 (dotnet-aspnet-codegenerator)。
      • 对于 Linux,使用以下命令将 .NET 工具目录添加到系统路径:

        echo 'export PATH=$HOME/.dotnet/tools:$PATH' >> ~/.bashrc
        source ~/.bashrc
        

        默认情况下,要安装的.NET二进制文件的体系结构表示当前运行的操作系统体系结构。 若要指定其他架构,请参阅如何使用 dotnet tool install 命令并配合 '--arch' 选项。 有关详细信息,请参阅 GitHub dotnet/aspnetcore.docs 议题 #29262 - 在 Apple Silicon 上添加“-a arm64”。

        生成项目。

        运行以下命令:

        dotnet aspnet-codegenerator controller -name TodoItemsController -async -api -m TodoItem -dc TodoContext -outDir Controllers
        

        上述命令为 TodoItemsController 创建基架。

        生成的代码:

      • 使用 [ApiController] 属性标记类。 此属性指示控制器响应 Web API 请求。 有关该属性启用的特定行为的信息,请参阅使用 ASP.NET Core 创建 Web API。
      • 使用 DI 将数据库上下文 (TodoContext) 注入到控制器中。 数据库上下文用于控制器中的每个 CRUD 方法。
      • ASP.NET Core 模板:

      • 具有视图的控制器在路由模板中包含 [action]。
      • API 控制器不在路由模板中包含 [action]。
      • 如果[action]标记不在路由模板中,则终结点中不会包含操作名称(方法名称)。 也就是说,不会在匹配的路由中使用操作的关联方法名称。

        打开生成的 Controllers/TodoItemsController.cs 文件以查看基架代码。 基架生成完整的工作控制器,其中包含创建、读取、更新和删除 TodoItem 数据的操作方法:

        GetTodoItems:获取所有待办项。
      • GetTodoItem:通过 ID 获取待办事项。 PostTodoItem:创建待办事项。 PutTodoItem:更新现有待办事项。 DeleteTodoItem:删除待办事项。

        以下各节将考察这些生成的方法,并从 PostTodoItem 开始。

        检查 PostTodoItem 的创建方法

        检查生成的 PostTodoItem 方法,该方法生成后即可正常工作。 return 语句使用 nameof 运算符,因此操作名称不会硬编码为字符串。 被注释掉的代码行显示了由 nameof 替代的等效硬编码形式:

        [HttpPost]
        public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
            _context.TodoItems.Add(todoItem);
            await _context.SaveChangesAsync();
            //    return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
            return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
        

        上述代码是 HTTP POST 方法,如 [HttpPost] 属性所指示。 此方法从 HTTP 请求正文获取 TodoItem 的值。

        有关详细信息,请参阅使用 Http [Verb] 特性的特性路由。

        CreatedAtAction 方法:

      • 如果成功,将返回 HTTP 201 状态代码。 HTTP 201 是在服务器上创建新资源的 HTTP POST 方法的标准响应。
      • 向响应添加 Location 标头。 标头 Location 指定新创建的 to-do 项的 URI 。 有关详细信息,请参阅创建的 10.2.2 201。
      • 引用 GetTodoItem 操作以创建 Location 标头的 URI。
      • 测试 PostTodoItem

      • 按 Ctrl+F5 运行应用。

      • 在 Swagger 浏览器窗口中,选择 POST /api/TodoItems,然后选择“ 试用”。

      • 在 “请求正文 输入”窗口中,更新 JSON。 例如,

        "name": "walk dog", "isComplete": true
      • 选择“执行”

        测试位置标头 URI

        在前面的 POST 中,Swagger UI 在“响应”标头下显示位置标头。 例如,location: https://localhost:7260/api/TodoItems/1。 位置标头显示创建资源的 URI。

        测试位置标头:

      • 在 Swagger 浏览器窗口中,选择 GET /api/TodoItems/{id},然后选择“ 试用”。

      • 在输入框中输入1,然后选择“id”。

        上一节展示了 /api/todoitems/{id} 路由的示例。

        按照 POST 说明添加另一个待办事项,然后使用 Swagger 测试 /api/todoitems 路由。

        此应用使用内存中数据库。 如果停止并启动应用,则前面的 GET 请求不会返回任何数据。 如果未返回任何数据,则向应用程序发送 POST 数据。

        路由和 URL 路径

        [HttpGet] 属性表示响应 HTTP GET 请求的方法。 每个方法的 URL 路径构造如下所示:

      • 在控制器的 Route 属性中以模板字符串开头:

        [Route("api/[controller]")]
        [ApiController]
        public class TodoItemsController : ControllerBase
        
      • 将 [controller] 替换为控制器的名称,按照惯例,在控制器类名称中去掉“Controller”后缀。 对于此示例,控制器类名称为 TodoItems控制器,因此控制器名称为“TodoItems”。 ASP.NET 核心 路由 不区分大小写。

      • 如果 [HttpGet] 属性具有路由模板(例如 [HttpGet("products")]),则将它追加到路径。 此示例不使用模板。 有关详细信息,请参阅使用 Http [Verb] 特性的特性路由。

        在下面的 GetTodoItem 方法中,"{id}" 是待办事项的唯一标识符的占位符变量。 调用 GetTodoItem 时,URL 中 "{id}" 的值会在 id 参数中提供给方法。

        [HttpGet("{id}")]
        public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
            var todoItem = await _context.TodoItems.FindAsync(id);
            if (todoItem == null)
                return NotFound();
            return todoItem;
                      GetTodoItems 和 GetTodoItem 方法的返回类型是 ActionResult<T> 类型。 ASP.NET Core 自动将对象序列化为 JSON,并将 JSON 写入响应消息的正文中。 此返回类型的响应代码为 200 OK(假设没有未处理的异常)。 未经处理的异常将转换为 5xx 错误。

        ActionResult 返回类型可以表示大范围的 HTTP 状态代码。 例如,GetTodoItem 可以返回两个不同的状态值:

      • 如果没有任何项与请求的 ID 匹配,该方法将返回 404 状态NotFound 错误代码。
      • 否则,此方法将返回具有 JSON 响应正文的 200。 返回 item 则产生 HTTP 200 响应。
      • PutTodoItem 方法

        检查 PutTodoItem 方法:

        [HttpPut("{id}")]
        public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
            if (id != todoItem.Id)
                return BadRequest();
            _context.Entry(todoItem).State = EntityState.Modified;
                await _context.SaveChangesAsync();
            catch (DbUpdateConcurrencyException)
                if (!TodoItemExists(id))
                    return NotFound();
                    throw;
            return NoContent();
                      PutTodoItem 与 PostTodoItem 类似,但使用的是 HTTP PUT。 响应是 204(无内容)。 根据 HTTP 规范,PUT 请求需要客户端发送整个更新的实体,而不仅仅是更改。 若要支持部分更新,请使用 HTTP PATCH。

        测试 PutTodoItem 方法

        本示例使用内存内、数据库,每次启动应用时都必须对其进行初始化。 在进行 PUT 调用之前,数据库中必须有一个项。 调用 GET,以确保在调用 PUT 之前数据库中存在项。

        使用 Swagger UI,使用 PUT 按钮更新 Id = 1 的 TodoItem 并将其名称设置为 "feed fish"。 请注意,响应为 HTTP 204 No Content。

        DeleteTodoItem 方法

        检查 DeleteTodoItem 方法:

        [HttpDelete("{id}")]
        public async Task<IActionResult> DeleteTodoItem(long id)
            var todoItem = await _context.TodoItems.FindAsync(id);
            if (todoItem == null)
                return NotFound();
            _context.TodoItems.Remove(todoItem);
            await _context.SaveChangesAsync();
            return NoContent();
        

        测试 DeleteTodoItem 方法

        使用 Swagger UI 删除 Id = 1 的 TodoItem。 请注意,响应为 HTTP 204 No Content。

        使用其他工具进行测试

        还有许多其他工具可用于测试 Web API,例如:

        Visual Studio 终结点资源管理器和 .http 文件
      • http-repl
      • curl. Swagger 使用 curl 并显示它提交的 curl 命令。 Fiddler

        有关详细信息,请参阅:

        最小 API 教程:使用 .http 文件和终结点资源管理器进行测试

        防止过度发布

        目前,示例应用公开了整个 TodoItem 对象。 生产应用通常使用模型的子集来限制输入和返回的数据。 这背后有多种原因,但安全性是主要原因。 模型的子集通常称为数据传输对象 (DTO)、输入模型或视图模型。 本教程使用 DTO。

        DTO 可用于:

      • 防止过度发布。
      • 隐藏客户端不应查看的属性。
      • 省略一些属性以缩减有效负载大小。
      • 平展包含嵌套对象的对象图。 对客户端而言,平展的对象图可能更方便。
      • 若要演示 DTO 方法,请更新 TodoItem 类,使其包含机密字段:

        namespace TodoApi.Models
            public class TodoItem
                public long Id { get; set; }
                public string? Name { get; set; }
                public bool IsComplete { get; set; }
                public string? Secret { get; set; }
        

        此应用需要隐藏机密字段,但管理应用可以选择公开它。

        确保可以发布和获取机密字段。

        创建 DTO 模型:

        namespace TodoApi.Models;
        public class TodoItemDTO
            public long Id { get; set; }
            public string? Name { get; set; }
            public bool IsComplete { get; set; }
        

        更新 TodoItemsController 以使用 TodoItemDTO:

        using Microsoft.AspNetCore.Mvc;
        using Microsoft.EntityFrameworkCore;
        using TodoApi.Models;
        namespace TodoApi.Controllers;
        [Route("api/[controller]")]
        [ApiController]
        public class TodoItemsController : ControllerBase
            private readonly TodoContext _context;
            public TodoItemsController(TodoContext context)
                _context = context;
            // GET: api/TodoItems
            [HttpGet]
            public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
                return await _context.TodoItems
                    .Select(x => ItemToDTO(x))
                    .ToListAsync();
            // GET: api/TodoItems/5
            // <snippet_GetByID>
            [HttpGet("{id}")]
            public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
                var todoItem = await _context.TodoItems.FindAsync(id);
                if (todoItem == null)
                    return NotFound();
                return ItemToDTO(todoItem);
            // </snippet_GetByID>
            // PUT: api/TodoItems/5
            // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
            // <snippet_Update>
            [HttpPut("{id}")]
            public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
                if (id != todoDTO.Id)
                    return BadRequest();
                var todoItem = await _context.TodoItems.FindAsync(id);
                if (todoItem == null)
                    return NotFound();
                todoItem.Name = todoDTO.Name;
                todoItem.IsComplete = todoDTO.IsComplete;
                    await _context.SaveChangesAsync();
                catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
                    return NotFound();
                return NoContent();
            // </snippet_Update>
            // POST: api/TodoItems
            // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
            // <snippet_Create>
            [HttpPost]
            public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
                var todoItem = new TodoItem
                    IsComplete = todoDTO.IsComplete,
                    Name = todoDTO.Name
                _context.TodoItems.Add(todoItem);
                await _context.SaveChangesAsync();
                return CreatedAtAction(
                    nameof(GetTodoItem),
                    new { id = todoItem.Id },
                    ItemToDTO(todoItem));
            // </snippet_Create>
            // DELETE: api/TodoItems/5
            [HttpDelete("{id}")]
            public async Task<IActionResult> DeleteTodoItem(long id)
                var todoItem = await _context.TodoItems.FindAsync(id);
                if (todoItem == null)
                    return NotFound();
                _context.TodoItems.Remove(todoItem);
                await _context.SaveChangesAsync();
                return NoContent();
            private bool TodoItemExists(long id)
                return _context.TodoItems.Any(e => e.Id == id);
            private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
               new TodoItemDTO
                   Id = todoItem.Id,
                   Name = todoItem.Name,
                   IsComplete = todoItem.IsComplete
        

        确保无法发布或获取机密字段。

        使用 JavaScript 调用 Web API

        请参阅教程:使用 JavaScript 调用 ASP.NET Core Web API。

        Web API 视频系列

        请参阅视频:初学者系列:Web API。

        企业 Web 应用模式

        有关创建可靠、安全、高性能、可测试且可缩放的 ASP.NET Core 应用的指导,请参阅 企业 Web 应用模式。 提供了一个完整且具备生产质量的示例 Web 应用,该应用实现了这些模式。

        向 Web API 添加身份验证支持

        ASP.NET Core Identity 将用户界面 (UI) 登录功能添加到 ASP.NET Core Web 应用。 若要保护 Web API 和 SPA,请使用以下项之一:

        Microsoft Entra ID Duende Identity Server

        Duende Identity Server 是适用于 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 框架。 Duende Identity Server 支持以下安全功能:

      • 身份验证即服务 (AaaS)
      • 跨多个应用程序类型的单一登录/注销 (SSO)
      • API 的访问控制
      • Important

        Duende Software 可能会要求你为 Duende Identity Server 的生产使用支付许可证费用。 有关详细信息,请参阅 从 .NET 5 中的 ASP.NET Core 迁移到 .NET 6。

        有关详细信息,请参阅 Duende Identity Server 文档(Duende Software 网站)。

        发布到 Azure

        有关部署到 Azure 的信息,请参阅快速入门:部署 ASP.NET Web 应用。

        查看或下载本教程的示例代码。 请参阅如何下载。

        有关详细信息,请参阅以下资源:

        使用 ASP.NET Core 创建 Web API 教程:使用 ASP.NET Core 创建最小 API 带有 Swagger/OpenAPI 的 ASP.NET Core Web API 文档 Razor ASP.NET Core 中带 Entity Framework Core 的页面 - 第 1 个教程(共 8 个) 在 ASP.NET Core 中路由到控制器操作 ASP.NET Core Web API 中控制器操作的返回类型 将 ASP.NET Core 应用部署到 Azure 应用程序服务 托管和部署 ASP.NET Core 使用 ASP.NET Core 创建 Web API

        本教程介绍生成使用数据库的基于控制器的 Web API 的基础知识。 在 ASP.NET Core 中创建 API 的另一种方法是创建 最小 API。 有关在最小 API 和基于控制器的 API 之间进行选择的帮助,请参阅 API 概述。 有关创建最小 API 的教程,请参阅 教程:使用 ASP.NET Core 创建最小 API。

        Overview

        本教程将创建以下 API:

        Description .NET 8 SDK

        Visual Studio Code 说明使用用于 ASP.NET Core 的 .NET CLI 开发功能,如项目创建。 可在(macOS、Linux 或 Windows)上或在任何代码编辑器中遵循这些说明。 如果使用 Visual Studio Code 以外的其他内容,则可能需要进行少量更改。

        创建 Web 项目

      • 在搜索框中输入 Web API。
      • 选择“ASP.NET Core Web API”模板,然后选择“下一步”。
      • 在“配置新项目”对话框中,将项目命名为“TodoApi”,然后选择“下一步”。
      • 在“其他信息”对话框中:
        • 确认框架为 .NET 8.0(长期支持)。
        • 确认选中了“使用控制器”复选框(取消选中以使用最小 API)。
        • 确认已选中“启用 OpenAPI 支持”复选框。
        • 选择 创建。
        • 添加 NuGet 包

          必须添加 NuGet 包以支持本教程中使用的数据库。

        • 在“工具”菜单中,选择“NuGet 包管理器”“管理解决方案的 NuGet 包”。
        • 选择“浏览”选项卡。
        • 在搜索框中输入“Microsoft.EntityFrameworkCore.InMemory”,然后选择 。
        • 选中右窗格中的“项目”复选框,然后选择“安装” 。
        • dotnet new webapi --use-controllers -o TodoApi
          cd TodoApi
          dotnet add package Microsoft.EntityFrameworkCore.InMemory
          code -r ../TodoApi
          

          以下命令:

        • 创建新的 Web API 项目,并在 Visual Studio Code 中打开它。
        • 添加下一部分所需的 NuGet 包。
        • 在 Visual Studio Code 的当前实例中打开 TodoApi 文件夹。
        • Visual Studio Code 可能会显示一个对话框,询问:“你是否信任此文件夹中的文件作者?”

        • 如果你信任父文件夹中的所有文件,请选择“信任父文件夹中所有文件的作者”。
        • 选择“是,我信任所有作者”,因为项目文件夹包含 .NET 生成的文件。
        • 当 Visual Studio Code 请求添加资产以生成和调试项目时,请选择“ 是”。 如果 Visual Studio Code 不提供添加生成和调试资产,请选择 “查看>命令面板 ”,然后在搜索框中键入“.NET”。 从命令列表中选择 .NET: Generate Assets for Build and Debug 命令。
        • Visual Studio Code 添加一个包含生成的 .vscode 和 launch.json 文件的 tasks.json 文件夹。

          上述命令需要 Linux 上的 .NET 9 或更高版本 SDK。 对于 .NET 8.0.401 或更早版本的 SDK 上的 Linux,请参阅 Linux 分发的文档来信任证书。

          如果证书以前不受信任,上述命令显示以下对话:

          Ctrl+单击 输出中的 HTTPS URL 以在浏览器中测试 Web 应用。

        • 默认浏览器会启动到 https://localhost:<port>/swagger/index.html,其中 <port> 是输出中显示的随机选择的端口号。 https://localhost:<port> 没有终结点,因此浏览器返回 HTTP 404 未找到。 将 /swagger 附加到 URL https://localhost:<port>/swagger。

          按照以下说明测试 Web 应用后,按集成终端中的 Ctrl+C 将其关闭。

          随即显示 Swagger 页面 /swagger/index.html。 选择 "GET">尝试>执行。 页面将显示:

        • 用于测试 WeatherForecast API 的 Curl 命令。
        • 用于测试 WeatherForecast API 的 URL。
        • 响应代码、正文和标头。
        • 包含媒体类型、示例值和架构的下拉列表框。
        • 如果 Swagger 页面未显示,请参阅此 GitHub 问题。

          Swagger 用于为 Web API 生成有用的文档和帮助页面。 本教程使用 Swagger 测试应用。 有关 Swagger 的详细信息,请参阅包含 Swagger / OpenAPI 的 ASP.NET Core Web API 文档。

          在浏览器中复制并粘贴 请求 URL : https://localhost:<port>/weatherforecast

          返回类似于以下示例的 JSON:

          "date": "2019-07-16T19:04:05.7257911-06:00", "temperatureC": 52, "temperatureF": 125, "summary": "Mild" "date": "2019-07-17T19:04:05.7258461-06:00", "temperatureC": 36, "temperatureF": 96, "summary": "Warm" "date": "2019-07-18T19:04:05.7258467-06:00", "temperatureC": 39, "temperatureF": 102, "summary": "Cool" "date": "2019-07-19T19:04:05.7258471-06:00", "temperatureC": 10, "temperatureF": 49, "summary": "Bracing" "date": "2019-07-20T19:04:05.7258474-06:00", "temperatureC": -1, "temperatureF": 31, "summary": "Chilly"

          添加模型类

          模型是一组类,表示应用管理的数据。 此应用的模型是 TodoItem 类。

        • 在 解决方案资源管理器中,右键单击项目。 选择“添加>新文件夹。 将该文件夹命名为 Models注册一个免费试用帐户。
        • 右键单击 Models 文件夹,然后选择“ 添加>类”。 将类命名 为 TodoItem ,然后选择“ 添加”。
        • 将模板代码替换为以下内容:
        • public long Id { get; set; } public string? Name { get; set; } public bool IsComplete { get; set; } Id 属性用作关系数据库中的唯一键。

          模型类可位于项目的任意位置,但按照惯例会使用 Models 文件夹。

          添加数据库上下文

          数据库上下文是协调数据模型的 Entity Framework 功能的主类。 此类由 Microsoft.EntityFrameworkCore.DbContext 类派生而来。

          public class TodoContext : DbContext public TodoContext(DbContextOptions<TodoContext> options) : base(options) public DbSet<TodoItem> TodoItems { get; set; } = null!;

          注册数据库上下文

          在 ASP.NET Core 中,服务(如数据库上下文)必须向依赖关系注入 (DI) 容器进行注册。 该容器向控制器提供服务。

          使用以下突出显示的代码更新 Program.cs:

          using Microsoft.EntityFrameworkCore;
          using TodoApi.Models;
          var builder = WebApplication.CreateBuilder(args);
          builder.Services.AddControllers();
          builder.Services.AddDbContext<TodoContext>(opt =>
              opt.UseInMemoryDatabase("TodoList"));
          builder.Services.AddEndpointsApiExplorer();
          builder.Services.AddSwaggerGen();
          var app = builder.Build();
          if (app.Environment.IsDevelopment())
              app.UseSwagger();
              app.UseSwaggerUI();
          app.UseHttpsRedirection();
          app.UseAuthorization();
          app.MapControllers();
          app.Run();
          

          前面的代码:

        • 添加 using 指令。
        • 将数据库上下文添加到 DI 容器。
        • 指定数据库上下文将使用内存中数据库。
        • 构建控制器

        • 在 Model 类中选择 TodoItem (TodoApi.Models)。
        • 在数据上下文类中选择 TodoContext (TodoApi.Models)。
        • 选择 并添加。
        • 如果搭建基架失败,请选择添加以尝试第二次搭建。

          dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
          dotnet add package Microsoft.EntityFrameworkCore.Design
          dotnet add package Microsoft.EntityFrameworkCore.SqlServer
          dotnet add package Microsoft.EntityFrameworkCore.Tools
          dotnet tool uninstall -g dotnet-aspnet-codegenerator
          dotnet tool install -g dotnet-aspnet-codegenerator
          dotnet tool update -g dotnet-aspnet-codegenerator
          

          前面的命令:

        • 添加构建所需的 NuGet 包。
        • 卸载任何可能的早期版本后,安装基架引擎 (dotnet-aspnet-codegenerator)。
        • 对于 Linux,使用以下命令将 .NET 工具目录添加到系统路径:

          echo 'export PATH=$HOME/.dotnet/tools:$PATH' >> ~/.bashrc
          source ~/.bashrc
          

          默认情况下,要安装的.NET二进制文件的体系结构表示当前运行的操作系统体系结构。 若要指定其他架构,请参阅如何使用 dotnet tool install 命令并配合 '--arch' 选项。 有关详细信息,请参阅 GitHub dotnet/aspnetcore.docs 议题 #29262 - 在 Apple Silicon 上添加“-a arm64”。

          生成项目。

          运行以下命令:

          dotnet aspnet-codegenerator controller -name TodoItemsController -async -api -m TodoItem -dc TodoContext -outDir Controllers
          

          上述命令为 TodoItemsController 创建基架。

          生成的代码:

        • 使用 [ApiController] 属性标记类。 此属性指示控制器响应 Web API 请求。 有关该属性启用的特定行为的信息,请参阅使用 ASP.NET Core 创建 Web API。
        • 使用 DI 将数据库上下文 (TodoContext) 注入到控制器中。 数据库上下文用于控制器中的每个 CRUD 方法。
        • ASP.NET Core 模板:

        • 具有视图的控制器在路由模板中包含 [action]。
        • API 控制器不在路由模板中包含 [action]。
        • 如果[action]标记不在路由模板中,则终结点中不会包含操作名称(方法名称)。 也就是说,不会在匹配的路由中使用操作的关联方法名称。

          打开生成的 Controllers/TodoItemsController.cs 文件以查看基架代码。 基架生成完整的工作控制器,其中包含创建、读取、更新和删除 TodoItem 数据的操作方法:

          GetTodoItems:获取所有待办项。 GetTodoItem:通过 ID 获取待办事项。 PostTodoItem:创建待办事项。 PutTodoItem:更新现有待办事项。 DeleteTodoItem:删除待办事项。

          以下各节将考察这些生成的方法,并从 PostTodoItem 开始。

          检查 PostTodoItem 的创建方法

          检查构建的 PostTodoItem 方法。 生成的代码已正常工作。 return 语句使用 nameof 运算符,因此操作名称不会硬编码为字符串。 被注释掉的代码行显示了由 nameof 替代的等效硬编码形式:

          [HttpPost]
          public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
              _context.TodoItems.Add(todoItem);
              await _context.SaveChangesAsync();
              //    return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
              return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
          

          上述代码是 HTTP POST 方法,如 [HttpPost] 属性所指示。 此方法从 HTTP 请求正文获取 TodoItem 的值。

          有关详细信息,请参阅使用 Http [Verb] 特性的特性路由。

          CreatedAtAction 方法:

        • 如果成功,将返回 HTTP 201 状态代码。 HTTP 201 是在服务器上创建新资源的 HTTP POST 方法的标准响应。
        • 向响应添加 Location 标头。 标头 Location 指定新创建的 to-do 项的 URI 。 有关详细信息,请参阅创建的 10.2.2 201。
        • 引用 GetTodoItem 操作以创建 Location 标头的 URI。
        • 测试 PostTodoItem

        • 按 Ctrl+F5 运行应用。

        • 在 Swagger 浏览器窗口中,选择 POST /api/TodoItems,然后选择“ 试用”。

        • 在 “请求正文 输入”窗口中,更新 JSON。 例如,

          "name": "walk dog", "isComplete": true
        • 选择“执行”

          测试位置标头 URI

          在前面的 POST 中,Swagger UI 在“响应”标头下显示位置标头。 例如,location: https://localhost:7260/api/TodoItems/1。 位置标头显示创建资源的 URI。

          测试位置标头:

        • 在 Swagger 浏览器窗口中,选择 GET /api/TodoItems/{id},然后选择“ 试用”。

        • 在输入框中输入1,然后选择“id”。

          上一节展示了 /api/todoitems/{id} 路由的示例。

          按照 POST 说明添加另一个待办事项,然后使用 Swagger 测试 /api/todoitems 路由。

          此应用使用内存中数据库。 如果停止并启动应用,则前面的 GET 请求不会返回任何数据。 如果未返回任何数据,则向应用程序发送 POST 数据。

          路由和 URL 路径

          [HttpGet] 属性表示响应 HTTP GET 请求的方法。 每个方法的 URL 路径构造如下所示:

        • 在控制器的 Route 属性中以模板字符串开头:

          [Route("api/[controller]")]
          [ApiController]
          public class TodoItemsController : ControllerBase
          
        • 将 [controller] 替换为控制器的名称,按照惯例,在控制器类名称中去掉“Controller”后缀。 对于此示例,控制器类名称为 TodoItems控制器,因此控制器名称为“TodoItems”。 ASP.NET 核心 路由 不区分大小写。

        • 如果 [HttpGet] 属性具有路由模板(例如 [HttpGet("products")]),则将它追加到路径。 此示例不使用模板。 有关详细信息,请参阅使用 Http [Verb] 特性的特性路由。

          在下面的 GetTodoItem 方法中,"{id}" 是待办事项的唯一标识符的占位符变量。 调用 GetTodoItem 时,URL 中 "{id}" 的值会在 id 参数中提供给方法。

          [HttpGet("{id}")]
          public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
              var todoItem = await _context.TodoItems.FindAsync(id);
              if (todoItem == null)
                  return NotFound();
              return todoItem;
                        GetTodoItems 和 GetTodoItem 方法的返回类型是 ActionResult<T> 类型。 ASP.NET Core 自动将对象序列化为 JSON,并将 JSON 写入响应消息的正文中。 此返回类型的响应代码为 200 OK(假设没有未处理的异常)。 未经处理的异常将转换为 5xx 错误。

          ActionResult 返回类型可以表示大范围的 HTTP 状态代码。 例如,GetTodoItem 可以返回两个不同的状态值:

        • 如果没有任何项与请求的 ID 匹配,该方法将返回 404 状态NotFound 错误代码。
        • 否则,此方法将返回具有 JSON 响应正文的 200。 返回 item 则产生 HTTP 200 响应。
        • PutTodoItem 方法

          检查 PutTodoItem 方法:

          [HttpPut("{id}")]
          public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
              if (id != todoItem.Id)
                  return BadRequest();
              _context.Entry(todoItem).State = EntityState.Modified;
                  await _context.SaveChangesAsync();
              catch (DbUpdateConcurrencyException)
                  if (!TodoItemExists(id))
                      return NotFound();
                      throw;
              return NoContent();
                        PutTodoItem 与 PostTodoItem 类似,但使用的是 HTTP PUT。 响应是 204(无内容)。 根据 HTTP 规范,PUT 请求需要客户端发送整个更新的实体,而不仅仅是更改。 若要支持部分更新,请使用 HTTP PATCH。

          测试 PutTodoItem 方法

          本示例使用内存内、数据库,每次启动应用时都必须对其进行初始化。 在进行 PUT 调用之前,数据库中必须有一个项。 调用 GET,以确保在调用 PUT 之前数据库中存在项。

          使用 Swagger UI,使用 PUT 按钮更新 Id = 1 的 TodoItem 并将其名称设置为 "feed fish"。 请注意,响应为 HTTP 204 No Content。

          DeleteTodoItem 方法

          检查 DeleteTodoItem 方法:

          [HttpDelete("{id}")]
          public async Task<IActionResult> DeleteTodoItem(long id)
              var todoItem = await _context.TodoItems.FindAsync(id);
              if (todoItem == null)
                  return NotFound();
              _context.TodoItems.Remove(todoItem);
              await _context.SaveChangesAsync();
              return NoContent();
          

          测试 DeleteTodoItem 方法

          使用 Swagger UI 删除 Id = 1 的 TodoItem。 请注意,响应为 HTTP 204 No Content。

          使用其他工具进行测试

          还有许多其他工具可用于测试 Web API,例如:

          Visual Studio 终结点资源管理器和 .http 文件
        • http-repl
        • curl. Swagger 使用 curl 并显示它提交的 curl 命令。 Fiddler

          有关详细信息,请参阅:

          最小 API 教程:使用 .http 文件和终结点资源管理器进行测试

          防止过度发布

          目前,示例应用公开了整个 TodoItem 对象。 生产应用通常使用模型的子集来限制输入和返回的数据。 这背后有多种原因,但安全性是主要原因。 模型的子集通常称为数据传输对象 (DTO)、输入模型或视图模型。 本教程使用 DTO。

          DTO 可用于:

        • 防止过度发布。
        • 隐藏客户端不应查看的属性。
        • 省略一些属性以缩减有效负载大小。
        • 平展包含嵌套对象的对象图。 对客户端而言,平展的对象图可能更方便。
        • 若要演示 DTO 方法,请更新 TodoItem 类,使其包含机密字段:

          namespace TodoApi.Models
              public class TodoItem
                  public long Id { get; set; }
                  public string? Name { get; set; }
                  public bool IsComplete { get; set; }
                  public string? Secret { get; set; }
          

          此应用需要隐藏机密字段,但管理应用可以选择公开它。

          确保可以发布和获取机密字段。

          创建 DTO 模型:

          namespace TodoApi.Models;
          public class TodoItemDTO
              public long Id { get; set; }
              public string? Name { get; set; }
              public bool IsComplete { get; set; }
          

          更新 TodoItemsController 以使用 TodoItemDTO:

          using Microsoft.AspNetCore.Mvc;
          using Microsoft.EntityFrameworkCore;
          using TodoApi.Models;
          namespace TodoApi.Controllers;
          [Route("api/[controller]")]
          [ApiController]
          public class TodoItemsController : ControllerBase
              private readonly TodoContext _context;
              public TodoItemsController(TodoContext context)
                  _context = context;
              // GET: api/TodoItems
              [HttpGet]
              public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
                  return await _context.TodoItems
                      .Select(x => ItemToDTO(x))
                      .ToListAsync();
              // GET: api/TodoItems/5
              // <snippet_GetByID>
              [HttpGet("{id}")]
              public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
                  var todoItem = await _context.TodoItems.FindAsync(id);
                  if (todoItem == null)
                      return NotFound();
                  return ItemToDTO(todoItem);
              // </snippet_GetByID>
              // PUT: api/TodoItems/5
              // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
              // <snippet_Update>
              [HttpPut("{id}")]
              public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
                  if (id != todoDTO.Id)
                      return BadRequest();
                  var todoItem = await _context.TodoItems.FindAsync(id);
                  if (todoItem == null)
                      return NotFound();
                  todoItem.Name = todoDTO.Name;
                  todoItem.IsComplete = todoDTO.IsComplete;
                      await _context.SaveChangesAsync();
                  catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
                      return NotFound();
                  return NoContent();
              // </snippet_Update>
              // POST: api/TodoItems
              // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
              // <snippet_Create>
              [HttpPost]
              public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
                  var todoItem = new TodoItem
                      IsComplete = todoDTO.IsComplete,
                      Name = todoDTO.Name
                  _context.TodoItems.Add(todoItem);
                  await _context.SaveChangesAsync();
                  return CreatedAtAction(
                      nameof(GetTodoItem),
                      new { id = todoItem.Id },
                      ItemToDTO(todoItem));
              // </snippet_Create>
              // DELETE: api/TodoItems/5
              [HttpDelete("{id}")]
              public async Task<IActionResult> DeleteTodoItem(long id)
                  var todoItem = await _context.TodoItems.FindAsync(id);
                  if (todoItem == null)
                      return NotFound();
                  _context.TodoItems.Remove(todoItem);
                  await _context.SaveChangesAsync();
                  return NoContent();
              private bool TodoItemExists(long id)
                  return _context.TodoItems.Any(e => e.Id == id);
              private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
                 new TodoItemDTO
                     Id = todoItem.Id,
                     Name = todoItem.Name,
                     IsComplete = todoItem.IsComplete
          

          确保无法发布或获取机密字段。

          使用 JavaScript 调用 Web API

          请参阅教程:使用 JavaScript 调用 ASP.NET Core Web API。

          Web API 视频系列

          请参阅视频:初学者系列:Web API。

          企业 Web 应用模式

          有关创建可靠、安全、高性能、可测试且可缩放的 ASP.NET Core 应用的指导,请参阅 企业 Web 应用模式。 提供了一个完整且具备生产质量的示例 Web 应用,该应用实现了这些模式。

          向 Web API 添加身份验证支持

          ASP.NET Core Identity 将用户界面 (UI) 登录功能添加到 ASP.NET Core Web 应用。 若要保护 Web API 和 SPA,请使用以下项之一:

          Microsoft Entra ID Duende Identity Server

          Duende Identity Server 是适用于 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 框架。 Duende Identity Server 支持以下安全功能:

        • 身份验证即服务 (AaaS)
        • 跨多个应用程序类型的单一登录/注销 (SSO)
        • API 的访问控制
        • Important

          Duende Software 可能会要求你为 Duende Identity Server 的生产使用支付许可证费用。 有关详细信息,请参阅 从 .NET 5 中的 ASP.NET Core 迁移到 .NET 6。

          有关详细信息,请参阅 Duende Identity Server 文档(Duende Software 网站)。

          发布到 Azure

          有关部署到 Azure 的信息,请参阅快速入门:部署 ASP.NET Web 应用。

          查看或下载本教程的示例代码。 请参阅如何下载。

          有关详细信息,请参阅以下资源:

          使用 ASP.NET Core 创建 Web API 教程:使用 ASP.NET Core 创建最小 API 带有 Swagger/OpenAPI 的 ASP.NET Core Web API 文档 Razor ASP.NET Core 中带 Entity Framework Core 的页面 - 第 1 个教程(共 8 个) 在 ASP.NET Core 中路由到控制器操作 ASP.NET Core Web API 中控制器操作的返回类型 将 ASP.NET Core 应用部署到 Azure 应用程序服务 托管和部署 ASP.NET Core 使用 ASP.NET Core 创建 Web API
  •