我们TypeNameHandling = TypeNameHandling.Objects在序列化程序设置中使用 Web API 和 Json.Net 。这工作正常,但我们只在客户端使用类型信息,从不用于反序列化。我们的序列化对象如下所示:
{
"$type": "PROJECTNAME.Api.Models.Directory.DtoName, PROJECTNAME.Api",
"id": 67,
"offices": [{
"$type": "PROJECTNAME.Api.Models.Directory.AnotherDtoName, PROJECTNAME.Api",
"officeName": "FOO"
}]
},
Run Code Online (Sandbox Code Playgroud)
我想自定义$type属性中的值,使其读取为:
{
"$type": "Models.Directory.DtoName",
"id": 67,
"offices": [{
"$type": "Models.Directory.AnotherDtoName",
"officeName": "FOO"
}]
},
Run Code Online (Sandbox Code Playgroud)
我已经有一个从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;
}
Run Code Online (Sandbox Code Playgroud)
在这一点上,我坚持提供财产的价值。
我不确定这是正确的方法,因为ValueProviderJson.Net 中的每个类型都将 aMemberInfo作为构造函数参数。我不有一个MemberInfo供应作为参数,所以....我坚持。
如何添加自定义$type值?由于我不在 C# 中进行反序列化,因此我永远不需要将类型信息转换回类型。
$type您应该创建一个customISerializationBinder和 override ,而不是添加合成属性ISerializationBinder.BindToName。在序列化期间调用此方法以指定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
}
Run Code Online (Sandbox Code Playgroud)
然后你可以DtoName用它序列化你的对象,如下所示:
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
SerializationBinder = new MySerializationBinder(),
TypeNameHandling = TypeNameHandling.Objects,
};
var json = JsonConvert.SerializeObject(dto, Formatting.Indented, settings);
Run Code Online (Sandbox Code Playgroud)
笔记:
NewtonsoftISerializationBinder在10.0.1 版中作为 的替代品引入System.Runtime.Serialization.SerializationBinder,显然是因为某些版本的 .Net 核心中缺少该类型。如果您使用的是 10.0.1 之前的 Json.NET 版本,则需要创建该版本的自定义版本。
另请注意,这SerializationBinder.BindToName()是在 .Net 4.0 中引入的,因此如果您使用旧版本的 Json.NET 和旧版本的 .Net 本身,则此解决方案将不起作用。
由于您没有在 c# 中进行反序列化,因此我只是从BindToType(). 但是如果有人要实现BindToType(),他们应该注意Newtonsoft Json 中 TypeNameHandling 的警告,并确保清理传入的类型以防止构建有害类型。
| 归档时间: |
|
| 查看次数: |
1000 次 |
| 最近记录: |