2

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.

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.

  <system.codedom>
    <compilers>
      <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"/>
      <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=\&quot;Web\&quot; /optionInfer+"/>
    </compilers>
  </system.codedom>

The Version=2.0.1.0 in both compiler lines were set to Version=1.0.8.0, and the version of the DLL that was published was 2.0.1.0. This gives an error that looks like this:

Image that shows the exception

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:

In the global.asax.cs file:

        void Application_Error(object sender, EventArgs e)
        {
            Exception ex = Server.GetLastError();

            if (ex != null)
                Logger.WriteToFile(ex.Message, ex);
        }

Also in the global.asax.cs file:

        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);
        }

In the WebApiConfig.Register function that is automatically added to the Web.API (that handles routing setup, for example):

        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Filters.Add(new GlobalExceptionFilterAttribute()); // <-- this line

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }

    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);
            }
        }
    }

And in the web.config file, I added a module that should (in theory) handle the IIS level errors (taken from Catch IIS level error to handle in ASP.NET):

  <system.webServer>
    <modules>
      <add type="ErrorHttpModule" name="ErrorHttpModule"/>
    </modules>
  </system.webServer>
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()
    {
    }
}

And none of these seem to catch the error, and log it. How do I catch this error?

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 https://github.com/Loyalar/IISExceptionCapture.

Loyalar
  • 2,131
  • 4
  • 24
  • 44

2 Answers2

0

Troubleshooting:

  1. enabled stdoutLogEnabled and checked IIS log.

  2. You may also check window log events.

Refer - https://weblog.west-wind.com/posts/2020/Jan/14/ASPNET-Core-IIS-InProcess-Hosting-Issues-in-NET-Core-31

Always_a_learner
  • 1,254
  • 1
  • 8
  • 16
  • It looks like `stdoutLogEnabled` is a feature for .NET core projects. This is a .NET Framework project, and cannot use logging features from .NET core, unfortunately. – Loyalar Apr 30 '20 at 07:59
0

You could use below code at the start of your application. In Program.cs, Startup.cs or your Global.asax file.

AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>
{
    Debug.WriteLine(eventArgs.Exception.ToString());
};

refer this below link for more detail:

https://stackify.com/csharp-catch-all-exceptions/

catch all unhandled exceptions in ASP.NET Web Api

Jalpa Panchal
  • 8,251
  • 1
  • 11
  • 26
  • To register the `FirstChanceException`s, one still needs the application to run the code in the `Global.asax.cs` file, which it unfortunately doesn't in my case. It never reaches the `global.asax.cs` code. The Startup.cs file is (as I read it) only for ASP.NET Core projects, which mine unfortunately isn't. The Stackify link goes through these same solutions - to no avail. And the `ExceptionLogger` "solution" in the other link you sent is unfortunately registered at the same point of the lifecycle - the `WebApiConfig.Register` function which is never reached. – Loyalar May 04 '20 at 06:12