9

I'm trying out building a web API with MVC 6. But when one of my controller methods throws an error, the content of the response is a really nicely formatted HTML page that would be very informative were this an MVC app. But since this is an API, I'd rather have some JSON returned instead.

Note: My setup is super basic right now, just setting:

    app.UseStaticFiles();
    app.UseIdentity();

    // Add MVC to the request pipeline.
    app.UseMvc();

I want to set this up universally. Is there a "right/best" way to set this up in MVC 6 for an API?

Thanks...

1 Answer 1

13

One way to achieve your scenario is to write an ExceptionFilter and in that capture the necessary details and set the Result to be a JsonResult.

// Here I am creating an attribute so that you can use it on specific controllers/actions if you want to.
public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
    public override void OnException(ExceptionContext context)
    {
        var exception = context.Exception;
        context.Result = new JsonResult(/*Your POCO type having necessary details*/)
        {
            StatusCode = (int)HttpStatusCode.InternalServerError
        };
    }
}

You can add this exception filter to be applicable to all controllers. Example:

app.UseServices(services =>
{
    services.AddMvc();
    services.Configure<MvcOptions>(options =>
    {
        options.Filters.Add(new CustomExceptionFilterAttribute());
    });
.....
}

Note that this solution does not cover all scenarios...for example, when an exception is thrown while writing the response by a formatter.

Sign up to request clarification or add additional context in comments.

5 Comments

So the other ways I saw to do this were: #1: Override OnActionExecuted in a base controller. And #2: app.UseErrorHandler("/Home/Error") to go to a controller method to handle the errors. They both work but both seem a bit dorky. This approach seems better, but none of the three can handle a simple 404 for example due to a bad url. This gets caught before any of these kick in. Is there a way to intercept all errors?
Thanks for the info. I am not sure about approach #1 and will have to check. The approach #2 seems to be a generic solution for any middleware which is registered after the ErrorHandler middleware and when an exception happens for the current request it is re-routed to a different url to handle it. Looking at the source code looks like this also does not handle the formatter write related exceptions.
And regarding your question about capturing 404 responses. These are not considered as exceptions in general, but if you want to capture these too, then some options i can think of are: 1)a catch-all route registered at the end of the route collection which when is hit confirms that none of the previous routes in your route collection matched and 2)a middleware which sits before MVC, but the issue with this is that you cannot differentiate if a the 404 returned from MVC is due to incorrect Url or let's say an action returning 404 as a product with a given id is not found.
This basically works, but will return a 200 Status Code, which should not be desired. Can you return a 500 with the CustomExceptionFilterAttribute?
@Hinrich You can specify the StatusCode of the JsonResult object like this var jsonResult = new JsonResult(exception); jsonResult.StatusCode = (int)HttpStatusCode.InternalServerError;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.