Cosmos DB RequestOptions Serialize/Deserialize NewtonSoft JsonConvert 失败

Cosmos DB RequestOptions Serialize/Deserialize Fails with NewtonSoft JsonConvert

我正在尝试打包一些参数对象以发送到 Azure Functions HttpTrigger 函数。包的一部分是 Cosmos DB 操作所必需的 RequestOptions 对象。应该很简单,在函数端序列化对象和反序列化。问题是 JsonConvert 不会序列化 RequestOptions 对象的 PartitionKey 对象。 class 是密封的。知道怎么做吗?我的代码是一个简单的测试。创建对象添加分区键。序列化它。反序列化它并检查 PartitionKey 的值。它始终为空。我一直无法找到答案。这似乎是 RequestOptions class 阻止 JsonConvert 序列化的可能错误。

    public static void Main(string[] args)
    {
        var partitionKeyValue = "39393939"; // Some partition key in Cosmos DB collection
        var requestOptions = new RequestOptions
        {
            PartitionKey = new PartitionKey(partitionKeyValue)
        };

        var data = JsonConvert.SerializeObject(requestOptions);

        // send data to Azure Functions
        var requestOptions1 = JsonConvert.DeserializeObject<RequestOptions>(data);
    }

我正在使用 VS 调试器检查这些值。我知道我可以使用 PartitionKey,因为我可以直接在 Azure Functions 函数中对其进行编码并且代码有效。所以问题出在为分区键生成 NULL 的序列化中。如果不能序列化,那意义何在?

PartitionKey class 不会公开 Json.Net 能够 "see" 的任何 public 成员以序列化到 JSON.因此,当您尝试直接序列化它时,它在 JSON 中作为一个空对象出现 {}。在反序列化时,Json.Net 尝试使用 PartitionKey 构造函数但不知道要为 keyValue 参数填充什么,所以它只使用 null。这样就解释了您看到的结果。

我注意到 PartitionKey class 本身似乎有一种支持的方法,可以通过使用其 ToString() 和 [=19= 将其与 JSON 相互转换] 方法。所以如果你想把这个 class 合并到一个更大的序列化中,你可以做一个简单的 JsonConverter 来让它工作:

public class PartitionKeyConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(PartitionKey);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        string s = (string)reader.Value;
        return s != null ? PartitionKey.FromJsonString(s) : null;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteValue(value.ToString());
    }
}

要使用转换器,只需将实例传递给 SerializeObjectDeserializeObject<T> 方法,如下所示:

var data = JsonConvert.SerializeObject(requestOptions, new PartitionKeyConverter());

var requestOptions1 = JsonConvert.DeserializeObject<RequestOptions>(data, new PartitionKeyConverter());

Fiddle: https://dotnetfiddle.net/Jqo7mg