我们在串行器设置中使用TypeNameHandling = TypeNameHandling.Objects
在Json.Net中使用Web API。这工作正常,但我们只在客户端使用类型信息,从不用于反序列化。我们的序列化对象如下所示:
{
"$type": "PROJECTNAME.Api.Models.Directory.DtoName, PROJECTNAME.Api",
"id": 67,
"offices": [{
"$type": "PROJECTNAME.Api.Models.Directory.AnotherDtoName, PROJECTNAME.Api",
"officeName": "FOO"
}]
},
我想自定义$type
属性中的值,使其显示为:
{
"$type": "Models.Directory.DtoName",
"id": 67,
"offices": [{
"$type": "Models.Directory.AnotherDtoName",
"officeName": "FOO"
}]
},
我已经拥有一份继承自CamelCasePropertyNamesContractResolver
的合约解析程序。我想我需要做的是关闭TypeNameHandling
并自己添加自定义属性。我95%在那里:
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var assemblyName = type.Assembly.GetName().Name;
var typeName = type.FullName.Substring(assemblyName.Length + 1);
var typeProperty = new JsonProperty()
{
PropertyName = "$type",
PropertyType = typeof(string),
Readable = true,
Writable = true,
ValueProvider = null // ????? typeName
};
var retval = base.CreateProperties(type, memberSerialization);
retval.Add(typeProperty);
return retval;
}
此时我一直坚持提供物业的价值。
我不确定这是正确的方法,因为Json.Net中的每个ValueProvider
类型都使用MemberInfo
作为构造函数参数。我不 一个MemberInfo
作为参数提供,所以....我被卡住了。
如何添加自定义$type
值?由于我没有在C#中进行反序列化,因此我永远不需要将类型信息转换回类型。
答案 0 :(得分:1)
您应该创建custom ISerializationBinder
并覆盖ISerializationBinder.BindToName
,而不是添加合成$type
属性。在序列化期间调用此方法以指定在启用TypeNameHandling
时要发出的类型信息。
例如,以下删除程序集信息以及命名空间的PROJECTNAME.Api.
部分:
public class MySerializationBinder : ISerializationBinder
{
const string namespaceToRemove = "PROJECTNAME.Api.";
readonly ISerializationBinder binder;
public MySerializationBinder() : this(new Newtonsoft.Json.Serialization.DefaultSerializationBinder()) { }
public MySerializationBinder(ISerializationBinder binder)
{
if (binder == null)
throw new ArgumentNullException();
this.binder = binder;
}
#region ISerializationBinder Members
public void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
binder.BindToName(serializedType, out assemblyName, out typeName);
if (typeName != null && typeName.StartsWith(namespaceToRemove))
typeName = typeName.Substring(namespaceToRemove.Length);
assemblyName = null;
}
public Type BindToType(string assemblyName, string typeName)
{
throw new NotImplementedException();
}
#endregion
}
然后,您可以按如下方式序列化DtoName
对象:
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
SerializationBinder = new MySerializationBinder(),
TypeNameHandling = TypeNameHandling.Objects,
};
var json = JsonConvert.SerializeObject(dto, Formatting.Indented, settings);
注意:
Newtonsoft在ISerializationBinder
中引入release 10.0.1作为System.Runtime.Serialization.SerializationBinder
的替代,显然是因为某些版本的.Net核心缺少该类型。如果您使用的是10.0.1之前的Json.NET版本,则需要创建该版本的自定义版本。
另请注意,{。3}}是在.Net 4.0中引入的,因此如果您使用旧版本的Json.NET和旧版本的.Net本身,那么此解决方案将无效。
< / LI>由于您没有在c#中进行反序列化,我只是从SerializationBinder.BindToName()
引发了异常。但如果有人要实施BindToType()
,他们应该注意 BindToType()
的注意事项,并确保对传入的类型进行清理,以防止构建有害类型。