title: Catching IIS-level unhandled exceptions
body: <p>I'm trying to implement error handling on one of our ASP.NET Web API (not core) projects (running .NET 4.7.2) to avoid running into an error in the future, that we had a couple of days ago. </p>
  
  <p>The error was that this code in the Web.Config file had not been updated, but the DLL that came with the project when it was published was updated, so there was a mismatch between the versions.</p>
  
  <pre class="lang-xml prettyprint-override"><code>  &lt;system.codedom&gt;
      &lt;compilers&gt;
        &lt;compiler language="c#;cs;csharp" extension=".cs"
          type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
          warningLevel="4" compilerOptions="/langversion:default /nowarn:1659;1699;1701"/&gt;
        &lt;compiler language="vb;vbs;visualbasic;vbscript" extension=".vb"
          type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
          warningLevel="4" compilerOptions="/langversion:default /nowarn:41008 /define:_MYTYPE=\&amp;quot;Web\&amp;quot; /optionInfer+"/&gt;
      &lt;/compilers&gt;
    &lt;/system.codedom&gt;
  </code></pre>
  
  <p>The <code>Version=2.0.1.0</code> in both <code>compiler</code> lines were set to <code>Version=1.0.8.0</code>, and the version of the DLL that was published was 2.0.1.0. This gives an error that looks like this: </p>
  
  <p><a href="https://i.stack.imgur.com/IWoiL.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/IWoiL.png" alt="Image that shows the exception"></a></p>
  
  <p>Now, I would like to handle this exception in the code, and log it to our logging stack. I have searched around and found a couple of different methods of catching exceptions in a web.api project, but none of them seem to have worked. The ones I have tried are: </p>
  
  <p>In the <code>global.asax.cs</code> file: </p>
  
  <pre class="lang-cs prettyprint-override"><code>        void Application_Error(object sender, EventArgs e)
          {
              Exception ex = Server.GetLastError();
  
              if (ex != null)
                  Logger.WriteToFile(ex.Message, ex);
          }
  </code></pre>
  
  <p>Also in the <code>global.asax.cs</code> file: </p>
  
  <pre class="lang-cs prettyprint-override"><code>        protected void Application_Start()
          {
              GlobalConfiguration.Configure(WebApiConfig.Register);
  
              AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
          }
  
          private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
          {
              Exception ex = (e.ExceptionObject as Exception);
  
              if (ex != null) 
                  Logger.WriteToFile(ex.Message, ex);
          }
  </code></pre>
  
  <p>In the <code>WebApiConfig.Register</code> function that is automatically added to the Web.API (that handles routing setup, for example): </p>
  
  <pre class="lang-cs prettyprint-override"><code>        public static void Register(HttpConfiguration config)
          {
              // Web API configuration and services
  
              // Web API routes
              config.MapHttpAttributeRoutes();
  
              config.Filters.Add(new GlobalExceptionFilterAttribute()); // &lt;-- this line
  
              config.Routes.MapHttpRoute(
                  name: "DefaultApi",
                  routeTemplate: "api/{controller}/{id}",
                  defaults: new { id = RouteParameter.Optional }
              );
          }
  </code></pre>
  
  <pre class="lang-cs prettyprint-override"><code>
      public class GlobalExceptionFilterAttribute : ExceptionFilterAttribute
      {
          public override void OnException(HttpActionExecutedContext context)
          {
              var exceptionType = context.Exception.GetType().ToString();
              var exception = context.Exception.InnerException ?? context.Exception;
  
              try
              {
                  if (exception != null)
                      Logger.WriteToFile(exception.Message, exception);
              }
              finally
              {
                  base.OnException(context);
              }
          }
      }
  </code></pre>
  
  <p>And in the web.config file, I added a module that should (in theory) handle the IIS level errors (taken from <a href="https://stackoverflow.com/questions/1989756/catch-iis-level-error-to-handle-in-asp-net">Catch IIS level error to handle in ASP.NET</a>): </p>
  
  <pre class="lang-xml prettyprint-override"><code>  &lt;system.webServer&gt;
      &lt;modules&gt;
        &lt;add type="ErrorHttpModule" name="ErrorHttpModule"/&gt;
      &lt;/modules&gt;
    &lt;/system.webServer&gt;
  </code></pre>
  
  <pre><code>public class ErrorHttpModule : IHttpModule
  {
      private HttpApplication _context;
  
      public ErrorHttpModule() { }
  
      public void Init(HttpApplication context)
      {
          _context = context;
          _context.Error += new EventHandler(ErrorHandler);
      }
  
      private void ErrorHandler(object sender, EventArgs e)
      {
          Exception ex = _context.Server.GetLastError();
  
          if (ex != null)
              Logger.WriteToFile(ex.Message, ex);
      }
  
      public void Dispose()
      {
      }
  }
  </code></pre>
  
  <p>And none of these seem to catch the error, and log it. How do I catch this error? </p>
  
  <p>I have reproduced this error in a completely blank Web.API project in addition to our main project. The blank Web.API project can be found at <a href="https://github.com/Loyalar/IISExceptionCapture" rel="nofollow noreferrer">https://github.com/Loyalar/IISExceptionCapture</a>. </p>