json.net – 如何在根对象上添加属性$type ONLY

前端之家收集整理的这篇文章主要介绍了json.net – 如何在根对象上添加属性$type ONLY前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我想修改我的json.NET序列化程序,只将$type属性添加到实现给定接口但不对任何属性或嵌套对象的对象.

使用TypeNameHandling.Auto(默认)

{
  "PropertyA": 123,"PropertyB": "foo","PropertyC": [1,2,3,4]
}

使用TypeNameHandling.All

{
  "$type": "JsonNetTypeNameHandling.TestEvent,jsonNetTypeNameHandling","PropertyA": 123,"PropertyC": {
    "$type": "System.Collections.Generic.List`1[[System.Int32,mscorlib]],mscorlib","$values": [1,4 ]
  }
}

我想要的是

{
  "$type": "JsonNetTypeNameHandling.TestEvent,4]
}

我正在尝试使用自定义的ContractResolver,但我没有让它工作:

class Program
{
    static void Main(string[] args)
    {
        var serializerSettings = new JsonSerializerSettings()
        {
            TypeNameHandling = TypeNameHandling.Auto,TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple,NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,ContractResolver = new EnableTypeNameHandlingAllOnlyForEvents(),Formatting = Formatting.Indented
        };

        var event1 = new TestEvent() { PropertyA = 123,PropertyB = "foo",PropertyC = new List<int> { 1,4 } };

        string event1Serialized = JsonConvert.SerializeObject(event1,serializerSettings);

        Console.WriteLine(event1Serialized);
        Console.ReadLine();
    }
}

public interface IEvent
{
}

public class TestEvent : IEvent
{
    public int PropertyA { get; set; }
    public string PropertyB { get; set; }
    public List<int> PropertyC { get; set; }
}

public class EnableTypeNameHandlingAllOnlyForEvents : DefaultContractResolver
{
    protected override JsonObjectContract CreateObjectContract(Type objectType)
    {
        var x = base.CreateObjectContract(objectType);

        if (typeof(IEvent).IsAssignableFrom(x.UnderlyingType))
        {
            // What to do to tell json.NET to add $type to instances of this (IEvent) type???
        }

        return x;
    }
}
如果您需要根对象上的“$type”属性,并且可以在嵌套的多态对象和数组中显示,如果需要,请使用以下重载以及TypeNameHandling.Auto: JsonConvert.SerializeObject(Object,Type,JsonSerializerSettings).

docs开始:

06000

type
Type: System.Type
The type of the value being serialized. This parameter is used when TypeNameHandling is Auto to write out the type name if the type of the value does not match. Specifing the type is optional.

即,做:

var serializerSettings = new JsonSerializerSettings()
{
    TypeNameHandling = TypeNameHandling.Auto,Formatting = Formatting.Indented
};

var event1Serialized = JsonConvert.SerializeObject(event1,typeof(IEvent),serializerSettings);

如果在根对象上需要“$type”并且在嵌套的多态对象和数组上不接受它,即使否则需要,您将需要使用TypeNameHandling.All以及设置JsonContainerContract.ItemTypeNameHandling = TypeNameHandling.Nonecustom contract resolver

public class SuppressItemTypeNameContractResolver : DefaultContractResolver
{
    // As of 7.0.1,Json.NET suggests using a static instance for "stateless" contract resolvers,for performance reasons.
    // http://www.newtonsoft.com/json/help/html/ContractResolver.htm
    // http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm
    // "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance."
    static SuppressItemTypeNameContractResolver instance;

    // Using a static constructor enables fairly lazy initialization.  http://csharpindepth.com/Articles/General/Singleton.aspx
    static SuppressItemTypeNameContractResolver() { instance = new SuppressItemTypeNameContractResolver(); }

    public static SuppressItemTypeNameContractResolver Instance { get { return instance; } }

    protected SuppressItemTypeNameContractResolver() : base() { }

    protected override JsonContract CreateContract(Type objectType)
    {
        var contract = base.CreateContract(objectType);
        var containerContract = contract as JsonContainerContract;
        if (containerContract != null)
        {
            if (containerContract.ItemTypeNameHandling == null)
                containerContract.ItemTypeNameHandling = TypeNameHandling.None; 
        }
        return contract;
    }
}

然后使用它像:

var serializerSettings = new JsonSerializerSettings()
{
    TypeNameHandling = TypeNameHandling.All,ContractResolver = SuppressItemTypeNameContractResolver.Instance,serializerSettings);

最后,请注意Newtonsoft docs中的这一注意事项:

TypeNameHandling should be used with caution when your application deserializes JSON from an external source. Incoming types should be validated with a custom SerializationBinder when deserializing with a value other than None.

有关为何需要这样做的讨论,请参阅TypeNameHandling caution in Newtonsoft Json,How to configure Json.NET to create a vulnerable web API和AlvaroMuñoz& Oleksandr Mirosh的黑帽纸https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf

原文链接:https://www.f2er.com/json/288542.html

猜你在找的Json相关文章