我们在MVC3项目中遇到了一个同时使用Microsoft JSON序列化程序和 JSON.NET 的情况。
每个人都知道 DateTime 在 Microsoft 的序列化程序中基本上被破坏了,所以我们切换到 JSON.NET 以避免这个问题。 这很好用,除了我们尝试序列化的一些类是具有 DataContract/DataMember 属性的 POCO。 它们在多个位置引用的程序集中定义。 此外,它们还有一些其他显示属性,这些属性未标记为 DataMembers,以提高效率。 例如,客户
[DataContract]
public class Customer
{
[DataMember]
public string FirstName { get; set;}
[DataMember]
public string LastName { get; set;}
public string FullName
{
get
{ return FirstName + " " + LastName; }
}
}
当此客户通过 WCF 传递时,客户端可以引用该程序集并很好地使用 FullName,但是当使用 JSON.NET 序列化时,它会看到 FullName 不是[DataMember]
并且不会对其进行序列化。 是否有一个选项可以传递给 JSON.NET 告诉它忽略类应用了[DataContract]
属性的事实?
注意:在 .NET 中使用 JavaScriptSerializer 可以很好地处理 FullName 属性,但 DateTimes 会损坏。 我需要 JSON.NET 忽略这个类具有 DataContract/DataMember 属性的事实,而只是执行标准的公共字段序列化,就像它们不存在一样。
只需使用 Json.Net 的 OptOut 属性即可。它将优先于数据合同。
[DataContract]
[JsonObject(MemberSerialization.OptOut)]
正如Amry所说,您可以使用自己的IContractResolver。
不幸的是,Amry提供的解决方案对我不起作用,以下是我设法工作的解决方案:
public class AllPropertiesResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
//property.HasMemberAttribute = true;
property.Ignored = false;
//property.ShouldSerialize = instance =>
//{
// return true;
//};
return property;
}
}
有几行评论,这些不是使我的解决方案工作所必需的,但你永远不知道!
这与Amry的解决方案具有相同的用法:
var json = JsonConvert.SerializeObject(result, new JsonSerializerSettings {
ContractResolver = new AllPropertiesResolver()
});
希望这有帮助!
我遇到了一个几乎与您遇到的问题有关的问题,并设法通过 Json.NET 的代码找到了解决方案。所以这可能不是最好的解决方案,但它对我有用。
为此,您需要实现自己的IContractResolver
。过度简化的实现以包含所有参数并忽略所有属性(不仅是DataContract
,还有其他内置 Json.NET 的规则,因此您设置的最初应该影响成员选择的任何选项现在都被以下代码覆盖):
class AllPropertiesResolver : DefaultContractResolver
{
protected override List<MemberInfo> GetSerializableMembers(Type objectType)
{
return objectType.GetProperties()
.Where(p => p.GetIndexParameters().Length == 0)
.Cast<MemberInfo>()
.ToList();
}
}
下面是代码使用示例:
var json = JsonConvert.SerializeObject(result, new JsonSerializerSettings {
ContractResolver = new AllPropertiesResolver()
});
根据 Json.NET 文档[DataMember]
如果属性也使用 Json.NET 特定属性(例如[JsonProperty]
)进行注释,则会忽略属性。有关详细信息,请参阅序列化属性文档:
Json.NET 属性优先于标准的 .NET 序列化属性,例如,如果属性上同时存在 JsonPropertyAttribute 和 DataMemberAttribute 并且都自定义名称,则将使用 JsonPropertyAttribute 中的名称。
该文档仅涵盖 name 属性,但根据我的经验,[JsonProperty]
属性也完全隐藏了 [DataMember]
属性完成的设置。因此,如果对您的情况可行,还要向应忽略 [DataMember] 注释的属性添加 Json.NET 属性。
如果要忽略所有类型的DataContractAttribute
的存在而不必添加其他属性,则自定义协定解析程序是正确的解决方案。 但是,从 9.0.1 Json.NET 开始,Amry 的解析器不再工作。 Doolali 的解析器可以工作,但它具有序列化所有公共属性(包括标有 [JsonIgnore]
的属性)的额外副作用。 如果您需要的协定解析程序仅忽略DataContractAttribute
的存在,但在其他方面的行为类似于默认合同解析程序,则可以使用以下方法:
public class IgnoreDataContractContractResolver : DefaultContractResolver
{
static MemberSerialization RemoveDataContractAttributeMemberSerialization(Type type, MemberSerialization memberSerialization)
{
if (memberSerialization == MemberSerialization.OptIn)
{
type = Nullable.GetUnderlyingType(type) ?? type;
// Json.NET interprets DataContractAttribute as inherited despite the fact it is marked with Inherited = false
// https://json.codeplex.com/discussions/357850
// https://stackoverflow.com/questions/8555089/datacontract-and-inheritance
// https://github.com/JamesNK/Newtonsoft.Json/issues/603
// Thus we need to manually climb the type hierarchy to see if one is present.
var dataContractAttribute = type.BaseTypesAndSelf().Select(t => t.GetCustomAttribute<DataContractAttribute>()).FirstOrDefault(a => a != null);
var jsonObjectAttribute = type.GetCustomAttribute<JsonObjectAttribute>();
if (dataContractAttribute != null && jsonObjectAttribute == null)
memberSerialization = MemberSerialization.OptOut;
}
return memberSerialization;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, RemoveDataContractAttributeMemberSerialization(type, memberSerialization));
return properties;
}
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
contract.MemberSerialization = RemoveDataContractAttributeMemberSerialization(objectType, contract.MemberSerialization);
return contract;
}
}
public static class TypeExtensions
{
public static IEnumerable<Type> BaseTypesAndSelf(this Type type)
{
while (type != null)
{
yield return type;
type = type.BaseType;
}
}
}
您可能希望缓存协定解析程序以获得最佳性能。
你试过这个吗?
忽略数据成员属性