Problem :
AppDomain 1 creates a new AppDomain (2) to run tasks within, tracing from AppDomain 2 needs to be conducted in AppDomain 1 to allow external app (NUnit) to access the Console where it's all being written.
Solution :
4 new classes :
- RemoteAppDomainEventHandlers - serializable class containing the event handling code to run in AppDomain 1
- RemoteTraceEventArgs - serializable event args used to transport tracing info between AppDomains
- RemoteTraceListener - sub class of TraceListener, wraps a RemoteTracing instance
- RemoteTracing - MarshalByRefObject that receives trace messages from RemoteTraceListener and raises events back to AppDomain 1
When AppDomain 2 is created an instance of RemoteTracing is created and unwrapped into AppDomain 1, EstablishRemoteTracing is called which sets up a RemoteTraceListener in AppDomain 2, finally the trace event is wired up to the RemoteTrace handler on an instance of RemoteAppDomainEventHandlers.
// we need to hook in tracing from the app domain back to here
m_remoteTracing = (RemoteTracing)m_appDomain.CreateInstanceAndUnwrap("com.iMeta.ApplicationUpdate","com.iMeta.ApplicationUpdate.Remote.RemoteTracing");
m_remoteTracing.EstablishRemoteTracing();
m_remoteTracing.Trace+=new TraceEventHandler(m_eventHandlers.RemoteTrace);
public void EstablishRemoteTracing()
{
// clear any existing trace listeners
System.Diagnostics.Trace.Listeners.Clear();
// create one of our remote listeners that wraps this RemoteTracing object
RemoteTraceListener rtl = new RemoteTraceListener(this);
System.Diagnostics.Trace.Listeners.Add(rtl);
}
Then when a call is made to Trace.Write in AppDomain 2 it hits the following code in the RemoteTraceListener
public override void Write(string message, string category)
{
m_remote.SendTraceToClient(message,category);
}
Which in turn calls the RemoteTracing instance it was created with:
public void SendTraceToClient(string message, string category)
{
// create a RemoteTraceEventArgs object and raise event with it
RemoteTraceEventArgs rtea = new RemoteTraceEventArgs(message,category);
OnTrace(rtea);
}
An event gets raised in AppDomain 2 and AppDomain 1 handles it by writing the trace in it's domain.
Originally the event handler for AppDomain 1 was on the class that loaded the AppDomain, this didn't seem to work too well as the event handlers were running in AppDomain 2 which caused some fun StackOverflowExceptions!