Multi-threaded and multi-AppDomain test scenario.

  • Thread starter Giulio Petrucci
  • Start date
G

Giulio Petrucci

Hi there,

I need to test that an exception is properly caught and re-thrown in an
anonymous callback enqueued in a ThreadPool. I designed my test suite in
order to do this:

- create a class with a method which executes the code to raise an
exception, and make it MarshalByRefObject, say 'Foo'..
- in my test suite code create a new AppDomain and call
CreateInstanceAndUnwrap to create a new Foo instance.
- call the method which raises an exception and...

....and now I don't know what to do. :)
Is there a way to check that in the separated AppDomain the exception
has been properly thrown?
Or am I totally wrong?

Thanks in advance,
Giulio
--
 
P

Peter Duniho

Giulio said:
Hi there,

I need to test that an exception is properly caught and re-thrown in an
anonymous callback enqueued in a ThreadPool. I designed my test suite in
order to do this:

- create a class with a method which executes the code to raise an
exception, and make it MarshalByRefObject, say 'Foo'..
- in my test suite code create a new AppDomain and call
CreateInstanceAndUnwrap to create a new Foo instance.
- call the method which raises an exception and...

....and now I don't know what to do. :)
Is there a way to check that in the separated AppDomain the exception
has been properly thrown?
Or am I totally wrong?

Can you elaborate on why you are using a new AppDomain? What about your
goals dictates that?

If there is no need to use the new AppDomain, it seems to me that a more
straight-forward approach would be to wrap the call to the method with
your own method that has a try/catch handler. Then you can just see if
the exception shows up there.

If that doesn't address your question, please be more specific.

Pete
 
G

Giulio Petrucci

Hi Pete,

Peter said:
If that doesn't address your question, please be more specific.

Here is a code snippet:

public interface IMessage {
Object Sender { get; }
}


public class MessageBroker {
public void Boradcast<T>(T message, Action<T> handler)
{
ThreadPool.QueueUserWorkerItem(o =>
{
try
{
action.DynamicInvoke((T)o);
}
catch (TargetInvocationException tie)
{
if (tie.InnerException != null)
throw tie.InnerException;
else throw;
}
}, message);
}
}

I need to test that the MessageBroker.Broadcast method correctly
re-throw the inner exception.
How can I do?

Thanks,
Giulio
--
 
P

Peter Duniho

Giulio said:
[...]
I need to test that the MessageBroker.Broadcast method correctly
re-throw the inner exception.
How can I do?

Using the code you posted, I can guarantee that the
MessageBroker.Broadcast() method will _not_ re-throw the inner
exception. It doesn't even have access to the inner exception. Only
the anonymous method declared within the MessageBroker.Broadcast()
method does.

If you are asking whether you can test that the anonymous method
rethrows the exception, it's not clear from your code example or your
question that you can.

That is, you can tell from looking at the code itself that it rethrows
an inner exception if one exists. But given the exact code example, you
can't test the exact behavior of the work item method, because it's
being passed directly to the QueueUserWorkItem() method, and the
ThreadPool simply consumes whatever exceptions are thrown form a worker
thread.

If that is truly a literal code example of what you're asking about,
then the answer is "you can't do it", other than just looking at the
code. If it's not truly a literal code example of what you're asking
about, then you should post a correct code example that is. Preferably
a concise-but-complete code example that demonstrates the problem.

Pete
 
G

Giulio Petrucci

Hi Pete,

first of all thanks for your reply.

Peter said:
Using the code you posted, I can guarantee that the
MessageBroker.Broadcast() method will _not_ re-throw the inner
exception. It doesn't even have access to the inner exception. Only
the anonymous method declared within the MessageBroker.Broadcast()
method does.

....and that's exactly what I meant! Sorry for this confusion. :)
If that is truly a literal code example of what you're asking about,
then the answer is "you can't do it", other than just looking at the
code. If it's not truly a literal code example of what you're asking
about, then you should post a correct code example that is. Preferably
a concise-but-complete code example that demonstrates the problem.

The only difference from the real-world code is that the Action<T> is
not passed as a method argument but it must have been previously stored
into a dictionary. Everything else is the same of the real code.
Anyway I think there *must* be a way: let's suppose you have an
application running different plugins: you need to load and execute them
into separate appdomains (or a crash in a plugin will bring your whole
application down). So, there must be a way to get which unhandled
exceptions have occurred in a separate appdomain, right?

Thanks in advance and have a nice day,
Giulio

--
 
P

Peter Duniho

Giulio said:
[...] let's suppose you have an
application running different plugins: you need to load and execute them
into separate appdomains (or a crash in a plugin will bring your whole
application down).

Personally, I think that's open for debate. It's true that loading a
plug-in into a separate AppDomain is the only way to protect against the
broadest possibilities. But most exceptions a plug-in might throw, you
can just catch them yourself with a handler around a call into the
plug-in, preventing them from causing a problem.

Some exceptions you won't be able to prevent from affecting your code.
For example, ThreadAbortException, StackOverflowException, etc. But
even if you make sure those only occur in some other AppDomain, that
does not necessarily mean it's safe for your own application to
continue, depending on exactly what the plug-in was supposed to be doing.

Perhaps in your own situation, you have a design where the plug-in only
ever interacts with the non-plug-in code at the call site (i.e. returns
data from the call). But that's not a requirement of a plug-in
architecture, so you can't say for _every_ plug-in implementation that
would be true.
So, there must be a way to get which unhandled
exceptions have occurred in a separate appdomain, right?

There is. But there's no unhandled exception in the code you posted.
So the fact that there is a way to do that is irrelevant to your question.

The AppDomain.UnhandledException exists for the purpose of detecting
exceptions that have traveled all the way up the call stack without
finding a handler. But the ThreadPool class protects its threads by
catching exceptions thrown by work item callbacks.

In the code you posted, it is not possible to detect from outside the
code that an exception was thrown in the work item callback (the
anonymous method you passed).

There are lots of ways you _can_ detect an exception being thrown, but
they all involve changing the code you posted (and frankly, in generally
obvious ways…i.e. insert your own code somewhere that will catch the
exception and report it).

Pete
 
G

Giulio Petrucci

Hi Peter,

I've tried to reply but I cannot see my message posted... :-/

Peter said:
There is. But there's no unhandled exception in the code you posted. So
the fact that there is a way to do that is irrelevant to your question.

Well... the anonymous callback raises an exception and nobody handles it
so... isn't it an unhandled exception?
The AppDomain.UnhandledException exists for the purpose of detecting
exceptions that have traveled all the way up the call stack without
finding a handler. But the ThreadPool class protects its threads by
catching exceptions thrown by work item callbacks.

Uhm... Could you link me a deeper explaination for this topic?
There are lots of ways you _can_ detect an exception being thrown, but
they all involve changing the code you posted (and frankly, in generally
obvious ways…i.e. insert your own code somewhere that will catch the
exception and report it).

Uhm... in the real-world scenario the exception must be re-thrown, so we
go back to the same problem: how can I handle it?

Thanks again and have a nice day,
Giulio
--
 
P

Peter Duniho

Giulio said:
Hi Peter,

I've tried to reply but I cannot see my message posted... :-/



Well... the anonymous callback raises an exception

Yes, if the delegate invocation throws an exception, that's correct.
and nobody handles it so...

Not correct.
isn't it an unhandled exception?

No. I already explained that the ThreadPool class does in fact handle
the exception.
Uhm... Could you link me a deeper explaination for this topic?

MSDN search works pretty well when you know the exact name of the class
and member you're looking for. First search result searching for
"AppDomain.UnhandledException" is this:
http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx
Uhm... in the real-world scenario the exception must be re-thrown, so we
go back to the same problem: how can I handle it?

It really doesn't matter what arbitrary requirement you have imposed on
the code is. If you are not able to change the code from being
structured the way the example you posted is structured, your
requirement is impossible to meet.

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top