教程:使用 ASP.NET Core 创建 Web APITutorial: Create a web API with ASP.NET Core

作者:Rick AndersonMike WassonBy Rick Anderson and Mike Wasson

本教程介绍使用 ASP.NET Core 构建 Web API 的基础知识。This tutorial teaches the basics of building a web API with ASP.NET Core.

在本教程中,你将了解:In this tutorial, you learn how to:

  • 创建 Web API 项目。Create a web API project.
  • 添加模型类和数据库上下文。Add a model class and a database context.
  • 使用 CRUD 方法构建控制器。Scaffold a controller with CRUD methods.
  • 配置路由、URL 路径和返回值。Configure routing, URL paths, and return values.
  • 使用 Postman 调用 Web API。Call the web API with Postman.

在结束时,你会获得可以管理存储在数据库中的“待办事项”的 Web API。At the end, you have a web API that can manage "to-do" items stored in a database.

概述Overview

本教程将创建以下 API:This tutorial creates the following API:

APIAPI 说明Description 请求正文Request body 响应正文Response body
GET /api/TodoItemsGET /api/TodoItems 获取所有待办事项Get all to-do items None 待办事项的数组Array of to-do items
GET /api/TodoItems/{id}GET /api/TodoItems/{id} 按 ID 获取项Get an item by ID None 待办事项To-do item
POST /api/TodoItemsPOST /api/TodoItems 添加新项Add a new item 待办事项To-do item 待办事项To-do item
PUT /api/TodoItems/{id}PUT /api/TodoItems/{id} 更新现有项  Update an existing item   待办事项To-do item None
DELETE /api/TodoItems/{id}    DELETE /api/TodoItems/{id}     删除项   Delete an item     None None

下图显示了应用的设计。The following diagram shows the design of the app.

右侧的框表示客户端。

系统必备Prerequisites

创建 Web 项目Create a web project

  • 从“文件”菜单中选择“新建”>“项目” 。From the File menu, select New > Project.
  • 选择“ASP.NET Core Web 应用程序”模板,再单击“下一步” 。Select the ASP.NET Core Web Application template and click Next.
  • 将项目命名为 TodoApi,然后单击“创建” 。Name the project TodoApi and click Create.
  • 在“创建新的 ASP.NET Core Web 应用程序”对话框中,确认选择“.NET Core”和“ASP.NET Core 3.0” 。In the Create a new ASP.NET Core Web Application dialog, confirm that .NET Core and ASP.NET Core 3.0 are selected. 选择“API”模板,然后单击“创建” 。Select the API template and click Create. 请不要选择“启用 Docker 支持” 。Don't select Enable Docker Support.

VS“新建项目”对话框

测试 APITest the API

项目模板会创建 WeatherForecast API。The project template creates a WeatherForecast API. 从浏览器调用 Get 方法以测试应用。Call the Get method from a browser to test the app.

按 Ctrl+F5 运行应用。Press Ctrl+F5 to run the app. Visual Studio 启动浏览器并导航到 https://localhost:<port>/WeatherForecast,其中 <port> 是随机选择的端口号。Visual Studio launches a browser and navigates to https://localhost:<port>/WeatherForecast, where <port> is a randomly chosen port number.

如果出现询问是否应信任 IIS Express 证书的对话框,则选择“是” 。If you get a dialog box that asks if you should trust the IIS Express certificate, select Yes. 在接下来出现的“安全警告” 对话框中,选择“是” 。In the Security Warning dialog that appears next, select Yes.

返回类似于以下项的 JSON:JSON similar to the following is returned:

[
    {
        "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"
    }
]

添加模型类Add a model class

模型 是一组表示应用管理的数据的类。A model is a set of classes that represent the data that the app manages. 此应用的模型是单个 TodoItem 类。The model for this app is a single TodoItem class.

  • 在“解决方案资源管理器” 中,右键单击项目。In Solution Explorer, right-click the project. 选择“添加” > “新建文件夹” 。Select Add > New Folder. 将文件夹命名为“Models” 。Name the folder Models.

  • 右键单击“Models” 文件夹,然后选择“添加” > “类” 。Right-click the Models folder and select Add > Class. 将类命名为 TodoItem,然后选择“添加” 。Name the class TodoItem and select Add.

  • 将模板代码替换为以下代码:Replace the template code with the following code:

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

Id 属性用作关系数据库中的唯一键。The Id property functions as the unique key in a relational database.

模型类可位于项目的任意位置,但按照惯例会使用 Models 文件夹。Model classes can go anywhere in the project, but the Models folder is used by convention.

添加数据库上下文Add a database context

数据库上下文是为数据模型协调 Entity Framework 功能的主类 。The database context is the main class that coordinates Entity Framework functionality for a data model. 此类由 Microsoft.EntityFrameworkCore.DbContext 类派生而来。This class is created by deriving from the Microsoft.EntityFrameworkCore.DbContext class.

添加 Add Microsoft.EntityFrameworkCore.SqlServerAdd Microsoft.EntityFrameworkCore.SqlServer

  • 在“工具”菜单中,依次选择“NuGet 包管理器”、“管理解决方案的 NuGet 包” 。From the Tools menu, select NuGet Package Manager > Manage NuGet Packages for Solution.
  • 选中“包括预发行版”复选框 。Select the Include prerelease checkbox.
  • 选择“浏览”选项卡,然后在搜索框中输入 Microsoft.EntityFrameworkCore.SqlServer 。Select the Browse tab, and then enter Microsoft.EntityFrameworkCore.SqlServer in the search box.
  • 在左窗口中选择“Microsoft.EntityFrameworkCore.SqlServer V3.0.0-preview” 。Select Microsoft.EntityFrameworkCore.SqlServer V3.0.0-preview in the left pane.
  • 选中右窗格中的“项目”复选框,然后选择“安装” 。Select the Project check box in the right pane and then select Install.
  • 使用上述说明添加 Microsoft.EntityFrameworkCore.InMemory NuGet 包。Use the preceding instructions to add the Microsoft.EntityFrameworkCore.InMemory NuGet package.

NuGet 程序包管理器

添加 TodoContext 数据库上下文Add the TodoContext database context

  • 右键单击“Models” 文件夹,然后选择“添加” > “类” 。Right-click the Models folder and select Add > Class. 将类命名为 TodoContext,然后单击“添加” 。Name the class TodoContext and click Add.
  • 输入以下代码:Enter the following code:

    using Microsoft.EntityFrameworkCore;
    
    namespace TodoApi.Models
    {
        public class TodoContext : DbContext
        {
            public TodoContext(DbContextOptions<TodoContext> options)
                : base(options)
            {
            }
    
            public DbSet<TodoItem> TodoItems { get; set; }
        }
    }
    

注册数据库上下文Register the database context

在 ASP.NET Core 中,服务(如数据库上下文)必须向依赖关系注入 (DI) 容器进行注册。In ASP.NET Core, services such as the DB context must be registered with the dependency injection (DI) container. 该容器向控制器提供服务。The container provides the service to controllers.

使用以下突出显示的代码更新 Startup.cs :Update Startup.cs with the following highlighted code:

// Unused usings removed
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

namespace TodoApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<TodoContext>(opt =>
               opt.UseInMemoryDatabase("TodoList"));
            services.AddControllers();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

前面的代码:The preceding code:

  • 删除未使用的 using 声明。Removes unused using declarations.
  • 将数据库上下文添加到 DI 容器。Adds the database context to the DI container.
  • 指定数据库上下文将使用内存中数据库。Specifies that the database context will use an in-memory database.

构建控制器Scaffold a controller

  • 右键单击 Controllers 文件夹。Right-click the Controllers folder.

  • 选择“添加”>“新建构建项” 。Select Add > New Scaffolded Item.

  • 选择“其操作使用实体框架的 API 控制器”,然后选择“添加” 。Select API Controller with actions, using Entity Framework, and then select Add.

  • 在“添加其操作使用实体框架的 API 控制器”对话框中 :In the Add API Controller with actions, using Entity Framework dialog:

    • 在“模型类”中选择“TodoItem (TodoAPI.Models)” 。Select TodoItem (TodoAPI.Models) in the Model class.
    • 在“数据上下文类”中选择“TodoContext (TodoAPI.Models)” 。Select TodoContext (TodoAPI.Models) in the Data context class.
    • 选择“添加” Select Add

生成的代码:The generated code:

  • 定义了没有方法的 API 控制器类。Defines an API controller class without methods.
  • 使用 [ApiController] 属性修饰类。Decorates the class with the [ApiController] attribute. 此属性指示控制器响应 Web API 请求。This attribute indicates that the controller responds to web API requests. 有关该属性启用的特定行为的信息,请参阅 使用 ASP.NET Core 创建 Web APIFor information about specific behaviors that the attribute enables, see 使用 ASP.NET Core 创建 Web API.
  • 使用 DI 将数据库上下文 (TodoContext) 注入到控制器中。Uses DI to inject the database context (TodoContext) into the controller. 数据库上下文将在控制器中的每个 CRUD 方法中使用。The database context is used in each of the CRUD methods in the controller.

检查 PostTodoItem create 方法Examine the PostTodoItem create method

替换 PostTodoItem 中的返回语句,以使用 nameof 运算符:Replace the return statement in the PostTodoItem to use the nameof operator:

// POST: api/TodoItems
[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);
}

正如 [HttpPost] 属性所指示,前面的代码是 HTTP POST 方法。The preceding code is an HTTP POST method, as indicated by the [HttpPost] attribute. 该方法从 HTTP 请求正文获取待办事项的值。The method gets the value of the to-do item from the body of the HTTP request.

CreatedAtAction 方法:The CreatedAtAction method:

  • 如果成功,则返回 HTTP 201 状态代码。Returns an HTTP 201 status code if successful. HTTP 201 是在服务器上创建新资源的 HTTP POST 方法的标准响应。HTTP 201 is the standard response for an HTTP POST method that creates a new resource on the server.
  • 向响应添加位置标头。Adds a Location header to the response. Location 标头指定新建的待办事项的 URIThe Location header specifies the URI of the newly created to-do item. 有关详细信息,请参阅创建的 10.2.2 201For more information, see 10.2.2 201 Created.
  • 引用 GetTodoItem 操作以创建 Location 标头的 URI。References the GetTodoItem action to create the Location header's URI. C# nameof 关键字用于避免在 CreatedAtAction 调用中硬编码操作名称。The C# nameof keyword is used to avoid hard-coding the action name in the CreatedAtAction call.

安装 PostmanInstall Postman

本教程使用 Postman 测试 Web API。This tutorial uses Postman to test the web API.

  • 安装 PostmanInstall Postman
  • 启动 Web 应用。Start the web app.
  • 启动 Postman。Start Postman.
  • 禁用 SSL 证书验证Disable SSL certificate verification
  • 在“文件”>“设置” (“常规”* 选项卡)中,禁用“SSL 证书验证” 。From File > Settings (*General tab), disable SSL certificate verification.

    警告

    在测试控制器之后重新启用 SSL 证书验证。Re-enable SSL certificate verification after testing the controller.

通过 Postman 测试 PostTodoItemTest PostTodoItem with Postman

  • 创建新请求。Create a new request.

  • 将 HTTP 方法设置为 POSTSet the HTTP method to POST.

  • 选择“正文”选项卡 。Select the Body tab.

  • 选择“原始”单选按钮 。Select the raw radio button.

  • 将类型设置为 JSON (application/json) Set the type to JSON (application/json).

  • 在请求正文中,输入待办事项的 JSON:In the request body enter JSON for a to-do item:

    {
      "name":"walk dog",
      "isComplete":true
    }
    
  • 选择“发送” 。Select Send.

    使用创建请求的 Postman

测试位置标头 URITest the location header URI

  • 在“响应” 窗格中选择“标头” 选项卡。Select the Headers tab in the Response pane.

  • 复制“位置” 标头值:Copy the Location header value:

    Postman 控制台的“标头”选项卡

  • 将方法设置为“GET”。Set the method to GET.

  • 粘贴 URI(例如,https://localhost:5001/api/TodoItems/1Paste the URI (for example, https://localhost:5001/api/TodoItems/1)

  • 选择“发送” 。Select Send.

检查 GET 方法Examine the GET methods

这些方法实现两个 GET 终结点:These methods implement two GET endpoints:

  • GET /api/TodoItems
  • GET /api/TodoItems/{id}

通过从浏览器或 Postman 调用两个终结点来测试应用。Test the app by calling the two endpoints from a browser or Postman. 例如:For example:

GetTodoItems 的调用生成类似于以下项的响应:A response similar to the following is produced by the call to GetTodoItems:

[
  {
    "id": 1,
    "name": "Item1",
    "isComplete": false
  }
]

使用 Postman 测试 GetTest Get with Postman

  • 创建新请求。Create a new request.
  • 将 HTTP 方法设置为“GET” 。Set the HTTP method to GET.
  • 将请求 URL 设置为 https://localhost:<port>/api/TodoItemsSet the request URL to https://localhost:<port>/api/TodoItems. 例如 https://localhost:5001/api/TodoItemsFor example, https://localhost:5001/api/TodoItems.
  • 在 Postman 中设置“两窗格视图” 。Set Two pane view in Postman.
  • 选择“发送” 。Select Send.

此应用使用内存中数据库。This app uses an in-memory database. 如果应用已停止并启动,则前面的 GET 请求将不会返回任何数据。If the app is stopped and started, the preceding GET request will not return any data. 如果未返回任何数据,将数据 POST 到应用。If no data is returned, POST data to the app.

路由和 URL 路径Routing and URL paths

[HttpGet] 属性表示响应 HTTP GET 请求的方法。The [HttpGet] attribute denotes a method that responds to an HTTP GET request. 每个方法的 URL 路径构造如下所示:The URL path for each method is constructed as follows:

  • 在控制器的 Route 属性中以模板字符串开头:Start with the template string in the controller's Route attribute:

    [Route("api/[controller]")]
    [ApiController]
    public class TodoItemsController : ControllerBase
    {
        private readonly TodoContext _context;
    
        public TodoItemsController(TodoContext context)
        {
            _context = context;
        }
    
  • [controller] 替换为控制器的名称,按照惯例,在控制器类名称中去掉“Controller”后缀。Replace [controller] with the name of the controller, which by convention is the controller class name minus the "Controller" suffix. 对于此示例,控制器类名称为“TodoItems”控制器,因此控制器名称为“TodoItems” 。For this sample, the controller class name is TodoItemsController, so the controller name is "TodoItems". ASP.NET Core 路由不区分大小写。ASP.NET Core routing is case insensitive.

  • 如果 [HttpGet] 属性具有路由模板(例如 [HttpGet("products")]),则将它追加到路径。If the [HttpGet] attribute has a route template (for example, [HttpGet("products")]), append that to the path. 此示例不使用模板。This sample doesn't use a template. 有关详细信息,请参阅使用 Http [Verb] 特性的特性路由For more information, see Attribute routing with Http[Verb] attributes.

在下面的 GetTodoItem 方法中,"{id}" 是待办事项的唯一标识符的占位符变量。In the following GetTodoItem method, "{id}" is a placeholder variable for the unique identifier of the to-do item. 调用 GetTodoItem 时,URL 中 "{id}" 的值会在 id 参数中提供给方法。When GetTodoItem is invoked, the value of "{id}" in the URL is provided to the method in itsid parameter.

// GET: api/TodoItems/5
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    return todoItem;
}

返回值Return values

GetTodoItemsGetTodoItem 方法的返回类型是 ActionResult<T> 类型The return type of the GetTodoItems and GetTodoItem methods is ActionResult<T> type. ASP.NET Core 自动将对象序列化为 JSON,并将 JSON 写入响应消息的正文中。ASP.NET Core automatically serializes the object to JSON and writes the JSON into the body of the response message. 在假设没有未经处理的异常的情况下,此返回类型的响应代码为 200。The response code for this return type is 200, assuming there are no unhandled exceptions. 未经处理的异常将转换为 5xx 错误。Unhandled exceptions are translated into 5xx errors.

ActionResult 返回类型可以表示大范围的 HTTP 状态代码。ActionResult return types can represent a wide range of HTTP status codes. 例如,GetTodoItem 可以返回两个不同的状态值:For example, GetTodoItem can return two different status values:

  • 如果没有任何项与请求的 ID 匹配,则该方法将返回 404 NotFound 错误代码。If no item matches the requested ID, the method returns a 404 NotFound error code.
  • 否则,此方法将返回具有 JSON 响应正文的 200。Otherwise, the method returns 200 with a JSON response body. 返回 item 则产生 HTTP 200 响应。Returning item results in an HTTP 200 response.

PutTodoItem 方法The PutTodoItem method

检查 PutTodoItem 方法:Examine the PutTodoItem method:

// PUT: api/TodoItems/5
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
    if (id != todoItem.Id)
    {
        return BadRequest();
    }

    _context.Entry(todoItem).State = EntityState.Modified;

    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!TodoItemExists(id))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }

    return NoContent();
}

PutTodoItemPostTodoItem 类似,但是使用的是 HTTP PUT。PutTodoItem is similar to PostTodoItem, except it uses HTTP PUT. 响应是 204(无内容)The response is 204 (No Content). 根据 HTTP 规范,PUT 请求需要客户端发送整个更新的实体,而不仅仅是更改。According to the HTTP specification, a PUT request requires the client to send the entire updated entity, not just the changes. 若要支持部分更新,请使用 HTTP PATCHTo support partial updates, use HTTP PATCH.

如果在调用 PutTodoItem 时出错,请调用 GET 以确保数据库中有项目。If you get an error calling PutTodoItem, call GET to ensure there's an item in the database.

测试 PutTodoItem 方法Test the PutTodoItem method

本示例使用内存数据库,每次启动应用时都必须对其进行初始化。This sample uses an in-memory database that must be initialed each time the app is started. 在进行 PUT 调用之前,数据库中必须有一个项。There must be an item in the database before you make a PUT call. 调用 GET,以确保在调用 PUT 之前数据库中存在项目。Call GET to insure there's an item in the database before making a PUT call.

更新 ID = 1 的待办事项并将其名称设置为“feed fish”:Update the to-do item that has ID = 1 and set its name to "feed fish":

  {
    "ID":1,
    "name":"feed fish",
    "isComplete":true
  }

下图显示 Postman 更新:The following image shows the Postman update:

显示 204(无内容)响应的 Postman 控制台

DeleteTodoItem 方法The DeleteTodoItem method

检查 DeleteTodoItem 方法:Examine the DeleteTodoItem method:

// DELETE: api/TodoItems/5
[HttpDelete("{id}")]
public async Task<ActionResult<TodoItem>> DeleteTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);
    if (todoItem == null)
    {
        return NotFound();
    }

    _context.TodoItems.Remove(todoItem);
    await _context.SaveChangesAsync();

    return todoItem;
}

DeleteTodoItem 响应是 204(无内容)The DeleteTodoItem response is 204 (No Content).

测试 DeleteTodoItem 方法Test the DeleteTodoItem method

使用 Postman 删除待办事项:Use Postman to delete a to-do item:

  • 将方法设置为 DELETESet the method to DELETE.
  • 设置要删除的对象的 URI,例如 https://localhost:5001/api/TodoItems/1Set the URI of the object to delete, for example https://localhost:5001/api/TodoItems/1
  • 选择“Send” Select Send

使用 JavaScript 调用 Web APICall the web API with JavaScript

有关分步说明,请参阅教程:使用 JavaScript 调用 ASP.NET Core Web APISee Tutorial: Call an ASP.NET Core web API with JavaScript.

在本教程中,你将了解:In this tutorial, you learn how to:

  • 创建 Web API 项目。Create a web API project.
  • 添加模型类和数据库上下文。Add a model class and a database context.
  • 添加控制器。Add a controller.
  • 添加 CRUD 方法。Add CRUD methods.
  • 配置路由和 URL 路径。Configure routing and URL paths.
  • 指定返回值。Specify return values.
  • 使用 Postman 调用 Web API。Call the web API with Postman.
  • 使用 JavaScript 调用 Web API。Call the web API with JavaScript.

在结束时,你会获得可以管理存储在关系数据库中的“待办事项”的 Web API。At the end, you have a web API that can manage "to-do" items stored in a relational database.

概述Overview

本教程将创建以下 API:This tutorial creates the following API:

APIAPI 说明Description 请求正文Request body 响应正文Response body
GET /api/TodoItemsGET /api/TodoItems 获取所有待办事项Get all to-do items None 待办事项的数组Array of to-do items
GET /api/TodoItems/{id}GET /api/TodoItems/{id} 按 ID 获取项Get an item by ID None 待办事项To-do item
POST /api/TodoItemsPOST /api/TodoItems 添加新项Add a new item 待办事项To-do item 待办事项To-do item
PUT /api/TodoItems/{id}PUT /api/TodoItems/{id} 更新现有项  Update an existing item   待办事项To-do item None
DELETE /api/TodoItems/{id}    DELETE /api/TodoItems/{id}     删除项   Delete an item     None None

下图显示了应用的设计。The following diagram shows the design of the app.

右侧的框表示客户端。

系统必备Prerequisites

警告

如果使用 Visual Studio 2017,请参阅 dotnet/sdk 问题 #3124,以了解无法与 Visual Studio 一起使用的 .NET Core SDK 版本的信息。If you use Visual Studio 2017, see dotnet/sdk issue #3124 for information about .NET Core SDK versions that don't work with Visual Studio.

创建 Web 项目Create a web project

  • 从“文件”菜单中选择“新建”>“项目” 。From the File menu, select New > Project.
  • 选择“ASP.NET Core Web 应用程序”模板,再单击“下一步” 。Select the ASP.NET Core Web Application template and click Next.
  • 将项目命名为 TodoApi,然后单击“创建” 。Name the project TodoApi and click Create.
  • 在“创建新的 ASP.NET Core Web 应用程序”对话框中,确认选择“.NET Core”和“ASP.NET Core 2.2” 。In the Create a new ASP.NET Core Web Application dialog, confirm that .NET Core and ASP.NET Core 2.2 are selected. 选择“API”模板,然后单击“创建” 。Select the API template and click Create. 请不要选择“启用 Docker 支持” 。Don't select Enable Docker Support.

VS“新建项目”对话框

测试 APITest the API

项目模板会创建 values API。The project template creates a values API. 从浏览器调用 Get 方法以测试应用。Call the Get method from a browser to test the app.

按 Ctrl+F5 运行应用。Press Ctrl+F5 to run the app. Visual Studio 启动浏览器并导航到 https://localhost:<port>/api/values,其中 <port> 是随机选择的端口号。Visual Studio launches a browser and navigates to https://localhost:<port>/api/values, where <port> is a randomly chosen port number.

如果出现询问是否应信任 IIS Express 证书的对话框,则选择“是” 。If you get a dialog box that asks if you should trust the IIS Express certificate, select Yes. 在接下来出现的“安全警告” 对话框中,选择“是” 。In the Security Warning dialog that appears next, select Yes.

会返回以下 JSON:The following JSON is returned:

["value1","value2"]

添加模型类Add a model class

模型 是一组表示应用管理的数据的类。A model is a set of classes that represent the data that the app manages. 此应用的模型是单个 TodoItem 类。The model for this app is a single TodoItem class.

  • 在“解决方案资源管理器” 中,右键单击项目。In Solution Explorer, right-click the project. 选择“添加” > “新建文件夹” 。Select Add > New Folder. 将文件夹命名为“Models” 。Name the folder Models.

  • 右键单击“Models” 文件夹,然后选择“添加” > “类” 。Right-click the Models folder and select Add > Class. 将类命名为 TodoItem,然后选择“添加” 。Name the class TodoItem and select Add.

  • 将模板代码替换为以下代码:Replace the template code with the following code:

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

Id 属性用作关系数据库中的唯一键。The Id property functions as the unique key in a relational database.

模型类可位于项目的任意位置,但按照惯例会使用 Models 文件夹。Model classes can go anywhere in the project, but the Models folder is used by convention.

添加数据库上下文Add a database context

数据库上下文是为数据模型协调 Entity Framework 功能的主类 。The database context is the main class that coordinates Entity Framework functionality for a data model. 此类由 Microsoft.EntityFrameworkCore.DbContext 类派生而来。This class is created by deriving from the Microsoft.EntityFrameworkCore.DbContext class.

  • 右键单击“Models” 文件夹,然后选择“添加” > “类” 。Right-click the Models folder and select Add > Class. 将类命名为 TodoContext,然后单击“添加” 。Name the class TodoContext and click Add.
  • 将模板代码替换为以下代码:Replace the template code with the following code:

    using Microsoft.EntityFrameworkCore;
    
    namespace TodoApi.Models
    {
        public class TodoContext : DbContext
        {
            public TodoContext(DbContextOptions<TodoContext> options)
                : base(options)
            {
            }
    
            public DbSet<TodoItem> TodoItems { get; set; }
        }
    }
    

注册数据库上下文Register the database context

在 ASP.NET Core 中,服务(如数据库上下文)必须向依赖关系注入 (DI) 容器进行注册。In ASP.NET Core, services such as the DB context must be registered with the dependency injection (DI) container. 该容器向控制器提供服务。The container provides the service to controllers.

使用以下突出显示的代码更新 Startup.cs :Update Startup.cs with the following highlighted code:

// Unused usings removed
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using TodoApi.Models;

namespace TodoApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the 
        //container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<TodoContext>(opt =>
                opt.UseInMemoryDatabase("TodoList"));
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP 
        //request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // The default HSTS value is 30 days. You may want to change this for 
                // production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseMvc();
        }
    }
}

前面的代码:The preceding code:

  • 删除未使用的 using 声明。Removes unused using declarations.
  • 将数据库上下文添加到 DI 容器。Adds the database context to the DI container.
  • 指定数据库上下文将使用内存中数据库。Specifies that the database context will use an in-memory database.

添加控制器Add a controller

  • 右键单击 Controllers 文件夹。Right-click the Controllers folder.

  • 选择“添加”>“新项” 。Select Add > New Item.

  • 在“添加新项”对话框中,选择“API 控制器类”模板 。In the Add New Item dialog, select the API Controller Class template.

  • 将类命名为 TodoController,然后选择“添加” 。Name the class TodoController, and select Add.

    “添加新项”对话框,“控制器”显示在搜索框中,并且“Web API 控制器”已选中

  • 将模板代码替换为以下代码:Replace the template code with the following code:

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.EntityFrameworkCore;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using TodoApi.Models;
    
    namespace TodoApi.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class TodoController : ControllerBase
        {
            private readonly TodoContext _context;
    
            public TodoController(TodoContext context)
            {
                _context = context;
    
                if (_context.TodoItems.Count() == 0)
                {
                    // Create a new TodoItem if collection is empty,
                    // which means you can't delete all TodoItems.
                    _context.TodoItems.Add(new TodoItem { Name = "Item1" });
                    _context.SaveChanges();
                }
            }
        }
    }
    

前面的代码:The preceding code:

  • 定义了没有方法的 API 控制器类。Defines an API controller class without methods.
  • 使用 [ApiController] 属性修饰类。Decorates the class with the [ApiController] attribute. 此属性指示控制器响应 Web API 请求。This attribute indicates that the controller responds to web API requests. 有关该属性启用的特定行为的信息,请参阅 使用 ASP.NET Core 创建 Web APIFor information about specific behaviors that the attribute enables, see 使用 ASP.NET Core 创建 Web API.
  • 使用 DI 将数据库上下文 (TodoContext) 注入到控制器中。Uses DI to inject the database context (TodoContext) into the controller. 数据库上下文将在控制器中的每个 CRUD 方法中使用。The database context is used in each of the CRUD methods in the controller.
  • 如果数据库为空,则将名为 Item1 的项添加到数据库。Adds an item named Item1 to the database if the database is empty. 此代码位于构造函数中,因此在每次出现新 HTTP 请求时运行。This code is in the constructor, so it runs every time there's a new HTTP request. 如果删除所有项,则构造函数会在下次调用 API 方法时再次创建 Item1If you delete all items, the constructor creates Item1 again the next time an API method is called. 因此删除可能看上去不起作用,不过实际上确实有效。So it may look like the deletion didn't work when it actually did work.

添加 Get 方法Add Get methods

若要提供检索待办事项的 API,请将以下方法添加到 TodoController 类中:To provide an API that retrieves to-do items, add the following methods to the TodoController class:

// GET: api/Todo
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItem>>> GetTodoItems()
{
    return await _context.TodoItems.ToListAsync();
}

// GET: api/Todo/5
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    return todoItem;
}

这些方法实现两个 GET 终结点:These methods implement two GET endpoints:

  • GET /api/todo
  • GET /api/todo/{id}

如果应用仍在运行,请停止它。Stop the app if it's still running. 然后再次运行它以包括最新更改。Then run it again to include the latest changes.

通过从浏览器调用两个终结点来测试应用。Test the app by calling the two endpoints from a browser. 例如:For example:

  • https://localhost:<port>/api/todo
  • https://localhost:<port>/api/todo/1

以下 HTTP 响应通过调用 GetTodoItems 来生成:The following HTTP response is produced by the call to GetTodoItems:

[
  {
    "id": 1,
    "name": "Item1",
    "isComplete": false
  }
]

路由和 URL 路径Routing and URL paths

[HttpGet] 属性表示响应 HTTP GET 请求的方法。The [HttpGet] attribute denotes a method that responds to an HTTP GET request. 每个方法的 URL 路径构造如下所示:The URL path for each method is constructed as follows:

  • 在控制器的 Route 属性中以模板字符串开头:Start with the template string in the controller's Route attribute:

    namespace TodoApi.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class TodoController : ControllerBase
        {
            private readonly TodoContext _context;
    
  • [controller] 替换为控制器的名称,按照惯例,在控制器类名称中去掉“Controller”后缀。Replace [controller] with the name of the controller, which by convention is the controller class name minus the "Controller" suffix. 对于此示例,控制器类名称为“Todo”控制器,因此控制器名称为“todo” 。For this sample, the controller class name is TodoController, so the controller name is "todo". ASP.NET Core 路由不区分大小写。ASP.NET Core routing is case insensitive.

  • 如果 [HttpGet] 属性具有路由模板(例如 [HttpGet("products")]),则将它追加到路径。If the [HttpGet] attribute has a route template (for example, [HttpGet("products")]), append that to the path. 此示例不使用模板。This sample doesn't use a template. 有关详细信息,请参阅使用 Http [Verb] 特性的特性路由For more information, see Attribute routing with Http[Verb] attributes.

在下面的 GetTodoItem 方法中,"{id}" 是待办事项的唯一标识符的占位符变量。In the following GetTodoItem method, "{id}" is a placeholder variable for the unique identifier of the to-do item. 调用 GetTodoItem 时,URL 中 "{id}" 的值会在 id 参数中提供给方法。When GetTodoItem is invoked, the value of "{id}" in the URL is provided to the method in itsid parameter.

// GET: api/Todo/5
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    return todoItem;
}

返回值Return values

GetTodoItemsGetTodoItem 方法的返回类型是 ActionResult<T> 类型The return type of the GetTodoItems and GetTodoItem methods is ActionResult<T> type. ASP.NET Core 自动将对象序列化为 JSON,并将 JSON 写入响应消息的正文中。ASP.NET Core automatically serializes the object to JSON and writes the JSON into the body of the response message. 在假设没有未经处理的异常的情况下,此返回类型的响应代码为 200。The response code for this return type is 200, assuming there are no unhandled exceptions. 未经处理的异常将转换为 5xx 错误。Unhandled exceptions are translated into 5xx errors.

ActionResult 返回类型可以表示大范围的 HTTP 状态代码。ActionResult return types can represent a wide range of HTTP status codes. 例如,GetTodoItem 可以返回两个不同的状态值:For example, GetTodoItem can return two different status values:

  • 如果没有任何项与请求的 ID 匹配,则该方法将返回 404 NotFound 错误代码。If no item matches the requested ID, the method returns a 404 NotFound error code.
  • 否则,此方法将返回具有 JSON 响应正文的 200。Otherwise, the method returns 200 with a JSON response body. 返回 item 则产生 HTTP 200 响应。Returning item results in an HTTP 200 response.

测试 GetTodoItems 方法Test the GetTodoItems method

本教程使用 Postman 测试 Web API。This tutorial uses Postman to test the web API.

  • 安装 PostmanInstall Postman
  • 启动 Web 应用。Start the web app.
  • 启动 Postman。Start Postman.
  • 禁用 SSL 证书验证Disable SSL certificate verification
  • 在“文件”>“设置”(“常规”选项卡)中,禁用“SSL 证书验证” 。From File > Settings (General tab), disable SSL certificate verification.

警告

在测试控制器之后重新启用 SSL 证书验证。Re-enable SSL certificate verification after testing the controller.

  • 创建新请求。Create a new request.
    • 将 HTTP 方法设置为“GET” 。Set the HTTP method to GET.
    • 将请求 URL 设置为 https://localhost:<port>/api/todoSet the request URL to https://localhost:<port>/api/todo. 例如 https://localhost:5001/api/todoFor example, https://localhost:5001/api/todo.
  • 在 Postman 中设置“两窗格视图” 。Set Two pane view in Postman.
  • 选择“发送” 。Select Send.

使用 Get 请求的 Postman

添加创建方法Add a Create method

在 Controllers / TodoController.cs 中添加以下 PostTodoItem 方法 :Add the following PostTodoItem method inside of Controllers/TodoController.cs:

// POST: api/Todo
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem item)
{
    _context.TodoItems.Add(item);
    await _context.SaveChangesAsync();

    return CreatedAtAction(nameof(GetTodoItem), new { id = item.Id }, item);
}

正如 [HttpPost] 属性所指示,前面的代码是 HTTP POST 方法。The preceding code is an HTTP POST method, as indicated by the [HttpPost] attribute. 该方法从 HTTP 请求正文获取待办事项的值。The method gets the value of the to-do item from the body of the HTTP request.

CreatedAtAction 方法:The CreatedAtAction method:

  • 如果成功,则返回 HTTP 201 状态代码。Returns an HTTP 201 status code, if successful. HTTP 201 是在服务器上创建新资源的 HTTP POST 方法的标准响应。HTTP 201 is the standard response for an HTTP POST method that creates a new resource on the server.

  • Location 标头添加到响应。Adds a Location header to the response. Location 标头指定新建的待办事项的 URI。The Location header specifies the URI of the newly created to-do item. 有关详细信息,请参阅创建的 10.2.2 201For more information, see 10.2.2 201 Created.

  • 引用 GetTodoItem 操作以创建 Location 标头的 URI。References the GetTodoItem action to create the Location header's URI. C# nameof 关键字用于避免在 CreatedAtAction 调用中硬编码操作名称。The C# nameof keyword is used to avoid hard-coding the action name in the CreatedAtAction call.

    // GET: api/Todo/5
    [HttpGet("{id}")]
    public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
    {
        var todoItem = await _context.TodoItems.FindAsync(id);
    
        if (todoItem == null)
        {
            return NotFound();
        }
    
        return todoItem;
    }
    

测试 PostTodoItem 方法Test the PostTodoItem method

  • 生成项目。Build the project.

  • 在 Postman 中,将 HTTP 方法设置为 POSTIn Postman, set the HTTP method to POST.

  • 选择“正文”选项卡 。Select the Body tab.

  • 选择“原始”单选按钮 。Select the raw radio button.

  • 将类型设置为 JSON (application/json) Set the type to JSON (application/json).

  • 在请求正文中,输入待办事项的 JSON:In the request body enter JSON for a to-do item:

    {
      "name":"walk dog",
      "isComplete":true
    }
    
  • 选择“发送” 。Select Send.

    使用创建请求的 Postman

    如果收到 405 不允许的方法错误,则可能是由于未在添加 PostTodoItem 方法之后编译项目。If you get a 405 Method Not Allowed error, it's probably the result of not compiling the project after adding the PostTodoItem method.

测试位置标头 URITest the location header URI

  • 在“响应” 窗格中选择“标头” 选项卡。Select the Headers tab in the Response pane.

  • 复制“位置” 标头值:Copy the Location header value:

    Postman 控制台的“标头”选项卡

  • 将方法设置为“GET”。Set the method to GET.

  • 粘贴 URI(例如,https://localhost:5001/api/Todo/2Paste the URI (for example, https://localhost:5001/api/Todo/2)

  • 选择“发送” 。Select Send.

添加 PutTodoItem 方法Add a PutTodoItem method

添加以下 PutTodoItem 方法:Add the following PutTodoItem method:

// PUT: api/Todo/5
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem item)
{
    if (id != item.Id)
    {
        return BadRequest();
    }

    _context.Entry(item).State = EntityState.Modified;
    await _context.SaveChangesAsync();

    return NoContent();
}

PutTodoItemPostTodoItem 类似,但是使用的是 HTTP PUT。PutTodoItem is similar to PostTodoItem, except it uses HTTP PUT. 响应是 204(无内容)The response is 204 (No Content). 根据 HTTP 规范,PUT 请求需要客户端发送整个更新的实体,而不仅仅是更改。According to the HTTP specification, a PUT request requires the client to send the entire updated entity, not just the changes. 若要支持部分更新,请使用 HTTP PATCHTo support partial updates, use HTTP PATCH.

如果在调用 PutTodoItem 时出错,请调用 GET 以确保数据库中有项目。If you get an error calling PutTodoItem, call GET to ensure there's an item in the database.

测试 PutTodoItem 方法Test the PutTodoItem method

本示例使用内存数据库,每次启动应用时都必须对其进行初始化。This sample uses an in-memory database that must be initialed each time the app is started. 在进行 PUT 调用之前,数据库中必须有一个项。There must be an item in the database before you make a PUT call. 调用 GET,以确保在调用 PUT 之前数据库中存在项目。Call GET to insure there's an item in the database before making a PUT call.

更新 id = 1 的待办事项并将其名称设置为“feed fish”:Update the to-do item that has id = 1 and set its name to "feed fish":

  {
    "ID":1,
    "name":"feed fish",
    "isComplete":true
  }

下图显示 Postman 更新:The following image shows the Postman update:

显示 204(无内容)响应的 Postman 控制台

添加 DeleteTodoItem 方法Add a DeleteTodoItem method

添加以下 DeleteTodoItem 方法:Add the following DeleteTodoItem method:

// DELETE: api/Todo/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();
}

DeleteTodoItem 响应是 204(无内容)The DeleteTodoItem response is 204 (No Content).

测试 DeleteTodoItem 方法Test the DeleteTodoItem method

使用 Postman 删除待办事项:Use Postman to delete a to-do item:

  • 将方法设置为 DELETESet the method to DELETE.
  • 设置要删除的对象的 URI,例如 https://localhost:5001/api/todo/1Set the URI of the object to delete, for example https://localhost:5001/api/todo/1
  • 选择“Send” Select Send

可通过示例应用删除所有项。The sample app allows you to delete all the items. 但如果删除最后一项,则在下次调用 API 时,模型类构造函数会创建一个新项。However, when the last item is deleted, a new one is created by the model class constructor the next time the API is called.

使用 JavaScript 调用 Web APICall the web API with JavaScript

在本部分中,将添加一个 HTML 页面,该页面使用 JavaScript 调用 Web API。In this section, an HTML page is added that uses JavaScript to call the web API. Fetch API 可启动该请求。The Fetch API initiates the request. JavaScript 会使用 Web API 响应的详细信息来更新页面。JavaScript updates the page with the details from the web API's response.

通过下面突出显示的代码更新 Startup.cs,配置应用来提供静态文件实现默认文件映射Configure the app to serve static files and enable default file mapping by updating Startup.cs with the following highlighted code:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        // The default HSTS value is 30 days. You may want to change this for 
        // production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }

    app.UseDefaultFiles();
    app.UseStaticFiles();
    app.UseHttpsRedirection();
    app.UseMvc();
}

在项目目录中创建 wwwroot 文件夹。Create a wwwroot folder in the project directory.

将一个名为 index.html 的 HTML 文件添加到 wwwroot 目录 。Add an HTML file named index.html to the wwwroot directory. 用以下标记替代其内容:Replace its contents with the following markup:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>To-do CRUD</title>
    <style>
        input[type='submit'], button, [aria-label] {
            cursor: pointer;
        }

        #spoiler {
            display: none;
        }

        table {
            font-family: Arial, sans-serif;
            border: 1px solid;
            border-collapse: collapse;
        }

        th {
            background-color: #0066CC;
            color: white;
        }

        td {
            border: 1px solid;
            padding: 5px;
        }
    </style>
</head>
<body>
    <h1>To-do CRUD</h1>
    <h3>Add</h3>
    <form action="javascript:void(0);" method="POST" onsubmit="addItem()">
        <input type="text" id="add-name" placeholder="New to-do">
        <input type="submit" value="Add">
    </form>

    <div id="spoiler">
        <h3>Edit</h3>
        <form class="my-form">
            <input type="hidden" id="edit-id">
            <input type="checkbox" id="edit-isComplete">
            <input type="text" id="edit-name">
            <input type="submit" value="Save">
            <a onclick="closeInput()" aria-label="Close">&#10006;</a>
        </form>
    </div>

    <p id="counter"></p>

    <table>
        <tr>
            <th>Is Complete</th>
            <th>Name</th>
            <th></th>
            <th></th>
        </tr>
        <tbody id="todos"></tbody>
    </table>

    <script src="https://code.jquery.com/jquery-3.3.1.min.js"
            integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
            crossorigin="anonymous"></script>
    <script src="site.js"></script>
</body>
</html>

将名为 site.js 的 JavaScript 文件添加到 wwwroot 目录 。Add a JavaScript file named site.js to the wwwroot directory. 用以下代码替代其内容:Replace its contents with the following code:

const uri = "api/todo";
let todos = null;
function getCount(data) {
  const el = $("#counter");
  let name = "to-do";
  if (data) {
    if (data > 1) {
      name = "to-dos";
    }
    el.text(data + " " + name);
  } else {
    el.text("No " + name);
  }
}

$(document).ready(function() {
  getData();
});

function getData() {
  $.ajax({
    type: "GET",
    url: uri,
    cache: false,
    success: function(data) {
      const tBody = $("#todos");

      $(tBody).empty();

      getCount(data.length);

      $.each(data, function(key, item) {
        const tr = $("<tr></tr>")
          .append(
            $("<td></td>").append(
              $("<input/>", {
                type: "checkbox",
                disabled: true,
                checked: item.isComplete
              })
            )
          )
          .append($("<td></td>").text(item.name))
          .append(
            $("<td></td>").append(
              $("<button>Edit</button>").on("click", function() {
                editItem(item.id);
              })
            )
          )
          .append(
            $("<td></td>").append(
              $("<button>Delete</button>").on("click", function() {
                deleteItem(item.id);
              })
            )
          );

        tr.appendTo(tBody);
      });

      todos = data;
    }
  });
}

function addItem() {
  const item = {
    name: $("#add-name").val(),
    isComplete: false
  };

  $.ajax({
    type: "POST",
    accepts: "application/json",
    url: uri,
    contentType: "application/json",
    data: JSON.stringify(item),
    error: function(jqXHR, textStatus, errorThrown) {
      alert("Something went wrong!");
    },
    success: function(result) {
      getData();
      $("#add-name").val("");
    }
  });
}

function deleteItem(id) {
  $.ajax({
    url: uri + "/" + id,
    type: "DELETE",
    success: function(result) {
      getData();
    }
  });
}

function editItem(id) {
  $.each(todos, function(key, item) {
    if (item.id === id) {
      $("#edit-name").val(item.name);
      $("#edit-id").val(item.id);
      $("#edit-isComplete")[0].checked = item.isComplete;
    }
  });
  $("#spoiler").css({ display: "block" });
}

$(".my-form").on("submit", function() {
  const item = {
    name: $("#edit-name").val(),
    isComplete: $("#edit-isComplete").is(":checked"),
    id: $("#edit-id").val()
  };

  $.ajax({
    url: uri + "/" + $("#edit-id").val(),
    type: "PUT",
    accepts: "application/json",
    contentType: "application/json",
    data: JSON.stringify(item),
    success: function(result) {
      getData();
    }
  });

  closeInput();
  return false;
});

function closeInput() {
  $("#spoiler").css({ display: "none" });
}

可能需要更改 ASP.NET Core 项目的启动设置,以便对 HTML 页面进行本地测试:A change to the ASP.NET Core project's launch settings may be required to test the HTML page locally:

  • 打开 Properties\launchSettings.json 。Open Properties\launchSettings.json.
  • 删除 launchUrl 以便在项目的默认文件 index.html 强制打开应用 。Remove the launchUrl property to force the app to open at index.html—the project's default file.

此示例调用 Web API 的所有 CRUD 方法。This sample calls all of the CRUD methods of the web API. 以下是 API 调用的说明。Following are explanations of the calls to the API.

获取待办事项的列表Get a list of to-do items

Fetch 将向 Web API 发送 HTTP GET 请求,该 API 返回表示待办事项的数组的 JSON。Fetch sends an HTTP GET request to the web API, which returns JSON representing an array of to-do items. 如果请求成功,则调用 success 回调函数。The success callback function is invoked if the request succeeds. 在该回调中使用待办事项信息更新 DOM。In the callback, the DOM is updated with the to-do information.

$(document).ready(function() {
  getData();
});

function getData() {
  $.ajax({
    type: "GET",
    url: uri,
    cache: false,
    success: function(data) {
      const tBody = $("#todos");

      $(tBody).empty();

      getCount(data.length);

      $.each(data, function(key, item) {
        const tr = $("<tr></tr>")
          .append(
            $("<td></td>").append(
              $("<input/>", {
                type: "checkbox",
                disabled: true,
                checked: item.isComplete
              })
            )
          )
          .append($("<td></td>").text(item.name))
          .append(
            $("<td></td>").append(
              $("<button>Edit</button>").on("click", function() {
                editItem(item.id);
              })
            )
          )
          .append(
            $("<td></td>").append(
              $("<button>Delete</button>").on("click", function() {
                deleteItem(item.id);
              })
            )
          );

        tr.appendTo(tBody);
      });

      todos = data;
    }
  });
}

添加待办事项Add a to-do item

Fetch 发送 HTTP POST 请求,请求正文中包含待办事项。Fetch sends an HTTP POST request with the to-do item in the request body. acceptscontentType 选项设置为 application/json,以便指定接收和发送的媒体类型。The accepts and contentType options are set to application/json to specify the media type being received and sent. 待办事项使用 JSON.stringify 转换为 JSON。The to-do item is converted to JSON by using JSON.stringify. 当 API 返回成功状态的代码时,将调用 getData 函数来更新 HTML 表。When the API returns a successful status code, the getData function is invoked to update the HTML table.

function addItem() {
  const item = {
    name: $("#add-name").val(),
    isComplete: false
  };

  $.ajax({
    type: "POST",
    accepts: "application/json",
    url: uri,
    contentType: "application/json",
    data: JSON.stringify(item),
    error: function(jqXHR, textStatus, errorThrown) {
      alert("Something went wrong!");
    },
    success: function(result) {
      getData();
      $("#add-name").val("");
    }
  });
}

更新待办事项Update a to-do item

更新待办事项与添加类似。Updating a to-do item is similar to adding one. url 更改为添加项的唯一标识符,并且 typePUTThe url changes to add the unique identifier of the item, and the type is PUT.

$.ajax({
  url: uri + "/" + $("#edit-id").val(),
  type: "PUT",
  accepts: "application/json",
  contentType: "application/json",
  data: JSON.stringify(item),
  success: function(result) {
    getData();
  }
});

删除待办事项Delete a to-do item

若要删除待办事项,请将 AJAX 调用上的 type 设为 DELETE 并指定该项在 URL 中的唯一标识符。Deleting a to-do item is accomplished by setting the type on the AJAX call to DELETE and specifying the item's unique identifier in the URL.

$.ajax({
  url: uri + "/" + id,
  type: "DELETE",
  success: function(result) {
    getData();
  }
});

其他资源Additional resources

查看或下载本教程的示例代码View or download sample code for this tutorial. 请参阅如何下载See how to download.

有关更多信息,请参见以下资源:For more information, see the following resources: