System.Text.Json API 是否有类似 IContractResolver 的东西

Dži*_*lić 11 c# serialization .net-core asp.net-core system.text.json

在新的System.Text.Json中;命名空间是否有类似 IContractResolver 的东西我正在尝试将我的项目从 Newtonsoft 迁移出去。

这是我试图移动的课程之一:

public class SelectiveSerializer : DefaultContractResolver
{
private readonly string[] fields;

public SelectiveSerializer(string fields)
{
  var fieldColl = fields.Split(',');
  this.fields = fieldColl
      .Select(f => f.ToLower().Trim())
      .ToArray();
}

protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
  var property = base.CreateProperty(member, memberSerialization);
  property.ShouldSerialize = o => fields.Contains(member.Name.ToLower());

  return property;
}
}
Run Code Online (Sandbox Code Playgroud)

Mic*_*iti 5

\n

System.Text.Json 中的等效类型 -JsonClassInfoJsonPropertyInfo- 是内部类型。System.Text.Json 中有一个与DefaultContractResolver 等效的开放增强功能\n #31257 \nasking 的公共等效项。\xe2\x80\x93 dbc 11 月 25 日 19:11

\n
\n

GitHub 问题:

\n\n

请尝试以下操作:
\n我将其编写为 System.Text.Json 的扩展,以提供缺少的功能: https: //github.com/dahomey-technologies/Dahomey.Json

\n

您将找到对编程对象映射的支持。

\n

定义您自己的 IObjectMappingConvention 实现:

\n
public class SelectiveSerializer : IObjectMappingConvention\n{\n    private readonly IObjectMappingConvention defaultObjectMappingConvention = new DefaultObjectMappingConvention();\n    private readonly string[] fields;\n\n    public SelectiveSerializer(string fields)\n    {\n        var fieldColl = fields.Split(\',\');\n        this.fields = fieldColl\n            .Select(f => f.ToLower().Trim())\n            .ToArray();\n    }\n\n    public void Apply<T>(JsonSerializerOptions options, ObjectMapping<T> objectMapping) where T : class\n    {\n        defaultObjectMappingConvention.Apply<T>(options, objectMapping);\n        foreach (IMemberMapping memberMapping in objectMapping.MemberMappings)\n        {\n            if (memberMapping is MemberMapping<T> member)\n            {\n                member.SetShouldSerializeMethod(o => fields.Contains(member.MemberName.ToLower()));\n            }\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

定义你的班级:

\n
public class Employee\n{\n    public int Id { get; set; }\n    public string FirstName { get; set; }\n    public string LastName { get; set; }\n    public string Email { get; set; }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

通过调用 JsonSerializerOptions 命名空间 Dahomey.Json 中定义的扩展方法 SetupExtensions 来设置 json 扩展:

\n
JsonSerializerOptions options = new JsonSerializerOptions();\noptions.SetupExtensions();\n
Run Code Online (Sandbox Code Playgroud)\n

为该类注册新的对象映射约定:

\n
options.GetObjectMappingConventionRegistry().RegisterConvention(\n    typeof(Employee), new SelectiveSerializer("FirstName,Email,Id"));\n
Run Code Online (Sandbox Code Playgroud)\n

然后使用常规 Sytem.Text.Json API 序列化您的类:

\n
Employee employee = new Employee\n{\n    Id = 12,\n    FirstName = "John",\n    LastName = "Doe",\n    Email = "john.doe@acme.com"\n};\n        \nstring json = JsonSerializer.Serialize(employee, options);\n// {"Id":12,"FirstName":"John","Email":"john.doe@acme.com"};\n
Run Code Online (Sandbox Code Playgroud)\n


dbc*_*dbc 5

合约自定义将在 .NET 7 中实现,并在Preview 6中提供。

\n

从Eirik Tsarpalis、Krzysztof Wicher 和 Layomi Akinrinade 的文档页面What\xe2\x80\x99s new in System.Text.Json in .NET 7: Contract Customization 中:

\n
\n

给定类型的合约元数据T使用 表示JsonTypeInfo<T>,在以前的版本中,它充当专门在源生成器 API 中使用的不透明令牌。从 .NET 7 开始,JsonTypeInfo合约元数据的大多数方面都已公开并可供用户修改。合约定制允许用户使用接口的实现编写自己的 JSON 合约解析逻辑IJsonTypeInfoResolver

\n
public interface IJsonTypeInfoResolver\n{\n    JsonTypeInfo? GetTypeInfo(Type type, JsonSerializerOptions options);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

合同解析器返回给JsonTypeInfoTypeJsonSerializerOptions组合的配置实例。如果解析器不支持指定输入类型的元数据,它可以返回 null。

\n

由默认的、基于反射的序列化器执行的合约解析现在通过DefaultJsonTypeInfoResolver实现IJsonTypeInfoResolver.

\n

从 .NET 7 开始,JsonSerializerContext源生成中使用的类也实现了IJsonTypeInfoResolver.

\n
\n

IJsonTypeInfoResolver您可以通过以下方法之一创建自己的:

\n
    \n
  1. 您可以子类化DefaultJsonTypeInfoResolver并覆盖GetTypeInfo(Type, JsonSerializerOptions). 这类似于覆盖 Json.NET 的DefaultContractResolver.CreateContract().

    \n
  2. \n
  3. 您可以添加一个Action<JsonTypeInfo>toDefaultJsonTypeInfoResolver.Modifiers来修改创建后为选定类型生成的默认值JsonTypeInfo

    \n

    使用此方法组合多个自定义看起来比使用继承方法更容易。但是,由于修改器操作是按顺序应用的,因此后面的修改器可能会与之前的修改器发生冲突。

    \n
  4. \n
  5. 您可以从头开始创建自己的IJsonTypeInfoResolver合约,只为您感兴趣的类型创建合约,并通过JsonTypeInfoResolver.Combine(IJsonTypeInfoResolver[]).

    \n

    JsonTypeInfoResolver.Combine()当您想要将编译时生成的JsonSerializerContext实例与仅针对某些类型自定义序列化的运行时契约解析器一起使用时,也很有用。

    \n
  6. \n
\n

一旦您有了自定义解析器,您就可以通过 进行设置JsonSerializerOptions.TypeInfoResolver

\n

因此,您可以使用修饰符大致如下SelectiveSerializer转换为 a 。DefaultJsonTypeInfoResolver首先定义以下流畅的扩展方法:

\n
public static partial class JsonSerializerExtensions\n{\n    public static DefaultJsonTypeInfoResolver SerializeSelectedFields(this DefaultJsonTypeInfoResolver resolver, string fields) =>\n        SerializeSelectedFields(resolver, fields?.Split(\',\', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) ?? throw new ArgumentNullException(nameof(fields)));\n\n    public static DefaultJsonTypeInfoResolver SerializeSelectedFields(this DefaultJsonTypeInfoResolver resolver, IEnumerable<string> membersToSerialize)\n    {\n        if (resolver == null)\n            throw new ArgumentNullException(nameof(resolver));\n        if (membersToSerialize == null)\n            throw new ArgumentNullException(nameof(membersToSerialize));\n        var membersToSerializeSet =  membersToSerialize.ToHashSet(StringComparer.OrdinalIgnoreCase); // Possibly this should be changed to StringComparer.Ordinal\n        resolver.Modifiers.Add(typeInfo => \n                               {\n                                   if (typeInfo.Kind == JsonTypeInfoKind.Object)\n                                   {\n                                       foreach (var property in typeInfo.Properties)\n                                       {\n                                           if (property.GetMemberName() is {} name && !membersToSerializeSet.Contains(name))\n                                               property.ShouldSerialize = static (obj, value) => false;\n                                       }\n                                   }\n                               });\n        return resolver;\n    }\n    \n    public static string? GetMemberName(this JsonPropertyInfo property) => (property.AttributeProvider as MemberInfo)?.Name;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

现在您可以按如下方式设置您的JsonSerializerOptions例如:

\n
var options = new JsonSerializerOptions\n{\n    TypeInfoResolver = new DefaultJsonTypeInfoResolver()\n        .SerializeSelectedFields("FirstName,Email,Id"),\n    // Add other options as required\n    PropertyNamingPolicy = JsonNamingPolicy.CamelCase, \n    WriteIndented = true,\n};\n
Run Code Online (Sandbox Code Playgroud)\n

笔记:

\n\n