3

I have bunch of Asynchronous commands. I want to write try..catch without much of repeating. Example:

_fooCommand = new AsynchronousCommand( () => { action } );
_barCommand = new AsynchronousCommand( () => { action } );

AsynchronousCommand is class that invokes Action using ThreadPool.QueueUserWorkItem( (state) => { action() } );.

Try..catch works well when is inside lambda:

_fooCommand = new AsynchronousCommand( () => { try.exception.catch } );

When outside then not:

try
    _fooCommand = new AsynchronousCommand( () => {...} );
catch

Exception is not catched.

Edit

I want to catch Exception not when creating command: when executing it using command.DoExecute(this) and if possible put try..catch inside lambda.

Tomasito
  • 1,864
  • 1
  • 20
  • 43
  • 3
    possible duplicate of [How to catch exceptions from a ThreadPool.QueueUserWorkItem?](http://stackoverflow.com/questions/753841/how-to-catch-exceptions-from-a-threadpool-queueuserworkitem) – HugoRune Mar 06 '14 at 15:28
  • No, I know how, I don't know how without repeating and I don't want to change ThreadPool to something else. – Tomasito Mar 06 '14 at 15:30
  • Move the try/catch into AsynchronousCommand constructor. – 001 Mar 06 '14 at 15:31
  • 3
    You understand that instantiating a new `AsynchronousCommand` does not actually invoke said command? Thus the try/catch on the outside could not possibly do anything. That being said, it looks like you want the semantics of async/await, which does propagate exceptions in the way you desire -- however they are not an in-place substitute for `QueueUserWorkItem` since it may or may not leverage threads. – Kirk Woll Mar 06 '14 at 15:32
  • @KirkWoll _fooCommand.DoExecute(this) invokes – Tomasito Mar 06 '14 at 15:33
  • That's a good point - my answer assumes you mean to invoke the command within the try catch, not just create it. – Chris Ballard Mar 06 '14 at 15:33

2 Answers2

3

Exceptions propagate up the call stack on the thread on which they are thrown. Because the commands run on a thread pool thread, it will be on a different thread to your try ... catch hence it doesn't get caught.

EDIT: Assuming you do actually invoke the command within the try ... catch

Chris Ballard
  • 3,771
  • 4
  • 28
  • 40
  • To resolve my problem I must put try..catch inside ThreadPool.QueueWorkItem and eventually invoke Action() from outside lambda if I don't want to write exception handling code in AsynchronousCommand (logging, etc)? – Tomasito Mar 06 '14 at 15:42
  • If you are running this code on a threadpool thread, the usual pattern is to have the exception handling within the `Action` itself, not in the code used to create the `AsynchronousCommand` or the code used to invoke it. – Chris Ballard Mar 06 '14 at 15:46
  • The `Action` is a call to external service. I want to catch `WebServiceException` and `WebException` but what when I'll need to catch some other exception. Commands can be different. – Tomasito Mar 06 '14 at 15:50
  • Just define your own action method, which itself wraps the external call in `try ... catch` and use that itself as the action when creating the `AsynchronousCommand` – Chris Ballard Mar 06 '14 at 15:52
2

You can get these semantics through the use of await. It when you await something it will schedule the remainder of the method as a continuation of the previous method, meaning that the operation is performed asynchronously. However, when the awaited operation finishes, if it represents something that throws an exception, that exception will be caught and then re-thrown within the context of your next continuation, allowing you to wrap a series of asynchronous operations in a single try/catch, having the syntax and semantics you desire. A simple example might look like:

public static async Task Foo()
{
    try
    {
        await Task.Run(() => DoSomething());
        await Task.Run(() => DoSomethingElse());
    }
    catch(Exception e)
    {
        Console.WriteLine(e);
    }
}

Here DoSomething and DoSomethingElse will be run in a thread pool thread, and if either throws an exception when running, not when being started, then the catch block will be hit.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • There is no guarantee that `DoSomething` and `DoSomethingElse` will be executed on a separate thread. It is likely to occur with the default task scheduler but explicitly not guaranteed when using `Task.Run()` – Odrade Mar 06 '14 at 15:54
  • @Odrade Any situation in which `Run` wouldn't start a new thread is almost certainly a context in which you wouldn't *want* it to use a new thread. Namely the only such situations are times where the current thread is also a thread pool thread, and would just end up being reclaimed if it didn't run the task synchronously, so it might as well just not get reclaimed and run the task inline. Any situation in which it would be important for `Run` to not run in the current thread is a situation in which it *won't* run in the current thread. It's not identical, true. it's superior. – Servy Mar 06 '14 at 15:58
  • @Tomasito Then you'll either need to find a way of emulating the `Task` model in this regard and having `AsynchronousCommand` catch the exception when invoking the action, and then re-throw it when the result is requested. If you cannot make such a change, or there is no mechanism whereby the caller is accessing the results (or it is not in the context you want to have your `try/catch`, then this isn't possible. – Servy Mar 06 '14 at 16:00
  • @Servy - I completely agree with you. I'm being pedantic because of the last sentence in your answer. – Odrade Mar 06 '14 at 16:01