I have found the source of confusion.
It seems, WebAPI by default is using this exception handler:
https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Http/ExceptionHandling/DefaultExceptionHandler.cs
and it has major differences from the suggested exception handling in this article:
http://www.asp.net/web-api/overview/web-api-routing-and-actions/web-api-global-error-handling
see chapter “Appendix: Base Class Details”, where the code of default exception base class is given.
In the example it checks for IsOutermostCatchBlock (which now seems to be moved to exceptionContext.CatchBlock.IsTopLevel) to see if it’s time to handle the exception. When CORS is enabled, such approach won’t work for the reasons I described above. ASP.NET team said, this behavior is by design and they won’t change anything.
I hope someone experienced will write an up-to-date article with instructions for doing exception handling the right way with and without CORS.
Currently I see two ways to work around this in my code:
-
don’t inherit my custom exception handler from
System.Web.Http.ExceptionHandling.ExceptionHandlerbut implementIExceptionHandlerdirectly -
if inheriting from
System.Web.Http.ExceptionHandling.ExceptionHandler, override
ShouldHandle method and returntruealways becauseCatchBlock.IsTopLevelmight never havetruevalue.
I tried both apporaches and they seem to work fine.