I\'ve recently joined a project where we are extending the functionality of an e
ID: 644373 • Letter: I
Question
I've recently joined a project where we are extending the functionality of an external application that our company has bought.
It is an Office Add-In with an admin console that allows you to create Windows Forms style forms with code-behind files, and gives you a single place to store common code. This can be quite challenging when implementing code that would be simple in a 'normal' Windows Forms application.
How do I implement global error handling so we can log all errors?
We aren't using Visual Studio and have no access to csproj files so we can't use IL weaving / AOP. We don't have access to the starting point of the application so we can't subscribe to thread or application unhandled exception events. I suspect this is already being subscribed to in the external code, as unhandled exceptions are exposed in a custom error message box by default.
I'm currently looking to see if we can extend the external dlls; however I don't see where I'm going to call our extended code.
The alternative is to go through every method and add a try/catch block in just to log errors, which makes my skin crawl! This project has been running for a year without dealing with error handling yet so it will also take a long time to implement this approach too.
Pseudo-Example class:
namespace Scriptlets
{
using System;
using System.Windows.Forms;
public partial class NewClient : FormScriptType
{
protected override void PageChanged(object sender, PageChangedEventArgs e)
{
ChangeAddressLabels();
}
...
}
}
Explanation / Answer
About the logging - if you want to spare some typing of try/catch blocks, you could create one method that takes a Func or Action and wraps the execution in a try/catch block:
public T ExecuteAndLogIfFail<T>(Func<T> action)
{
try
{
return action();
}
catch (Exception exception)
{
Console.WriteLine("Implement your logger here: {0}", exception.Message);
}
return default(T);
}
You can now wrap your new code into this and you will always have exception handling.
Usage of the wrapper:
ExecuteAndLogIfFail<Boolean>(() =>
{
Console.WriteLine("Do something without output");
return true;
});
var zero = 0;
List<Int32> items = new List<Int32> { 10, 20, 30, 40, 50 };
var result = ExecuteAndLogIfFail<Int32>(() =>
{
return items.Sum(i => i / 10);
});
Console.WriteLine(result);
ExecuteAndLogIfFail<Boolean>(() =>
{
result /= zero; // catch and log!
return true;
});
If you haven't tried this already you could experiment with the AppDomain.CurentDomain object and hook the unhandled exception event:
AppDomain.CurrentDomain.UnhandledException += (s, e) =>
{
Console.WriteLine("something happened ...");
};
If you figured out, that the new window launch is wrapped in a try/catch block, you could try to modify (if this is ok) the assembly using Cecil and add a throw statement into the catch block. I once used the Reflexil Reflector plugin to inject code into an assembly and save the modified executable - no app start points needed. The plugin site states, that it works with Telerik's JustDecompile too.
The conclusion is - maintaining closed legacy systems is PITA.
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.