In case you haven’t already found out, every application will fail sooner rather than later.
The question is not how you can code the perfect application that will never break. The question is how you can code an application that will make it easier to find and solve problems in the future.
Besides showing an error to the user, you’ll want to log the error details somewhere. It could be to a file, to a database, to a web service or even in an email. I would recommend doing it to more than one place.
In this post, we’re going to see how to log errors to the Windows Event Log (Start Menu -> Administrative Tools -> Event Viewer).
The .NET Framework provides the EventLog class to easily read and write entries to the Windows Event Log. This class is in the System.Diagnostics namespace.
To write to the Event Log, we call the WriteEntry method, which has several overloads. For instance, we can call the following static (shared) overload. This way, we don’t need to create an instance of the EventLog class.
EventLog.WriteEntry("Source", "Error Description.", EventLogEntryType.Warning);
The first parameter corresponds to the Source of the event, which usually is the application or component name.
The second parameter is the description or message of the event. In this case, we would want to log the details of an exception.
The third parameter is for the type or level of the event. It could be Information, Warning, or Error. There are a couple other types that are specific to Security log. The EventLogEntryType enumeration holds the different event types.
There are other overloads of this method that allow us to specify an event ID and a category. We can define different values for these numeric fields according to the error type in our application.
Before we can use a source to write entries in the event log, we need to register it. We register the event source with the CreateEventSource method.
EventLog.CreateEventSource("Application name", "Log name");
The first parameter is the source name, and it would usually be the application name. This method scans all the logs to make sure the new source name is unique. There could problems calling this method similar to the problems with the SourceExists method, which we discuss below.
The second parameter is the log we want to write entries to every time we use this source. It could be Application, Security, System, or a custom log. If we pass a log name that doesn’t exist, a new custom log is created.
We only need to register an event source once. We can check if a source is already registered with the SourceExists method.
if (!EventLog.SourceExists("Application name"))
This method scans every log to check if a source name exists.
Starting with Windows Vista, we need Administration rights to read the Security log. If we don’t have enough rights, we could get a SecurityException when calling SourceExists.
The source was not found, but some or all event logs could not be searched. Inaccessible logs: Security.
This would happen if our source was not found in any of the accessible logs, such as Application. If the source is found before the method tries to scan the Security log, there would be no issues. So at least the first time we’re trying to write an entry to the event log, we need to run the application as administrator.
The ideal solution would be to create the source during the installation of the application since the installer is run with administrative privileges.
Here’s a little error handler we could use in our applications.
using System; using System.Windows.Forms; using System.Diagnostics; namespace Example.Business { public enum ErrorType { Critical, Minor, Information } class ErrorHandler { private const String source = "Sample App"; private const String log = "Application"; internal static void LogError(String msg, ErrorType type, Exception ex) { try { if (!EventLog.SourceExists(source)) EventLog.CreateEventSource(source, log); if (type == ErrorType.Information) EventLog.WriteEntry(source, ex.ToString(), EventLogEntryType.Information); else if (type == ErrorType.Minor) EventLog.WriteEntry(source, ex.ToString(), EventLogEntryType.Warning); else EventLog.WriteEntry(source, ex.ToString(), EventLogEntryType.Error); } catch { } } internal static void HandleError(String msg, ErrorType type, Exception ex) { //Log error LogError(msg, type, ex); //show message if appropriate if (type == ErrorType.Critical) { MessageBox.Show(msg, source, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } } } }
We give the option to show the error to the user. We could create a form to display more details to the user, but here, we just use a message box.
I left the code to create the event source if it doesn’t exist already. As I mentioned before, it’s better to put that in the application installer. We’ll see how to create an installer in another post.
Here’s some code from a form to try out the error handler.
using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; using Example.Business; namespace Example.UI { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { try { throw new Exception("Unable to load form."); } catch (Exception ex) { ErrorHandler.HandleError("An error has occurred loading Form1.", ErrorType.Critical, ex); } } } }
Here’s the message the user would get.
And here’s the entry in the Event Viewer.
Please leave your comments if you have any question or suggestion.