How to Ignore Get-Only Properties in JSON.Net Without Using JSONignore Attributes

Is there a way to ignore get-only properties in Json.NET without using JsonIgnore attributes?

You can do this by implementing a custom IContractResolver and using that during serialization. If you subclass the DefaultContractResolver, this becomes very easy to do:

class WritablePropertiesOnlyResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
return props.Where(p => p.Writable).ToList();
}
}

Here is a test program demonstrating how to use it:

using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

class Program
{
static void Main(string[] args)
{
Widget w = new Widget { Id = 2, Name = "Joe Schmoe" };

JsonSerializerSettings settings = new JsonSerializerSettings
{
ContractResolver = new WritablePropertiesOnlyResolver()
};

string json = JsonConvert.SerializeObject(w, settings);

Console.WriteLine(json);
}
}

class Widget
{
public int Id { get; set; }
public string Name { get; set; }
public string LowerCaseName
{
get { return (Name != null ? Name.ToLower() : null); }
}
}

Here is the output of the above. Notice that the read-only property LowerCaseName is not included in the output.

{"Id":2,"Name":"Joe Schmoe"}

Newtonsoft JSON - Way of ignoring properties without adding [JsonIgnore]

Yes, this is possible using a custom contract resolver.

Something like this:

public class BaseClass
{
public string BaseClassProperty { get; set; }
}

public class ChildClass: BaseClass
{
public string ChildClassProperty { get; set; }
}

public class CustomContractResolver : DefaultContractResolver
{

protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
var propsToIgnore = typeof(BaseClass).GetProperties().Select(p => p.Name).ToList();

properties =
properties.Where(p => !propsToIgnore.Contains( p.PropertyName) ).ToList();

return properties;
}
}

so then this:

var test = new ChildClass { BaseClassProperty = "a", ChildClassProperty = "b" };

var searialisedString = JsonConvert.SerializeObject(test, new JsonSerializerSettings
{
ContractResolver = new CustomContractResolver()
});

Console.WriteLine(searialisedString);

produces the expected output:

{"ChildClassProperty":"b"}

Json.Net attribute to ignore all properties

If you mark your class with [JsonObject(MemberSerialization.Fields)], that will get you most of the way there. This attribute tells Json.Net that you want it to serialize all fields in a class, regardless of access modifiers, but not properties.

However, if you have any auto properties in your class (i.e. those declared with { get; set; }) then this attribute will cause the compiler-generated backing fields to be serialized as well, which you may not want. To suppress those, you will need to use a custom IContractResolver. You can create one by inheriting from the DefaultContractResolver and overriding the CreateProperty method. In that method, check whether the class has the [JsonObject(MemberSerialization.Fields)] attribute applied, and if so, check whether the member is a compiler-generated field. If it is, then set it to be ignored.

class CustomResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty prop = base.CreateProperty(member, memberSerialization);
JsonObjectAttribute attr = prop.DeclaringType.GetCustomAttribute<JsonObjectAttribute>();
if (attr != null && attr.MemberSerialization == MemberSerialization.Fields &&
member.GetCustomAttribute<CompilerGeneratedAttribute>() != null)
{
prop.Ignored = true;
}
return prop;
}
}

To use the resolver, you need to pass it to the SerializeObject method via the JsonSerializerSettings:

var settings = new JsonSerializerSettings
{
ContractResolver = new CustomResolver(),
Formatting = Formatting.Indented
};
string json = JsonConvert.SerializeObject(yourObject, settings);

Here is a proof of concept: https://dotnetfiddle.net/aNXWbn

How to omit get-only properties only when [JsonProperty] attribute is not set on it?

You can implement your resolver like this:

public class CustomContractResolver : DefaultContractResolver
{
public static readonly CustomContractResolver Instance = new CustomContractResolver();

protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);

// Ignore get-only properties that do not have a [JsonProperty] attribute
if (!property.Writable && member.GetCustomAttribute<JsonPropertyAttribute>() == null)
property.Ignored = true;

return property;
}
}

Fiddle: https://dotnetfiddle.net/4oi04N

Custom JSON contract resolver to ignore all properties without a custom annotation

JsonProperty has an AttributeProvider on it which you can use to find the custom attributes on that property. I recommend you use that. So basically you would try to get the attribute, and if it exists, you set the name like you are doing, otherwise you set Ignored = true.

As an aside, I would recommend you rename your MyCustomProperty class to MyCustomPropertyAttribute, in keeping with standard conventions for classes that derive from System.Attribute. (Don't worry, the [MyCustomProperty("name")] annotation need not change, as the Attribute part is optional in annotations.) You should also apply the [AttributeUsage] attribute to your custom attribute class to indicate how it is allowed to be used. Lastly, I recommend you rename Property to PropertyName to make it clear that it is a name (string) and not the property itself (e.g. PropertyInfo).

So the code would look like this:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class MyCustomPropertyAttribute : Attribute
{
public string PropertyName { get; set; }
public MyCustomPropertyAttribute(string propertyName)
{
PropertyName = propertyName;
}
}

public class CustomResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
MyCustomPropertyAttribute customAttribute = (MyCustomPropertyAttribute)property.AttributeProvider.GetAttributes(typeof(MyCustomPropertyAttribute), true).FirstOrDefault();
if (customAttribute != null)
{
property.PropertyName = customAttribute.PropertyName;
}
else
{
property.Ignored = true;
}
return property;
}
}

Working demo: https://dotnetfiddle.net/thQc0f


All of that said, you don't actually need a custom resolver to get the behavior you want. You could simply apply a [JsonObject(MemberSerialization.OptIn)] attribute to MyClass and then use the normal [JsonProperty] attributes on those properties that you want to be included. Any properties not marked will then be ignored. (See Serialization Attributes in the Json.Net documentation.)

[JsonObject(MemberSerialization.OptIn)]
public class MyClass
{
[JsonProperty("name")]
public string SomeName { get; set; }

[MyCustomProperty("value")]
public string SomeValue { get; set; }

public string AnotherName {get; set; }

public string AnotherValue {get; set; }
}

Demo: https://dotnetfiddle.net/qY6nGR

How to exclude property from Json Serialization

If you are using Json.Net attribute [JsonIgnore] will simply ignore the field/property while serializing or deserialising.

public class Car
{
// included in JSON
public string Model { get; set; }
public DateTime Year { get; set; }
public List<string> Features { get; set; }

// ignored
[JsonIgnore]
public DateTime LastModified { get; set; }
}

Or you can use DataContract and DataMember attribute to selectively serialize/deserialize properties/fields.

[DataContract]
public class Computer
{
// included in JSON
[DataMember]
public string Name { get; set; }
[DataMember]
public decimal SalePrice { get; set; }

// ignored
public string Manufacture { get; set; }
public int StockCount { get; set; }
public decimal WholeSalePrice { get; set; }
public DateTime NextShipmentDate { get; set; }
}

Refer http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size for more details

Ignore a property when deserializing using Json.Net with ItemRequired = Required.Always

Evidently JsonIgnore will only control the serialization in this case. JsonIgnore is required to specify that the FullName property should not be serialized to the json representation.

To ignore the property during deserialization we need to add the JsonProperty annotation with Required = Required.Default (which means not required).

So, this is how to avoid the JsonSerializationException:

[JsonObject(ItemRequired = Required.Always)]
public class Hamster
{
public string FirstName { get; set; }
public string LastName { get; set; }
[JsonIgnore]
[JsonProperty(Required = Required.Default)]
public string FullName { get { return FirstName + LastName; }}
}

Is it possible to make [JsonIgnore] to default and only annotate properties which I want?

Above class:

[JsonObject(MemberSerialization.OptIn)]

Above any property you want to serialize:

[JsonProperty]

Check this link for further information.



Related Topics



Leave a reply



Submit