I have an application developed in C # that uses a SQL Server database, this application is made available through a virtualized application server, I do not have direct access to the database or the application server.
I want to create a way to log all errors in the application so that later I can check them and correct them, if possible.
I was able to do this in the following way:
// Fontes
// http://www.macoratti.net/13/07/c_excep.htm
// https://tiesontrowbridge.com/code/using-linq-to-easily-serialize-an-exception-to-xml
// Classe que executa a aplicação (Program.cs)
static void Main()
{
// define o modo de tratamento dos erros não manipulados
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmMenu());
}
// -----------------------------------------------------------------------------
// Classe que serializa Exception (ExceptionXElement.cs)
using System;
using System.Collections;
using System.Linq;
using System.Xml.Linq;
public class ExceptionXElement : XElement
{
public ExceptionXElement(Exception exception)
: this(exception, false)
{ ; }
public ExceptionXElement(Exception exception, bool omitStackTrace)
: base(new Func<XElement>(() =>
{
XElement root = new XElement(exception.GetType().ToString());
if (exception.Message != null)
{
root.Add(new XElement("Message", exception.Message));
}
if (!omitStackTrace && exception.StackTrace != null)
{
root.Add(
new XElement("StackTrace",
from frame in exception.StackTrace.Split('\n')
let prettierFrame = frame.Substring(6).Trim()
select new XElement("Frame", prettierFrame))
);
}
if (exception.Data.Count > 0)
{
root.Add(
new XElement("Data",
from entry in exception.Data.Cast<DictionaryEntry>()
let key = entry.Key.ToString()
let value = (entry.Value == null) ? "null" : entry.Value.ToString()
select new XElement(key, value))
);
}
if (exception.InnerException != null)
{
root.Add(new ExceptionXElement(exception.InnerException, omitStackTrace));
}
return root;
})())
{ ; }
}
// -----------------------------------------------------------------------------
// Classe que representa o formulário principal de aplicação (frmMenu.cs)
using System;
using System.Threading;
using System.Windows.Forms;
public partial class frmMenu : Form
{
public frmMenu()
{
InitializeComponent();
// assina o evento para tratar exceções não manipuladas
Application.ThreadException +=
new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
}
private void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
ExceptionXElement logException = new ExceptionXElement(e.Exception);
logException.Save(@"D:\" + DateTime.Now.ToString("dd-MM-yy_HH-mm-ss") + ".xml");
Close();
}
private void frmMenu_Shown(object sender, EventArgs e)
{
int dividendo = 15, divisor = 0, resultado;
resultado = dividendo / divisor; // linha 25
Console.WriteLine("{0} / {1} = {2}", dividendo, divisor, resultado);
}
}
The output looks like this:
<?xml version="1.0" encoding="utf-8"?>
<System.DivideByZeroException>
<Message>Tentativa de divisão por zero.</Message>
<StackTrace>
<Frame>frmMenu.frmMenu_Shown(Object sender, EventArgs e) na frmMenu.cs:linha 25</Frame>
<Frame>System.Windows.Forms.Form.OnShown(EventArgs e)</Frame>
<Frame>System.Windows.Forms.Form.CallShownEvent()</Frame>
<Frame>System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme)</Frame>
<Frame>System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)</Frame>
<Frame>System.Threading.ExecutionContext.runTryCode(Object userData)</Frame>
<Frame>System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)</Frame>
<Frame>System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)</Frame>
<Frame>System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)</Frame>
<Frame>System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)</Frame>
<Frame>System.Windows.Forms.Control.InvokeMarshaledCallbacks()</Frame>
</StackTrace>
</System.DivideByZeroException>
My doubts are as follows:
- Is this the correct way to log in all application errors?
- Is there any contraindication to using this method?
- How should I display the error message for users in the
Application_ThreadException
method? Something very generic or more specific?