web-dev-qa-db-ja.com

JSON.NETを構成してDataContract / DataMember属性を無視する

Microsoft JSONシリアライザーとJSON.NETの両方を使用するMVC3プロジェクトで状況が発生しています。

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]ではなく、シリアル化されません。クラスに[DataContract]属性が適用されているという事実を無視するように指示するために、JSON.NETに渡すオプションはありますか?

注: .NETでJavaScriptSerializerを使用すると、FullNameプロパティで問題なく機能しますが、DateTimeが壊れます。このクラスにDataContract/DataMember属性があるという事実を無視して、そこにない場合と同じように標準のパブリックフィールドのシリアル化を行うには、JSON.NETが必要です。

35
Nick

Json.NetのOptOut属性を使用するだけです。 DataContractよりも優先されます。

[DataContract]
[JsonObject(MemberSerialization.OptOut)]
31
seldary

アムリーが言ったように、独自の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()
});

お役に立てれば!

18
Doolali

私はあなたが持っているものにほぼ関連する問題を抱えていたので、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()
});
14
Amry

Json.NETのドキュメントによると、プロパティがJson.NET固有の属性([DataMember]など)でも注釈が付けられている場合、[JsonProperty]属性は無視されます。 シリアル化属性のドキュメント を参照してください。詳細については:

Json.NET属性は、標準の.NETシリアル化属性よりも優先されます。 JsonPropertyAttributeとDataMemberAttributeの両方がプロパティに存在し、両方が名前をカスタマイズする場合、JsonPropertyAttributeの名前が使用されます。

ドキュメントはnameプロパティのみをカバーしていますが、私の経験では、[JsonProperty]属性も[DataMember]属性によって行われた設定を完全に隠しています。したがって、ケースに適している場合は、[DataMember]アノテーションを無視する必要があるプロパティにJson.NET属性も追加します。

8
rene

追加の属性を追加せずにすべてのタイプのDataContractAttributeの存在を無視する場合は、 カスタムコントラクトリゾルバー が正しい解決策です。ただし、Json.NET 9.0.1以降 Amryのリゾルバー は機能しなくなりました。 Doolaliのリゾルバー は機能しますが、シリアル化allのパブリックプロパティに [JsonIgnore]onlyDataContractAttributeの存在を無視するコントラクトリゾルバーが必要であるが、それ以外の場合はデフォルトのコントラクトリゾルバーのように動作する場合、以下を使用できます。 :

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;
        }
    }
}

最高のパフォーマンスを得るためにコントラクトリゾルバーをキャッシュする にすることもできます。

8
dbc