A standard RESTful service returns the representation of an entire object; all its fields in a representation of the class instance. So, if we have a service that returns student data, the response JSON to the following call:
/api/Students
might look like this:
[
{
id: 1,
lastName: "Alexander",
firstMidName: "Carson",
enrollmentDate: "2005-09-01T00:00:00",
enrollments: null
},
{
id: 2,
lastName: "Alonso",
firstMidName: "Meredith",
enrollmentDate: "2002-09-01T00:00:00",
enrollments: null
},
{
id: 3,
lastName: "Anand",
firstMidName: "Arturo",
enrollmentDate: "2003-09-01T00:00:00",
enrollments: null
}
]
Now, our service client may only be interested in the first and last names, so ideally we'd like to restrict the response object to only those fields. We can implement a "fields" query parameter, allowing us to specify the fields that we're interested in. That would look like this:
/api/Students?fields=lastName,firstMidName
Now, to implement this, we simply add the fields parameter in the controller like so:
// GET: api/Students
[HttpGet]
public IEnumerable<Object> GetStudents(string fields)
Ok, so we now have a set of fields specified in a string. Let's parse that string (there are cooler ways to do this, but back to basics for now) Let's create a method for parsing the "fields" string:
public object SummariseObject(object o,string fields)
{
Let us parse the input "fields" string into a collection of strings named "word". Each string represents the name of a field which is needed in the resulting JSON:
//parse fields string
string[] words;
string[] separators = { ",", ".", "!", "?", ";", ":", " " };
words = fields.Split(separators, StringSplitOptions.RemoveEmptyEntries);
We now have a collection of field names which will match properties on our POCO object.
So let's filter the properties of our object based on that collection of field names
To do that, we need to know what the properties of an object are, which can be easily achieved through reflection:
Type t = o.GetType();
string str = "";
foreach (string f in words)
{
try
{
//get the corresponding value from the array
PropertyInfo p = t.GetProperty(f, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.InstObjeance);
This gets us the value of each property specified inthe "fields" string. Now we need somewhere to put these values. Fortunately, even though C# is a strongly typed language, the framework makes provision for a dynamically typed object, constructed at runtime. In the .NET framework, this object has the exotic name of an "ExpandObject"; an object which can be contructed programatically.
We initialise the ExpandoObject as a dictionary of name, value pairs:
var exp = new ExpandoObject() as IDictionary<string, Object>;
Then let's put the reflected value from the original object, into our ExpandoObject, iterate through all the fields then return the dynamic ExpandoObject as JSON:
foreach (string f in words)
{
try
{
//get the corresponding value from the array
PropertyInfo p = t.GetProperty(f, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
str = p.GetValue(o).ToString();
//add property to dynamic object
exp.Add(f, str);
}
catch(Exception e)
{
FieldNotFoundException ex = new FieldNotFoundException("The Field named " + f + " Does not exist in this object",e);
throw ex;
}
}
//return the dynamic object
return exp;
Now with our query of:
/api/Students?fields=lastName,firstMidName
We get a return of:
[
{
lastName: "Alexander",
firstMidName: "Carson"
},
{
lastName: "Alonso",
firstMidName: "Meredith"
},
{
lastName: "Anand",
firstMidName: "Arturo"
}
]
Code for this sample can be messaged by emailing [email protected]
Roland Kamsika 2017