title: Exceptions in ASP.NET Web API custom exception handler never reach top level when CORS is enabled
body: <p>I have created a custom Web API global exception handler like this:</p>
  
  <pre class="lang-cs prettyprint-override"><code>public class MyGlobalExceptionHandler : ExceptionHandler
  {
      public override void Handle(ExceptionHandlerContext context)
      {
          // here I handle them all, no matter sync or not
      }
  
      public override Task HandleAsync(ExceptionHandlerContext context, 
          CancellationToken cancellationToken)
      {
          // not needed, but I left it to debug and find out why it never reaches Handle() method
          return base.HandleAsync(context, cancellationToken);
      }
  
      public override bool ShouldHandle(ExceptionHandlerContext context)
      {
          // not needed, but I left it to debug and find out why it never reaches Handle() method
          return context.CatchBlock.IsTopLevel;
      }
  }
  </code></pre>
  
  <p>I'm registering it in my Global.asax Application_Start:</p>
  
  <pre class="lang-cs prettyprint-override"><code>GlobalConfiguration.Configuration.Services.Replace(typeof(IExceptionHandler),
      new MyGlobalExceptionHandler());
  </code></pre>
  
  <p>Everything worked fine, no matter where I threw exceptions - inside controller methods or in my custom attributes above controller methods, and no matter if I call it from AJAX requests or directly from browser.</p>
  
  <p>But then one day I needed CORS support for my AJAX requests. I enabled CORS globally as described in the article <a href="http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api#enable-cors">Enabling Cross-Origin Requests in ASP.NET Web API</a></p>
  
  <pre class="lang-cs prettyprint-override"><code>var cors = new EnableCorsAttribute("*", "*", "*"); // * is just for debugging purpose
  config.EnableCors(cors);
  </code></pre>
  
  <p>At first everything seemed OK, CORS worked as expected, the server responded to OPTIONS request.</p>
  
  <p>But the problems started when I wanted to check my authentication. Suddenly the exception was swallowed and I got an empty JSON <code>{}</code> response instead of my custom JSON formatted exception which I create in the Handle() method of my MyGlobalExceptionHandler.</p>
  
  <p>While debugging, I was surprised to find that now for AJAX requests ShouldHandle() method is called only with IsTopLevel = false, thus the exception never bubbles up and never reaches my Handle() method. As soon as I disable CORS, everything works fine again (except cross-domain requests, of course).</p>
  
  <p><strong>Why IsTopLevel is never true when I enable CORS? How should I fix this?</strong></p>
  
  <p><em>One more side effect is as follows. If CORS is disabled, then if I throw any exception inside Handle() method, it reaches the Application_Error handler in  Global.asax. But if I enable CORS and throw exceptions in my handler methods, these exceptions never reach Application_Error.</em></p>
  
  <h2>UPDATED WITH MORE DETAILS:</h2>
  
  <p>It seems, I found exactly when this is happening.</p>
  
  <p>If I throw an exception in a controller method when CORS is enabled, then CORS doesn't kick in at all and does not send the Access-Control-Allow-Origin header. When the browser doesn't receive the header, it immediately disrupts the request and this disruption seems to affect also the exception handler - it never reaches ShouldHandle() method with IsTopLevel = true.
  Chrome and Mozilla act like this even when I run AJAX request from a local html file to my websiet on IIS Express localhost.</p>
  
  <p>But the situation is different on IE 11. When I open the html file there, it first asks me permissions to enable scripts. After I agree, then IE 11 ignores the fact that there are no CORS headers present and it doesn't disrupt the request, thus my exception handler receives  IsTopLevel = true and is able to return a customised error response.</p>
  
  <p>I guess, this should be fixed in the Web API core - even if I throw exceptions, CORS should still be able to kick in and send its headers, so the browser accepts the response. I have created a minimal test case application and I'll send it to the ASP.NET Team on CodePlex.
  <a href="http://1drv.ms/1sb6rRt">Link to the test project</a>.  (the project zip file will be marked, just click Download and ignore all the other files in that folder)</p>