How to handle errors differently for (or distinguish between) API calls and MVC (views) calls in ASP.NET Core

asp.net-core, asp.net-core-mvc, asp.net-web-api, c#, error-handling

Solution

There are many ways to achive your goal:

1- Using two different exception filter(i would go with this approach because your question is about mvc pipline)

Implementation:

// For api
public class ApiExceptionFilterAttribute : ExceptionFilterAttribute
{
    public override void OnException(ExceptionContext context)
    {
        // send error as json
    }
}


[ApiExceptionFilter]
public class ApiController : Controller{...}

// For mvc
public class MvcExceptionFilterAttribute : ExceptionFilterAttribute
{
    public override void OnException(ExceptionContext context)
    {
        // send view result
    }
}


[MvcExceptionFilter]
public class HomeController : Controller{...}

If you want to add filter globally, see Register filter for an area

2- Using `UseWhen` and `UseExceptionHandler`

         app.UseWhen(x => x.Request.Path.Value.StartsWith("/api"), builder =>
         {
             builder.UseExceptionHandler(new ExceptionHandlerOptions()
             {
                 ExceptionHandler = async (ctx) =>
                 {
                     var feature = ctx.Features.Get<IExceptionHandlerFeature>();
                     var error = feature?.Error;
                     // send json
                 }
             });
         });
        app.UseWhen(x => !x.Request.Path.Value.StartsWith("/api"), builder =>
        {
            builder.UseExceptionHandler("/Error");
        });`

3- Using `UseExceptionHandler` conditionally:

        app.UseExceptionHandler(new ExceptionHandlerOptions()
        {
            ExceptionHandler = async (ctx) =>
            {
                if (ctx.Request.Path.Value.StartsWith("/api"))
                {
                    var feature = ctx.Features.Get<IExceptionHandlerFeature>();
                    var error = feature?.Error;
                    // send json
                }
                else
                {
                    // redirect error page
                }
            }
        });

Problem

In my applications based on ordinary MVC and WebApi I had two different error handling routes. If an error occurred during WebApi call, I would intercept it (using standard web api options) and return json message with corresponding HTTP Status Code so that client app can handle it. If the error happened in MVC, then I would use some standard handlers that would redirect user to some default error screen possibly based on status code. Now in ASP.NET Core both are joined in the same framework, so if I just intercept and return JSON, then I risk showing json to a user, since it can be an action that returns a view. On the other hand if I use `app.UseExceptionHandler` then my API calls would get HTML from the error page that is unusable inside js. What is the good way to provide separate error handling for this two cases? Or perhaps there is a better way to handle it altogether? P.S. I would rather reuse the MVC exception handler that comes out of the box and only add the web api part.

Original source