ExpandoObject


The ExpandoUtilities class contains a generic static method GetSpecificFields<TSource>. This is an extension method targeting List<TSource> where TSource is any class. The purpose of this method is to construct a list of ExpandoObject where each ExpandoObject represents an object of TSource type, but only includes specified properties. The names of these properties are provided as a string argument fields, where multiple property names are separated by a comma.


Here is a breakdown of this code:
1) An empty list of ExpandoObject named result is created. If the source (List) does not contain any items or if no fields are specified in the fields string, the method returns this empty list.
2) If both conditions are met, the fields string is split by commas into an array, where each item in this array represents the name of the property that needs to be included in the resulting ExpandoObject.
3) It then obtains the PropertyInfo for each specified field (property name) in TSource type using reflection and stores these into a list.
4) If the list of PropertyInfo objects is not empty, it creates a new ExpandoObject for each object in the source list, sets the obtained properties to it and adds it to the result.
5) Finally, it returns the list of dynamically shaped objects (each represented as ExpandoObject).

In particular, this code is useful when you want to dynamically shape the output of your API, allowing the consumer to request just the data they need. In the given context, BooksController.QueryExpando(...) uses this method to filter the fields of booksDto based on the ResourceParameters provided in the request. In this way, the data returned by the API can be tailored based on user's request, potentially improving performance and bandwidth usage.

public static class ExpandoUtilities
{
public static IEnumerable<ExpandoObject> GetSpecificFields<TSource>(this List<TSource> source, string fields)
{
var result = new List<ExpandoObject>();
if (!source.Any())
{
return result;
}

if (string.IsNullOrWhiteSpace(fields))
{
return result;
}

var fieldsArray = fields.Split(',').Select(field => field.Trim()).ToArray();

var propertyInfoList = fieldsArray
.Select(propertyName
=> typeof(TSource).GetProperty(propertyName,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase))
.Where(propertyInfo => propertyInfo != null)
.ToList();

if (!propertyInfoList.Any()) return result;
{
foreach (TSource sourceObject in source)
{
var dataShapedObject = new ExpandoObject();

foreach (var propertyInfo in propertyInfoList)
{
var propertyValue = propertyInfo?.GetValue(sourceObject);
((IDictionary<string, object>)dataShapedObject!).Add(propertyInfo?.Name!, propertyValue!);
}

result.Add(dataShapedObject);
}

return result;
}

}
}

 

Usage: 

var filteredResults = booksDto.GetSpecificFields(resourceParameters.Fields);

 


No files yet, migration hasn't completed yet!