Azure Cosmos DB为何将Dictionary<Object>值存为ValueKind?求解决方案
问题现象
使用C# .NET 8.0及Azure Cosmos DB SDK 3.40.0(NoSQL)定义了如下记录类型:
public record test_rec { private System.Collections.Generic.Dictionary<String, Object> m_custom; public System.Collections.Generic.Dictionary<String, Object> custom { get { return m_custom; } set { m_custom = value; } } public test_rec() { init_members(); } private void init_members() { m_custom = null; } }
通过custom属性存储键值对的示例代码:
test_rec rec = new test_rec(); rec.custom = new System.Collections.Generic.Dictionary<String,Object>(); rec.custom.Add("key1", null ); rec.custom.Add("key2", "string" ); rec.custom.Add("key3", 100 );
将记录存入Cosmos DB后,在Azure门户查看custom字段的JSON为:
"custom": { "key1": null, "key2": { "ValueKind": 3 }, "key3": { "ValueKind": 4 } }
期望的正确结果应为:
"custom": { "key1": null, "key2": "string", "key3": 100 }
原因解释
这是因为Cosmos DB SDK默认使用的System.Text.Json序列化器,在处理Dictionary<string, object>中的装箱值类型(如int、string等)时,会将其识别为JsonElement的包装对象,进而序列化出ValueKind属性而非原始值。当值类型被装箱为object类型存入字典时,System.Text.Json无法正确解析其原始类型,导致序列化结果不符合预期。
解决方案
方案1:自定义System.Text.Json转换器
通过配置Cosmos客户端的序列化选项,添加自定义转换器来处理object类型的序列化,确保原始值被正确序列化:
// 自定义转换器 public class ObjectValueTypeConverter : JsonConverter<object> { public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return reader.TokenType switch { JsonTokenType.String => reader.GetString(), JsonTokenType.Number => reader.GetInt32(), JsonTokenType.True => true, JsonTokenType.False => false, JsonTokenType.Null => null, _ => JsonSerializer.Deserialize(ref reader, typeToConvert, options) }; } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) { if (value == null) { writer.WriteNullValue(); return; } var valueType = value.GetType(); if (valueType == typeof(string)) { writer.WriteStringValue((string)value); } else if (valueType == typeof(int)) { writer.WriteNumberValue((int)value); } else if (valueType == typeof(bool)) { writer.WriteBooleanValue((bool)value); } // 按需扩展支持更多值类型(如double、long等) else { JsonSerializer.Serialize(writer, value, valueType, options); } } } // 初始化Cosmos客户端时配置序列化选项 var cosmosOptions = new CosmosClientOptions { SerializerOptions = new JsonSerializerOptions { Converters = { new ObjectValueTypeConverter() } } }; var cosmosClient = new CosmosClient("your-connection-string", cosmosOptions);
方案2:切换到Newtonsoft.Json序列化器
Newtonsoft.Json对object类型的序列化处理更贴合预期,无需自定义转换器即可正确序列化字典中的值类型。
- 安装NuGet包:
Install-Package Microsoft.Azure.Cosmos.NewtonsoftJson
- 配置Cosmos客户端使用NewtonsoftJson序列化器:
var cosmosOptions = new CosmosClientOptions { Serializer = new NewtonsoftJsonSerializer() }; var cosmosClient = new CosmosClient("your-connection-string", cosmosOptions);
内容的提问来源于stack exchange,提问作者bdcoder
相关产品推荐
相关产品推荐

