- It is depending on your approach for example TPL: throw--> AggregateException.
- BackGroundWorker--> you have to take care about the error in result.
- Threads--> you have to marshall the error to the main thread.
- Tasks--> throw--> AggregateException.
- Async/await--> throw also AggregateException (I'm not sure).
Tasks approach offer a continuation to handle exceptions thrown by the antecedent and good error handling.
Async/await very flexible.
BackGroundWroker is legacy but still sometimes required.
Asynchronous programming with callbacks (in your case is also legacy) but it can be used; I recommend you to use the Tasks.
AggregateException: Represents one or more errors that occur during application execution. You will get a list of exceptions(from other thread) in the root AggregateException