练习 - 添加控制器

已完成

控制器是一个公共类,具有一个或多个称为“操作”的公共方法。 按照惯例,控制器放在项目根目录的 Controllers 目录中。 这些操作在 Web API 控制器内公开为 HTTP 终结点。

添加控制器

  1. 在 Visual Studio Code 中选择 Controllers 文件夹,并添加名为 PizzaController.cs 的新文件。

    Screenshot of Visual Studio Code that shows adding a new file to the Controllers folder.

    系统会在 Controllers 目录中创建名为 PizzaController.cs 的空类文件。 目录名称“Controllers”是一种约定。 目录名称来自 Web API 使用的模型-视图-控制器体系结构。

    注意

    按照惯例,控制器类名称后缀为 Controller

  2. 将以下代码添加到 Controllers/PizzaController.cs。 保存所做更改。

    using ContosoPizza.Models;
    using ContosoPizza.Services;
    using Microsoft.AspNetCore.Mvc;
    
    namespace ContosoPizza.Controllers;
    
    [ApiController]
    [Route("[controller]")]
    public class PizzaController : ControllerBase
    {
        public PizzaController()
        {
        }
    
        // GET all action
    
        // GET by Id action
    
        // POST action
    
        // PUT action
    
        // DELETE action
    }
    

    如前文所述,此类派生自 ControllerBase,后者是 ASP.NET Core 中用于处理 HTTP 请求的基类。 它还包含你已经了解的两个标准属性,即 [ApiController][Route]。 如前文所述,[Route] 属性定义了到 [controller] 令牌的映射。 由于此控制器类名为 PizzaController,因此该控制器处理对 https://localhost:{PORT}/pizza 的请求。

获取所有披萨

需要实现的第一个 REST 谓词是 GET,使用该谓词,客户端可以从 API 获取所有披萨。 可使用内置 [HttpGet] 属性来定义从服务返回披萨的方法。

将 Controllers/PizzaController.cs 中的 // GET all action 注释替换为以下代码:

[HttpGet]
public ActionResult<List<Pizza>> GetAll() =>
    PizzaService.GetAll();

上一个操作:

  • 仅响应 HTTP GET 谓词,如 [HttpGet] 属性所示。
  • 返回类型为 List<Pizza>ActionResult 实例。 ActionResult 类型是 ASP.NET Core 中所有操作结果的基类。
  • 查询服务以获取所有披萨,并通过 Content-Type 的值 application/json 自动返回数据。

检索单种披萨

客户端可能还需要请求获取特定披萨而非整个列表的相关信息。 你可以实现另一个 GET 操作,此操作需要 id 参数。 可使用内置 [HttpGet("{id}")] 属性来定义从服务返回披萨的方法。 路由逻辑将 [HttpGet](没有 id)和 [HttpGet("{id}")](具有 id)注册为两个不同的路由。 然后,你可以编写一个单独的操作来检索单个项。

将 Controllers/PizzaController.cs 中的 // GET by Id action 注释替换为以下代码:

[HttpGet("{id}")]
public ActionResult<Pizza> Get(int id)
{
    var pizza = PizzaService.Get(id);

    if(pizza == null)
        return NotFound();

    return pizza;
}

上一个操作:

  • 仅响应 HTTP GET 谓词,如 [HttpGet] 属性所示。
  • 要求 pizza/ 之后的 URL 段中包含 id 参数的值。 请记住,控制器级别的 [Route]属性定义了/pizza模式。
  • 查询数据库以获取与所提供的 id 参数匹配的披萨。

上述操作中使用的每个 ActionResult 实例都映射到下表中对应的 HTTP 状态代码:

ASP.NET Core
操作结果
HTTP 状态代码 说明
Ok 为隐式 200 内存中缓存中存在与所提供的 id 参数匹配的产品。
该产品包含在由 accept HTTP 请求标头中所定义的媒体类型(默认情况下为 JSON)的响应正文中。
NotFound 404 内存中缓存中不存在与所提供的 id 参数匹配的产品。

生成并运行新控制器

运行以下命令,生成并启动 Web API:

dotnet run

使用 .http 文件测试控制器

  1. 打开 ContosoPizza.http

  2. 添加新的 GET 以在 ### 分隔符下调用 Pizza 终结点:

    GET {{ContosoPizza_HostAddress}}/pizza/
    Accept: application/json
    
    ###
    
  3. 选择此新 GET 调用上方的“发送请求”命令

    前面的命令将以 JSON 格式返回所有披萨列表:

    HTTP/1.1 200 OK
    Connection: close
    Content-Type: application/json; charset=utf-8
    Date: Wed, 17 Jan 2024 16:57:09 GMT
    Server: Kestrel
    Transfer-Encoding: chunked
    
    [
        {
            "id": 1,
            "name": "Classic Italian",
            "isGlutenFree": false
        },
        {
            "id": 2,
            "name": "Veggie",
            "isGlutenFree": true
        }
    ]   
    
  4. 若要查询单个披萨,可以使用以下命令发出 GET 请求,但传入 id 参数:

    GET {{ContosoPizza_HostAddress}}/pizza/1
    Accept: application/json
    
    ###
    

    前面的命令返回 Classic Italian,输出结果如下:

    HTTP/1.1 200 OK
    Content-Type: application/json; charset=utf-8
    Date: Fri, 02 Apr 2021 21:57:57 GMT
    Server: Kestrel
    Transfer-Encoding: chunked
    
    {
        "id": 1,
        "name": "Classic Italian",
        "isGlutenFree": false
    }
    
  5. 我们的 API 还可以处理项不存在的情况。 使用以下命令再次调用该 API,但传入一个无效的披萨 id 参数:

    GET {{ContosoPizza_HostAddress}}/pizza/5
    Accept: application/json
    
    ###
    

    前面的命令返回 404 Not Found 错误,输出结果如下:

    HTTP/1.1 404 Not Found
    Content-Type: application/problem+json; charset=utf-8
    Date: Fri, 02 Apr 2021 22:03:06 GMT
    Server: Kestrel
    Transfer-Encoding: chunked
    
    {
        "type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
        "title": "Not Found",
        "status": 404,
        "traceId": "00-ec263e401ec554b6a2f3e216a1d1fac5-4b40b8023d56762c-00"
    }
    

你现在已经完成了 GET 谓词的实现。 在下一个单元中,你可以向 PizzaController 添加更多操作以支持对披萨数据执行 CRUD 操作。

可选:使用命令行 HTTP REPL 测试控制器

  1. 打开现有 httprepl 终端,或者通过从主菜单中选择“终端”>“新终端”,从 Visual Studio Code 中打开新的集成终端。

  2. 通过运行以下命令连接到 Web API:

    httprepl https://localhost:{PORT}
    

    或者,在 HttpRepl 运行时随时运行以下命令:

    connect https://localhost:{PORT}
    
  3. 若要查看新的可用 Pizza 终结点,请运行以下命令:

    ls
    

    前面的命令将检测连接的终结点上所有可用的 API。 此命令应显示以下代码:

     https://localhost:{PORT}/> ls
     .                 []
     Pizza             [GET]
     WeatherForecast   [GET]
    
  4. 运行以下命令以转到 Pizza 终结点:

    cd Pizza
    

    前面的命令将显示 Pizza 终结点的可用 API 的输出:

    https://localhost:{PORT}/> cd Pizza
    /Pizza    [GET]
    
  5. 使用以下命令在 HttpRepl 中发出 GET 请求:

    get
    

    前面的命令将以 JSON 格式返回所有披萨列表:

      HTTP/1.1 200 OK
      Content-Type: application/json; charset=utf-8
      Date: Fri, 02 Apr 2021 21:55:53 GMT
      Server: Kestrel
      Transfer-Encoding: chunked
    
      [
          {
              "id": 1,
              "name": "Classic Italian",
              "isGlutenFree": false
          },
          {
              "id": 2,
              "name": "Veggie",
              "isGlutenFree": true
          }
      ]
    
  6. 若要查询单个披萨,可以使用以下命令发出 GET 请求,但传入 id 参数:

    get 1
    

    前面的命令返回 Classic Italian,输出结果如下:

    HTTP/1.1 200 OK
    Content-Type: application/json; charset=utf-8
    Date: Fri, 02 Apr 2021 21:57:57 GMT
    Server: Kestrel
    Transfer-Encoding: chunked
    
    {
        "id": 1,
        "name": "Classic Italian",
        "isGlutenFree": false
    }
    
  7. 我们的 API 还可以处理项不存在的情况。 使用以下命令再次调用该 API,但传入一个无效的披萨 id 参数:

    get 5
    

    前面的命令返回 404 Not Found 错误,输出结果如下:

    HTTP/1.1 404 Not Found
    Content-Type: application/problem+json; charset=utf-8
    Date: Fri, 02 Apr 2021 22:03:06 GMT
    Server: Kestrel
    Transfer-Encoding: chunked
    
    {
        "type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
        "title": "Not Found",
        "status": 404,
        "traceId": "00-ec263e401ec554b6a2f3e216a1d1fac5-4b40b8023d56762c-00"
    }
    
  8. 在 Visual Studio Code 中,返回到下拉列表中的 dotnet 终端,并通过选择键盘上的 CTRL+C 来关闭 Web API。

你现在已经完成了 GET 谓词的实现。 在下一个单元中,你可以向 PizzaController 添加更多操作以支持对披萨数据执行 CRUD 操作。