When using convention based routing I am able to use a DelegatingHandler to create a response wrapper by overriding the SendAsync method.
DelegatingHandler[] handler = new DelegatingHandler[] {
new ResponseWrapper()
};
var routeHandler = HttpClientFactory.CreatePipeline(new HttpControllerDispatcher(config), handler);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}",
defaults: null,
constraints: null,
handler: routeHandler
);
However, this approach does not work for methods that rely upon attribute routing. In my case convention based routing will not work for all scenarios and the routeHandler does not apply to the attribute based routes.
How can I apply a response wrapper to all attribute based route responses?
I was able to add a global message handler that applies to all requests.
config.MessageHandlers.Add(new ResponseWrapper());
Since I am using swagger, I also had to ignore the swagger request URI. Here is the code for the ResponseWrapper class in the event it helps someone. I have not had a chance to go back through it so there are certain to be some improvements...
public class ResponseWrapper : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken);
if (request.RequestUri.ToString().Contains("swagger"))
{
return response;
}
return BuildApiResponse(request, response);
}
private static HttpResponseMessage BuildApiResponse(HttpRequestMessage request, HttpResponseMessage response)
{
object content = null;
string errorMessage = null;
response.TryGetContentValue(out content);
if (!response.IsSuccessStatusCode)
{
content = null;
var error = new HttpError(response.Content.ReadAsStringAsync().Result);
var data = (JObject)JsonConvert.DeserializeObject(error.Message);
errorMessage = data["message"].Value<string>();
if (!string.IsNullOrEmpty(error.ExceptionMessage) && string.IsNullOrEmpty(errorMessage))
{
errorMessage = error.ExceptionMessage;
}
}
var newResponse = request.CreateResponse(response.StatusCode, new ApiResponse(response.StatusCode, content, errorMessage));
foreach (var header in response.Headers)
{
newResponse.Headers.Add(header.Key, header.Value);
}
return newResponse;
}
}