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

.NET 7中BadRequestObjectResult仍使用驼峰命名策略问题

解决BadRequestObjectResult返回ODataError时的命名格式问题

这问题出在OData的错误响应序列化逻辑上——你全局配置的JsonSerializerOptions并没有被BadRequestObjectResult处理ODataError时复用,它走了OData自己的默认序列化逻辑,所以还是驼峰命名。下面给你几个可行的解决办法:

办法1:用JsonResult替代BadRequestObjectResult(最简单)

直接把返回类型换成JsonResult,同时传入你全局配置的JsonSerializerOptions,这样就能严格遵循你设置的命名规则,还能保持400的错误状态码:

protected ActionResult ValidationFailed()
{
    var err = new ODataError 
    {
        Message = "Validation error",
        Details = ModelState.ToDictionary(
            kvp => kvp.Key,
            kvp => kvp.Value.Errors.Select(e => e.ErrorMessage).ToArray()
        ).Select(e => new ODataErrorDetail() {
            ErrorCode = e.Key,
            Message = string.Join("\n", e.Value.ToArray())
        }).ToList()
    };

    // 拿到全局配置的Json序列化选项
    var jsonOptions = HttpContext.RequestServices.GetRequiredService<IOptions<JsonOptions>>().Value.JsonSerializerOptions;
    // 返回JsonResult并指定状态码为400
    return new JsonResult(err, jsonOptions) { StatusCode = StatusCodes.Status400BadRequest };
}

办法2:全局配置OData错误序列化(一劳永逸)

如果想让所有OData错误都统一用你的命名规则,可以在配置OData的时候自定义错误序列化器,让它复用全局的JSON配置:

首先添加自定义的ODataErrorSerializer:

public class CustomODataErrorSerializer : ODataErrorSerializer
{
    private readonly JsonSerializerOptions _globalJsonOptions;

    public CustomODataErrorSerializer(JsonSerializerOptions jsonOptions) : base(ODataPayloadKind.Error)
    {
        _globalJsonOptions = jsonOptions;
    }

    public override async Task WriteObjectAsync(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
    {
        if (graph is ODataError error)
        {
            // 用全局配置序列化错误对象
            var jsonWriter = messageWriter.CreateODataJsonWriter();
            await JsonSerializer.SerializeAsync(jsonWriter, error, _globalJsonOptions);
            await jsonWriter.FlushAsync();
            return;
        }
        await base.WriteObjectAsync(graph, type, messageWriter, writeContext);
    }
}

然后在Startup/Program里配置OData时注册这个序列化器:

builder.Services.AddControllers()
    .AddJsonOptions(options => {
        options.JsonSerializerOptions.PropertyNamingPolicy = null;
        options.JsonSerializerOptions.DictionaryKeyPolicy = null;
    })
    .AddOData(options =>
    {
        options.Select().Filter().OrderBy().Expand().Count().SetMaxTop(null);
        options.AddRouteComponents("odata", GetEdmModel(), services =>
        {
            var globalJsonOptions = services.BuildServiceProvider().GetRequiredService<IOptions<JsonOptions>>().Value.JsonSerializerOptions;
            services.AddSingleton<ODataSerializerProvider>(sp =>
                new DefaultODataSerializerProvider(sp)
                {
                    ODataErrorSerializer = new CustomODataErrorSerializer(globalJsonOptions)
                });
        });
    });

办法3:自定义错误类包装ODataError(繁琐不推荐)

如果你不想改返回方式或全局配置,也可以自己写个错误类,用[JsonPropertyName]强制指定序列化后的键名,再把ODataError包进去返回:

public class CustomErrorResponse
{
    [JsonPropertyName("Error")]
    public ODataError Error { get; set; }
}

protected ActionResult ValidationFailed()
{
    var err = new ODataError 
    {
        Message = "Validation error",
        Details = ModelState.ToDictionary(
            kvp => kvp.Key,
            kvp => kvp.Value.Errors.Select(e => e.ErrorMessage).ToArray()
        ).Select(e => new ODataErrorDetail() {
            ErrorCode = e.Key,
            Message = string.Join("\n", e.Value.ToArray())
        }).ToList()
    };

    return new BadRequestObjectResult(new CustomErrorResponse { Error = err });
}

效果验证

用办法1修改后,返回的响应就会和你预期的一致:

{
    "Error": {
        "Code": "",
        "Message": "Validation error",
        "Details": [
            {
                "Code": "Person.Corpid",
                "Message": "Corpid field must be value"
            } 
        ]
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 00:55:17