4

When certain exceptions are thrown in controllers, I want to catch those exceptions and do some extra logic.

I was able to achieve this with a custom IExceptionFilter that is added to the global filters list.

However, I preffer to handle these exception within a custom Owin middleware. My middleware looks like this:

      try
        {

            await Next.Invoke(context);
        }
        catch (AdalSilentTokenAcquisitionException e)
        {
           //custom logic
        }

This piece of code does not work, it looks like the exception is already catched and handled in MVC. Is there a way to skip the exception processing from MVC and let the middleware catch the exception?

Identity
  • 1,553
  • 1
  • 22
  • 44
  • Possible duplicate of [How do I disable \*all\* exception handling in ASP.NET Web API 2 (to make room for my own)?](http://stackoverflow.com/questions/34201527/how-do-i-disable-all-exception-handling-in-asp-net-web-api-2-to-make-room-for) – Tomas Aschan Nov 23 '16 at 16:34
  • 1
    Not a duplicate - the other question is about Web API 2, this is about MVC Framework. Part of that answer (the OWIN middleware) is applicable, but the mechanism to turn off the default error handling is different. – Tomas Aschan Nov 23 '16 at 20:33

2 Answers2

5

Update: I've found a cleaner approach, see my updated code below. With this approach, you don't need a custom Exception Filter and best of all, you don't need the HttpContext ambient service locator pattern in your Owin middleware.

I have a working approach in MVC, however, somehow it doesn't feel very comfortable, so I would appreciate other people's opinion.

First of all, make sure there are no exception handlers added in the GlobalFilters of MVC.

Add this method to the global asax:

    protected void Application_Error(object sender, EventArgs e)
    {
        var lastException = Server.GetLastError();
        if (lastException != null)
        {
            HttpContext.Current.GetOwinContext().Set("lastException", lastException);
        }
    }

The middleware that rethrows the exception

public class RethrowExceptionsMiddleware : OwinMiddleware
{
    public RethrowExceptionsMiddleware(OwinMiddleware next) : base(next)
    {
    }

    public override async Task Invoke(IOwinContext context)
    {
        await Next.Invoke(context);
        var exception = context.Get<Exception>("lastException");
        if (exception != null)
        {
            var info = ExceptionDispatchInfo.Capture(exception);
            info.Throw();
        }
    }
}
Identity
  • 1,553
  • 1
  • 22
  • 44
  • 1
    You don't need to add the Exception to the OwinContext from Application_Error. Any Exception thrown from MVC Controller will be added to the HttpContext.AllErrors. You can retrieve the HttpContextBase from IOwinContext then handle all the error it contains. – alans Jan 11 '19 at 18:39
2

There's no perfect way to do this (that I know of), but you can replace the default IExceptionHandler with one that just passes the error through to the rest of the stack.

I did some extensive digging about this, and there really doesn't seem to be a better way for now.

Tomas Aschan
  • 58,548
  • 56
  • 243
  • 402
  • Also, see http://stackoverflow.com/questions/34201527/how-do-i-disable-all-exception-handling-in-asp-net-web-api-2-to-make-room-for – Tomas Aschan Nov 23 '16 at 16:34
  • Thanks for the reply, however I am using MVC and not Web Api, so I replaced config.Services.Replace(typeof(IExceptionHandler), new MyExceptionHandler()); with GlobalFilters.Filters.Add(new MyExceptionHandler()); This way, the exception is not handled in the middleware... How should I configure MyExceptionHandler in MVC? – Identity Nov 23 '16 at 16:49
  • @Identity: MVC as in ASP.NET Core 1.0? Or as in pre-Core MVC Framework? – Tomas Aschan Nov 23 '16 at 20:33
  • I am using Asp.net MVC 5, (.NET 4.6) – Identity Nov 24 '16 at 08:11
  • What do you think of my approach below? Do you have any concerns? – Identity Nov 25 '16 at 11:08
  • I'm confused. Should you really have both Global.asax and OWIN? – Tomas Aschan Nov 25 '16 at 12:09
  • The global asax is only needed to get the error in the owin middleware. Even if I would have no exception filters in MVC, the error was never passed to owin. This way, I can read out if an exception was set, en rethrow it. This way I can handle all errors in the owin middleware... – Identity Nov 25 '16 at 13:44