C#中appsettings.json转类对象遇IConvertible实现问题
问题描述
appsettings 配置
"testData": [ { "target": "MarketMirrorClient.GetContests", "mockData": [ { "request": { "contestKeys": [ "testContestKey1" ] }, "response": { "contests": [ { "contestKey": "testContestKey1", "contestType": "football", "contestStatus": "InPlay" } ] } }, { "request": { "contestKeys": [ "testContestKey2" ] }, "response": { "contests": [ { "contestKey": "testContestKey2", "contestType": "soccer", "contestStatus": "PreGame" } ] } } ] } ]
模型类代码
public class MockTestData { public List<TestData> TestData { get; set; } = new(); } public class TestData { public string Target { get; set; } public List<MockData> MockData { get; set; } = new(); } public class MockData { public Dictionary<string, object> Request { get; set; } public object Response { get; set; } }
问题场景
执行 builder.Services.Configure<MockTestData>("testData"); 绑定配置时,testData.mockData.request 被序列化为 Dictionary<string, object>,但从字典中取出对象转换为特定类型(如 List<string>)时,抛出需实现 IConvertible 的异常。尝试将类型改为 dynamic 或 ExpandoObject,要么仍提示需要 IConvertible,要么无法转换为目标类型。
解决方案
不需要手动实现 IConvertible,问题根源在于配置绑定的类型匹配逻辑,以下是几种可行处理方式:
1. 强类型绑定替代字典
如果Request的结构固定,直接定义对应强类型类,避免使用 Dictionary<string, object>:
// 新增Request的强类型类 public class ContestRequest { public List<string> ContestKeys { get; set; } = new(); } // 修改MockData类 public class MockData { public ContestRequest Request { get; set; } public object Response { get; set; } }
配置绑定时会直接将contestKeys序列化为List<string>,无需后续手动转换,自然不会触发IConvertible异常。
2. 自定义配置绑定转换器
如果Request结构不固定必须用字典,可自定义类型转换器处理object到目标类型的转换(以Newtonsoft.Json为例):
public class ObjectToListConverter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(List<>); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.StartArray) { var listType = objectType.GetGenericArguments()[0]; var list = Activator.CreateInstance(objectType); var addMethod = objectType.GetMethod("Add"); while (reader.Read() && reader.TokenType != JsonToken.EndArray) { var item = serializer.Deserialize(reader, listType); addMethod.Invoke(list, new[] { item }); } return list; } return existingValue; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { serializer.Serialize(writer, value); } }
注册转换器并完成配置绑定:
builder.Services.Configure<MockTestData>(options => { var configSection = builder.Configuration.GetSection("testData"); var rawJson = configSection.GetRawJson(); JsonConvert.PopulateObject(rawJson, options, new JsonSerializerSettings { Converters = { new ObjectToListConverter() } }); });
3. 序列化工具手动转换
如果不想修改绑定逻辑,从字典取到object后,用Json序列化工具重新反序列化为目标类型:
// 从Request字典中取出contestKeys对象 var contestKeysObj = mockData.Request["contestKeys"]; // 通过序列化再反序列化完成类型转换 var contestKeys = JsonConvert.DeserializeObject<List<string>>(JsonConvert.SerializeObject(contestKeysObj));
这种方式利用Json工具的类型转换能力,绕开IConvertible的要求。
内容的提问来源于stack exchange,提问作者Maxx
相关产品推荐
相关产品推荐

