How to Find and View Unhandled Exceptions
Learn how to find and catch all exceptions in C# applications. .NET provides several different ways to catch exceptions and view unhandled exceptions.
Join the DZone community and get the full member experience.
Join For FreeException handling is a critical component of every software application. The last thing you want is your users to see weird errors, or even worse, your application keeps crashing. In this article, we are going to discuss how to find and catch all exceptions in C# applications. .NET provides several different ways to catch exceptions and view unhandled exceptions.
Catching “First Chance Exceptions”
If you want to find and catch every single exception in your application, you need to be aware of “first chance exceptions.” The .NET Framework provides an easy mechanism to subscribe to every single exception that is ever thrown in your code. This includes exceptions that are caught deep inside your code that never gets surfaced anywhere. Although you can’t technically “catch” them, you can subscribe to .NET Framework events so you can log them. Finding these exceptions is a great way to improve performance and eliminate weird application behaviors.
It is also important to note that first chance exceptions can include a lot of noise. Some exceptions happen because they are expected to, or may only happen when an application starts up as various warnings. Don’t be alarmed if you see some of this noise all of a sudden if you start logging these errors.
By subscribing to the event, you can potentially log every exception to help identify weird and hidden problems in your application. I don’t recommend doing this long term on a production application due to the sheer volume of noise and data it can cause. It is best used during development or to help find pesky production problems.
AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>
{
Debug.WriteLine(eventArgs.Exception.ToString());
};
ASP.NET Exception Handling
For ASP.NET web applications, you want to prevent users from receiving 500 level HTTP internal server error responses. How you do this exactly varies depending on if you are using various ASP.NET frameworks or ASP.NET Core. For starters, be sure to enable custom errors within your web.config file so your users never see exception pages.
Subscribe to Global.asax Application_Error Event
If your application has a Global.asax, which is essentially a HttpApplication, you should set up events around unhandled exceptions. It is important to know that depending on if you are using MVC, Web API, Nancy, SerivceStack, WCF, etc, that not all exceptions may bubble up to your Global.asax error handler. Those specific web frameworks may also have their own error handling mechanisms. We will cover those below as well!
//Global.asax
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
if (exception != null)
{
//log the error
}
}
protected void Application_Start()
{
//may have some MVC registration stuff here or other code
}
}
MVC Error Handling
With MVC you have the ability to utilize the HandleErrorAttribute to do custom error handling per MVC controller action. It also has an OnException event within the Controller. In general, you should be safe with global error handling via your Global.asax file to catch all exceptions.
More: Best Practices for Error Handling in ASP.NET MVC
Web API Error Handling
Web API has more advanced exception handling capabilities that you need to be aware of.
- Exception filter: Ability to customize error handling for specific controllers and actions.
- Exception logger: Enables logging all unhandled exceptions.
- Exception handler: Global handler to customize the response back to the calling party of your API.
An example of using the unhandled exception logger:
public class UnhandledExceptionLogger : ExceptionLogger
{
public override void Log(ExceptionLoggerContext context)
{
var log = context.Exception.ToString();
//Write the exception to your logs
}
}
You then need to register your exception logger as part of the startup configuration of Web API.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
//Register it here
config.Services.Replace(typeof(IExceptionLogger), new UnhandledExceptionLogger());
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
WCF Error Handling
Like Web API, WCF has a lot of customization options around exception handling. If you are using WCF, it is really critical that you setup an IServiceBehavior and IErrorHandler to properly catch all exceptions. Check out this example on CodeProject for the proper way to do it: WCF Global Exception Handling
ASP.NET Core Error Handling
A lot has changed with ASP.NET Core. How you collect unhandled exceptions is done via an ExceptionFilterAttribute. You can register it as a global filter and it will function as a global exception handler. Another option is to use a custom middleware designed to do nothing but catch unhandled exceptions.
public class ErrorHandlingFilter : ExceptionFilterAttribute
{
public override void OnException(ExceptionContext context)
{
var exception = context.Exception;
//log your exception here
context.ExceptionHandled = true; //optional
}
}
You must also register your filter as part of the Startup code.
//in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc(options =>
{
options.Filters.Add(new ErrorHandlingFilter());
});
}
.NET Framework Exception Events
The .NET Framework provides a couple events that can be used to catch unhandled exceptions. You only need to register for these events once in your code when your application starts up. For ASP.NET, you would do this in the Startup class or Global.asax. For Windows applications, it could be the first couple lines of code in the Main() method.
static void Main(string[] args)
{
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
}
static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
// Log the exception, display it, etc
Debug.WriteLine(e.Exception.Message);
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// Log the exception, display it, etc
Debug.WriteLine((e.ExceptionObject as Exception).Message);
}
More: AppDomain.UnhandledException Event (MSDN).
Find All C# Exceptions With Retrace
One of the great features of is it’s error monitoring capabilities. Retrace can automatically collect all .NET exceptions that are occurring within your application with no code changes. This includes unhandled exceptions but can also include all thrown exceptions, or first chance exceptions.
The best thing about this is it works with all types of ASP.NET applications. It works perfectly with MVC, WCF, Web API, .NET Core, etc.
Retrace provides excellent reporting around all of your exceptions. You can even setup alerts for high application exception rates or when a new exception is found.
Retrace offers three modes:
- No exceptions.
- Unhandled exceptions only.
- All exceptions thrown; use this to catch all exceptions.
View Exceptions in Windows Event Viewer
If your application has unhandled exceptions, that may be logged in the Windows Event Viewer under the category of “Application.” This can be helpful if you can’t figure out why your application suddenly crashes.
Windows Event Viewer may log 2 different entries for the same exception. One with a .NET Runtime error and another more generic Windows Application Error.
From the .NET Runtime:
Application: Log4netTutorial.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.IndexOutOfRangeException
at Log4netTutorial.Program.Main(System.String[])
Logged under Application Error:
Faulting application name: Log4netTutorial.exe, version: 1.0.0.0, time stamp: 0x58f0ea6b
Faulting module name: KERNELBASE.dll, version: 10.0.14393.953, time stamp: 0x58ba586d
Exception code: 0xe0434352
Fault offset: 0x000da882
Faulting process id: 0x4c94
Faulting application start time: 0x01d2b533b3d60c50
Faulting application path: C:UsersmattDocumentsVisual Studio 2015ProjectsLog4netTutorialbinDebugLog4netTutorial.exe
Faulting module path: C:WINDOWSSystem32KERNELBASE.dll
Report Id: 86c5f5b9-9d0f-4fc4-a860-9457b90c2068
Faulting package full name:
Faulting package-relative application ID:
Summary
Having good best practices around logging and exceptions is critical for every software application. Logging is typically the eyes and the ears of the developer. In this guide we covered several ways to find and catch all exceptions in C#. Be sure to also check out our exception handling and logging best practices guides.
Published at DZone with permission of Matt Watson, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments