M
Marcel Overweel
Hi,
I've got a problem with exception handling when using async methods.
Actually, the code seems to runs fine, but the debugger reports that an
exception is not handled by user code, while in fact it is handled properly.
Basicly, I start a method using a delegate's BeginInvoke().
In this method, an exception is raised.
In the callback methode, I catch this exception and store it in a variable
of a custom asyncresult object.
This whole is wrapped in a set of Begin/CallBack/End methods which
uses this custom asyncresult object to return the result of the process.
It is difficult for me to just explaining the details,
so here is the code, excluding irrelevant details:
* Code of the class containing the async agony:
// This method is called using a delegate.BeginInvoke (see below)
protected BasicReturnCode DoPing()
{
.. some irrelevant code ..
BasicReturnCode res = DoSomeWork();
.. some irrelevant code ..
return res;
}
private BasicReturnCode DoSomeWork()
{
.. Here, some work is done and a
.. TimeoutException can be thrown.
. <-- Exception is thrown here at the end of the method
} <-- Here the debugger reports the following:
"TimeoutException was unhandled by user code"
private delegate BasicReturnCode PingDelegate();
// The caller will call this method to start the ascyn operation:
public IAsyncResult BeginPing(
AsyncCallback userCallback, Object stateObject)
{
AsyncResult<BasicReturnCode> ar =
new AsyncResult<BasicReturnCode>(userCallback, stateObject);
PingDelegate d = new PingDelegate(this.DoPing);
IAsyncResult i_ar = d.BeginInvoke(
new AsyncCallback(this.PingCallback), ar);
return ar;
}
public BasicReturnCode EndPing(IAsyncResult asyncResult)
{
return ((AsyncResult<BasicReturnCode>)asyncResult).EndInvoke();
}
protected void PingCallback(IAsyncResult i_ar)
{
Exception ex_return = null;
BasicReturnCode ret = null;
try
{
ret = ((PingDelegate)
((AsyncResult)i_ar).AsyncDelegate).EndInvoke(i_ar);
}
catch (TimeoutException ex) <-- Exception IS catched AFTER the
debugger reported that is was unhandled!
{
ex_return = ex; // Time-out during communication.
}
AsyncResult<BasicReturnCode> ar =
(AsyncResult<BasicReturnCode>)(i_ar.AsyncState);
if (ex_return == null)
ar.SetAsCompleted(ret, false);
else
ar.SetAsCompleted(ex_return, false);
}
* Code on the calling Form:
private void buttonPing_Click(object sender, EventArgs e)
{
Terminal t = new Terminal(.. some parameters ..);
t.BeginPing(this.OnPingComplete, t);
}
private void OnPingComplete(IAsyncResult ar)
{
Terminal t = ((Terminal)ar.AsyncState);
try
{
BasicReturnCode r = t.EndPing(ar);
.. show result ..
}
catch (TimeoutException ex) // Timeout during communication
{
.. show exception .. <-- This is performed, so it IS handled
}
}
Note that all code is in the same assembly except for the calling code
(the buttonPing_Click and OnPingComplete).
And all code is user code.
So why do I get that message from the debugger?
If it's just an annoying message, I can live with it.
But this means I've made some structural error, I do not want to
release it to our clients.
Also, I don't want to disable the catching of these exceptions becuase
I do want to know it when I don't catch it myself.
regards,
Marcel
I've got a problem with exception handling when using async methods.
Actually, the code seems to runs fine, but the debugger reports that an
exception is not handled by user code, while in fact it is handled properly.
Basicly, I start a method using a delegate's BeginInvoke().
In this method, an exception is raised.
In the callback methode, I catch this exception and store it in a variable
of a custom asyncresult object.
This whole is wrapped in a set of Begin/CallBack/End methods which
uses this custom asyncresult object to return the result of the process.
It is difficult for me to just explaining the details,
so here is the code, excluding irrelevant details:
* Code of the class containing the async agony:
// This method is called using a delegate.BeginInvoke (see below)
protected BasicReturnCode DoPing()
{
.. some irrelevant code ..
BasicReturnCode res = DoSomeWork();
.. some irrelevant code ..
return res;
}
private BasicReturnCode DoSomeWork()
{
.. Here, some work is done and a
.. TimeoutException can be thrown.
. <-- Exception is thrown here at the end of the method
} <-- Here the debugger reports the following:
"TimeoutException was unhandled by user code"
private delegate BasicReturnCode PingDelegate();
// The caller will call this method to start the ascyn operation:
public IAsyncResult BeginPing(
AsyncCallback userCallback, Object stateObject)
{
AsyncResult<BasicReturnCode> ar =
new AsyncResult<BasicReturnCode>(userCallback, stateObject);
PingDelegate d = new PingDelegate(this.DoPing);
IAsyncResult i_ar = d.BeginInvoke(
new AsyncCallback(this.PingCallback), ar);
return ar;
}
public BasicReturnCode EndPing(IAsyncResult asyncResult)
{
return ((AsyncResult<BasicReturnCode>)asyncResult).EndInvoke();
}
protected void PingCallback(IAsyncResult i_ar)
{
Exception ex_return = null;
BasicReturnCode ret = null;
try
{
ret = ((PingDelegate)
((AsyncResult)i_ar).AsyncDelegate).EndInvoke(i_ar);
}
catch (TimeoutException ex) <-- Exception IS catched AFTER the
debugger reported that is was unhandled!
{
ex_return = ex; // Time-out during communication.
}
AsyncResult<BasicReturnCode> ar =
(AsyncResult<BasicReturnCode>)(i_ar.AsyncState);
if (ex_return == null)
ar.SetAsCompleted(ret, false);
else
ar.SetAsCompleted(ex_return, false);
}
* Code on the calling Form:
private void buttonPing_Click(object sender, EventArgs e)
{
Terminal t = new Terminal(.. some parameters ..);
t.BeginPing(this.OnPingComplete, t);
}
private void OnPingComplete(IAsyncResult ar)
{
Terminal t = ((Terminal)ar.AsyncState);
try
{
BasicReturnCode r = t.EndPing(ar);
.. show result ..
}
catch (TimeoutException ex) // Timeout during communication
{
.. show exception .. <-- This is performed, so it IS handled
}
}
Note that all code is in the same assembly except for the calling code
(the buttonPing_Click and OnPingComplete).
And all code is user code.
So why do I get that message from the debugger?
If it's just an annoying message, I can live with it.
But this means I've made some structural error, I do not want to
release it to our clients.
Also, I don't want to disable the catching of these exceptions becuase
I do want to know it when I don't catch it myself.
regards,
Marcel