将自定义属性添加到json.net

时间:2015-10-02 13:45:48

标签: c# .net attributes json.net

JSON.NET附带了[JsonIgnore][JsonProperty]等属性属性。

我想创建一些在序列化运行时运行的自定义项,例如 [JsonIgnoreSerialize]或[JsonIgnoreDeserialize]

我如何扩展框架以包含此内容?

3 个答案:

答案 0 :(得分:9)

您可以像这样编写自定义合约解析程序

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;
    }
}

您可以在序列化/反序列化中使用它,如

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

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

答案 1 :(得分:3)

由于您的目标是忽略序列化但不反序列化的属性,因此您可以使用ContractResolver

请注意,以下类就是这样做的,它基于CamelCasePropertyNamesContractResolver,以确保它序列化为驼峰式Json字段。如果您不想要,则可以将其从DefaultContractResolver继承。

此外,我自己的示例基于字符串的名称,但您可以轻松检查属性是否由自定义属性修饰,而不是比较属性名称。

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;
    }
}

然后,您可以按如下方式使用它:

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

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

最后,自定义属性可以是任何类型,但要匹配示例:

internal class JsonIgnoreSerializeAttribute : Attribute
{
}

该方法经过测试,也适用于嵌套对象。

答案 2 :(得分:0)

不知道这是否是新的,但我建议使用直接处理成员信息的方法GetSerializableMembers。这样,就可以避免不得不处理JsonProperty。

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