简体   繁体   中英

Catching an exception thrown in an asynchronous callback

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?

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

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.

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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM