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

.NET Core 3.1使用JsonPropertyName处理带索引点属性反序列化问题

问题原因

System.Text.Json 原生的JsonPropertyName特性仅支持完全匹配JSON键名,你当前配置的[JsonPropertyName("user.email")]只能匹配键名恰好为user.email的属性,无法自动识别带[索引]后缀的user.email[0]/user.email[1]这类扁平化键,也不会自动把多个同前缀带索引的键聚合为List集合。

解决方案

分两种场景处理:

方案1:调整前端传参结构(改造成本最低)

如果可以协调前端修改传参格式,直接传标准嵌套JSON结构即可,无需额外开发:

{
  "id": "B1346",
  "businessType": "RENTAL",
  "company.city": "LUND",
  "company.zipcode": "99999",
  "company.email": "support@samplecompany.com",
  "user": {
    "email": ["support2@samplecompany.com", "support3@samplecompany.com"],
    "name": ["Tom", "Harry"]
  }
}

对应修改POCO结构:

public class Form
{
  public string Id { get; set;}
  public string BusinessType { get; set;}
  [JsonPropertyName("company.city")]
  public string CompanyCity { get; set;}
  [JsonPropertyName("company.zipcode")]
  public string CompanyZipcode { get; set;}
  [JsonPropertyName("company.email")]
  public string CompanyEmail { get; set;}
  public UserInfo User { get; set; }
}

public class UserInfo
{
  public List<string> Email { get; set; }
  public List<string> Name { get; set; }
}

默认反序列化即可正常解析。

方案2:自定义JsonConverter(前端传参无法修改时使用)

如果不能调整前端传参格式,手动实现JsonConverter<Form>处理带索引的扁平化键即可:

第一步:实现自定义转换器

using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;

public class FormJsonConverter : JsonConverter<Form>
{
    // 匹配带索引的键的正则,比如 user.email[0] 会匹配出前缀user.email、索引0
    private readonly Regex _arrayKeyRegex = new Regex(@"^(?<prefix>.+)\[(?<index>\d+)\]$", RegexOptions.Compiled);

    public override Form Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var form = new Form
        {
            UserEmail = new List<string>(),
            UserName = new List<string>()
        };
        if (reader.TokenType != JsonTokenType.StartObject)
            throw new JsonException();

        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndObject)
                return form;

            if (reader.TokenType != JsonTokenType.PropertyName)
                throw new JsonException();

            var propertyName = reader.GetString();
            reader.Read();
            var value = reader.GetString();

            // 先处理普通属性
            switch (propertyName)
            {
                case "id":
                    form.Id = value;
                    continue;
                case "businessType":
                    form.BusinessType = value;
                    continue;
                case "company.city":
                    form.CompanyCity = value;
                    continue;
                case "company.zipcode":
                    form.CompanyZipcode = value;
                    continue;
                case "company.email":
                    form.CompanyEmail = value;
                    continue;
            }

            // 处理带索引的数组属性
            var match = _arrayKeyRegex.Match(propertyName);
            if (!match.Success) continue;

            var prefix = match.Groups["prefix"].Value;
            var index = int.Parse(match.Groups["index"].Value);
            if (prefix == "user.email")
            {
                FillList(form.UserEmail, index, value);
            }
            else if (prefix == "user.name")
            {
                FillList(form.UserName, index, value);
            }
        }
        throw new JsonException();
    }

    // 填充列表,处理索引超过当前列表长度的情况
    private void FillList(List<string> list, int index, string value)
    {
        while (list.Count <= index)
        {
            list.Add(null);
        }
        list[index] = value;
    }

    public override void Write(Utf8JsonWriter writer, Form value, JsonSerializerOptions options)
    {
        // 如果不需要序列化回原扁平化格式可以直接用默认实现,或者自己按需实现
        JsonSerializer.Serialize(writer, value, options);
    }
}

第二步:注册转换器

两种注册方式二选一:

  • 直接给Form类加特性:
    [JsonConverter(typeof(FormJsonConverter))]
    public class Form
    {
        // 原有属性不变,不需要再给UserEmail/UserName加JsonPropertyName特性了
        public string Id { get; set;}
        public string BusinessType { get; set;}
        [JsonPropertyName("company.city")]
        public string CompanyCity { get; set;}
        [JsonPropertyName("company.zipcode")]
        public string CompanyZipcode { get; set;}
        [JsonPropertyName("company.email")]
        public string CompanyEmail { get; set;}
        public List<string> UserEmail { get; set;}
        public List<string> UserName { get; set;}
    }
    
  • 全局注册(Startup.cs的ConfigureServices方法中):
    services.AddControllers()
        .AddJsonOptions(options =>
        {
            options.JsonSerializerOptions.Converters.Add(new FormJsonConverter());
        });
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 19:09:01