Welcome to the navigation

Elit, ut cillum fugiat aliquip ex dolore ullamco nostrud proident, in ea sit veniam, labore qui voluptate mollit laborum, aliqua, commodo et non excepteur magna. Exercitation duis consequat, et pariatur, commodo proident, velit amet, tempor occaecat eiusmod ad labore fugiat quis voluptate do sed irure elit, esse officia in nisi

Yeah, this will be replaced... But please enjoy the search!

Global exception handling in ASP.NET Core

I had the need for a global exception handling in ASP.NET Core that separates Page controllers and API controllers.

There are a few good guides on how to implement general or global exception handling. One increasingly popular way of achieving this is to use the UseExceptionHandler extension method on the IApplicationBuilder. In example

app.UseExceptionHandler(a => a.Run(async context =>
    var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
    var exception = exceptionHandlerPathFeature.Error;

    var result = JsonConvert.SerializeObject(new { error = exception.Message });
    context.Response.ContentType = "application/json";
    await context.Response.WriteAsync(result);

Simple and compact, the downside of this is that it is GLOBAL, meaning it doesn't really play well unless you are building API-only applications.

Using ExceptionFilterAttribute

Another more versatile way of managing global exceptions is to implement a custom ExceptionFilterAttribute. This is way more powerful and we do get access to the ActionContext since the ExceptionContext implements it via the FilterContext. The ActionContext property ActionDescriptor can be cast into a ControllerActionDescriptor which is what the ExceptionContext implement.

Why is this useful?

The ControlerActionDescriptor contain a ControllerTypeInfo property that allows us to see what controller implementation that caused the exception. This is done by checking if the controller implements ControllerBase and or Controller. The general rules are

  • Api's implements ControllerBase but not Controller
  • Pages implements both ControllerBase and Controller

The quick implementation of this would look like this

using System;
using Microsoft.ApplicationInsights;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace Project.Business.Filters
    public class ExceptionActionFilter : ExceptionFilterAttribute
        private readonly IHostingEnvironment _hostingEnvironment;
        private readonly TelemetryClient _telemetryClient;

        public ExceptionActionFilter(
            IHostingEnvironment hostingEnvironment,
            TelemetryClient telemetryClient)
            _hostingEnvironment = hostingEnvironment;
            _telemetryClient = telemetryClient;

        #region Overrides of ExceptionFilterAttribute

        public override void OnException(ExceptionContext context)
            var actionDescriptor = (Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)context.ActionDescriptor;
            Type controllerType = actionDescriptor.ControllerTypeInfo;

            var controllerBase = typeof(ControllerBase);
            var controller = typeof(Controller);

            // Api's implements ControllerBase but not Controller
            if (controllerType.IsSubclassOf(controllerBase) && !controllerType.IsSubclassOf(controller))
                // Handle web api exception

            // Pages implements ControllerBase and Controller
            if (controllerType.IsSubclassOf(controllerBase) && controllerType.IsSubclassOf(controller))
                // Handle page exception

            if (!_hostingEnvironment.IsDevelopment())
                // Report exception to insights


Register in services

services.AddMvc(options =>

Adjust accordingly, the TelemetryClient is optional, this can also be split into different filters depending on your needs.

A typical return of mine for the web api would look like this

// Api's implements ControllerBase but not Controller
if (controllerType.IsSubclassOf(controllerBase) && !controllerType.IsSubclassOf(controller))
    // Handle web api exception
    context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
    context.HttpContext.Response.ContentType = "application/json";
    context.Result = new JsonResult(context.Exception.Message);