I am trying to implement field selection within Web Api but cannot get this to work for named nested properties. I am doing this with the code below.
Here is the aggregate that I am using in my example:
public class Release
{
public int Id { get; set; }
public string Title { get; set; }
public Artist Artist { get; set; }
public string Genre { get; set; }
}
public class Artist
{
public int Id { get; set; }
public string Name { get; set; }
public Label Label { get; set; }
}
public class Label
{
public int Id { get; set; }
public string Name { get; set; }
public LabelOwner Owner { get; set; }
}
public class LabelOwner
{
public int Id { get; set; }
public string Name { get; set; }
}
And the Json.Net Resolver I have written:
public class NamedFieldSerializer<T> : DefaultContractResolver
{
private readonly string _typeName;
private readonly string[] _fields;
public NamedFieldSerializer(string fields)
{
_typeName = typeof(T).Name;
_fields = fields.Split(',').Select(x =>
{
var field = x.Trim();
if (!field.Contains("."))
{
field = $"{_typeName}.{field}";
}
return field.ToLower();
}).ToArray();
}
private bool NoFieldsSpecified()
{
return !_fields.Any();
}
private bool IsNestedType(MemberInfo member)
{
var prop = member as PropertyInfo;
var isSystemType = prop.PropertyType.FullName.StartsWith("System");
return !isSystemType && _fields.Any(x => x.Contains($"{member.Name}.".ToLower()));
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
property.ShouldSerialize = _ =>
{
if (NoFieldsSpecified()) return true;
if (IsNestedType(member)) return true;
var prop = member as PropertyInfo;
var fullMemberName = $"{prop.ReflectedType.Name}.{member.Name}".ToLower();
var split = _fields.Select(x => x.Split(new [] { fullMemberName }, StringSplitOptions.RemoveEmptyEntries));
return split.Any(x => x.Length == 0 || (x.Length == 1 && x.First().EndsWith(".")));
};
return property;
}
}
Where fields is "title,genre,artist.name,artist.label.name,artist.label.owner.name"
Now this does work if the property name used in the fields is the same as the type. I cannot use a different name like for "artist.label.owner.name", it does however work for "artist.label.labelowner.name"
Anyone got any ideas?