Yes, this is a real problem, not very easy one: let's say, you have started with Application Domain and created another application domain. This is really what you had to do if you need to load some assembly as a plug-in using
System.Reflection
and need to unload it on a regular basis and load another one. This is because there is no a way to unload a loaded assembly, you can only unload the whole Application Domain.
So here is your first option: you need to review your design and see if you really need using a separate Application Domain. If you are not unloading anything in some cycle, you should better load your assembly in your current Application Domain. That was a suggestion just in case. I hope your design is well based, so let's assume you really need to unload the Application Domain for the next step.
Now, let's assume you are calling some method in the Application Domain in the thread you are using in your host Application Domain. This is quite possible; the only problem is that Application Domains are isolated in data; you share the stack, but the heap and static memory storage are not shared between the Application Domain, but strongly isolated, in the same way as different processes. That said: to pass data, you can only need IPC (Inter-Process Communication). When you throw an exception in one Application Domain, you can catch it the other Application Domain. This is because the propagation of exceptions is some special kind of jumps over the stack of one thread. But — when you catch the exception beyond the Application Domain boundary, you cannot get exception information itself, as the boundary between Application Domains is not transparent for data. This is exactly what you observe.
So, what to do in this case? Let's say you call some method across the Application Domain using
System.AppDomain.DoCallback
(please see all the links below). How to pass some data to be used on the other side of Application Domain boundary? Right, by using IPC. The class
System.AppDomain
has the simplified IPC facility,
GetData/SetData
. You can share some data cells on both sides of the Application Domain boundary identified with some keys of the string type. As the strings for the keys are constants, you can have identical string values in both domains. At to the values passed, they are of the type
System.Object
and are serialized and deserialized behind the scene, so the type of data should be serializeable (please see the last link below).
So, the scenario would using some kind of what I call "
exception thunk", which is applicable in many cases, such as using APIs based on different technologies, remote APIs and more. You can put some data in the Application Domain using
SetData
. The delegate executed in other Application Domain should read this data using
GetData
, then it should perform the operation and catch all the
exceptions before return. This is the key. In the exception handler, the delegate code should pack required exception information in some serializeable data structure and put it in the cell dedicated for exception information using
SetData
. The calling part of the code executing in the host Application Domain should pick up this exception information using
GetData
and
use it. To complete the "thunk", this part of code can actually throw a brand new exception based on received exception information.
So we the exception itself was caught immediately on the stack, and the exception information was carried over the bridge over the boundary between Application Domains ("thunk") which is based on
System.ApplicationDomain.SetData/GetData
using embedded IPC and serialization.
Please see:
http://msdn.microsoft.com/en-us/library/system.appdomain.aspx[
^],
http://msdn.microsoft.com/en-us/library/system.appdomain.docallback.aspx[
^],
http://msdn.microsoft.com/en-us/library/37z40s1c.aspx[
^],
http://msdn.microsoft.com/en-us/library/system.appdomain.getdata.aspx[
^],
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.iserializable.aspx[
^].
I've actually implemented this techniques and it worked well.
Please also see my past solutions I sent in response to questions on related topics:
Create WPF Application that uses Reloadable Plugins...[
^],
AppDomain refuses to load an assembly[
^],
code generating using CodeDom[
^].
—SA