Add a custom attribute to json.net

后端 未结 3 1843
温柔的废话
温柔的废话 2021-01-02 10:38

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

I want to create some custom ones that get run when the seria

相关标签:
3条回答
  • 2021-01-02 10:56

    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>()
                });
    
    0 讨论(0)
  • 2021-01-02 11:01

    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.

    0 讨论(0)
  • 2021-01-02 11:11

    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();
      }
    }
    
    0 讨论(0)
提交回复
热议问题