10

I have some objects that I want to serialize as JSON. However, some of the objects have properties which are deemed 'SensitiveData' via attributes.

[SensitiveDataAttribute]
public string SomeSensitiveProperty {get; set;}

At the moment, I am overriding the 'CreateProperty' method on the serializer so that I can alter whether or not a property should be serialized dependent upon whether it has this 'SensitiveData' attribute:

public class SensitiveDataResolver : DefaultContractResolver
    {
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            var property = base.CreateProperty(member, memberSerialization);
            property.ShouldSerialize = instance =>
            {
                if (member is PropertyInfo)
                {
                    var prop = (PropertyInfo) member;
                    var isSensitiveData = Attribute.IsDefined(prop, typeof (SensitiveDataAttribute));
                    return !isSensitiveData;
                }
                return false;
            };
            return property;
        }
    }
}

When I serialize, I then use that resolver as settings for the serializer:

var settings = new JsonSerializerSettings() { ContractResolver = new SensitiveDataResolver() };
var requestString = JsonConvert.SerializeObject(someObject, settings);

My problem is, I don't want the properties to be excluded from the serialization. I want them to be serialized but with the default value 'SensitiveData' set against them.

Is there a way I can achieve this using Attributes?

Tom Bowers
  • 4,951
  • 3
  • 30
  • 43
JBond
  • 3,062
  • 5
  • 27
  • 31
  • Does this answer your question? [Overriding a property value in custom JSON.net contract resolver](https://stackoverflow.com/questions/46977905/overriding-a-property-value-in-custom-json-net-contract-resolver) – Liam Jul 10 '20 at 11:32

4 Answers4

10

Instead of using the ShouldSerialize method, you can just override the property value if the member has the attribute. To do this, you need to supply a custom IValueProvider for Json.NET to use when serializing.

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

    if (member is PropertyInfo)
    {
        var prop = (PropertyInfo)member;
        var isSensitiveData = Attribute.IsDefined(prop, typeof (SensitiveDataAttribute));

        if (isSensitiveData)
            property.ValueProvider = new StringValueProvider("SensitiveData");
    }

    return property;
}

StringValueProvider is a custom implementation of the IValueProvider interface.

public class StringValueProvider : IValueProvider
{
    private readonly string _value;

    public StringValueProvider(string value)
    {
        _value = value;
    }

    public void SetValue(object target, object value)
    {
        throw new NotSupportedException();
    }

    public object GetValue(object target)
    {
        return _value;
    }
}
Tom Bowers
  • 4,951
  • 3
  • 30
  • 43
1

Implement IValueProvider for sensitive data property and use it for PropertyValueProvider.

public class SensitiveDataProvider : IValueProvider
{
    readonly string sesitiveDatatag = "Sensitive Data";
    public object GetValue(object target)
    {
        return sesitiveDatatag;
    }

    public void SetValue(object target, object value)
    {
        target = sesitiveDatatag;
    }
}

Now your DefaultContractResolver would be:

    public class SensitiveDataResolver : DefaultContractResolver
    {
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            var property = base.CreateProperty(member, memberSerialization);

            if (member is PropertyInfo)
            {
                var prop = (PropertyInfo)member;
                var isSensitiveData = Attribute.IsDefined(prop, typeof(SensitiveDataAttribute));

                if(isSensitiveData)
                {
                    property.ValueProvider = new SensitiveDataProvider();
                }
            }

            return property;
        }
    }
vendettamit
  • 14,315
  • 2
  • 32
  • 54
0

Instead of setting property.ShouldSerialize you can overwrite the property value itself.

public class SensitiveDataResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        if (this.IsSensitiveProperty(member))
        {
            ((PropertyInfo)member).SetValue(member, "SensitiveData", null);
        }

        var property = base.CreateProperty(member, memberSerialization);
        return property;
    }

    private bool IsSensitiveProperty(MemberInfo member)
    {
        if (member is PropertyInfo)
        {
            var prop = (PropertyInfo) member;
            var isSensitiveData = Attribute.IsDefined(prop, typeof (SensitiveDataAttribute));
            return isSensitiveData;
        }
        return false;
    }
}
Andrei Mihalciuc
  • 2,148
  • 16
  • 14
-1

You could do this with reflection inside of your contract resolver.

PropertyInfo[] props = typeof(instanceOfMyClass).GetProperties();
foreach (PropertyInfo prop in props)
{
     object[] attrs = prop.GetCustomAttributes(true);
     foreach (object attr in attrs)
     {
           var sensitive = attr as SensitiveDataAttribute;
           if (sensitive != null)
           {
               //add the default value to your property here
              prop.SetValue(instanceOfMyClass, "Default Value", null);
          }
     }
}
Stephen Brickner
  • 2,584
  • 1
  • 11
  • 19