📜 ⬆️ ⬇️

Error message window for WinForms and WPF applications


Greetings

In the article dedicated to my profiler for the Entity Framework, I briefly described the form I used to inform the user about an exceptional error in the application. After estimating the number of downloads of the sample code, it was decided to separate this example into a separate project, and also add support for WPF applications.
The sources of the library, along with examples, are published on CodePlex under a free MIT license: https://uiexceptionhandler.codeplex.com/

Details under the cut.

Introduction

Everyone knows that applications periodically crash for a variety of reasons, while it is highly desirable to show the user a friendly error message in the application, instead of the standard Windows message.
')
What happened

When the library is connected, if the application crashes, the following message will be shown asking you to add a description of the steps that led to the error and your email for the response, while the error text is saved to the log file.


When clicking on the “Error detail information” button, additional error information is displayed:


The Debug button allows you to connect the Visual Studio debugger.
The “Send to Developer” button sends an email to the developer. In case of an error in sending a message, the user will be asked to send the log file to the developer himself by mail.
The message sent to the developer will come in this form:


Using

1. Pick up the latest version of the code https://uiexceptionhandler.codeplex.com/SourceControl/latest
2. Build in release mode.
3. From the “UIExceptionHandlerLibs \ Deploy” folder connect the UIExceptionHandlerWinForms.dll library to the project in the case of the WinForms application and UIExceptionHandlerWPF.dll in the case of the WPF application.
4. Initialize by calling a static method with a number of parameters:
UIException.Start( string serverSmtp, int portSmtp, string passwdSmtp, string userSmtp, string programmerEmail, string fromEmail, string subject ) 

How it works

The static UIException.Start method signs the HandleError method on the AppDomain.CurrentDomain.UnhandledException event:
 AppDomain.CurrentDomain.UnhandledException += (sender, e) => HandleError((Exception)e.ExceptionObject); 

HandleError Method:
 private static void HandleError(Exception exception) { try { //             IErrorHandlerForm new ErrorHandlerController(exception, new ErrorHandlerForm()).Run(); } catch (Exception e) { //      LogHelper.Logger.Error(e); //               MessageBox.Show("Error processing exception. Please send log file " + LogHelper.ExceptionLogFileName + " to developer: " + Settings.ProgrammerEmail + " \r\n Exception:" + e); //      if (MessageBox.Show("Attach debugger? \n Only for developer!!!", "Debugging...", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) { Debugger.Launch(); throw; } } finally { //     windows       Environment.Exit(1); } } 

Interface IErrorHandlerForm:
 public interface IErrorHandlerForm { event Action OnSendButtonClick; event Action OnShowErrorLinkClick; event Action OnLogFileLinkClick; event Action OnDebugButtonClick; //    void SetHeight(int height); //      string ExceptionInfoText { get; set; } //         string ExceptionDetailText { get; set; } // email    string ReplyEmail { get; } void ShowExceptionInfoTextBox(bool isShow); //    void ShowInfoMessageBox( string text, string caption); //    bool ShowQuestionDialog( string text, string caption); //     !          finaly void ShowViewDialog(); void UpdateContactEmail(string contactEmail); } 

NLog is used as a logging library. In order to avoid the appearance of unnecessary xml files, the entire configuration of the Nlog is done in the code:
 private static void ConfigureNlog() { var config = new LoggingConfiguration(); var fileTarget = new FileTarget(); config.AddTarget("file", fileTarget); fileTarget.Layout = @"${longdate} ${message}"; fileTarget.FileName = "${basedir}/" + ExceptionLogFileName; var rule2 = new LoggingRule("*", LogLevel.Trace, fileTarget); config.LoggingRules.Add(rule2); LogManager.Configuration = config; } 

In order to achieve maximum simple integration into the project, I decided to combine all the used assemblies into one library. This is done using the ILMerge application, by adding a script to the post-build event:
 if $(ConfigurationName) == Release ( "$(SolutionDir)ILMerge\ILMerge.exe" /out:"$(SolutionDir)Deploy\$(TargetFileName)" "$(TargetDir)*.dll" /target:dll /targetplatform:v4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319 /wildcards ) 



Afterword

This solution was written for a fairly large project, it has been used for more than 2 years, significantly improving the error correction process, because you will know about every application crash instantly, without additional notification from the user.

I hope all this will be useful to someone!
Thank you all for your attention!

Source: https://habr.com/ru/post/222163/


All Articles