Настройте JSON.NET для игнорирования атрибутов DataContract / DataMember

Мы сталкиваемся с ситуацией в проекте MVC3 с сериализаторами Microsoft JSON и JSON.NET.

Всем известно, что DateTime'ы в основном не работают в сериализаторах Microsoft, поэтому мы перешли на JSON.NET, чтобы избежать этой проблемы. Это прекрасно работает, за исключением того, что некоторые классы, которые мы пытаемся сериализовать, являются POCO с атрибутами DataContract / DataMember. Они определены в сборке, на которую ссылаются в нескольких местах. Кроме того, они имеют некоторые другие свойства отображения, которые не помечены как 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] атрибут применяется?

Note: Использование JavaScriptSerializer в .NET прекрасно работает для свойства FullName, но DateTimes не работают. Мне нужно, чтобы JSON.NET игнорировал тот факт, что этот класс имеет атрибуты DataContract / DataMember, и просто выполнял стандартную сериализацию открытых полей, как если бы их там не было.

 Kendall Bennett10 июл. 2012 г., 02:03
Вы решили это? У меня точно такая же проблема, и мне нужно найти решение
 Nick09 авг. 2012 г., 21:53
В итоге я добавил атрибут JsonProperty для Json.Net

Ответы на вопрос(6)

В соответствии с документацией Json.NET[DataMember] атрибуты игнорируются, если свойства также помечены специальными атрибутами Json.NET (такими как[JsonProperty]). См.Документация по атрибутам сериализации для деталей:

Json.NET attributes take presidence over standard .NET serialization attributes, e.g. if both JsonPropertyAttribute and DataMemberAttribute are present on a property and both customize the name, the name from JsonPropertyAttribute will be used.

Документация охватывает только имя свойства, но по моему опыту[JsonProperty] Атрибут также полностью настройки тени, сделанные[DataMember] приписывать. Поэтому, если это возможно для вашего случая, также добавьте атрибуты Json.NET к свойствам, для которых аннотация [DataMember] должна игнорироваться.

Если вы хотите игнорировать присутствиеDataContractAttribute для всех типов без необходимости добавления дополнительных атрибутов, а затемопределитель таможенного договора это правильное решение. Однако, начиная с Json.NET 9.0.1Резольвер Амри больше не работает.Резольвер Doolali работает, но имеет дополнительный побочный эффект сериализацииall общественные объекты, в том числе помеченные[JsonIgnore], Если вам требуется решатель контракта,only игнорирует присутствие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;
        }
    }
}

Вы можете захотетькэшировать обработчик контракта для лучшей производительности.

 17 сент. 2016 г., 02:08
Хорошее исправление, но я заметил, чтоRemoveDataContractAttributeMemberSerialization расточительно вызывается дважды за тип. Это потому чтоbase.Creat,eObjectContract звонкиCreateProperties, Я представилаan issue в JSON.NET об этом.
 17 сент. 2016 г., 01:43
@HappyNomad -DefaultContractResolver не предоставляет простой способ ввода атрибутов. Я переопределяюCreateProperties() пройти вOptOut - но ценностьcontract.MemberSerialization все еще возвращался какOptIn, Поскольку это казалось противоречивым, я решил переопределитьCreateObjectContract() также.
 17 сент. 2016 г., 02:10
Да, я заметил это сразу после публикации моего комментария и переписал мой комментарий.

Просто используйте атрибут OptOut Json.Net. Это будет иметь приоритет над DataContract.

[DataContract]
[JsonObject(MemberSerialization.OptOut)]
 08 июн. 2018 г., 18:13
Огромное спасибо. Это должно быть помечено как правильный ответ. Я работал над очень старым приложением (WCF с RESTFul api) и хотел сериализовать некоторые данные, чтобы передать их в новый сервис web api. это решение работало как шарм. До голосования.

Вы пробовали это?

IgnoreDataMemberAttribute

 Nick15 июн. 2012 г., 20:03
Я хочу сделать противоположное игнорированию поля, я хочу, чтобы поле было включено при сериализации с использованием JSON.NET

Как сказал Амри, вы можете использовать свой собственный 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()
});
 02 мая 2016 г., 19:18
Это не работает.
 21 окт. 2017 г., 11:23
Этот ответ работал на меня для версии Json.NET еще в 2012 году. Я не знаю, будет ли она работать сейчас в 2017 году (кажется, она больше не работает), и, к сожалению, у меня нет Лично мне нужно использовать его сейчас, в 2017 году, поэтому я не буду предлагать работоспособное решение.
 09 июн. 2017 г., 18:32
Отлично. Почему бы и нет? Что не работает? Помогите нам помочь вам.
 12 окт. 2017 г., 21:47
Этот подход также не сработал для меня, Амри, есть ли что-то еще, что ты должен был добавить, чтобы заставить это работать?

Ваш ответ на вопрос