.NET 8.0合并多API端点为单个GET端点,通用DTO实现方案咨询
合并多DTO为通用DTO的实现方案及传参说明
一、通用DTO设计
定义包含请求类型标识和所有原DTO属性的通用DTO,其中请求类型为必填项,其余属性设为可空类型以适配不同请求场景的字段需求:
using System.ComponentModel.DataAnnotations; public class GeneralRequestDto { // 必填:用于区分10种原请求类型 [Required(ErrorMessage = "RequestType is required")] public string RequestType { get; set; } // 以下为原10个DTO的所有属性,根据实际需求设置可空/可选 public int? UserId { get; set; } public string? ProductName { get; set; } public DateTime? StartDate { get; set; } public decimal? MinPrice { get; set; } // 补充其他原DTO的属性... }
二、端点实现与业务路由
基础分支实现
在Controller中接收通用DTO,通过RequestType分支调用对应业务方法,同时针对每种请求类型做字段合法性校验:
[ApiController] [Route("api/[controller]")] public class GeneralQueryController : ControllerBase { private readonly IUserService _userService; private readonly IProductService _productService; // 注入其他业务服务... public GeneralQueryController(IUserService userService, IProductService productService) { _userService = userService; _productService = productService; } [HttpGet("execute")] public IActionResult ExecuteQuery([FromQuery] GeneralRequestDto request) { if (!ModelState.IsValid) { return BadRequest(ModelState); } return request.RequestType switch { "GetUserDetails" => HandleGetUserDetails(request), "SearchProducts" => HandleSearchProducts(request), // 补充其他8种请求类型的分支... _ => BadRequest("Invalid RequestType value") }; } private IActionResult HandleGetUserDetails(GeneralRequestDto request) { if (!request.UserId.HasValue) { return BadRequest("UserId is required for GetUserDetails request"); } var user = _userService.GetUserById(request.UserId.Value); return Ok(user); } private IActionResult HandleSearchProducts(GeneralRequestDto request) { if (string.IsNullOrWhiteSpace(request.ProductName)) { return BadRequest("ProductName is required for SearchProducts request"); } var products = _productService.SearchByName(request.ProductName); return Ok(products); } // 其他请求类型的处理方法... }
优雅优化:策略模式
若请求类型较多,避免Controller分支逻辑臃肿,可采用策略模式拆分处理逻辑:
- 定义处理器接口:
public interface IRequestHandler { string SupportedRequestType { get; } IActionResult Handle(GeneralRequestDto request); }
- 实现对应请求类型的处理器:
public class GetUserDetailsHandler : IRequestHandler { private readonly IUserService _userService; public GetUserDetailsHandler(IUserService userService) { _userService = userService; } public string SupportedRequestType => "GetUserDetails"; public IActionResult Handle(GeneralRequestDto request) { if (!request.UserId.HasValue) { return new BadRequestObjectResult("UserId is required"); } var user = _userService.GetUserById(request.UserId.Value); return new OkObjectResult(user); } } // 其他9种请求类型的处理器类...
- 注册处理器并改造Controller:
// 在Program.cs中注册所有处理器 builder.Services.AddScoped<IRequestHandler, GetUserDetailsHandler>(); builder.Services.AddScoped<IRequestHandler, SearchProductsHandler>(); // 注册其他处理器... // Controller改造 [ApiController] [Route("api/[controller]")] public class GeneralQueryController : ControllerBase { private readonly Dictionary<string, IRequestHandler> _handlerMap; public GeneralQueryController(IEnumerable<IRequestHandler> handlers) { _handlerMap = handlers.ToDictionary(h => h.SupportedRequestType, h => h); } [HttpGet("execute")] public IActionResult ExecuteQuery([FromQuery] GeneralRequestDto request) { if (!ModelState.IsValid) { return BadRequest(ModelState); } if (!_handlerMap.TryGetValue(request.RequestType, out var handler)) { return BadRequest("Unsupported RequestType"); } return handler.Handle(request); } }
三、客户端传参说明
客户端不需要传递通用DTO的所有属性,仅需传递:
- 必填的
RequestType字段(用于标识当前请求对应的原业务场景); - 该
RequestType对应原端点所需的字段。
示例:
- 调用原"GetUserDetails"端点:
GET /api/generalquery/execute?RequestType=GetUserDetails&UserId=1001 - 调用原"SearchProducts"端点:
GET /api/generalquery/execute?RequestType=SearchProducts&ProductName=WirelessHeadset
四、额外优化建议
- 条件验证:使用FluentValidation等库实现基于
RequestType的条件验证,替代硬编码的字段校验,提升代码可维护性; - Swagger文档:通过Swagger特性(如
[SwaggerExample])为不同RequestType生成对应的请求示例,方便客户端开发者理解; - 参数校验:在业务层二次校验参数合法性,避免因DTO校验遗漏导致的业务逻辑异常。
内容的提问来源于stack exchange,提问作者prasidh
相关产品推荐
相关产品推荐

