2013-03-21 31 views
2

我需要從應用程序(Core.exe)讀取標準輸出,該應用程序在相同的進程中運行,但在不同的appDomain中運行。當處理流程時,重定向輸出很容易,但appDomains概念對我來說是新的。在isolataed的AppDomainCross-appDomain訪問控制檯.Out

所以..我開始應用類似的

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

我已經tride重定向當前進程假設,如果應用程序共享相同的過程中會有一個非標準的輸出Console.Out 。

但它只顯示默認的appDomain標準輸出。

因此,總結一下,我需要訪問另一個appDomain應用程序標準輸出。或者可能有一種方法來調用位於「核心」appDomain的默認appDomain中的方法?

回答

5

也許這可以幫助你。 我使用這些類可以偵聽遠程AppDomain 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確保錯誤,同時嘗試引用包含此代碼的程序集。
  • 此代碼必須存在於兩個進程中並共享相同的名稱空間。我在庫中使用它,並將程序集引用添加到這兩個應用程序。
  • 另請注意,可序列化屬性和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); 
     } 
    } 

Finnaly可以整齊地打包這一切在一個靜態類。



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

通過在應用程序中這樣做,將註冊遠程跟蹤按摩。



    CrossDomainTrace.StartListening(theFarAppDomain); 

剩下的唯一的事情就是一個TraceListner添加到收藏Trace.Listeners在這方面做你想要的信息什麼都。

希望它有幫助。

+0

它有幫助。謝謝。我最終將TextWriter的引用從默認appDomain發送到遠程,並在RemoteWrite方法中使用WriteLine。 – wazelin 2013-03-22 08:19:55