Catching Exceptions INSIDE a delegate in a generic fashion - c#

I need help identifying a generic way of catching exceptions that are thrown from within a delegate when that delegate contains a Task.Run that is throwing an exception. Currently, when I invoke a delegate (in this case a func) that is passed into another "master" method and an exception is thrown from within a Task.Run in the delegate, the exception is not caught with a try/catch in the code surrounding the invocation. The following simplified example shows the exceptions inside the delegate being caught by the try/catch inside the delegate but being "lost" elsewhere:
public static void Main()
{
AppDomain.CurrentDomain.UnhandledException += (s, e) => CurrentDomain_UnhandledException();
TaskScheduler.UnobservedTaskException += (s, e) => CurrentDomain_UnhandledException();
HandledDelegate(() => Task.Run(() =>
{
try
{
Console.WriteLine("Executed");
throw new Exception($"Caught");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw new Exception($"Caught Again");
}
}
));
}
private static void CurrentDomain_UnhandledException()
{
Console.WriteLine("Unhandled Exception Occurred.");
}
public static void HandledDelegate(Action a)
{
try
{
a.Invoke();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
Thread.Sleep(10000);
}
And the following example shows the exception not being caught within the try/catch around the invoke, and bubbling up to the app domain as an unhandled exception.
public static void Main()
{
AppDomain.CurrentDomain.UnhandledException += (s, e) => Console.WriteLine("Unhandled Exception");
HandleDelegateEx(async () => await Task.Run(() => throw new Exception("test")));
Thread.Sleep(1000);
}
public static void HandleDelegateEx(Action a)
{
try
{
a.Invoke();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
This last one is most like my current code which I need to fix. The delegates often Task the code off on a background thread and don't handle any errors (expecting them to be caught by where the delegate is invoked.
This code is used throughout the app in hundreds of locations, and few, if any, catch exceptions within the delegate (as other programmers erroneously thought that exceptions thrown by the delegate would be caught). Is there any way to catch exceptions thrown from inside these delegates without massively refactoring each and every delegate to catch exceptions?

The issue is not connected to delegate itself. In your fiddle you don't wait for Task returned by delegate to complete. Basically the delegate will return Task and the method will continue. In your original code in question:
try
{
// Execute the requested action.
retval = clientOperation.Invoke(remoteObj);
}
catch(ex)
{
// log here.
}
finally
{
CloseChannel(remoteObj);
}
It will jump straight to finally clause and attempt to close connection. You need to handle Func's returning tasks separately:
public void HandleDelegateEx<T>(Func<T> a)
{
try
{
a.Invoke();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public async Task HandleDelegateExAsync<T>(Func<Task<T>> a)
{
try
{
await a.Invoke();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
HandleDelegateEx<int>(() => throw new Exception("test")); // prints "test"
Func<Task<int>> func = () => Task.FromException<int>(new Exception("test async"));
HandleDelegateEx(func); // does not print anything
await HandleDelegateExAsync(func); // prints "test async"
You can get the same behavior without delegates:
Task task = null;
try
{
task = Task.FromException(new Exception("test async"));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message); // does not go here
}
await task; // throws here

In order for your exceptions to be observed, you would either have to await the returned task as Guru Stron suggests (implying a massive refactoring I guess). Or somehow adding Wait() to the result of the Task.Run() call, but this will block the calling thread (I'm assuming this is the UI thread) while the background thread churns the delegate - neglecting the benefit of the task being a background thread in the first place.
So, most probably, here is the crux of the problem: you need to wait for the background Task to finish so you can observe any possible exceptions, without blocking the UI thread, and do this while modifying the least amount of code.
I'm assuming your application is either Windows Forms or WPF.
For the first problem -waiting for the task to finish without blocking the UI thread-, I would turn to the old (and very frowned upon) Application.DoEvents() (or its equivalent in WPF, second answer). This is strongly discouraged these days, but I guess it is much better than ignoring exceptions that should have been handled (and keep in mind this was valid and in fact, the only way of keeping a responsive UI in the 16-bit era).
Instead of adding Wait(), to the background task, I would wait for its completion with the following loop:
while( !backgroundTask.IsCompleted ) {
Application.DoEvents(); // keep UI responsive while background task finishes
}
Now, the second problem, we would have to somehow inject this loop right after the background task is queued in the thread pool, and as you describe, this occurs in potentially hundreds of places.
Here I would try using Harmony, a very powerful dynamic IL patching tool. This tool allows you to target a method and piggyback a prefix and/or a postfix method. The prefix method will be called automatically before the target method is called, and the postfix method will be called after the target method is called.
The patching would look something like this:
// Must be called once before the target delegates are executed
private void MyClass.Patch() {
var original = typeof(Task).GetMethod("Run", ...); // I'm omitting the code that would select the (Action action) overload
var postfix = typeof(MyClass).GetMethod("WaitWithResponsiveUI", ...);
harmony.Patch(original, postfix: new HarmonyMethod(postfix));
}
private void MyClass.WaitWithResponsiveUI(ref Action __result) {
// __result contains the original Task returned by Task.Run()
while( !__result.IsCompleted ) {
Application.DoEvents(); // keep UI responsive while background task finishes
}
__result.Wait(); // Any exceptions produced inside the delegate should be rethrown at this moment, and they should be trappable by the code that invoked the delegate
}
Of course, this has the disadvantage that every Task.Run(Action action) called after patching would now wait until the task is done, globally, and this might not be desirable for every call.
EDIT: In defense of Application.DoEvents();
Here is a very well written answer detailing all the potential pitfalls of using Application.DoEvents(). These pitfalls are real and should be considered.
However, one aspect I strongly disagree is the assertion that the async-await mechanism is a safe way to avoid all these problems. That is simply not true.
When a UI event handler finds an await, it basically sets up a continuation that will be able to resume the event handling in the future, and immediately returns, giving the application's message pump a chance to continue running (basically what Application.DoEvents(), with the difference that the latter will return once the event queue is empty).
When the awaited operation completes, the continuation IS enqueued as another event into the Message event queue, so it won't resume execution until the message pump has handled all the events that have been posted before. My point being - While the operation is awaited, messages ARE being processed and you still need to protect your application from any reentrancy pitfalls manually. See here: Handling Reentrancy in Async Apps (C#).
Another pitfall exclusive to async-await UI code is that some components (DataGridView comes to mind) pass some of their event arguments to their handlers in objects that implement IDisposable. The component raises the event, and disposes the arguments as soon as the event handler returns. In async code, this return to the caller will happen when the first await in the handler code is reached. This has the effect that when the awaited code resumes, accessing the event-arguments object throws an ObjectDisposedException, as it has already been disposed by the raising component itself!
The "false multithreading" aspect is already being handled here, as the work is truly being offloaded to the thread pool.
So, in my opinion, the only real problem to address is the potential stack-overflow problem, that could be addressed by reentrancy avoidance measures that have to be accounted for in the first place, whether you use async/await or DoEvents().

Related

Invoke event asynchronously and catching exceptions without stopping other tasks from running

Given the following code:
public delegate Task AsyncEventHandler<in TEventArgs>(object sender, TEventArgs eventArgs);
public static Task InvokeAsync(this AsyncEventHandler eventHandler, object sender, EventArgs eventArgs)
{
if (eventHandler == null) return Task.CompletedTask;
var delegates = eventHandler.GetInvocationList().Cast<AsyncEventHandler>();
var tasks = delegates.Select(it => it.Invoke(sender, eventArgs));
return Task.WhenAll(tasks);
}
I have a test function whereby the faulty handlers should throw exceptions, and the workinghanlder should run - currently only the first FaultyHandler1 is called and no others event handlers.
private class NonGenericNotifier
{
public event AsyncEventHandler SomethingHappened;
public Task OnSomethingHappening() => SomethingHappened.InvokeAsync(this, EventArgs.Empty);
}
public async Task Multiple_Exceptions_That_Occur_During_Event_Handling_Should_Be_Propagated()
{
var isHandler1Called = false;
var isHandler2Called = false;
var isWorkingHandlerCalled = false;
var notifier = new NonGenericNotifier();
Task FaultyHandler1(object sender, EventArgs eventArgs)
{
isHandler1Called = true;
throw new InvalidOperationException();
}
Task FaultyHandler2(object sender, EventArgs eventArgs)
{
isHandler2Called = true;
throw new InvalidOperationException();
}
Task WorkingHandler(object sender, EventArgs eventArgs)
{
isWorkingHandlerCalled = true;
return Task.CompletedTask;
}
notifier.SomethingHappened += FaultyHandler1;
notifier.SomethingHappened += FaultyHandler2;
notifier.SomethingHappened += WorkingHandler;
await Should.ThrowAsync<InvalidOperationException>(async () => await notifier.OnSomethingHappening());
isHandler1Called.ShouldBe(true);
isHandler2Called.ShouldBe(true);
isWorkingHandlerCalled.ShouldBe(true);
}
Assuming a single exception can be thrown I beleive this should be an AggregateException containing an exception for each Task, and most importantly the InvokeAsync method above should bail on the first exception encountered.
I have started to create a List<Exception> within the InvokeAsync extension method, and wrap each it => it.Invoke(sender, eventArgs) with a try/catch construct and within the catch add the exception to the exception list.
However I am lost on how to collate this list of exceptions and then send on as an AggregateException.
UPDATE (FIX?)
Thanks to Artur for pointing me in the right direction. I changed the InvokeAsync extension method to the below, and it works - no longer halting on the first task. We have gone from var tasks = delegates.Select(it => it.Invoke(sender, eventArgs)); to the below using the code here:
public static Task InvokeAsync(this AsyncEventHandler eventHandler, object sender, EventArgs eventArgs)
{
if (eventHandler == null) return Task.CompletedTask;
var delegates = eventHandler.GetInvocationList().Cast<AsyncEventHandler>();
var tasks = delegates.Select(async it => await it.Invoke(sender, eventArgs));
return Task.WhenAll(tasks).WithAggregatedExceptions();
}
static Task WithAggregatedExceptions(this Task task)
{
// using AggregateException.Flatten as a bonus
return task.ContinueWith(
continuationFunction: priorTask =>
priorTask.IsFaulted &&
priorTask.Exception is AggregateException ex && (ex.InnerExceptions.Count > 1 || ex.InnerException is AggregateException) ? Task.FromException(ex.Flatten()) : priorTask,
cancellationToken: CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
scheduler: TaskScheduler.Default).Unwrap();
}
My issue is subscribers of this event, writing synchronous handlers over which I have no control - this would stop the other event handlers (sync and async) running that are attached to the same event.
I also appreciate this is the designed function of Task.WhenAll if you were mixing async and non-async handlers... if there is one reason to not write synchronous code in an async function without await Task.Yield() this is it.
Question
Can we say that wrapping the delegates.Select(async it => await it.Invoke(sender, eventArgs) with async/await allows synchronous method to run, and at worst(?) wrap twice an async method (which is the same as nesting async/await function calls) so is actually a non-issue?
Are there any side effects that have been introduced?
With the bounty looking for authorative guidance on how this would be implemented, one answer (much appreciated for contributing to the discussion) says to avoid async events, yet in other places like the discord c# client they have embraced async events (with timeout wrappers etc).
Task.WhenAll will invoke all the handlers when it reifies its parameter. It will invoke them one at a time, and then will asynchronously wait for all the tasks to complete.
The reason you were seeing the halting on the first exception was because the exception was thrown during reification. It's normal for asynchronous (Task-returning) functions to place any exceptions on the returned task. It's abnormal for asynchronous functions to throw exceptions directly.
So, this is the problematic code:
Task FaultyHandler1(object sender, EventArgs eventArgs)
{
isHandler1Called = true;
throw new InvalidOperationException();
}
One of these would be correct:
async Task FaultyHandler1(object sender, EventArgs eventArgs)
{
isHandler1Called = true;
throw new InvalidOperationException();
}
Task FaultyHandler1(object sender, EventArgs eventArgs)
{
isHandler1Called = true;
return Task.FromException(new InvalidOperationException());
}
You're seeing the odd behavior because the asynchronous handler is misbehaving (by throwing a synchronous exception).
Now, if you want to allow misbehaving asynchronous handlers, you can do that, either with an explicit try/catch or the extra async/await:
var tasks = delegates.Select(it => try { return it.Invoke(sender, eventArgs); } catch (Exception ex) { return Task.FromException(ex); });
// async/await is necessary to handle misbehaving asynchronous handlers that throw synchronous exceptions
var tasks = delegates.Select(async it => await it.Invoke(sender, eventArgs));
If you do keep the async/await approach, please do comment it, because coding constructs like that are often assumed to be spurious and may be removed by a future maintainer.
The WithAggregatedExceptions looks fine as-is, but it can be simplified if you want:
static async Task WithAggregatedExceptions(this Task task)
{
try { await task; }
catch { throw task.Exception; }
}
My issue is subscribers of this event, writing synchronous handlers over which I have no control - this would stop the other event handlers (sync and async) running that are attached to the same event.
Well, yes. Task.WhenAll reifies its collection of tasks synchronously, which invokes all the handlers one at a time.
If you want to allow synchronous handlers as well as asynchronous ones all at the same time, you can wrap the invocations in a Task.Run:
var tasks = delegates.Select(it => Task.Run(() => it.Invoke(sender, eventArgs)));
Can we say that wrapping the delegates.Select(async it => await it.Invoke(sender, eventArgs) with async/await allows synchronous method to run, and at worst(?) wrap twice an async method (which is the same as nesting async/await function calls) so is actually a non-issue?
The extra async/await for asynchronous handlers is a non-issue; it's very slightly less efficient, and appears unnecessary, so I'd say it's in danger of being removed (unless commented). It doesn't "allow synchronous methods to run"; instead, it corrects the misbehaving methods that throw exceptions directly instead of placing them on the returned Task as expected.
Are there any side effects that have been introduced?
Not really. If you do use the Task.Run approach, then all the handlers are invoked on thread pool threads and may run concurrently, which may be surprising.
one answer (much appreciated for contributing to the discussion) says to avoid async events, yet in other places like the discord c# client they have embraced async events (with timeout wrappers etc).
I am 100% in agreement with that answer.
Here's how I think about it:
The Observer pattern is a way to notify observers of state changes. The Observer pattern is a clear fit for "events" in OOP: any number of observers may subscribe to state change notifications. This is what C# events were patterned after: notifying subscribers of things. There's no mechanism for information to "flow back". While the language allows C# events with return values, it's not natural by any means. The same limitation happens with exceptions (which can be considered a kind of return): the standard handler?.Invoke pattern starts to break (stopping invocations at the first exception, etc).
As soon as you have information "flowing back" (including needing to handle exceptions, or needing to await all the handlers to complete), you're no longer in the Observer pattern, and you are no longer in the happy path of C# events.
Generally, I find most "events" of this type are usually related to a Strategy or Visitor pattern, rather than Observer. Neither Strategy nor Visitor are good fits for C# events, although they are often (sadly) implemented that way. I consider that a common design mistake (for all OOP languages).
In my opinion, the design of using C# events in an async way is not robust, and it will always behave in a slightly uncontrolled way. There are better techniques to make event processing robust.
One of the best such technologies is TPL Dataflows (https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/dataflow-task-parallel-library). This library allows you to program stream processing in a very controlled way, it helps you deal with task schedulers etc. Once you apply this successfully, all the problems in your question will be addressed.
There are obviously other alternatives out there, but I would clearly abstain from re-implementing this by using C# events....

How to catch an Exception that has been thrown in the ContinueWith part of a task?

On a button_click event, I start a Task to do some time consuming calculations asynchronously. I use Task.ContinueWith and set the TaskSheduler for the continuation to the UI synchronization context to display the result of the asynchronous calculations in a Textbox.
Now lets say this last part throws an Exception like this:
private void button1_Click(object sender, EventArgs e)
{
Task.Factory.StartNew(DoSomeCalculations).ContinueWith
(t => { throw new Exception("Some Exception"); }, TaskScheduler.FromCurrentSynchronizationContext());
}
If I enable the debug option "Enable Just My Code" then the program halts and I get a warning: "Exception was unhandled by user code"
But if I don't set this option, the Exception disappears in nowhere (no program crash, just nothing).
So how/where can I handle this Exception?
Edit: Please note, as the tag suggests, I'm using .NET-4.0
If you want to handle the exception then either have a try/catch block inside the continuation itself, so that it handles its own exceptions or add an additional continuation to the continuation to handle exceptions.
Note that if you use await rather than ContinueWith to add continuations it's typically simpler, particularly when dealing with exceptions, as it will add the continuations on your behalf.
If you are using .NET framework 4.5, there's a new way to deal with Task objects.
private async void button1_Click(object sender, EventArgs e)
{
await Task.Run(() =>
{
DoSomethingAsync()
});
//this line will run in UI thread
throw new Exception("Some Exception");
}
And take note that any exception that's happening inside the Task object is swallowed inside the state machine created by the compiler when you use the async keyword. But this exception is set inside the Task object so basically you can still have reference to the exception using the Task object.
Something for your reference:
http://blog.stephencleary.com/2012/02/async-and-await.html
According to best practices if we can't escape the use of async void methods (especially for event handlers), the try catch should be implemented in that method. But you need to make sure that all the async methods you are calling have the async Task method signature in order to catch the exception being thrown.

call method from another thread without blocking the thread (or write custom SynchronizationContext for non-UI thread) C#

This is probably one of the most frequent questions in the Stackoverflow, however I couldn't find the exact answer to my question:
I would like to design a pattern, which allows to start thread B from thread A and under specific condition (for example when exception occurs) call the method in thread A. In case of exception the correct thread matters a lot because the exception must call a catch method in the main thread A. If a thread A is an UI thread then everything is simple (call .Invoke() or .BeginInvoke() and that's it). The UI thread has some mechanism how it is done and I would like to get some insights how it would be possible to write my own mechanism for the non-UI thread. The commonly suggested method to achieve this is using the message pumping http://www.codeproject.com/Articles/32113/Understanding-SynchronizationContext-Part-II
but the while loop would block the thread A and this is not what I need and not the way how UI thread handles this issue. There are multiple ways to work around this issue but I would like to get a deeper understanding of the issue and write my own generic utility independently of the chosen methods like using System.Threading.Thread or System.Threading.Tasks.Task or BackgroundWorker or anything else and independently if there is a UI thread or not (e.g. Console application).
Below is the example code, which I try to use for testing the catching of the exception (which clearly indicates the wrong thread an exception is thrown to). I will use it as an utility with all the locking features, checking if a thread is running, etc. that is why I create an instance of a class.
class Program
{
static void Main(string[] args)
{
CustomThreads t = new CustomThreads();
try
{
// finally is called after the first action
t.RunCustomTask(ForceException, ThrowException); // Runs the ForceException and in a catch calls the ThrowException
// finally is never reached due to the unhandled Exception
t.RunCustomThread(ForceException, ThrowException);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
// well, this is a lie but it is just an indication that thread B was called
Console.WriteLine("DONE, press any key");
Console.ReadKey();
}
private static void ThrowException(Exception ex)
{
throw new Exception(ex.Message, ex);
}
static void ForceException()
{
throw new Exception("Exception thrown");
}
}
public class CustomThreads
{
public void RunCustomTask(Action action, Action<Exception> action_on_exception)
{
Task.Factory.StartNew(() => PerformAction(action, action_on_exception));
}
public void RunCustomThread(Action action, Action<Exception> action_on_exception)
{
new Thread(() => PerformAction(action, action_on_exception)).Start();
}
private void PerformAction(Action action, Action<Exception> action_on_exception)
{
try
{
action();
}
catch (Exception ex)
{
action_on_exception.Invoke(ex);
}
finally
{
Console.WriteLine("Finally is called");
}
}
}
One more interesting feature that I've found is that new Thread() throws unhandled Exception and finally is never called whereas new Task() does not, and finally is called. Maybe someone could comment on the reason of this difference.
and not the way how UI thread handles this issue
That is not accurate, it is exactly how a UI thread handles it. The message loop is the general solution to the producer-consumer problem. Where in a typical Windows program, the operating system as well as other processes produce messages and the one-and-only UI thread consumes.
This pattern is required to deal with code that is fundamentally thread-unsafe. And there always is a lot of unsafe code around, the more convoluted it gets the lower the odds that it can be made thread-safe. Something you can see in .NET, there are very few classes that are thread-safe by design. Something as simple is a List<> is not thread-safe and it up to you to use the lock keyword to keep it safe. GUI code is drastically non-safe and no amount of locking is going to make it safe.
Not just because it is hard to figure out where to put the lock statement, there is a bunch of code involved that you did not write. Like message hooks, UI automation, programs that put objects on the clipboard that you paste, drag and drop, shell extensions that run when you use a shell dialog like OpenFileDialog. All of that code is thread-unsafe, primarily because its author did not have to make it thread-safe. If you trip a threading bug in such code then you do not have a phone number to call and a completely unsolvable problem.
Making a method call run on a specific thread requires this kind of help. It is not possible to arbitrarily interrupt the thread from whatever it is doing and force it to call a method. That causes horrible and completely undebuggable re-entrancy problems. Like the kind of problems caused by DoEvents(), but multiplied by a thousand. When code enters the dispatcher loop then it is implicitly "idle" and not busy executing its own code. So can take an execution request from the message queue. This can still go wrong, you'll shoot your leg off when you pump when you are not idle. Which is why DoEvents() is so dangerous.
So no shortcuts here, you really do need to deal with that while() loop. That it is possible to do so is something you have pretty solid proof for, the UI thread does it pretty well. Consider creating your own.

Task and exception silence

Why exceptions thrown within a task are silent exception and you never know if a certain exception has been thrown
try
{
Task task = new Task(
() => {
throw null;
}
);
task.Start();
}
catch
{
Console.WriteLine("Exception");
}
the program run successfully in a complete silence!
where the behavior of threads is different
try
{
Thread thread = new Thread(
() => {
throw null;
}
);
thread .Start();
}
catch
{
Console.WriteLine("Exception");
}
a null pointer exception will be thrown in this case.
What is the difference?
The behaviour of that scenario depends on what framework you have; in 4.0, you actually need to be careful - if you don't handle TaskScheduler.UnobservedTaskException, it will error later when it gets collected/finalized, and will kill your process.
TaskScheduler.UnobservedTaskException += (sender, args) =>
{
Trace.WriteLine(args.Exception.Message); // somebody forgot to check!
args.SetObserved();
};
This changes in 4.5, IIRC.
To check the outcome of a Task that might fail, you could register a continuation - i.e. call ContinueWith and check the result's exception. Alternatively, accessing the .Result of the task (which would also do an implicit Wait()) will re-surface the exception that happened. It is good to observe the result of a task, as that clears the finalization flag, meaning it can be collected more cheaply.
No, tasks are not threads. Tasks represent a high level abstraction - they are a unit of work that is inherently parallelisable. Threads run units of work.
In your first example, you create a unit of work and then tell it to run itself (how it does so is an implementation detail of Task). Whereas in your second example you explicitly schedule a unit of work (it would appear in a different manner to the implementation of Task).
The following assumes .NET 4.0, and the using the default TaskScheduler.
First of all notice that the exceptions are raised inside the delegates you pass, so they are raised in a different thread, not in the one you (logically) are doing your catch. So somehow the exception must be propagated from the thread that executes your delegate / lambda code to the one that started the thread/task.
Note that for Task, I think that the library can also choose not to run it on it's own thread, but rather on the calling thread (but I'm not sure if that was only true for Parallel.ForEach, etc. and not for a "naked" Task object).
For that two happen, two things must be fulfilled:
The calling thread is still active. Otherwise there is nothing left that could actually perform the catch.
The exception that was caused in the thread/task must somehow be preserved and reraised for you to catch it.
Having that said, both of your examples don't wait for the thread/task to finish. In the first example you're missing a task.Wait() (or similar) and in the second a thread.Join(). Depending on your test codes timing behavior this may mean that you may never be able to observe the exception from the thread/task (item 1 above).
Even if you add the two calls this is what happens for me (again .NET 4.0):
Task example: the call to task.Wait() actually reraises the exception originally left unhandled in the task's delegate (this is what the TPL will do for you internally), it does wrap it inside a System.AggregateException, which you could/would see if you'd use something more precise then a flat "catch-all".
Thread example: the exception raised by the delegate remains unhandled and your application exits (unless you do anything to deal with unhandled exceptions differently)
In other words I would have the examples as follows:
// Thread example
var thread = new Thread(() => { throw null; });
thread.Start();
thread.Join();
// Should never reach here, depending on timing sometimes not even
// until the Join() call. The process terminates as soon as the other
// thread runs the "throw null" code - which can logically happen somewhere
// after the "start" of the "Start()" call.
// Task example
try
{
var task = new Task(() => { throw null; });
task.Start();
task.Wait();
}
catch (AggregateException ex)
{
Console.WriteLine("Exception: " + ex);
}
I think you are not getting exception in case of Task because you are not waiting for exception in the main thread. You are just continuing. Put task.Wait() and you will get the exception in main thread.

c# try...catch statement doesn't capture exception when exception occurred in asynchronous operation

for example:
first step:bind UnhandledException event.
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
second step:
try
{
//at here,do asynchronous operation and throw a exception.
}
catch (Exception ex)
{
Console.WriteLine("error");
}
when the asynchronous operation throw a exception,the catch code it not called,just only the UnhandledException event is triggered,after end event called then exit application.
i want capture exception anything in catch statement and avoid exit application.
=======================================================
the asynchronous code is the asynchronous socket operation.in the socket asynchronous receive message event(BeginReceive,EndReceive),i throw a OverFlowException.
throw new OverflowException("chunk size too long.");
=============================================
you are right,now i capture the exception in asynchronous operation and passed it to original class(this means exception will throw on the same thread,that can try...catcy statement can was called)
An asynchronous task by default will operate in a different context from the one it was instantiated in. The try/catch block is therefore not effective in this case.
Think about it in the following way.
Worker worker = new HouseMaid();
try
{
worker.DoSomeWork();
}
catch(WorkerIsSickException ex)
{
worker.TakeMedicin();
worker.StopWorkingAndRestForAWhile();
}
Here we see that when the worker gets sick, the work process breaks and the exception will be handeled. However, when we do:
Worker worker = new HouseMaid();
try
{
Worker otherWorker = new HouseMaidHelper();
worker.DelegateWorkTo(otherWorker, CallBackWhenOTherWorkerIsDone);
worker.GoOnDoSomethingElse();
}
catch(WorkerIsSickException ex)
{
worker.TakeMedicin();
worker.StopWorkingAndRestForAWhile();
}
The work try/catch block (or safety net if you will), will only apply for the worker, not otherWorker. The otherWorker has its own scope to work in. If the other worker fails, that shouldnt mean that the worker has to take the medicine.
Your question isn't clear, but if it's the asynchronous operation which throws the exception, then the code you've shown could easily have completed before the exception is thrown anyway - it's all asynchronous, right?
Basically asynchrony makes you rethink error handling - and quite how you do it depends on your asynchrony approach. You'd often catch the exception in the callback - or not even catch it, but check for it with something like Task.Status.
Admittedly all the work in C# 5 for async stuff should make some of this easier, but you still need to think about the asynchrony.
The asynchronous operation will get started successfully, hence execution will continue successfully and miss your exception handler. If you want to catch the exception within the asynchronous operation, you will need exception handling in the code that is executing asynchronously. You could then put a call back to a function in your original class if you want to handle the exception there.

Categories

Resources