第三章 控制器和动作方法

3.1 控制器基础

控制器的定义与作用

控制器(Controller)是ASP.NET Core Web API的核心组件,负责处理HTTP请求并生成HTTP响应。在Web API中,控制器通常:

  • 继承自ControllerBase类(而非MVC应用中的Controller类)
  • 使用[ApiController]特性标记
  • 包含一个或多个动作方法(Action Methods)
  • 负责协调模型和视图(在API中是指响应数据)

创建基本控制器

以下是创建控制器的基本步骤:

  1. Controllers文件夹中创建新文件(如TodoItemsController.cs

  2. 添加以下代码:

    using Microsoft.AspNetCore.Mvc;
    using TodoApi.Models;

    namespace TodoApi.Controllers
    {
    [Route("api/[controller]")]
    [ApiController]
    public class TodoItemsController : ControllerBase
    {
    private readonly TodoContext _context;

    复制代码
         // 通过依赖注入获取数据上下文
         public TodoItemsController(TodoContext context)
         {
             _context = context;
         }
    
         // 动作方法将在后续添加
     }

    }

关键组件:

  • [Route("api/[controller]")] :定义路由模板,[controller]会被替换为控制器名称(不含"Controller"后缀)
  • [ApiController]:启用API特定行为
  • ControllerBase:包含API控制器所需的基本功能
  • 依赖注入 :通过构造函数注入TodoContext

3.2 Action Methods(动作方法)

动作方法简介

动作方法(Action Methods)是控制器中处理特定HTTP请求的公共方法。它们:

  • 映射到特定的HTTP方法(GET, POST, PUT, DELETE等)
  • 返回数据或IActionResult派生类型
  • 可以接收来自请求的参数
  • 执行业务逻辑或调用服务

HTTP动词属性

ASP.NET Core使用特性(Attributes)将HTTP动词映射到动作方法:

HTTP动词特性 对应HTTP方法 典型用途
[HttpGet] GET 获取资源
[HttpPost] POST 创建资源
[HttpPut] PUT 更新资源
[HttpDelete] DELETE 删除资源
[HttpPatch] PATCH 部分更新

例如,添加获取所有待办事项的GET方法:

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

3.3 实现CRUD操作

以下是待办事项API的完整CRUD实现:

获取所有项目(Read All)

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

获取特定项目(Read One)

复制代码
// 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;
}

创建新项目(Create)

复制代码
// POST: api/TodoItems
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
    _context.TodoItems.Add(todoItem);
    await _context.SaveChangesAsync();

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

更新项目(Update)

复制代码
// 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();
}

private bool TodoItemExists(long id)
{
    return _context.TodoItems.Any(e => e.Id == id);
}

删除项目(Delete)

复制代码
// 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();
}