在创建 JsonObjectContract 时禁止$type
本文关键字:type 禁止 创建 JsonObjectContract | 更新日期: 2023-09-27 18:35:20
我试图强制抑制一些特定的$type输出(同时保留其他输出)Json.NET。它们在我的应用程序中是不必要的。Json.NET 源代码显示了这一点:
private bool ShouldWriteType(...)
{
TypeNameHandling resolvedTypeNameHandling =
((member != null) ? member.TypeNameHandling : null)
?? ((containerProperty != null) ? containerProperty.ItemTypeNameHandling : null)
?? ((containerContract != null) ? containerContract.ItemTypeNameHandling : null)
?? Serializer._typeNameHandling;
这让我认为我可以通过在容器协定中设置ItemTypeNameHandling
来覆盖序列化程序设置。唉,它不适用于数组。我尝试覆盖该方法以获取数组协定,但那里的设置会影响数组中的每个项目。那不是我想要的。(SignalR 发送对象数组中的所有方法参数。这是我的完整演示代码,我试图弄清楚如何在输出中保留A
类型,但抑制B
类型(以及所有sealed
类)。如何覆盖合约解析程序以正确执行此操作?
using System;
using System.Diagnostics;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace DemoBadTypeInclusion
{
class A { public int P1 { get; set; } }
// this attribute doesn't work and I don't want to have to reference Json.NET in my POCO
//[JsonObject(ItemTypeNameHandling = TypeNameHandling.None)]
sealed class B { public int P2 { get; set; } }
internal class DtoContractResolver : DefaultContractResolver
{
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
if (objectType.IsSealed && objectType.BaseType == typeof(object))
{
contract.ItemTypeNameHandling = TypeNameHandling.None;
}
return contract;
}
}
class Program
{
static void Main()
{
var objs = new object[] {new A {P1 = 3}, new B {P2 = 4}};
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto,
NullValueHandling = NullValueHandling.Ignore,
TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple,
ContractResolver = new DtoContractResolver(),
};
var json = JsonConvert.SerializeObject(objs, settings);
Console.WriteLine(json);
if (Debugger.IsAttached)
Console.ReadKey();
}
}
}
更新:在研究了 Json.NET 代码之后,似乎SerializeList
的这一行是我麻烦的根源:
JsonContract valueContract = contract.FinalItemContract ?? GetContractSafe(value);
我想要回退值(GetContractSafe
)。有谁知道如何使FinalItemContract
为空?
如果禁止对象 Array 的一个类型引用,则会使孔 Array 不可反序列化。因此,您可以禁止数组的所有类型引用。
仅禁止对象数组的类型引用
protected override JsonArrayContract CreateArrayContract(Type objectType)
{
var c = base.CreateArrayContract(objectType);
if(objectType == typeof(Object[]))
c.ItemTypeNameHandling = TypeNameHandling.None;
return c;
}
如果不需要反序列化回原始对象,只需设置
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.None,
...
};
我知道这不是一个确切的答案,但我认为没有用用于标识对象数组的某些元素的组件,这些元素具有要反序列化的类型。所以我认为,这就是为什么它不受 json.net 支持的原因
毕竟这里有一种解决方法,它只抑制一种类型:
static void Main()
{
var objs = new object[] { new A { P1 = 3 }, new B { P2 = 4 } };
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects,
NullValueHandling = NullValueHandling.Ignore,
TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple,
ContractResolver = new DtoContractResolver(),
};
var serial = JsonSerializer.Create(settings);
var jsonArray = new JArray();
foreach (var obj in objs)
{
if (obj != null && obj.GetType().IsSealed && obj.GetType().BaseType == typeof(object))
serial.TypeNameHandling = TypeNameHandling.None;
else
serial.TypeNameHandling = TypeNameHandling.Objects;
jsonArray.Add(JObject.FromObject(obj, serial));
}
var json = jsonArray.ToString(Formatting.None);
Console.WriteLine(json);
if (Debugger.IsAttached)
Console.ReadKey();
}