1

I have an application developed in ASP.NET Core MVC with a set of controllers for normal view responses and Web API.

I am trying to figure a correct way to wrap all Web API responses with a consistent class.

My first question is what would be a correct approach to wrap the responses coming from Web API controllers. Since I have two controller types, I would need to distinguish between them as the responses should only be wrapped for API controller, and not view controllers.

As I understand there are two choices a middleware or an action filter.

At first I thought the middleware would be the best choice, but then I realized that I would still need to figure out what kind of request is being processed which would add more potential headache with maintenance?

Then I looked at an action filter and it seems that it would be a better choice to plugin the wrapping handling.

For example an action filter can be added to a base controller just for Web API and not controllers handling the views.

So the question is whether the action filters are best approach to achieve this?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
NullReference
  • 862
  • 1
  • 11
  • 27

1 Answers1

3

I would recommend you to look at result filters for this. Result filters run after a controller action has produced a result, and it allows you to look at that result and then perform some action.

For example, when you return View in a controller action, then what gets returned is a ViewResult which makes it easy to identify results that would cause a Razor view to be rendered.

Within an API controller, you would usually return a ActionResult<T>, some model object directly, or an ObjectResult. The former two will be automatically converted into an ObjectResult as the action gets executed. So you can just look for ObjectResults and then change the result to have some wrapper object instead. This would look something like this:

public class WrapApiResponseResultFilter : IResultFilter
{
    public void OnResultExecuting(ResultExecutingContext context)
    {
        var result = context.Result;
        if (result is ObjectResult)
        {
            // wrap the inner object
            var newValue = new WrapperObject(result.Value);

            // replace the result
            context.Result = new ObjectResult(newValue)
            {
                // copy the status code
                StatusCode = result.StatusCode,
            };
        }
    }

    public void OnResultExecuted(ResultExecutedContext context)
    { }
}
poke
  • 369,085
  • 72
  • 557
  • 602