gpt4 book ai didi

c# - CosmosClient : Custom json converter works out of the box with NewtonSoft, 不包含 System.Text.Json

转载 作者:行者123 更新时间:2023-12-03 05:12:06 27 4
gpt4 key购买 nike

场景:

  • 我有一个存储在 Azure 中的 cosmosDb 容器。

  • 我有这种可以读取和写入的数据类:

    public class MyClass {
    public Guid Id { get; private set; }
    public string PartitionKey { get; private set; }

    [JsonConverter(typeof(MyTypeJsonConverter))]
    //[Newtonsoft.Json.JsonConverter(typeof(MyTypeNewtonsoftJsonConverter))]
    public MyType Custom { get; private set; }

    [JsonConstructor] // <-- I've tried with and without this
    public MyClass(Guid id, string pk, MyType custom) {
    Custom = custom; Id = id; PartitionKey = pk;
    }
    }
  • 如您所见,有一个自定义类型 MyType,可以使用自定义转换器进行转换。

  • 出于测试目的,我使用 Newtonsoft 和 System.Text 编写了转换器:

    public class MyTypeJsonConverter : JsonConverter<MyType> {

    public override bool CanConvert(Type objectType) { ... }
    public override void Write(...) { ... }
    public override Context Read(...) { ... }
    }

    public class ContextNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter {

    ...
    }
  • 我知道 MyType 可以工作并且转换器可以工作,因为当我使用 System.Text.Json 和 Newtonsoft.Json 时,序列化和反序列化都按预期工作。就这样做:

      Newtonsoft
    //var myClass = JsonConvert.DeserializeObject<MyClass>(someJson);

    //System.Text.Json
    var myClass2 =
    JsonSerializer.Deserialize<MyClass>(someJson,
    new JsonSerializerOptions()
    { IgnoreNullValues = false, PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  • 当我从 CosmosDb 读取和写入对象时,也会发生类似的反序列化。

         CosmosClientOptions options = new()
    {
    ConnectionMode = DebugHelper.DebugMode ?
    ConnectionMode.Gateway : ConnectionMode.Direct,
    SerializerOptions = new CosmosSerializationOptions
    {
    IgnoreNullValues = false,
    PropertyNamingPolicy = CosmosPropertyNamingPolicy.CamelCase
    },
    };
    var cosmosClient = CosmosClient
    .CreateAndInitializeAsync(connectionString,
    containersList, options)
    .GetAwaiter()
    .GetResult();

    var container = cosmosClient .GetContainer("mydatabase", "mycontainer");


    var items = container.GetItemLinqQueryable<MyType>(allowSynchronousQueryExecution: true);
    foreach (var item in items)
    {
    await container.DeleteItemAsync<MyType>(item.Id.ToString(), new PartitionKey(item.PartitionKey));
    }

问题:

上面的代码与 NewtonSoft 版本完美配合......但是 System.Text.Json 版本失败。

---- Newtonsoft.Json.JsonSerializationException : Error converting value "my string value" to type'MyType'.-------- System.ArgumentException : Could not cast or convert from System.String to MyType.

该异常不会发生内部 ReadWrite转换器的功能。它发生在“之前”。就像 [JsonConverter(...)]属性由 JsonSerializer.Deserialize<Mytype> 理解但不是 cosmosContainer.DoSomethingWithItem<MyType> .

再次;它可以与普通的序列化/反序列化一起使用,并且当我使用 Newtonsoft 时,它可以与 CosmosClient 一起使用。

问题:

  • (在深入研究复杂的 Json 之前)您能发现一个明显错误吗?
  • 我是否需要注册自定义 JsonConverter,如果需要,最紧凑的方法是什么? (任何不需要我实现整个自定义序列化器来传递给 CosmosDb 的东西......除非你能向我证明,有一个很好的解释为什么 Newtonsoft 可以在没有它但 System.Text 的情况下做到这一点.Json 不能)

最佳答案

是的,您可以(并且应该根据您的情况)注册自定义序列化程序:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Azure.Cosmos;

namespace FooBar
{
// Custom implementation of CosmosSerializer which works with System.Text.Json instead of Json.NET.
// https://github.com/Azure/azure-cosmos-dotnet-v3/issues/202
// This is temporary, until CosmosDB SDK v4 is available, which should remove the Json.NET dependency.
public class CosmosNetSerializer : CosmosSerializer
{
private readonly JsonSerializerOptions _serializerOptions;

public CosmosNetSerializer() => this._serializerOptions = null;

public CosmosNetSerializer(JsonSerializerOptions serializerOptions) => this._serializerOptions = serializerOptions;

public override T FromStream<T>(Stream stream)
{
using (stream)
{
if (typeof(Stream).IsAssignableFrom(typeof(T)))
{
return (T)(object)stream;
}

return JsonSerializer.DeserializeAsync<T>(stream, this._serializerOptions).GetAwaiter().GetResult();
}
}

public override Stream ToStream<T>(T input)
{
var outputStream = new MemoryStream();

//TODO: replace with sync variant too?
JsonSerializer.SerializeAsync<T>(outputStream, input, this._serializerOptions).GetAwaiter().GetResult();

outputStream.Position = 0;
return outputStream;
}
}
}
CosmosClientBuilder clientBuilder = new CosmosClientBuilder(sysConfig.CosmosEndpointUri, tokenCredential)
.WithConnectionModeDirect()
// ... With()...
.WithCustomSerializer(new CosmosNetSerializer(Globals.JsonSerializerOptions))

完整示例 here

关于c# - CosmosClient : Custom json converter works out of the box with NewtonSoft, 不包含 System.Text.Json,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76219161/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com