Игнорировать свойство, определенное в интерфейсе при сериализации с использованием JSON.net
У меня есть интерфейс с таким свойством:
public interface IFoo {
// ...
[JsonIgnore]
string SecretProperty { get; }
// ...
}
Я хочу, чтобы SecretProperty
игнорировался при сериализации всех реализующих классов. Но мне кажется, что я должен определить атрибут JsonIgnore
для каждой реализации свойства. Есть ли способ достичь этого, не JsonIgnore
атрибут JsonIgnore
к каждой реализации? Я не нашел настройки сериализатора, которые мне помогли.
Ответы
Ответ 1
После небольшого поиска я нашел этот вопрос:
Как наследовать атрибут от интерфейса к объекту при его сериализации с помощью JSON.NET
Я взял код Jeff Sternal и добавил обнаружение JsonIgnoreAttribute
, поэтому он выглядит так:
class InterfaceContractResolver : DefaultContractResolver
{
public InterfaceContractResolver() : this(false) { }
public InterfaceContractResolver(bool shareCache) : base(shareCache) { }
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
var interfaces = member.DeclaringType.GetInterfaces();
foreach (var @interface in interfaces)
{
foreach (var interfaceProperty in @interface.GetProperties())
{
// This is weak: among other things, an implementation
// may be deliberately hiding an interface member
if (interfaceProperty.Name == member.Name && interfaceProperty.MemberType == member.MemberType)
{
if (interfaceProperty.GetCustomAttributes(typeof(JsonIgnoreAttribute), true).Any())
{
property.Ignored = true;
return property;
}
if (interfaceProperty.GetCustomAttributes(typeof(JsonPropertyAttribute), true).Any())
{
property.Ignored = false;
return property;
}
}
}
}
return property;
}
}
Используя этот InterfaceContractResolver
в моих JsonSerializerSettings
, все свойства, имеющие JsonIgnoreAttribute
в любом интерфейсе, также игнорируются, даже если они имеют JsonPropertyAttribute
(из-за порядка внутренних блоков if
).
Ответ 2
Мне было проще прописать DTO только те свойства, которые я хочу, и сериализовать этот объект в JSON. он создает множество небольших объектов, специфичных для контекста, но управление базой кода намного проще, и мне не нужно думать о том, что я сериализую против того, что я игнорирую.
Ответ 3
В более поздних версиях Json.NET применение [JsonIgnore]
к свойствам интерфейса теперь просто работает и успешно предотвращает их сериализацию для всех реализующих типов, если свойство объявлено в том же классе, где интерфейс объявлен. Пользовательский преобразователь контракта больше не требуется.
Например, если мы определим следующие типы:
public interface IFoo
{
[JsonIgnore]
string SecretProperty { get; set; }
string Include { get; set; }
}
public class Foo : IFoo
{
public string SecretProperty { get; set; }
public string Include { get; set; }
}
Затем следующий тест проходит в Json.NET 11 и 12 (и, возможно, также в более ранних версиях):
var root = new Foo
{
SecretProperty = "Ignore Me",
Include = "Include Me",
};
var json = JsonConvert.SerializeObject(root);
Assert.IsTrue(json == "{\"Include\":\"Include Me\"}");// Passes
Демо-скрипты здесь и здесь.
Я считаю, что это было добавлено в Json.NET 4.0.3, несмотря на то, что JsonIgnore
не было явно упомянуто в примечаниях к выпуску:
Новая функция - атрибуты JsonObject и JsonProperty теперь можно размещать на интерфейсе и использовать при сериализации реализующих объектов.
(Реализация может быть найдена в JsonTypeReflector.GetAttribute<T>(MemberInfo memberInfo)
.)
Однако, как отметил Виталием , это не работает, когда свойство наследуется от базового класса класса, в котором объявлен интерфейс. Демонстрационная скрипка здесь.
Ответ 4
Вы должны добавить [DataContract]
перед именем класса.
Он изменяет значение по умолчанию из всех свойств, включая только явно помеченные свойства. После этого добавьте "[DataMember]" перед каждым свойством, которое вы хотите включить в выход JSON.