Home All Groups Group Topic Archive Search About

Exception handling bug?: Control.Invoke()

Author
25 Apr 2007 10:18 AM
MagicBox
Hello all,

I'm currently working on exception handling for a multithreaded component.
It looks like I've ran into a framework bug when inner exceptions is
concerned.

The code:

        internal delegate void TcpipMethod(TcpipSocket socket);
        private TcpipMethod _internalReceive;

        private void CallbackReceive(IAsyncResult result)
        {
            TcpipCloseMode closeMode = TcpipCloseMode.None;
            TcpipSocket socket = result.AsyncState as TcpipSocket;
            try
            {
             ..
             ..
             if (_syncControl != null) _syncControl.Invoke(_internalReceive,
new object[] { socket });
             else InternalReceive(socket);
            }
            catch (ObjectDisposedException)
            {
            }
            catch (Exception exception)
            {
                if (!(exception is SocketException &&
((SocketException)exception).ErrorCode == 10054))
                {
                    if (_syncControl != null)
_syncControl.Invoke(_internalError, new object[] { socket, exception });
                    else InternalError(socket, exception);
                }
            }
       }

        private void InternalReceive(TcpipSocket socket)
        {
            try
            {
                DoReceive(new TcpipEventArgs<T>(socket));
            }
            catch (Exception e)
            {
                throw new TcpipException("Exception in receive event.", e);
            }
        }

The CallbackReceive method runs on its own asynchronous thread. The property
_syncControl is filled with UI control. This would allow me to synchronize
the read event (DoReceive) to the application main thread. This event is
called through the method InternalReceive which is the actual method being
synchronized.

The event caller (DoReceive) is placed in a try..catch block to capture any
exceptions that occur inside the user event. The reason for this approach is
to make sure user exceptions do not break the component.
ObjectDisposedException is one that could potentially break the component, as
it is generated by the user, and not in response to attempting to use a
closed socket inside the component.

The try block then raises a new exception (TcpipException) which takes the
caught exception as the inner exception parameter. One would expect this
raised exception be propagated back to the callback method as the
documentation for Control.Invoke() explains.

However, in the catch block inside the callback method, the exception is NOT
the newly raised exception TcpipException, but it is the inner exception
itself! If inside the user event an ObjectDisposed exception would have been
thrown, this would be the type of the caught exception in the callback
try..catch block.

When I re-raise the exception without specifying the inner exception, it
works fine and the callback method will catch the re-raised exception. But as
soon as an inner exception is specified, the re-raised exception gets ignored
somehow where the inner exception takes its place?

I am not sure if this intended behaviour, but to me this sure doesn't seem
to be the intended way. I've searched for any information on this subject,
but I haven't found any exceptional situations to this.

Effectively, it appears I can not 'remap' exceptions thrown in
Control.Invoke'd methods while this (in my eyes) expected behaviour is
critical for the component to operate...

AddThis Social Bookmark Button