Add a custom attribute to json.net

JSON.NET comes with property attributes like [JsonIgnore] and [JsonProperty].

I want to create some custom ones that get run when the serialisation runs e.g. [JsonIgnoreSerialize] or [JsonIgnoreDeserialize]

How would I go about extending the framework to include this?

You can write a custom contract resolver like this

public class MyContractResolver<T> : Newtonsoft.Json.Serialization.DefaultContractResolver 
                                        where T : Attribute
{
    Type _AttributeToIgnore = null;

    public MyContractResolver()
    {
        _AttributeToIgnore = typeof(T);
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        var list =  type.GetProperties()
                    .Where(x => !x.GetCustomAttributes().Any(a => a.GetType() == _AttributeToIgnore))
                    .Select(p => new JsonProperty()
                    {
                        PropertyName = p.Name,
                        PropertyType = p.PropertyType,
                        Readable = true,
                        Writable = true,
                        ValueProvider = base.CreateMemberValueProvider(p)
                    }).ToList();

        return list;
    }
}

You can use it in serialization/deserialization like

var json = JsonConvert.SerializeObject(
            obj, 
            new JsonSerializerSettings() {
                ContractResolver = new MyContractResolver<JsonIgnoreSerialize>()
            });

var obj = JsonConvert.DeserializeObject<SomeType>(
            json, 
            new JsonSerializerSettings() {
                ContractResolver = new MyContractResolver<JsonIgnoreDeserialize>()
            });

Serialization Attributes, public enum UserStatus { NotConfirmed, Active, Deleted } public class User { public string UserName { get; set; } [JsonConverter(typeof(StringEnumConverter ))]� This sample uses the T:Newtonsoft.Json.JsonConverterAttribute to specify that a T:Newtonsoft.Json.JsonConverter should be used when serializing and deserializing a property.

Since your goal is to ignore a property on serialization but not deserialization, you can use a ContractResolver.

Note that the following class does just that, and is based on CamelCasePropertyNamesContractResolver, to make sure it serializes to camel-cased Json fields. If you don't want that, you can make it inherit from DefaultContractResolver instead.

Also, the example I had myself is based on the name of a string, but you can easily check if the property is decorated by your custom attribute instead of comparing the property name.

public class CamelCaseIgnoringPropertyJsonResolver<T> : CamelCasePropertyNamesContractResolver
{        
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        // list the properties to ignore
        var propertiesToIgnore =  type.GetProperties()
                .Where(x => x.GetCustomAttributes().OfType<T>().Any());

        // Build the properties list
        var properties = base.CreateProperties(type, memberSerialization);

        // only serialize properties that are not ignored
        properties = properties
            .Where(p => propertiesToIgnore.All(info => info.Name != p.UnderlyingName))
            .ToList();

        return properties;
    }
}

Then, you can use it as follows:

    static private string SerializeMyObject(object myObject)
    {
        var settings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCaseIgnoringPropertyJsonResolver<JsonIgnoreSerializeAttribute>()
        };

        var json = JsonConvert.SerializeObject(myObject, settings);
        return json;
    }

Finally, the custom attribute can be of any type, but to match the example:

internal class JsonIgnoreSerializeAttribute : Attribute
{
}

The approach is tested, and also works with nested objects.

JsonConverterAttribute on a property, The web service used one-letter property names, and I wanted to have something a little more descriptive in my code, public string ProbabilityOfPrecipitation { get; set; } The solution? Custom contract resolvers. JSON.Net has a class called� Register a custom converter to make the Serialize and Deserialize methods use it. Choose one of the following approaches: Add an instance of the converter class to the JsonSerializerOptions.Converters collection. Apply the [JsonConverter] attribute to the properties that require the custom converter.

Not sure if this is new, but I would suggest using the method GetSerializableMembers which handles the member infos directly. This way, one can avoid having to deal with the JsonProperty.

public class MyJsonContractResolver : DefaultContractResolver
{
  protected override List<MemberInfo> GetSerializableMembers(Type objectType)
  {
    return base.GetSerializableMembers(objectType)
      .Where(mi => mi.GetCustomAttribute<JsonIgnoreSerializeAttribute>() != null)
      .ToList();
  }
}

Using Custom Contract Resolvers for JSON.NET, Add an instance of the converter class to the JsonSerializerOptions.Converters collection. Apply the [JsonConverter] attribute to the properties that� How can I add a custom root node when serializing an object with JSON.NET? (4) I have added a custom property to some of my objects like this: The attribute is

How to write custom converters for JSON serialization, Register this custom converter by using an attribute on individual long properties or by adding the converter to the Converters collection. The MemberSerialization flag on this attribute specifies whether member serialization is opt-in (a member must have the JsonProperty or DataMember attribute to be serialized), opt-out (everything is serialized by default but can be ignored with the JsonIgnoreAttribute, Json.NET's default behavior) or fields (all public and private fields are serialized and properties are ignored).

Migrate from Newtonsoft.Json to System.Text.Json, JSON.NET, by default, will not allow serializing custom property back to the object, we can use reflection same way to set the property value. One possible reason is it does not have a parameterless constructor. (A parameterless constructor is required when using the converter from the [JsonConverter] attribute because Json.net would not know what to pass to other constructors in order to instantiate the converter.) – Brian Rogers Oct 3 '13 at 19:24

Reflection Deserialization and Custom Attributes, A JSON serializer that uses Newtonsoft Json.NET. Json.NET attributes are supported. NET serializer adds a Byte Order Mark (BOM). To disable In the example below, the custom writer omits the Byte Order Mark (BOM). For an example of a custom plain text input formatter, see TextPlainInputFormatter on GitHub. View or download sample code (how to download) When to use custom formatters. Use a custom formatter to add support for a content type that isn't handled by the built-in formatters. Overview of how to use a custom formatter. To create a custom formatter:

Comments
  • do they need to be attributes ? what do you want to do in your custom serialization attribute ?
  • I would like to be able to ignore a property on serialisation but not on deserialisation. I thought it would be easy to just add an attribute e.g. [JsonIgnoreSerialize] to the property.
  • This solution works as advertised, but it has a problem: it does not honor the standard Json.NET attributes [JsonIgnore] and (more importantly) [JsonProperty]. See dotnetfiddle.net/Et265h. You should be calling base.CreateProperties() first, then filtering that list based on the custom attributes. See dotnetfiddle.net/gDGfrO.
  • I did not downvote, but I would guess the reason is that your solution does not actually show how to implement the custom attributes as was originally asked. Instead, one has to pass the name of the property to ignore to your resolver and it only handles that single property. What if there are more than one?
  • Fair enough, Brian. Thank you for the constructive comment :)
  • I have updated my answer with a more suitable implementation.
  • Looks better. One question: what is TrackExtended in the signature of your SerializeMyObject method? Shouldn't that just be object?
  • Absolutely. Sorry, that was a leftover of my sample to test the code ;) -Fixed!