如何在序列化json时忽略JsonProperty(PropertyName=“someName”)

本文关键字:PropertyName someName JsonProperty 序列化 json | 更新日期: 2024-10-19 03:06:20

我有一些使用ASP的C#代码。Net MVC,它正在使用Json。Net来序列化一些DTO。为了减少负载,我在序列化过程中使用了[JsonProperty(PropertyName="shortName")]属性来使用较短的属性名称。

当客户是另一个时,这非常有效。Net应用程序或服务,因为反序列化将对象层次结构重新组合在一起,使用更长更友好的名称,同时保持较低的实际传输负载。

当客户端通过浏览器使用javascript/ajax时,问题就出现了。它发出请求,并获取json。。。但json使用的是不太友好的缩写名称。

如何使json.net序列化引擎以编程方式忽略[JsonProperty(PropertyName="shortName")]属性?理想情况下,我的MVC服务将在那里运行,并通常使用缩短的属性名称进行序列化。当我的代码检测到一个特定的参数时,我希望使用较长的名称序列化数据,并忽略[JsonProperty()]属性。

有什么建议吗?

谢谢,

Kevin

如何在序列化json时忽略JsonProperty(PropertyName=“someName”)

使用自定义合约解析程序可以很容易地完成这项工作。以下是您需要的所有代码:

class LongNameContractResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        // Let the base class create all the JsonProperties 
        // using the short names
        IList<JsonProperty> list = base.CreateProperties(type, memberSerialization);
        // Now inspect each property and replace the 
        // short name with the real property name
        foreach (JsonProperty prop in list)
        {
            prop.PropertyName = prop.UnderlyingName;
        }
        return list;
    }
}

以下是使用解析器的快速演示:

class Program
{
    static void Main(string[] args)
    {
        Foo foo = new Foo
        {
            CustomerName = "Bubba Gump Shrimp Company",
            CustomerNumber = "BG60938"
        };
        Console.WriteLine("--- Using JsonProperty names ---");
        Console.WriteLine(Serialize(foo, false));
        Console.WriteLine();
        Console.WriteLine("--- Ignoring JsonProperty names ---");
        Console.WriteLine(Serialize(foo, true));
    }
    static string Serialize(object obj, bool useLongNames)
    {
        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.Formatting = Formatting.Indented;
        if (useLongNames)
        {
            settings.ContractResolver = new LongNameContractResolver();
        }
        return JsonConvert.SerializeObject(obj, settings);
    }
}
class Foo
{
    [JsonProperty("cust-num")]
    public string CustomerNumber { get; set; }
    [JsonProperty("cust-name")]
    public string CustomerName { get; set; }
}

输出:

--- Using JsonProperty names ---
{
  "cust-num": "BG60938",
  "cust-name": "Bubba Gump Shrimp Company"
}
--- Ignoring JsonProperty names ---
{
  "CustomerNumber": "BG60938",
  "CustomerName": "Bubba Gump Shrimp Company"
}

只想用反序列化程序类"扩展"Brian的答案

static T Deserialize<T>(string json)
{
    return JsonConvert.DeserializeObject<T>(json, new JsonSerializerSettings()
    {
        ContractResolver = new LongNameContractResolver()
    });
}

如果您正在使用。Net7和System.Text.Json,并试图实现相同的结果,这里有一个利用DefaultJsonTypeInfoResolver的解决方案(从另一篇文章中找到并简化了一点):

1-定义自定义属性,而不是使用JsonPropertyName进行反序列化:

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, Inherited = true)]
public sealed class JsonAlternativeNameAttribute : Attribute
{
    public JsonAlternativeNameAttribute(string? name) => this.Name = name;
    public string? Name { get; private set; }
}

2-添加一个具有以下实现的扩展类:

using System.Reflection;
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using System.Linq;
namespace MyApp.Core.Extension;
    public static class JsonSerializationExtensions
    {
        private static Action<JsonTypeInfo> AlternativeNamesContract() =>
            static typeInfo =>
            {
                if (typeInfo.Kind != JsonTypeInfoKind.Object)
                    return;
                foreach (var property in typeInfo.Properties)
                {
                    if (property.AttributeProvider?.GetCustomAttributes(typeof(JsonAlternativeNameAttribute), true) is { } list && list.Length > 0)
                        property.Name = list.OfType<JsonAlternativeNameAttribute>().FirstOrDefault()?.Name ?? property.GetMemberName() ?? property.Name;
                }
            };
    
        private static string? GetMemberName(this JsonPropertyInfo property) => (property.AttributeProvider as MemberInfo)?.Name;
    
        public static JsonSerializerOptions DefaultDeserializerOptions = 
            new () 
            {
                TypeInfoResolver = new DefaultJsonTypeInfoResolver
                {
                    Modifiers = { AlternativeNamesContract() }
                }
            };
        public static JsonSerializerOptions DefaultSerializerOptions =
            new()
            {
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                PropertyNameCaseInsensitive = true,
                WriteIndented = true
            };
    }

3-使用扩展类中的DefaultDeserializerOptions基于JsonAlternativeName属性中的修饰名称来反序列化模型

class Foo
{
    [JsonAlternativeName("cust-num")]
    public string CustomerNumber { get; set; }
    [JsonAlternativeName("cust-name")]
    public string CustomerName { get; set; }
}
var foo = JsonSerializer.Deserialize<Foo>("your foo json here", JsonSerializationExtensions.DefaultDeserializerOptions);

4-要根据属性名称序列化对象,可以使用自定义的JsonSerializerOptions,而无需设置TypeInfoResolver。扩展类中的DefaultSerializerOptions是一个可以在这里使用的示例:

var jsonString = JsonSerializer.Serialize(new Foo {CustomerName="Joe", CustomerNumber="123"}, JsonSerializationExtensions.DefaultSerializerOptions);

序列化结果为:

{
  "customerNumber": "123",
  "customerName": "Joe"
}