I created a logging helper that I use for my WPF project. This is a large project with many different components. This was before I learned how to work with MVVM so please excuse if this breaks the pattern. This system is continuously expanding with new components to handle different tasks. You can think of a component as a standalone unit which handles a specific task, with the Main Component being the master of them all. This logging allowed us to log errors no matter in which component they occurred. It may be an overkill, but worked very well for us.
I am using the same principle to log all system wide events (User Actions, Data Changes..etc)
In my App.xaml.cs I catch all unhandled errors. Note that this is last resort of logging, I use try catch wherever I would expect exceptions to occur (db connections for example).
public partial class App : Application
{
void Application_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
ErrorEvent errorEvent = new ErrorEvent();
errorEvent.LogErrorEvent(e.Exception);
e.Handled = true;
}
}
ErrorEvent is a class within my Utilities dll that uses Event Routing to log the errors. I have different type of errors, depending on severity. All these errors are logged into a database, and the only component aware of the database connections is the main one. This is why I use Routing Event to send the exception to the Main Component to be logged. The ErrorEventHelper gets populated and routed to the Main Component. In situations where I am using try catches, I create the EventHelper and pass it to be logged using LogErrorEvent method. The ShowMessage property is used to decide if the user will be inform of the exception, or if it will only be logged.
public class ErrorEvent : UserControl
{
public delegate void ErrorEventEventHandler(object sender, RoutedCustomEventArgs e);
public static readonly RoutedEvent EventOccuredEvent = EventManager.RegisterRoutedEvent(
"EventOccured", RoutingStrategy.Bubble, typeof(ErrorEventEventHandler), typeof(ErrorEvent));
// Provide CLR accessors for the event
public event RoutedEventHandler EventOccured
{
add { AddHandler(EventOccuredEvent, value); }
remove { RemoveHandler(EventOccuredEvent, value); }
}
public void LogErrorEvent(ErrorEventHelper occuredEventDetails)
{
RoutedEventArgs newEventArgs = new RoutedCustomEventArgs(ErrorEvent.EventOccuredEvent, occuredEventDetails);
RaiseEvent(newEventArgs);
}
public void LogErrorEvent(Exception exception)
{
ErrorEventHelper occuredEventDetails = new ErrorEventHelper();
occuredEventDetails.ErrorType = ErrorEventHelper.EventTypes.Critical;
occuredEventDetails.ErrorValue = exception.Message;
occuredEventDetails.ErrorStack = exception.StackTrace;
occuredEventDetails.ShowMessage = true;
RoutedEventArgs newEventArgs = new RoutedCustomEventArgs(ErrorEvent.EventOccuredEvent, occuredEventDetails);
RaiseEvent(newEventArgs);
if (exception.InnerException != null)
{
LogErrorEvent(exception.InnerException);
}
}
public class RoutedCustomEventArgs : RoutedEventArgs
{
public ErrorEventHelper OccuredEventDetails { get; private set; }
public RoutedCustomEventArgs(RoutedEvent routedEvent, ErrorEventHelper occuredEventDetails)
: base(routedEvent)
{
this.OccuredEventDetails = occuredEventDetails;
}
}
}
public class ErrorEventHelper
{
public string ErrorValue { get; set; }
private EventTypes _ErrorType = EventTypes.Critical;
public EventTypes ErrorType
{
get
{
return _ErrorType;
}
set
{
_ErrorType = value;
}
}
public string ErrorStack { get; set; }
public bool ShowMessage { get; set; }
public enum EventTypes
{
Critical,
Warning,
Information
}
public void SendMessage()
{
ErrorEvent newEvent = new ErrorEvent();
newEvent.LogErrorEvent(this);
}
}
In the MainWindow I register the event handler.
EventManager.RegisterClassHandler(typeof(ErrorEvent),
ErrorEvent.EventOccuredEvent, new ErrorEvent.ErrorEventEventHandler(LogOccuredErrors));
And finally handle it:
private void LogOccuredErrors(object sender, ErrorEvent.RoutedCustomEventArgs e)
{
ErrorEventHelper eventHelper = e.OccuredEventDetails;
//Call Database Helper to log to database or output to file and email
StringBuilder builder = new StringBuilder();
builder.AppendLine(eventHelper.ErrorType);
builder.AppendLine(eventHelper.ErrorValue);
builder.AppendLine(eventHelper.ErrorStack);
if (eventHelper.ShowMessage)
{
MessageBox.Show(eventHelper.ErrorValue);
}
//Create your log file and email it
File.WriteAllText(@"C:\log.txt", ControllerBuilder.ToString())
//email here
}