As mentioned in the question I had raised the question "Contextual serialization from WebApi endpoint based on permissions" which I have answered myself. I did initially look at using a MediaFormatter
but I believe this would then restrict you to what kind of response you could return. If you wanted to return JSON and XML you would need to implement two formatters. To only have to implement the filter in one place you need to go higher up the stack to theDelegatingHandler
.
In my implementation I wanted to look up which fields the client had access to and remove any from the response that the client should not see. This is quite similar to what you want to do.
In your senario you would need to reflect over the object and pick out any fields that contain your attribute and set those values to null. If returning JSON or XML then the properties are not included in the response if the values are null so you will not even leak the property name.
Example
Here is an example implementation of a DelegatingHandler
that uses reflection to filter out properties on the response object content that implement the Sensitive
attribute. It assumes the object hierarchy is flat so if you have nested objects you will need to navigate the object graph and do the same for each object in the hierarchy.
public class ResponseDataFilterHandler : DelegatingHandler
{
protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return base.SendAsync(request, cancellationToken)
.ContinueWith(task =>
{
var response = task.Result;
//Manipulate content here
var content = response.Content as ObjectContent;
if (content != null && content.Value != null)
{
FilterFields(content.Value);
}
return response;
});
}
private void FilterFields(object objectToFilter)
{
var properties = objectToFilter
.GetType()
.GetProperties(
BindingFlags.IgnoreCase |
BindingFlags.GetProperty |
BindingFlags.Instance |
BindingFlags.Public);
foreach (var propertyInfo in properties)
{
if (propertyInfo.GetCustomAttributes(typeof(SensitiveAttribute), true).Any())
{
propertyInfo.SetValue(objectToFilter, null, new object[0]);
}
}
}
}