.NET 6 - 通过 PropertyNamingPolicy 使用驼峰命名法进行类型无关的 Json 序列化

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

我需要一种方法通过 asp.net 6 后端读取 json 配置,并将其以 json 格式和驼峰属性名称发送到前端。原始 json 配置使用 PascalCasing 作为其属性名称。后端不知道 json 的格式,因此不可能进行类型化对象绑定。

我尝试的方法是让 ASP.NET 将 json 的这些部分绑定到对象或 JsonElement 属性,但这似乎不起作用,因为未使用默认使用驼峰命名法的 ASP.NET 标准序列化选项通过 JsonElement 序列化器。这看起来非常奇怪和意外的行为,但已被报告并确认为此处的设计功能: https://github.com/dotnet/runtime/issues/61843 https://github.com/dotnet/runtime/issues/66661

第一个指出您不能使用 JsonElement 来实现此目的,而应该使用 JsonNode。 第二个指出 JsonNode 也不支持这一点,这是设计上的。官方文档也证实了这一点。 那么我应该如何使用标准 System.Text.Json 工具提供此功能?对于这种情况,必须编写自己的转换器或使用 Newtonsoft 进行转换似乎很荒谬。

一篇中等帖子似乎提到可以通过在 JsonObject 上使用 ToJsonString 序列化器选项来实现这一点,但我无法复制这种行为。对于我来说,在 .net 6 和 .net 8 上,命名策略仍然被忽略,并且 ToJsonString 输出与从配置中读取的相同的 json。 https://medium.com/@serhiikokhan/mastering-the-use-of-system-text-json-e4d37564ab44

任何提示或建议将不胜感激。

c# asp.net json .net-6.0 system.text.json
1个回答
0
投票

正如您所指出的,此行为是由 MSFT 设计的,请参阅已解决的问题 JsonNode 不尊重 PropertyNamingPolicy #66661 进行确认。

作为解决方法,您可以创建一个自定义

JsonConverter<JsonNode>
,使用
JsonNode
 指定的命名策略来编写 
JsonSerializerOptions.PropertyNamingPolicy
层次结构,如下所示:

public class NamingPolicyJsonNodeConverter : JsonConverter<JsonNode>
{
    public override bool CanConvert(Type typeToConvert) => typeof(JsonNode).IsAssignableFrom(typeToConvert) && !typeof(JsonValue).IsAssignableFrom(typeToConvert);

    public override void Write(Utf8JsonWriter writer, JsonNode? value, JsonSerializerOptions options) 
    {
        var namingPolicy = options.PropertyNamingPolicy;
        switch (value)
        {
            case JsonObject obj:
                writer.WriteStartObject();
                foreach (var pair in obj)
                {
                    writer.WritePropertyName(namingPolicy?.ConvertName(pair.Key) ?? pair.Key);
                    Write(writer, pair.Value, options);
                }
                writer.WriteEndObject();
                break;
            case JsonArray array: // We need to handle JsonArray explicitly to ensure that objects inside arrays are alphabetized
                writer.WriteStartArray();
                foreach (var item in array)
                    Write(writer, item, options);
                writer.WriteEndArray();
                break;
            case null:
                writer.WriteNullValue();
                break;
            default: // JsonValue
                value.WriteTo(writer, options);
                break;
        }
    }
    
    public override JsonNode? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => JsonNode.Parse(ref reader);
}

然后在重新序列化

JsonNode
层次结构时使用它来重新映射属性名称,如下所示:

var options = new JsonSerializerOptions
{
    Converters = { new NamingPolicyJsonNodeConverter() },
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    WriteIndented = true,
};

// Parse or deserialize the JSON using one of the two methods:
// var node = JsonSerializer.Deserialize<JsonNode>(inputJson, options);
var node = JsonNode.Parse(inputJson);   

// Then serializing using the specified options + converter to remap property names:
var outputJson = JsonSerializer.Serialize(node, options);

演示 .NET 6 fiddle 这里

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