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

.NET 6中如何在到达Controller前读取JSON原始Post请求体?

.NET 6 同路由多请求体场景的模型绑定与验证实现

针对同路由HttpPost接口需支持10余种请求体组合、保留原有路由且要自动完成模型验证的需求,可通过自定义模型绑定器+多场景模型类的方案实现,替代Java中用HashMap接收后判断action的方式,同时利用.NET的数据注解完成自动校验。

1. 定义多场景模型类

先创建包含共享字段(如action)的基类,再为每个请求场景创建专属模型,通过数据注解标记必填/校验规则:

using System.ComponentModel.DataAnnotations;

// 基类:所有请求共享的字段
public abstract class BaseApprovalRequest
{
    [Required(ErrorMessage = "action字段为必填项")]
    public string Action { get; set; }
}

// 示例场景1:审批通过请求
public class ApproveRequest : BaseApprovalRequest
{
    [Required(ErrorMessage = "staffId字段为必填项")]
    public string StaffId { get; set; }
    
    [Range(1, int.MaxValue, ErrorMessage = "approvalLevel必须大于0")]
    public int ApprovalLevel { get; set; }
}

// 示例场景2:驳回请求
public class RejectRequest : BaseApprovalRequest
{
    [Required(ErrorMessage = "staffId字段为必填项")]
    public string StaffId { get; set; }
    
    [Required(ErrorMessage = "rejectReason字段为必填项")]
    public string RejectReason { get; set; }
}

// 其他场景模型依此类推...

2. 自定义模型绑定器

实现IModelBinder接口,读取原始JSON请求体,根据action字段反序列化为对应场景模型,并处理反序列化错误:

using Microsoft.AspNetCore.Mvc.ModelBinding;
using System.Text.Json;

public class ApprovalRequestBinder : IModelBinder
{
    public async Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
            throw new ArgumentNullException(nameof(bindingContext));

        // 读取原始JSON请求体
        using var reader = new StreamReader(bindingContext.HttpContext.Request.Body);
        var jsonBody = await reader.ReadToEndAsync();
        if (string.IsNullOrEmpty(jsonBody))
        {
            bindingContext.ModelState.AddModelError(string.Empty, "请求体不能为空");
            return;
        }

        // 先反序列化为JsonElement获取action字段
        var jsonElement = JsonSerializer.Deserialize<JsonElement>(jsonBody);
        if (!jsonElement.TryGetProperty("action", out var actionElement) || string.IsNullOrEmpty(actionElement.GetString()))
        {
            bindingContext.ModelState.AddModelError("action", "action字段不能为空");
            return;
        }

        string action = actionElement.GetString()!.ToLower();
        BaseApprovalRequest requestModel = action switch
        {
            "approve" => JsonSerializer.Deserialize<ApproveRequest>(jsonBody),
            "reject" => JsonSerializer.Deserialize<RejectRequest>(jsonBody),
            // 添加其他action对应的模型映射
            _ => null
        };

        if (requestModel == null)
        {
            bindingContext.ModelState.AddModelError("action", $"不支持的action类型:{action}");
            return;
        }

        // 触发数据注解校验
        var validationContext = new ValidationContext(requestModel);
        var validationResults = new List<ValidationResult>();
        if (!Validator.TryValidateObject(requestModel, validationContext, validationResults, validateAllProperties: true))
        {
            foreach (var validationResult in validationResults)
            {
                bindingContext.ModelState.AddModelError(validationResult.MemberNames.FirstOrDefault() ?? string.Empty, validationResult.ErrorMessage);
            }
            return;
        }

        // 绑定成功,设置模型
        bindingContext.Result = ModelBindingResult.Success(requestModel);
    }
}

3. 注册模型绑定提供者(可选)

如果不想在每个控制器参数上手动指定绑定器类型,可创建IModelBinderProvider自动匹配基类:

using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;

public class ApprovalRequestBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context.Metadata.ModelType.IsAssignableTo(typeof(BaseApprovalRequest)))
        {
            return new BinderTypeModelBinder(typeof(ApprovalRequestBinder));
        }
        return null;
    }
}

在Program.cs中注册:

builder.Services.AddControllers(options =>
{
    options.ModelBinderProviders.Insert(0, new ApprovalRequestBinderProvider());
});

4. 控制器实现

直接使用基类作为参数,自动触发模型绑定与验证,无需手动处理原始请求体:

using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("your-existing-route")] // 保留原有路由,不可修改
public class ApprovalController : ControllerBase
{
    private readonly IAuthorizationService _authorizationService;
    private readonly IApprovalService _approvalService;
    private readonly ILogger<ApprovalController> _logger;

    public ApprovalController(IAuthorizationService authorizationService, IApprovalService approvalService, ILogger<ApprovalController> logger)
    {
        _authorizationService = authorizationService;
        _approvalService = approvalService;
        _logger = logger;
    }

    [HttpPost]
    public async Task<IActionResult> PostForApproving([FromBody] BaseApprovalRequest request)
    {
        // 自动验证模型,失败直接返回400
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        // 获取RequestStore(对应Java中的request.getAttribute)
        var requestStore = HttpContext.Items["requestStore"] as RequestStore;
        _logger.LogInformation("postForApproving({@RequestStore})", requestStore);

        // 权限校验
        _authorizationService.CheckApiRole(requestStore, $"postForApproving_{entity_name}", "Staff-Management");

        // 服务层分发处理(用模式匹配替代Java的else-if)
        var respBody = request switch
        {
            ApproveRequest approveReq => await _approvalService.HandleApprove(requestStore, approveReq),
            RejectRequest rejectReq => await _approvalService.HandleReject(requestStore, rejectReq),
            // 其他场景模型的处理分支
            _ => throw new NotSupportedException("不支持的请求类型")
        };

        // 构造响应(对应Java的ResponseEntity)
        var responseHeaders = GetResponseHeaders(requestStore);
        foreach (var header in responseHeaders)
        {
            Response.Headers.Append(header.Key, header.Value);
        }
        return Created("", respBody);
    }

    // 模拟Java的HttpUtilities.getResponseHeaders方法
    private Dictionary<string, string> GetResponseHeaders(RequestStore requestStore)
    {
        return new Dictionary<string, string>
        {
            // 填充响应头逻辑
        };
    }
}

5. 服务层处理

利用C#的模式匹配,直接根据模型类型分发到对应处理方法:

public interface IApprovalService
{
    Task<Dictionary<string, object>> HandleApprove(RequestStore requestStore, ApproveRequest request);
    Task<Dictionary<string, object>> HandleReject(RequestStore requestStore, RejectRequest rejectReq);
    // 其他场景的处理方法
}

public class ApprovalService : IApprovalService
{
    // 实现各场景的具体业务逻辑...
}

内容的提问来源于stack exchange,提问作者Shameel Perayil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 15:24:25