【问题标题】:Cross-appDomain access to Console.Out跨应用域访问 Console.Out
【发布时间】:2013-03-21 13:02:46
【问题描述】:

我需要读取运行在同一进程但在不同 appDomain 中的应用程序 (Core.exe) 的标准输出。当处理进程时重定向输出很容易,但 appDomains 概念对我来说是新概念。

所以.. 我像这样在孤立的 appDomain 中启动应用程序

new HostedApp("core", "Core.exe").Run();

class HostedApp
{
    internal string DomainName;
    internal string AssemblyName;
    internal AppDomain Ad;
    internal Thread AppThrd;

    public HostedApp(string a_domain, string a_assemblyName)
    {
        DomainName = a_domain;
        AssemblyName = a_assemblyName;
        Ad = AppDomain.CreateDomain(a_domain);
    }

    public void Run()
    {
        AppThrd = new Thread(RunApp);
        AppThrd.Start();
    }

    private void RunApp()
    {
        try
        {
            Ad.ExecuteAssembly(AssemblyName);
        }
        catch(Exception _ex)
        {
            MessageBox.Show("Unhandled exception\n" + _ex);
        }
    }
}

我已经尝试将 Console.Out 重定向到当前进程,假设如果应用程序共享相同的进程,则会有单一的标准输出。

但它只显示默认的 appDomain 标准输出。

所以,总而言之,我需要访问另一个 appDomain 应用程序标准输出。或者可能有一种方法可以从“核心”appDomain 调用位于默认 appDomain 中的方法?

【问题讨论】:

    标签: c# appdomain


    【解决方案1】:

    也许这可以帮助你。 我使用这些类能够监听远程 AppDomains Trace.(Write/WriteLine) 调用。

    第一个类是允许我将 TraceListen Write/WriteLine 方法重定向到自定义委托的类。

    
    
        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);
            }
        }
    
    

    然后是我的远程 AppDomain 跟踪侦听器类的核心。 这是棘手的部分。我会尽量不混淆解释。这对我来说很棘手,但它就是这样。

    1. (本地)CrossDomainTracer 对象在远端 AppDomain 上创建(远端)CrossDomainTracer 对象。
    2. (本地)CrossDomainTracer 对象调用(远)CrossDomainTracer 对象 .StartListening 并将其自身作为参考发送(本地)。
    3. (远)CrossDomainTracer 对象开始侦听(远)其域中的任何 Trace.Write/WriteLine 调用。
    4. 当进行(远)Trace.Write/WriteLine 调用时,它会从(本地)远程 AppDomain 调用 .RemoteWrite 方法。
    5. (本地).RemoteWrite 调用它自己的 AppDomain 范围 Trace.Write,以便(本地)侦听器可以正确显示消息。

    注意事项:

    • AssemblyResolve 可确保在尝试引用包含此代码的程序集时出错。
    • 此代码必须存在于两个进程中并共享相同的命名空间。我在库中使用它并将程序集引用添加到两个应用程序。
    • 还要注意Serializable 属性和MarshalByRefObject 继承。这是框架在 AppDomain 之间正确编组对象所必需的。

    
    
        [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);
            }
        }
    
    

    最后,您可以将所有这些巧妙地打包在一个静态类中。

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

    通过在将注册远 Trace 按摩的应用中执行此操作。

    
    
        CrossDomainTrace.StartListening(theFarAppDomain);
    
    

    剩下的唯一事情就是在这一侧的 Trace.Listeners 集合中添加一个 TraceListner 来对消息做任何你想做的事情。

    希望对你有帮助。

    【讨论】:

    • 它有帮助。谢谢你。我最终将 TextWriter 的引用从默认 appDomain 发送到远程,并在 RemoteWrite 方法中使用 WriteLine。
    猜你喜欢
    • 2014-09-28
    • 2013-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-18
    • 1970-01-01
    • 1970-01-01
    • 2014-05-29
    相关资源
    最近更新 更多