Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# (not ASP/MVC/WinForms) - Catch all exceptions in a class

Tags:

Some background info

I am programming in a system that uses a proprietary programming language, with the option of using specially attributed .Net classes in the proprietary code.

Unfortunately, the system doesn't handle unhandled exceptions bubbling up from .Net code well, if fact not at all; the system crashes with no explanation. This is annoying, because we often want to handle exceptions in the proprietary system, not in .Net code. The solution offered by the vendor of the system is to repackage the exception into a special object that the system does handle.

Our .Net code is written in a façade pattern, and the problem is that to make sure every exception that bubbles up from the .Net code is handled, every method in the facade must include a try/catch block that repackages any exceptions that may occur.

The question

I've read a lot of threads here describing similar scenarios, most of them WinForms- or web-related. Because our code is neither, the question is if there is some way to catch all exceptions in a class, so that we can repackage it and rethrow a modified version of them?

Obviously, the interface between the .Net dll's containing the classes and the proprietary language is completely beyond our control.

Edit

I tried the currentDomain.UnhandledException method suggested by @VMAtm, unfortunately to no avail. The event handler didn't fire, and the parent system got hold of the exception and then misbehaved as usual. That led me onto Google once more, and I found this paragraph here:

The first thing to understand is that the UnhandledException event is not an unhandled exception "handler". Registering for the event, contrary to what the documentation says :-(, does not cause unhandled exceptions to be handled. (Since then they wouldn't be unhandled, but I'll stop with the circular reasoning already...) The UnhandledException event simply notifies you that an exception has gone unhandled, in case you want to try to save state before your thread or application dies.

Jonathan Keljo, CLR Exceptions PM

That was too bad, I liked the idea of having a "global" try/catch block. What I guess it means is that I'm not successful in hiding the exception from the parent system. Since I don't know the first thing about how this is implemented in that system (and frankly, I don't know the first thing about how I'd go on to implement it myself) I'm on really thin ice with my assumptions, so if anyone can correct me in any way, please go ahead!

Ohh, the error I'm getting in the parent system is Exception has been thrown by the target of an invocation., which is as far as I know the message from the outer .Net exception occurring. If it's possible to read anything out of that, I don't know.

I'll have a go at the Castle Dynamic Proxy suggested by @jlew as well, but it looked a lot harder than the two AppDomain lines and scared me quite a bit :)

Solution

If you are having the same problem as I had, you should try the currentDomain.UnhandledException method suggested by @VMAtm first, because it's because of my parent system being especially anal it didn't work.

I got it working by using the Castle DynamicProxy setup. It was really very easy to set up. My test case was a façade class encapsulating the XmlAttribute class. The first thing I had to do was to write the proxy class:

public class AttribInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        try
        {
            invocation.Proceed();
        }
        catch (Exception e)
        {
            // Custom exception repackaging here
        }
    }
}

Then I had to instruct the façade object to actually use the proxy. I kept my old backend field, but added the following to the c'tor:

public class CapXmlAttribute : CapPmlNetObject
{
    private XmlAttributeBackend _xmlAttribute;

    public CapXmlAttribute()
    {
        var generator = new ProxyGenerator();
        _xmlAttribute = (XmlAttributeBackend) generator.CreateClassProxy(
            typeof (XmlAttributeBackend), new AttribInterceptor());
    }
}

The last step was setting all methods in the backend that is exposed to the façade as virtual. This was no problem for me, but might be a dealbreaker for others.

DynamicProxy really isn't that good documented, but I learned a lot from Krzysztof Koźmic's tutorial and Hamilton Verissimo's codeproject.

like image 662
joneberg Avatar asked Jul 07 '11 13:07

joneberg


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

What is C in C language?

What is C? C is a general-purpose programming language created by Dennis Ritchie at the Bell Laboratories in 1972. It is a very popular language, despite being old. C is strongly associated with UNIX, as it was developed to write the UNIX operating system.

Is C language easy?

Compared to other languages—like Java, PHP, or C#—C is a relatively simple language to learn for anyone just starting to learn computer programming because of its limited number of keywords.

Why is C named so?

Because a and b and c , so it's name is C. C came out of Ken Thompson's Unix project at AT&T. He originally wrote Unix in assembly language. He wrote a language in assembly called B that ran on Unix, and was a subset of an existing language called BCPL.


2 Answers

As I understood the answer, you need to catch and rethrow unhandled exception, right? You can add handler for the AppDomain.UnhandledException Event:

  AppDomain currentDomain = AppDomain.CurrentDomain;
  currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);

  static void MyHandler(object sender, UnhandledExceptionEventArgs args)
  {
        Exception e = (Exception) args.ExceptionObject;
        // handle exception here, you can easily package exceptions there.
  }

Update:

I've discovered another event in AppDomain class, AppDomain.FirstChanceException Event:

Occurs when an exception is thrown in managed code, before the runtime searches the call stack for an exception handler in the application domain.

May be this can solve your problem - this event occurs before any code in catch blocks.

like image 75
VMAtm Avatar answered Oct 07 '22 02:10

VMAtm


I would take a look at using something like Castle Dynamic Proxy.
This will allow your class method calls to be intercepted in a generic way, which would give you a central place to put a "catch-all" exception handler. (That said, it's unclear to me how your classes are actually instantiated, which might make this approach problematic)

like image 28
jlew Avatar answered Oct 07 '22 00:10

jlew