迁移旧API到.NET Core时System.Text.Json序列化重名属性碰撞报错如何解决
问题根因
- 你配置的
PropertyNameCaseInsensitive = true仅作用于反序列化阶段,用来实现忽略大小写匹配C#类属性,对序列化逻辑没有任何影响,无法解决你要输出大小写不同同名属性的需求。 - 报错的核心原因:
- 默认System.Text.Json序列化时如果开启了全局驼峰命名转换,你匿名类中定义的
id和ID两个属性会被统一转换为id,触发属性名重复校验。 - 匿名类无法自定义序列化后的属性名,无法规避命名策略的转换规则。
- 默认System.Text.Json序列化时如果开启了全局驼峰命名转换,你匿名类中定义的
解决方案
方案1:使用字典构造返回数据(改造成本最低)
直接在查询投影中返回Dictionary<string, object>类型,手动指定JSON属性名,不会受全局命名策略影响,代码示例如下:
[HttpGet] public async Task<ActionResult<IEnumerable<object>>> GetContacts(string projectID) { Project project = _context.Projects.Where(a => a.Name == projectID) .FirstOrDefault(); var contacts = await _context.Contacts.Where(a => a.ProjectId == project.Id) .Select(o => new Dictionary<string, object> { ["Id"] = o.Id, ["id"] = o.Id }).ToListAsync(); return contacts; }
你不需要修改现有的Json全局配置,就能得到预期的输出结构。
方案2:自定义DTO类 + 显式指定序列化属性名
如果你需要强类型约束,可以自定义DTO类,通过JsonPropertyName特性显式指定序列化后的属性名:
首先定义DTO类:
public class ContactDto { [JsonPropertyName("Id")] public int Id { get; set; } [JsonPropertyName("id")] public int LowerCaseId { get; set; } }
修改Action中的投影逻辑:
[HttpGet] public async Task<ActionResult<IEnumerable<ContactDto>>> GetContacts(string projectID) { Project project = _context.Projects.Where(a => a.Name == projectID) .FirstOrDefault(); var contacts = await _context.Contacts.Where(a => a.ProjectId == project.Id) .Select(o => new ContactDto { Id = o.Id, LowerCaseId = o.Id }).ToListAsync(); return contacts; }
需要注意如果你的全局Json配置中开启了驼峰命名转换,JsonPropertyName指定的属性名优先级高于全局配置,不会被覆盖。
内容的提问来源于stack exchange,提问作者Plarent Haxhidauti
相关产品推荐
相关产品推荐

