You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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分支逻辑臃肿,可采用策略模式拆分处理逻辑:

  1. 定义处理器接口:
public interface IRequestHandler
{
    string SupportedRequestType { get; }
    IActionResult Handle(GeneralRequestDto request);
}
  1. 实现对应请求类型的处理器:
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种请求类型的处理器类...
  1. 注册处理器并改造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的所有属性,仅需传递:

  1. 必填的RequestType字段(用于标识当前请求对应的原业务场景);
  2. 该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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 18:15:09