Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filtering Out Properties in an ASP.NET Core API

I want to serve up the following JSON in my API:

{
  "id": 1
  "name": "Muhammad Rehan Saeed",
  "phone": "123456789",
  "address": {
    "address": "Main Street",
    "postCode": "AB1 2CD"
  }
}

I want to give the client the ability to filter out properties they are not interested in. So that the following URL returns a subset of the JSON:

`/api/contact/1?include=name,address.postcode

{
  "name": "Muhammad Rehan Saeed",
  "address": {
    "postCode": "AB1 2CD"
  }
}

What is the best way to implement this feature in ASP.NET Core so that:

  1. The solution could be applied globally or on a single controller or action like a filter.
  2. If the solution uses reflection, then there must also be a way to optimize a particular controller action by giving it some code to manually filter out properties for performance reasons.
  3. It should support JSON but would be nice to support other serialization formats like XML.

I found this solution which uses a custom JSON.Net ContractResolver. A contract resolver could be applied globally by adding it to the default contract resolver used by ASP.Net Core or manually to a single action like this code sample but not to a controller. Also, this is a JSON specific implementation.

like image 297
Muhammad Rehan Saeed Avatar asked Apr 02 '16 06:04

Muhammad Rehan Saeed


1 Answers

You can use dynamic with ExpandoObject to create a dynamic object containing the properties you need. ExpandoObject is what a dynamic keyword uses under the hood, which allows adding and removing properties/methods dynamically at runtime.

[HttpGet("test")]
public IActionResult Test()
{
    dynamic person = new System.Dynamic.ExpandoObject();

    var personDictionary = (IDictionary<string, object>)person;
    personDictionary.Add("Name", "Muhammad Rehan Saeed");

    dynamic address = new System.Dynamic.ExpandoObject();
    var addressDictionary = (IDictionary<string, object>)address;
    addressDictionary.Add("PostCode", "AB1 2CD");

    personDictionary.Add("Address", address);

    return Json(person);
}

This results in

{"Name":"Muhammad Rehan Saeed","Address":{"PostCode":"AB1 2CD"}}

You'd just need to create a service/converter or something similar that will use reflection to loop through your input type and only carry over the properties you specify.

like image 168
Tseng Avatar answered Oct 22 '22 06:10

Tseng