Why do we need exception handling?
- Prevent giving away sensitive business information
- Prevent the leakage of personally identifiable information
- Prevent giving away information that attackers can use to infiltrate our systems
- Ensure that our applications fail in a safe way that does not compromise our systems
- Provide application resiliency
- Provide a centralized location to channel our errors for monitoring and review
- Prevent uncaught or unanticipated errors from bubbling up to the end users
- Provide a means to log errors so that we can troubleshoot problems
To my business peers (because in an agile world we IT engineers and developers are your partners), addressing all of the concerns listed above translate to the prevention of lost dollars and a harmed business reputation. Properly implemented error handling can significantly reduce the time it takes to resolve problems so that we can stay focused on creating new features that add business value.
In ASP.NET Core, we have new middleware methods we can use to help achieve several of the error handling goals listed above.
Capture Exceptions During Host Startup
In an ASP.NET Core web application, the host is responsible for the startup and lifetime management of the applications. You can use an instance of the WebHostBuilder to create a host in the Main method of the Program.cs file.
The typical default host configuration setup looks something like the following:
You can configure some additional resiliency by adding the CaptureStartupErrors method to your WebHostBuilder configuration and pass in a value of true to instruct the host to attempt to capture startup exceptions and start the server. By default, the CaptureStartupErrors method displays a generic error page when a host startup error occurs. To see more detailed startup error information (for development purposes only), you can add the UserSetting method (with the “detailedErrors” key and a value of “true”) to your WebHostBuilder configuration. See lines 15-16 in the code sample below.
In the example above I have temporarily hard-coded the presentation of detailed host startup errors as I will address this concern in a future post on application configuration.
For more information on host configuration, see the Microsoft documentation called Hosting in ASP.NET Core.
Display Runtime Exception Details Using Middleware
ASP.NET Core runtime exceptions can be captured in the HTTP processing pipeline using one or more middleware options.
For my ASP.NET Core web services, I prefer to capture and log exception details and rethrow generic (non-detailed) messages to the client applications. However, when in development, I want all the details I can get to help me troubleshoot problems.
I have added new debugging middleware to my ASP.NET core web service Startup.cs file (see below).
I only want to see a detailed exception page when I am developing locally on my computer. In the Startup.cs file Configure method, I add an “if” statement block to determine whether I am running my code in the development environment by checking the IsDevelopment method for a value of true (on line 22).
I add the UseDeveloperExceptionPage method (line 24) to the ApplicationBuilder middleware configuration to elicit the display of a developer friendly error details page whenever an unhandled exception occurs.
I add the UseStatusCodePages method (line 25) to the ApplicationBuilder middleware configuration to elicit the display of a developer friendly short text message page whenever an HTTP exception occurs. This handy troubleshooting feature saves me time as I do not need to use debugging tools in a browser to determine what type of an HTTP exception occurred.
IMPORTANT: Do not use these exception details middleware methods in your production release code as they will give away too much sensitive information.
For more information on ASP.NET Core exception handling middleware, see the Microsoft documentation called: Error Handling in ASP.NET Core.
Other exception handling best practices include but are not limited to the use of try/catch blocks to log unhandled exceptions closer to a specific location in your code so that you can log enough details to assist with problem resolution, attempt resiliency actions, and obfuscate the problem message that bubbles up to client application code to prevent leaking sensitive information.
You can obtain the source code here.
You can find my other tutorials here.