3

同じプロセスで異なる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をリダイレクトしようと試みました。アプリが同じプロセスを共有する場合、単一の標準出力があると想定して、現在のプロセスから外れます。

ただし、デフォルトのappDomain標準出力のみが表示されます。

したがって、要約すると、別のappDomainアプリケーションの標準出力にアクセスする必要があります。または、「コア」appDomainからデフォルトのappDomainにあるメソッドを呼び出す方法があるのでしょうか。

4

1 に答える 1

6

多分これはあなたを助けることができます。これらのクラスを使用して、リモートの 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. (far)CrossDomainTracer オブジェクトは、(far) 彼のドメインで Trace.Write/WriteLine 呼び出しのリッスンを開始します。
  4. (far)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);
        }
    }

遠トレースのマッサージを登録するアプリでこれを行うことによって。



    CrossDomainTrace.StartListening(theFarAppDomain);

あとは、TraceListner をこちら側の Trace.Listeners コレクションに追加して、メッセージに対して必要なことを行うだけです。

それが役に立てば幸い。

于 2013-03-21T16:22:12.120 に答える