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

.NET Core WebAPI:带数字后缀的蛇形命名JSON属性无法映射DTO

解决.NET Core WebAPI中带数字后缀的蛇形JSON属性无法绑定到DTO的问题

我在使用集成Swagger的.NET Core WebAPI项目时,遇到了JSON属性绑定异常。当传入如下请求JSON时:

{
  "year": 2023,
  "vat_amount": 2000,
  "vat_period": "January",
  "vat_amount_20": 2000,
  "turnover_description": "Some description of turnover",
  "turnover_description_10": "Turnover Description 10",
  "turnover_description_20": "Turnover Description 20",
  "related_party_identifier": "106723546"
}

大部分属性能被Newtonsoft.Json识别并填充到DTO,但带字母数字组合的属性(如vat_amount_20、turnover_description_10、turnover_description_20)无法正确绑定。

我的DTO定义如下:

[JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))]
public class VatRecordingIndividualRequestDto
{
    [JsonProperty("turnover_description")]
    public string? TurnoverDescription { get; set; }

    [JsonProperty("turnover_description_10")]
    public string? TurnoverDescription10 { get; set; }

    [JsonProperty("turnover_description_20")]
    public string? TurnoverDescription20 { get; set; }

    [JsonProperty("vat_amount_20")]
    public double? VatAmount20 { get; set; }

    [JsonProperty("vat_amount")]
    public double? VatAmount { get; set; }

    [JsonProperty("vat_period")]
    public string? VatPeriod { get; set; }

    [JsonProperty("year")]
    public int Year { get; set; }
}

同时在Program.cs中配置了自定义的SnakeCasePropertyNamingPolicy(基于System.Text.Json):

builder.Services.AddControllers().AddJsonOptions(options =>
{
    options.JsonSerializerOptions.PropertyNamingPolicy = new SnakeCasePropertyNamingPolicy();
});

自定义命名策略代码:

public class SnakeCasePropertyNamingPolicy : JsonNamingPolicy
{
    public override string ConvertName(string name)
    {
        return name.ToSnakeCase();
    }
}

public static class StringExtensions
{
    public static string ToSnakeCase(this string str)
    {
        return string.Concat(str.Select((character, index) =>
                index > 0 && char.IsUpper(character)
                    ? "_" + character
                    : character.ToString()))
            .ToLower();
    }
}

问题根源

当前的ToSnakeCase扩展方法仅处理了大写字母前加下划线的情况,但未覆盖字母后跟数字的场景。比如DTO属性VatAmount20,按照现有逻辑会被转换为vat_amount20,但请求JSON中的对应属性是vat_amount_20(数字前多了下划线),两者不匹配导致绑定失败。

解决方案

修改ToSnakeCase方法,新增字母后跟数字场景的处理逻辑,在字母与数字之间插入下划线。修改后的代码如下:

public static class StringExtensions
{
    public static string ToSnakeCase(this string str)
    {
        var result = new StringBuilder();
        for (int i = 0; i < str.Length; i++)
        {
            var currentChar = str[i];
            // 处理大写字母:前面加下划线后转小写
            if (char.IsUpper(currentChar))
            {
                if (i > 0)
                {
                    result.Append('_');
                }
                result.Append(char.ToLower(currentChar));
            }
            // 处理数字:若前一个字符是字母,先加下划线再追加数字
            else if (char.IsDigit(currentChar))
            {
                if (i > 0 && char.IsLetter(str[i - 1]))
                {
                    result.Append('_');
                }
                result.Append(currentChar);
            }
            // 其他字符直接追加
            else
            {
                result.Append(currentChar);
            }
        }
        return result.ToString();
    }
}

补充说明

  • 新增数字判断逻辑后,VatAmount20会被正确转换为vat_amount_20,与JSON属性名完全匹配,实现正常绑定。
  • 使用StringBuilder替代原LINQ拼接逻辑,性能更优且可读性更强。
  • 若项目同时混用Newtonsoft.Json和System.Text.Json,建议保持一致性:
    • 若依赖Newtonsoft.Json(已添加AddNewtonsoftJson()),可移除自定义System.Text.Json命名策略,直接依赖Newtonsoft原生的SnakeCaseNamingStrategy。
    • 若使用System.Text.Json,建议移除DTO上的Newtonsoft特性,改用[JsonPropertyName]指定属性名,或依赖修改后的自定义命名策略自动转换。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 04:54:52