Controller
Controller 这一层别写重。
它主要做四件事:
- 接收 HTTP 请求
- 完成路由与参数绑定
- 调用
Contract或Service - 通过
ApiControllerBase返回标准响应
这些事情尽量别放在 Controller 里:
- 直接编写复杂业务逻辑
- 直接拼写 SQL
- 直接把数据库实体返回给前端
一个常见写法
通常直接继承 ApiControllerBase:
using Aegis.Core.Infrastructure.Controller;
using Aegis.Transfer.Responses;
using Aegis.Webapi.Contract;
using Microsoft.AspNetCore.Mvc;
namespace Aegis.Webapi.BaseDemo.Controllers;
public class UserController : ApiControllerBase
{
private readonly IUserContract _userService;
private readonly ILogger<UserController> _logger;
public UserController(IUserContract userService, ILogger<UserController> logger)
{
_userService = userService;
_logger = logger;
}
[HttpPost("GetUsers")]
public async Task<ApiResponse> GetUsers(GetUsersRequest request)
{
var result = await _userService.GetUsersAsync(request);
return SuccessListResult(result);
}
}
入参怎么放
简单参数直接写
像 id、code 这样的简单查询参数,可以直接放在方法签名中。
[HttpGet("GetUser")]
public async Task<ApiResponse> GetUser(long id)
复杂参数单独建 Request
只要参数开始变复杂,就建议建立 Request 类,并放在 Dto 项目的 Requests 目录中。
平时按下面几条写就够:
- 统一使用
record - 优先使用
init - 为请求建立对应的
Validator - 不把数据库字段直接暴露给前端
示例:
public record GetUsersRequest
{
public string Name { get; init; }
public int Age { get; init; }
}
放在 Dto 项目的 Requests 目录下会比较顺手。
参数绑定
在 HttpPost 场景下,不带标记的复杂对象通常来自请求体。
如果你需要从查询串读取参数,可以显式标记 [FromQuery]。
[HttpGet("GetList")]
public async Task<ApiResponse> GetList([FromQuery] PageListRequest request)
返回值怎么统一
对外公开的方法统一返回 ApiResponse。
具体是单对象还是列表,不靠方法签名区分,而是靠 ApiControllerBase 里的返回方法区分。
具体可以看 ApiControllerBase。
最小接口应该长什么样
最小闭环其实很简单:
- Request 进入 Controller
- Controller 调用
IUserContract或具体 Service - Service 从 Repository 获取数据
- Controller 使用
SuccessResult或SuccessListResult返回 - 在 Swagger 中可以直接调试验证
如果你想继续看返回包装和响应方法,接着读 ApiControllerBase。