c#之跨应用域访问 Console.Out

wayfarer 阅读:38 2024-10-01 17:34:08 评论:0

我需要读取在同一进程中但在不同 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 中的方法?

请您参考如下方法:

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

第一个类是允许我将 TraceListen Write/WriteLine 方法重定向到自定义委托(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); 
        } 
    } 
 

然后是我的远程 AppDomain 跟踪监听器类的核心。
这是棘手的部分。我会尽量不混淆解释。这对我来说很棘手,但它就在这里。
  • (本地)CrossDomainTracer 对象在远端 AppDomain 上创建(远端)CrossDomainTracer 对象。
  • (本地)CrossDomainTracer 对象调用(远)CrossDomainTracer 对象 .StartListening 并将其自身作为引用发送(本地)。
  • (远)CrossDomainTracer 对象开始监听(远)他的域中的任何 Trace.Write/WriteLine 调用。
  • 当进行(远)Trace.Write/WriteLine 调用时,它会从(本地)远程 AppDomain 调用 .RemoteWrite 方法。
  • (本地) .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); 
     
    

    剩下的唯一事情就是将 TraceListner 添加到这一侧的 Trace.Listeners 集合中,以对消息执行任何您想要的操作。

    希望能帮助到你。


    标签:C#
    声明

    1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

    关注我们

    一个IT知识分享的公众号