使用 System.Text.Json 有条件地将对象序列化为单个字符串

问题描述 投票:0回答:1

我正在用 C# 开发 ActivityPub 实现,有时链接是像 url 链接一样的“字符串”,有时链接是具有 Link 子类型的对象。 (链接:实体)

我想知道如果一组特定条件为真(只需将一个字符串写入编写器),是否有可能使用 System.Text.Json 将 Link 对象序列化为字符串,并将整个默认对象写入如果条件不成立,请联系作者。

我尝试遵循此解决方案:How to use default serialization in a custom System.Text.Json JsonConverter?,它仍然适用于代码小提琴,但不适用于我的实现,我不太确定为什么。

有谁知道我如何调试这个,或者有更好的方法来确保

Link : Entity
对象有时可以序列化为字符串?

我收到以下错误:

enter image description here

(在这种情况下,我什至尝试将获取的默认 ctor 添加到 修改选项)

无论如何,它表示没有为 Link 类映射数据。 我还尝试将

JsonSerializeable
属性直接添加到 Link 类中。

错误:

类型“ActivityPub.Types.Link”的元数据未提供给序列化器。使用的序列化程序方法不支持基于反射创建序列化相关类型元数据。如果使用源生成,请确保传递给序列化器的所有根类型都已用“JsonSerializedAttribute”指示,以及可能以多态方式序列化的任何类型

我的基础代码库:https://github.com/Meep-Tech/ActivityHub.Net/tree/collapse_links_during_serialization

测试代码:

static void Main(string[] args) {
      Settings.DefaultContext = new Link("ActivityPub.Net.Testing");

      var testObject = new Object {
        Type = "Test",
        At = new Link("/terry") {
          Rels = new string[] {
            "test",
            "test2"
          }
        },
        Attribution = "/meep",
        Audience = new Link("/all") {
          Rel = "test"
        }
      };

      string json = testObject
        .Serialize();

      System.IO.File.WriteAllLines(
        "test.json",
        new[] { json }
      );

      Object @object = json.DeSerializeEntity<Object>();
      System.IO.File.WriteAllLines(
        "test1.json",
        new[] { @object.ToString() }
      );
    }
c# json system.text.json .net-6.0 activitypub
1个回答
2
投票

在我的DefaultConverterFactory<T>

的原始版本中,我缓存了默认转换器,因为在其文档如何在.NET中编写用于JSON序列化(编组)的自定义转换器中,Microsoft建议在序列化复杂对象时缓存出于性能原因所需的任何转换器:

public DictionaryEnumConverterInner(JsonSerializerOptions options) { // For performance, use the existing converter if available. _valueConverter = (JsonConverter<TValue>)options .GetConverter(typeof(TValue)); // Cache the key and value types. _keyType = typeof(TKey); _valueType = typeof(TValue); }

但是,由于以下几个原因,这已被证明是有问题的:

  1. 当使用

    object声明

    类型序列化多态值时,
    GetConverter()
    返回非功能转换器。

  2. 序列化数值时,返回的转换器会忽略

    NumberHandling

     设置。
    

  3. 现在看来您可能遇到了第三个问题:当使用

    编译时序列化器源生成时,返回的转换器可能无法工作。

这些问题足以让我们忽略微软的建议。 简单

DefaultConverter<T>

如下:

public abstract class DefaultConverterFactory<T> : JsonConverterFactory { class DefaultConverter : JsonConverter<T> { readonly JsonSerializerOptions modifiedOptions; readonly DefaultConverterFactory<T> factory; public DefaultConverter(JsonSerializerOptions options, DefaultConverterFactory<T> factory) { this.factory = factory; this.modifiedOptions = options.CopyAndRemoveConverter(factory.GetType()); } public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) => factory.Write(writer, value, modifiedOptions); public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => factory.Read(ref reader, typeToConvert, modifiedOptions); } protected virtual T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions modifiedOptions) => (T)JsonSerializer.Deserialize(ref reader, typeToConvert, modifiedOptions); protected virtual void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions modifiedOptions) => JsonSerializer.Serialize(writer, value, modifiedOptions); public override bool CanConvert(Type typeToConvert) => typeof(T) == typeToConvert; public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) => new DefaultConverter(options, this); } public static class JsonSerializerExtensions { public static JsonSerializerOptions CopyAndRemoveConverter(this JsonSerializerOptions options, Type converterType) { var copy = new JsonSerializerOptions(options); for (var i = copy.Converters.Count - 1; i >= 0; i--) if (copy.Converters[i].GetType() == converterType) copy.Converters.RemoveAt(i); return copy; } }
然后,在从 

DefaultConverterFactory<T>

 派生的任何类(例如 
this one)中,从 JsonConverter<T> defaultConverter
Read()
 中删除最后一个参数 
Write()
,您的代码现在应该可以工作了。

(顺便说一句,您似乎错误地使用了

[JsonSerializable(typeof(Link))]

。您正在将其应用于模型类Link
,但是根据
docs,它应该应用于JsonSerializerContext
的某些子类你的模型——不是模型本身。)

© www.soinside.com 2019 - 2024. All rights reserved.