1

I am trying to access the parent object (or property) through the ContractResolver callback in order to omit certain properties in the property being serialized if it is not the parent.

I have classes which follow a database pattern. i.e:

Class base
  Private settings As Json.JsonSerializerSettings
  Public Property ID As Long = 0 ' all database records have an id
  Public Sub New() ' set up settings for later use
    settings = New Json.JsonSerializerSettings() With {
      .NullValueHandling = Json.NullValueHandling.Ignore,
      .MissingMemberHandling = Newtonsoft.Json.MissingMemberHandling.Ignore,
      .TypeNameHandling = Json.TypeNameHandling.Auto,
      .ContractResolver = New ShouldSerializeIfParent With {
      .NamingStrategy = New LowercaseNamingStrategy()
      }
    }
  End Sub
End Class
Class Address
  Inherits base
  Public Property Number As String = ""
  Public Property Street As String = ""
  Public Property City As String = ""
End Class
Class Email
  Inherits base
  Public Property Address As String = ""
  Public Property IsPrimary As Boolean = False
End Class
Class User
  Inherits base
  Public Property Name as String = ""
  Public Property Emails() as Email = {} ' users can have more than 1 email
  Public Property Address() as Address = {} ' users can have more than  1 address
End Class

When serializing or deserializing these objects, everything works using a ContractResolver which lower cases the keys.

I set this up like this:

Public Class ShouldSerializeIfParent
  Inherits Json.Serialization.DefaultContractResolver
  Protected Overrides Function CreateProperty(ByVal member As MemberInfo, ByVal memberSerialization As Json.MemberSerialization) As Json.Serialization.JsonProperty
    Dim prop As Json.Serialization.JsonProperty = MyBase.CreateProperty(member, memberSerialization)
    If prop.PropertyName = "id" Then 'ID comes lower cased, because we told it to 
      prop.Ignored = True
    End If
    Return prop
  End Function
End Class
Public Class LowercaseNamingStrategy
  Inherits Json.Serialization.NamingStrategy
  Protected Overrides Function ResolvePropertyName(ByVal name As String) As String
    Return name.ToLowerInvariant()
  End Function
End Class

As you can see I am ignoring all ID's and this does work, no ID's are being outputted. Would there be any way to access the parent or even determine is there is a parent during serialization?

I would prefer not to output child ID's in the resulting json string. The only variables I have to work with are member and prop and I cannot find any way to determine if either of these are the parent.

Thanks in advance.

Mike
  • 419
  • 4
  • 11
  • 1
    Json.NET isn't designed to serialize the same type differently depending upon its position in the serialization graph. It is a contract-based serializer which creates a contract for each type to be serialized, then serializes according to the contract. For some workarounds and partial attempts to do this see [Json.NET serialize by depth and attribute](https://stackoverflow.com/q/36159424/3744182) and [How to perform partial object serialization providing “paths” using Newtonsoft JSON.NET](https://stackoverflow.com/q/30304128/3744182). – dbc Jul 29 '20 at 01:19

1 Answers1

0

I had the same issue when I want to Ignore Serializing Json properties on run time [JsonIgnore]. So I wrote the below class :

public class DynamicContractResolver : DefaultContractResolver
{
    private readonly string[] props;

    public DynamicContractResolver(params string[] prop)
    {
        this.props = prop;
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> retval = base.CreateProperties(type, memberSerialization);
        var ret= retval.Where(p => !this.props.Contains(p.DeclaringType.FullName+"."+ p.PropertyName)).ToList();
        return ret;
        //return  retval.Where(p => !this.props.Contains(p.PropertyName)).ToList();
    }
}

So when you want to use it you can do something like this :

        var json = JsonConvert.SerializeObject(values, Formatting.Indented,
                new JsonSerializerSettings
                {
                    ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                    ContractResolver = new DynamicContractResolver("Entities.Contact.Address1")
                });

where Values come from DB like this :

var values = await _dbContext
                .Set<EntityName>()
                .Include(e => e.Contact)
                .Where(e => e. ..... )
Ali Mahmoodi
  • 858
  • 10
  • 14