.NET 6使用Options模式读取含Int键JSON文件的映射问题
问题根源
.NET配置系统的默认绑定逻辑不会自动将JSON中的字符串类型字典键(如"4")转换为整数类型,因此模型中Dictionary<int, CategoryMapping>和Dictionary<int, List<SubcategoryMapping>>类型的属性无法被正确解析,最终返回null。
解决方案
方案1:改用System.Text.Json直接读取(最简单)
放弃通过IConfiguration绑定,直接用System.Text.Json读取JSON文件,通过配置允许字符串转数值类型,自动处理整数键映射:
- 新增根模型类匹配JSON结构:
public class RootConfig { public List<Sender> TestMap { get; set; } }
- 读取并反序列化JSON:
using System.Text.Json; using System.Text.Json.Serialization; // 拼接JSON文件路径 var jsonPath = Path.Combine(AppContext.BaseDirectory, "Properties/test.json"); var jsonContent = File.ReadAllText(jsonPath); // 配置序列化选项,允许将字符串解析为数值 var serializeOptions = new JsonSerializerOptions { NumberHandling = JsonNumberHandling.AllowReadingFromString, PropertyNameCaseInsensitive = true // 可选,避免大小写匹配问题 }; // 反序列化获取数据 var rootConfig = JsonSerializer.Deserialize<RootConfig>(jsonContent, serializeOptions); List<Sender> people = rootConfig.TestMap;
此方案会自动处理所有字符串形式的整数键,包括CategoryMappings和SubcategoryMappings的转换。
方案2:自定义配置绑定转换器(适配IConfiguration)
若必须使用IConfiguration绑定,可实现自定义转换器手动转换键类型:
- 实现通用整数键字典转换器:
using Microsoft.Extensions.Configuration; public class IntKeyDictionaryConverter<TValue> : IConfigurationConverter<Dictionary<int, TValue>> { public Dictionary<int, TValue> Convert(IConfiguration configuration) { var dict = new Dictionary<int, TValue>(); foreach (var childSection in configuration.GetChildren()) { if (int.TryParse(childSection.Key, out int key)) { var value = childSection.Get<TValue>(); dict[key] = value; } } return dict.Count > 0 ? dict : null; } }
- 绑定时指定转换器:
var binderOptions = new BinderOptions { Converters = { new IntKeyDictionaryConverter<CategoryMapping>(), new IntKeyDictionaryConverter<List<SubcategoryMapping>>() } }; List<Sender> people = Configuration.GetSection("TestMap").Get<List<Sender>>(binderOptions);
方案3:手动绑定配置节点(最灵活)
若需精细控制,可手动遍历配置节点并转换键类型:
var testMapSection = Configuration.GetSection("TestMap"); List<Sender> people = new List<Sender>(); foreach (var senderSection in testMapSection.GetChildren()) { var sender = new Sender { SenderID = senderSection["SenderID"], FeedType = senderSection["FeedType"], CategoryMappings = new Dictionary<int, CategoryMapping>() }; // 处理CategoryMappings var categorySection = senderSection.GetSection("CategoryMappings"); foreach (var catNode in categorySection.GetChildren()) { if (int.TryParse(catNode.Key, out int catKey)) { var categoryMapping = catNode.Get<CategoryMapping>(); categoryMapping.SubcategoryMappings = new Dictionary<int, List<SubcategoryMapping>>(); // 处理SubcategoryMappings var subcatSection = catNode.GetSection("SubcategoryMappings"); if (subcatSection.Exists()) { foreach (var subcatNode in subcatSection.GetChildren()) { if (int.TryParse(subcatNode.Key, out int subKey)) { var subList = subcatNode.Get<List<SubcategoryMapping>>(); categoryMapping.SubcategoryMappings[subKey] = subList; } } } sender.CategoryMappings[catKey] = categoryMapping; } } people.Add(sender); }
内容的提问来源于stack exchange,提问作者ZpfSysn
相关产品推荐
相关产品推荐

