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)
\n\nSystem.Text.Json 中的等效类型 -
\nJsonClassInfo
和JsonPropertyInfo
- 是内部类型。System.Text.Json 中有一个与DefaultContractResolver 等效的开放增强功能\n #31257 \nasking 的公共等效项。\xe2\x80\x93 dbc 11 月 25 日 19:11
GitHub 问题:
\n请尝试以下操作:
\n我将其编写为 System.Text.Json 的扩展,以提供缺少的功能: https: //github.com/dahomey-technologies/Dahomey.Json。
您将找到对编程对象映射的支持。
\n定义您自己的 IObjectMappingConvention 实现:
\npublic 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定义你的班级:
\npublic 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 扩展:
\nJsonSerializerOptions options = new JsonSerializerOptions();\noptions.SetupExtensions();\n
Run Code Online (Sandbox Code Playgroud)\n为该类注册新的对象映射约定:
\noptions.GetObjectMappingConventionRegistry().RegisterConvention(\n typeof(Employee), new SelectiveSerializer("FirstName,Email,Id"));\n
Run Code Online (Sandbox Code Playgroud)\n然后使用常规 Sytem.Text.Json API 序列化您的类:
\nEmployee 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
合约自定义将在 .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\n给定类型的合约元数据
\nT
使用 表示JsonTypeInfo<T>
,在以前的版本中,它充当专门在源生成器 API 中使用的不透明令牌。从 .NET 7 开始,JsonTypeInfo
合约元数据的大多数方面都已公开并可供用户修改。合约定制允许用户使用接口的实现编写自己的 JSON 合约解析逻辑IJsonTypeInfoResolver
:Run Code Online (Sandbox Code Playgroud)\npublic interface IJsonTypeInfoResolver\n{\n JsonTypeInfo? GetTypeInfo(Type type, JsonSerializerOptions options);\n}\n
合同解析器返回给
\nJsonTypeInfo
定Type
和JsonSerializerOptions
组合的配置实例。如果解析器不支持指定输入类型的元数据,它可以返回 null。由默认的、基于反射的序列化器执行的合约解析现在通过
\nDefaultJsonTypeInfoResolver
实现IJsonTypeInfoResolver
.从 .NET 7 开始,
\nJsonSerializerContext
源生成中使用的类也实现了IJsonTypeInfoResolver
.
IJsonTypeInfoResolver
您可以通过以下方法之一创建自己的:
您可以子类化DefaultJsonTypeInfoResolver
并覆盖GetTypeInfo(Type, JsonSerializerOptions)
. 这类似于覆盖 Json.NET 的DefaultContractResolver.CreateContract()
.
您可以添加一个Action<JsonTypeInfo>
toDefaultJsonTypeInfoResolver.Modifiers
来修改创建后为选定类型生成的默认值JsonTypeInfo
。
使用此方法组合多个自定义看起来比使用继承方法更容易。但是,由于修改器操作是按顺序应用的,因此后面的修改器可能会与之前的修改器发生冲突。
\n您可以从头开始创建自己的IJsonTypeInfoResolver
合约,只为您感兴趣的类型创建合约,并通过JsonTypeInfoResolver.Combine(IJsonTypeInfoResolver[])
.
JsonTypeInfoResolver.Combine()
当您想要将编译时生成的JsonSerializerContext
实例与仅针对某些类型自定义序列化的运行时契约解析器一起使用时,也很有用。
一旦您有了自定义解析器,您就可以通过 进行设置JsonSerializerOptions.TypeInfoResolver
。
因此,您可以使用修饰符大致如下SelectiveSerializer
转换为 a 。DefaultJsonTypeInfoResolver
首先定义以下流畅的扩展方法:
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
例如:
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笔记:
\nJsonPropertyInfo.ShouldSerialize
(也是.NET 7 中的新增功能)可用于属性的条件序列化。
当 aJsonPropertyInfo
由反射或源生成解析器创建时,JsonPropertyInfo.AttributeProvider
将是底层的PropertyInfo
或FieldInfo
。
为了确认这一点,请参阅layomia对System.Text.Json的评论:In .NET 7, how can I certain the JsonPropertyInfo created for a certain member, so I can custom the serialization of that member? #77761 .
\n所有序列化元数据都应使用区域设置不变的字符串逻辑来构造。在您的代码中,您使用ToLower()
但最好使用ToLowerInvariant()
. 在我的修饰符操作中,我使用StringComparer.OrdinalIgnoreCase
它避免了将字符串小写的需要。
System.Text.Json 默认情况下区分大小写,因此您可能希望在过滤选定字段时使用区分大小写的属性名称匹配。
\n 归档时间: |
|
查看次数: |
6157 次 |
最近记录: |