使用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; } }
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.None
的custom 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