Reputation: 4317
I have a method that takes a callback argument to execute asynchronously, but the catch block doesn't seem to be catching any exceptions thrown by the synchronous call (this.Submit
refers to a synchronous method).
public void Submit(FileInfo file, AnswerHandler callback)
{
SubmitFileDelegate submitDelegate = new SubmitFileDelegate(this.Submit);
submitDelegate.BeginInvoke(file, (IAsyncResult ar) =>
{
string result = submitDelegate.EndInvoke(ar);
callback(result);
}, null);
}
Is there a way to catch the exception thrown by the new thread and send it to the original thread? Also, is this the "proper" way to handle async exceptions? I wrote my code so it could be called like this (assuming the exception issue is fixed):
try
{
target.Submit(file, (response) =>
{
// do stuff
});
}
catch (Exception ex)
{
// catch stuff
}
but is there a more proper or elegant way to do this?
Upvotes: 9
Views: 17117
Reputation: 25201
If you're targeting .NET 4.0, you can utilize the new Task Parallel Library, and observe the Task
object's Exception
property.
public Task Submit(FileInfo file)
{
return Task.Factory.StartNew(() => DoSomething(file));
}
private void DoSomething(FileInfo file)
{
throw new Exception();
}
Then use it like this:
Submit(myFileInfo).ContinueWith(task =>
{
// Check task.Exception for any exceptions.
// Do stuff with task.Result
});
where DoSomething
is the method you'd like call asynchronously, and the delegate you pass to ContinueWith
is your callback.
More information about exception handling in TPL can be found here: http://msdn.microsoft.com/en-us/library/dd997415.aspx
Upvotes: 9
Reputation: 40516
This is not a 'best practice' solution, but I think it's a simple one that should work.
Instead of having the delegate defined as
private delegate string SubmitFileDelegate(FileInfo file);
define it as
private delegate SubmitFileResult SubmitFileDelegate(FileInfo file);
and define the SubmitFileResult as follows:
public class SubmitFileResult
{
public string Result;
public Exception Exception;
}
Then, the method that actually does the file submission (not shown in the question) should be defined like this:
private static SubmitFileResult Submit(FileInfo file)
{
try
{
var submissionResult = ComplexSubmitFileMethod();
return new SubmitFileResult { Result = submissionResult };
}
catch (Exception ex)
{
return new SubmitFileResult {Exception = ex, Result = "ERROR"};
}
}
This way, you'll examine the result object, see if it has the Result or the Exception field set, and act accordingly.
Upvotes: 8
Reputation: 13947
In short, no.
When you call submitDelegate.BeginInvoke
, it spawns the new thread, returns, and promptly exits your try/catch block (while the new thread runs in the background).
You could, however, catch all unhandled exceptions like this:
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(YourException);
This will catch everything in the application domain, however (not just your async method).
Upvotes: 5