Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

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.

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote