Cross-appDomain access to Console.Out

只愿长相守 提交于 2019-12-03 09:04:11

Maybe this can help you. I use these classes to be able to listen to remote AppDomains Trace.(Write/WriteLine) calls.

The first class is a class that allows me to redirect the TraceListen Write/WriteLine methods to a custom delegate.



    public delegate void TraceWriterHandler(string message);

    internal class SynchronizedTraceListener : TraceListener
    {
        private TraceWriterHandler messageHandler;

        public SynchronizedTraceListener(TraceWriterHandler writeHandler)
        {
            messageHandler = writeHandler;
        }

        public override void Write(string message)
        {
            messageHandler(message);
        }

        public override void WriteLine(string message)
        {
            messageHandler(message + System.Environment.NewLine);
        }
    }

Then the core of my remote AppDomain trace listener class. This is the tricky part. I'll try not to mess the explanation. This is tricky for me to, but here it goes.

  1. The (local) CrossDomainTracer object creates a (far) CrossDomainTracer object on the far AppDomain.
  2. The (local) CrossDomainTracer object calls the (far) CrossDomainTracer object .StartListening and sends (local) it self as a reference.
  3. The (far)CrossDomainTracer object starts listening to any Trace.Write/WriteLine calls in (far) his domain.
  4. When a (far)Trace.Write/WriteLine call is made it calls the .RemoteWrite method from the (local) remote AppDomain.
  5. The (local) .RemoteWrite makes a call to it's own AppDomain scope Trace.Write so that the (local) listener can properly display the message.

Notes:

  • The AssemblyResolve ensures errors while trying to reference the assembly that contains this code.
  • This code must exist in both processes and share the same namespace. I use it in a library and add the assembly reference to both apps.
  • Also note Serializable attribute and the MarshalByRefObject inheritance. This is required by the framework to proper Marshalling of the objects between AppDomains.



    [Serializable]
    public sealed class CrossDomainTracer : MarshalByRefObject
    {
        private CrossDomainTracer remoteTracer;
        private SynchronizedTraceListener remoteListener;

        public CrossDomainTracer()
        {
        }

        public CrossDomainTracer(AppDomain farDomain)
        {
            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
            this.remoteTracer = farDomain.CreateInstanceFrom(Assembly.GetExecutingAssembly().Location, typeof(CrossDomainTracer).FullName).Unwrap() as CrossDomainTracer;
            AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(CurrentDomain_AssemblyResolve);
            if (remoteTracer != null)
            {
                remoteTracer.StartListening(this);
            }
        }

        public void StartListening(CrossDomainTracer farTracer)
        {
            this.remoteTracer = farTracer;
            this.remoteListener = new SynchronizedTraceListener(new TraceWriterHandler(Write));
            Trace.Listeners.Add(this.remoteListener);
        }

        public void Write(string message)
        {
            this.remoteTracer.RemoteWrite("AppDomain(" + AppDomain.CurrentDomain.Id.ToString() +") " + message);
        }

        public void RemoteWrite(string message)
        {
            Trace.Write(message);
        }

        Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            try
            {
                Assembly assembly = System.Reflection.Assembly.Load(args.Name);
                if (assembly != null)
                {
                    return assembly;
                }
            }
            catch { }

            // Try to load by assembly fullname (path to file)
            string[] Parts = args.Name.Split(',');
            string File = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\" + Parts[0].Trim() + ".dll";

            return System.Reflection.Assembly.LoadFrom(File);
        }
    }

Finnaly you can neatly pack all this in a static class.



    public static class CrossDomainTrace
    {
        public static void StartListening(AppDomain remoteDomain)
        {
            new CrossDomainTracer(remoteDomain);
        }
    }

By doing this in the app that will be registering the far Trace massages.



    CrossDomainTrace.StartListening(theFarAppDomain);

The only thing left is to add a TraceListner to the Trace.Listeners collection on this side to do what ever you want with the messages.

Hope it helps.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!