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

2024-01-08

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

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

我尝试过以下解决方案:如何在自定义 System.Text.Json JsonConverter 中使用默认序列化? https://stackoverflow.com/questions/65430420/how-to-use-default-serialization-in-a-custom-system-text-json-jsonconverter,它仍然适用于代码小提琴,但不适用于我的实现,我不太清楚为什么。

有谁知道我如何调试这个,或者更好的方法来确保Link : Entity对象有时可以序列化为字符串?

With that I get the following error:enter image description here

(在这种情况下,我什至尝试将获取的默认构造函数添加到modifiedOptions中) 无论如何,它表示没有为 Link 类映射数据。 我还尝试将 JsonSerializeable 属性直接添加到 Link 类中。

错误:Metadata for type 'ActivityPub.Types.Link' was not provided to the serializer. The serializer method used does not support reflection-based creation of serialization-related type metadata. If using source generation, ensure that all root types passed to the serializer have been indicated with 'JsonSerializableAttribute', along with any types that might be serialized polymorphically.

我的基本代码库:https://github.com/Meep-Tech/ActivityHub.Net/tree/collapse_links_during_serialization 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() }
      );
    }

In my 的原始版本DefaultConverterFactory<T> https://stackoverflow.com/revisions/65430421/3,我缓存了默认转换器,因为在其文档中如何在 .NET 中编写用于 JSON 序列化(编组)的自定义转换器 https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to#sample-factory-pattern-converter,出于性能原因,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. 当使用 a 序列化多态值时declared类型object,返回一个非功能转换器GetConverter().

  2. 序列化数值时,返回的转换器会忽略NumberHandling https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.numberhandling?view=net-6.0#System_Text_Json_JsonSerializerOptions_NumberHandling环境。

  3. 现在看来您可能遇到了第三个问题:在使用时编译时序列化器源代码生成 https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-source-generation?pivots=dotnet-6-0,返回的转换器可能无法工作。

这些问题足以让我们忽略微软的建议。简单地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>例如这里这个 https://github.com/Meep-Tech/ActivityHub.Net/blob/collapse_links_during_serialization/Types/Link.cs#L188,去掉最后一个参数JsonConverter<T> defaultConverter from Read() and Write(),您的代码现在应该可以工作了。

(顺便说一句,你似乎正在使用[JsonSerializable(typeof(Link))] https://github.com/Meep-Tech/ActivityHub.Net/blob/05d18532631b33ba765784078b2b95f91589ac1f/Types/Link.cs错。您正在将其应用到您的模型类中Link但是,根据docs https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-source-generation?pivots=dotnet-6-0,它应该应用于某些子类JsonSerializerContext https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonserializercontext?view=net-6.0对于你的模型——而不是模型本身。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • Android ASync 任务 ProgressDialog 在后台线程完成之前不会显示

    我有一个 Android 活动 它从 URL 获取 RSS 提要 并使用 SAX 解析器将 XML 中的每个项目粘贴到数组中 这一切都工作正常 但正如预期的那样 需要一些时间 所以我想使用 AsyncActivity 在后台执行此操作 我的
  • Android 中的 sendStickyBroadcast 和 sendBroadcast 有什么区别

    有什么区别sendStickyBroadcast and sendBroadcast在安卓中 Android SDK 是这么说的sendStickyBroadcast http developer android com reference
  • 从 ASP.NET 应用程序将文件直接上传到 Amazon S3

    我的 ASP NET MVC 应用程序将占用大量带宽和存储空间 如何设置 ASP NET 上传页面 以便用户上传的文件将直接发送到 Amazon S3 而不使用我的 Web 服务器的存储和带宽 2016 年 2 月更新 AWS SDK 现在
  • Angular 2:使用函数生成路由链接/动态生成routerLink

    我想动态创建路线链接 我已经随页面加载了 html 但是 我需要在 URL 中使用 id 该 id 稍后可用 HTML a href Add Content to Cartoon Box a 此路由链接中的链接包含卡通盒的 id carto
  • 如何在Windows 7中控制和调节音量?

    我想在C Win Form中控制和调整Windows 7的音量 任何提示 这是如何做到的 看看这里 http www geekpedia com tutorial176 Get and set the wave sound volume h
  • 从时间戳列中选择日期范围

    目前我的表有一列用于存储日期和时间 该列的数据类型是没有时区的时间戳 所以它的值格式为 2011 09 13 11 03 44 537 我需要检索与日期有关的行 如果我使用 select from table where mdate gt
  • 如何在特定日期用 PHP 和 MySQL 发送邮件?

    我在用PHP and MySQL 我正在尝试发送邮件 但无法正常工作 我想检查两个日期并在特定日期发送邮件 if isset POST mail sub selectDate select from insurance data query
  • wordpress - 使自定义字段值可单击以便稍后检索

    我想在 WordPress 管理面板的所有帖子页面添加一个自定义列 场景是 每个帖子都有一个特色图片 当我查看管理面板中的所有帖子页面时 我有一个自定义列 即 并且每行都有值 我想单击特定行的列值以使其被选中并具有不同的外观 即粗体字体 然
  • HotJar 如何生成他们的录音?

    跟踪鼠标移动 滚动 单击事件很容易 但它们如何保存屏幕并保持同步 页面渲染得非常好 至少对于静态 HTML 页面 尚未在 Angular 或任何 SPA 上进行测试 同步几乎是完美的 要生成并上传 23fps 的屏幕录制 1920x1080
  • Snakemake 通配符:使用目录输出中的通配符文件

    我是 Snakemake 的新手 并尝试在规则中使用特定文件 来自directory 克隆 git 存储库的另一个规则的输出 目前 这给了我一个错误Wildcards in input files cannot be determined
  • Browserify 不起作用 - 为什么?

    我将以下代码浏览到bundle js 并将其包含在我的前端 在加载任何其他 js 文件之前 我浏览器化的文件就是这样的 var firebase require firebase 然后 我在前端包含的下一个文件中对该变量调用authoriz
  • 如何在 Intellij Idea 中使用自定义 sbt 版本?

    我有一个 scala sbt 项目 当我在 intellij 中打开终端并执行 sbt sbtVersion 时 我看到 0 13 8 我想使用我自己的本地安装版本 0 13 5 当我打开新的命令提示符时 我看到 sbt 版本是 0 13
  • 托管身份 - 如何在本地调试

    我正在使用以下代码在我的 Web 应用程序上测试系统托管身份 当我在 Azure 中部署时它工作正常 但有没有办法在本地进行测试 无需向我的 Azure 帐户授予该资源的权限 AzureServiceTokenProvider azureS
  • 由 NullPointerException 引起的一般错误 [50000-175]

    我在客户端 服务器模式下使用 H2 数据库 服务器运行版本为 1 3 175 客户端运行版本为 1 3 168 一切似乎工作正常 但执行一些查询时出现异常 org h2 jdbc JdbcSQLException 一般错误 java lan
  • Java中如何移动数组中的位置?

    一个简单地移动数组元素的程序 两个变量 userInputVariable and blankSpaceVariable 我有一个名为 table 的二维数组 定义为table userInputVariable 1 6 我以表格格式打印这
  • 如何在类中正确实现 Set 作为属性?

    假设我有以下示例 TDelphiIDECompatibility Delphi1 Delphi2 Delphi3 从类中 我如何将上述内容正确实现为属性 我的想法是 在我的组件中 我希望有一个字段 允许您为集合中的某些元素选择 True 或
  • 如何在重定向到另一个页面之前显示加载图像?

    我有一个要加载的图像 我正在使用 onclick 方法进行重定向 因此当有人单击 div 时 会将他们带到另一个页面 当页面重定向到另一个图像时 我如何能够加载 loading gif 图像 我真的很想使用它 因为这对用户更加友好 而且我的
  • 如何在 svg 路径中​​添加图像?

    我想将图像添加到 SVG 路径 我在某种程度上尝试过 但它是一个半生不熟的代码 并且图像没有采用正确的 SVG 形状 下面是该内容的 HTML div class top fold div class curve img div div
  • 使用 MySQL 空间数据获取 Google 地图上最近的地点

    我有一个数据库 其中包含商店列表以及每个商店的纬度和经度 因此 根据我输入的当前 纬度 经度 位置 我想获取某个半径 如 1 公里 5 公里等 内的项目列表 算法应该是什么 我需要算法本身的 PHP 代码 您只需要使用以下查询 例如 您输入
  • 使用 System.Text.Json 有条件地将对象序列化为单个字符串

    我正在用 C 开发 ActivityPub 实现 有时链接是像 url 链接一样的 字符串 有时链接是具有 Link 子类型的对象 链接 实体 我想知道如果一组特定条件为真 只需将一个字符串写入编写器 是否有可能使用 System Text