views:

223

answers:

2

I'm creating an STA version of the SynchronizationContext for use in Windows Workflow 4.0. I'm wondering what to do about exceptions when Post-ing callbacks.

The SynchronizationContext can be used to Send (execute synchronously) or Post (execute asynchronously) delegates of type SendOrPostCallback. Although in both cases I invoke the delegate on a STA thread, its easy to know how to handle exceptions when executing synchronously. I block the calling thread, Invoke the callback on my worker thread, record any exceptions, unblock the calling thread, and throw any recorded exceptions on the calling thread.

What I should do on the asynchronous Post is less clear. There is no mechanism for transferring that exception from the executing thread back to the calling thread; Post is 100% fire and forget. There is no EndInvoke() or WaitHandle in the SendOrPostCallback. Any exceptions thrown will result in the application being torn down.

Do I have no choice but to let an exception thrown in a Post tear down my application? That seems to be the default behavior in the SynchronizationContexts in the framework (thank you, Reflector). I can't seem to figure out why this is. Shouldn't there be some way to prevent asynchronous Posts from going boom?

+5  A: 

In situations like this I let the substitution principle guide me. I would implement the same behavior as the existing instances of SynchronizationContext. To do otherwise violates the substitution principle and could come back to bite you in unexpected ways.

JaredPar
Hmmmm, good point. But What's the deal with this design? Is there a good reason why the framework designers didn't provide a way to handle exceptions? You could easily provide an OnException callback in the SendOrPostCallback class, but they didn't. Its almost as if they WANT you to fail fast if the SC encounters an exception, no matter how inconsequential.
Will
There's no point in an OnException. You can just put a try-catch in the delegate you pass, and do whatever you like there (marshal the exception back, whatever).
Brian
@Will, the caller to Post could just as easily wrap their call in a try / catch statement and deal with the exception themselves. Having the application die fast forces the responsibility of error handling to the caller where it should be.
JaredPar
Except you can't really do that without blocking the calling thread when Post-ing, which defeats the Post in the first place. Also, while you can create a SC for use by other components, you may NOT be able to dictate how the delegate passed is handled. For instance, my SC will be used by WorkflowApplication. It would be up to the WA to "marshall" that exception back onto the calling thread. This isn't possible for me to control.
Will
(cont) I could wrap the exception within my SC, but the question becomes *now what?* In the case of the WorkflowApplication, I won't be able to figure out what thread I should marshall back to without some convoluted piping, all of which wouldn't be necessary if the SendOrPostCallback was built for bringing exceptions back to the immediate calling thread.
Will
Just what black magic are you imagining here? If, say, a threadpool thread Post()s a delegate that throws, what could you possibly want to do? The threadpool thread that Post()ed might not even exist any more! A general mechanism is completely unimplementable/infeasible.
Brian
Put another way, "fire and forget" is completely incompatible with "exception handling". An exception is a "return value" that ought not be ignored. If I 'fire' a delegate at you that throws, then the only reasonable thing for you do to is crash the process (possibly after kindly asserting in Debug mode). Anything else would probably be 'rude' API behavior.
Brian
+2  A: 

Dying is awesome.

http://stackoverflow.com/questions/576532/is-dying-is-awesome-preferred

Brian
Look, I'm all for death, but the framework generally provides a way out in other asynchronous situations (APM, etc). Why not here??
Will
See my comment on @JaredPar's answer. The user code has a delegate, it's in full control already.
Brian