0

I am building an asp.net core web api and I need to keep track of properties that were actually included in a JSON body, since .NET doesnt have the concept of undefined as in javascript, just null.

I created an interface which all of my models implement which is just a string array called IncludedProperties:

string[] IncludedProperties {get; set;}

I might have models which have more of these models nested inside. Any time I am deserializing one of these models, I want it to populate this list of IncludedProperties.

For example, in my controller:

public async Task<ActionResult> PatchModel([FromRoute]Guid id, [FromBody] RootModel model) { ... }

And classes are is defined as:

public class RootModel : IIncludedProperties
{
    public string Name { get; set;}
    public string Description {get; set;}
    public NestedModel SubEntity { get; set;}
    public string[] IncludedProperties {get; set;}
}

public class NestedModel : IIncludedProperties
{
   public string Name {get; set;}
   public decimal Value {get; set;}
   public string[] IncludedProperties {get; set;}
}

If the JSON body is as follows:

{
    "Name": "New Entity 01",
    "SubEntity": {
        "Name": "Child Entity 01",
        "Value": 0.5
    }
}

The included properties for the root would be [ "Name", "SubEntity"] and the included properties for the nested model would be [ "Name", "Value" ].

I am going through the documentation from Microsoft on custom converters for JSON, but it seems I will need to rewrite the entire json converter just to add in a bit of extra functionality. Is there any way I could "plug in" to the existing converter, just to capture the included property names?

Zach
  • 1,311
  • 3
  • 16
  • 36

1 Answers1

0

This can be solved with reflection and recursion. If you don't mind adding one more line inside each controller, you can call this function after model binding:

void PopulateIncludedProperties(IIncludedProperties obj)
{
    var properties = obj.GetType().GetProperties().ToList();
    obj.IncludedProperties = properties
        .Where(p => p.Name != "IncludedProperties" && p.GetValue(obj) != null)
        .Select(p => p.Name).ToArray();

    foreach (var prop in properties)
    {
        var value = prop.GetValue(obj);
        if (value is IIncludedProperties includedPropValue)
        {
            PopulateIncludedProperties(includedPropValue);
        }
    }
}

Please customize yourself if you want to populate IncludedProperties of an IEnumerable<IIncludedProperties>

Củ Su Hào
  • 372
  • 6
  • 15