2013-06-11 99 views
5

內開始我有一個創建一個應用程序域並啓動它的服務:獲取組件名稱爲過程的應用程序域

this._appDomain = AppDomain.CreateDomain(this._appName, AppDomain.CurrentDomain.Evidence, appDomainSetup); 
this._startStopControllerToRun = (IStartStop)this._appDomain.CreateInstanceFromAndUnwrap(assemblyName, this._fullyQualifiedClassName); 
this._startStopControllerToRun.Start(); 

這已經很長一段時間,現在運行良好。問題在於,在此應用程序域中啓動的控制器調用框架日誌記錄類。記錄器獲取條目程序集名稱並將其作爲源記錄在事件日誌中。這是記錄器如何得到源(主叫)名稱:

private static string GetSource() 
{ 
    try 
    { 
     var assembly = Assembly.GetEntryAssembly(); 

     // GetEntryAssembly() can return null when called in the context of a unit test project. 
     // That can also happen when called from an app hosted in IIS, or even a windows service. 
     if (assembly == null) 
     { 
      // From http://stackoverflow.com/a/14165787/279516: 
      assembly = new StackTrace().GetFrames().Last().GetMethod().Module.Assembly; 
     } 

     return assembly.GetName().Name; 
    } 
    catch 
    { 
     return "Unknown"; 
    } 
} 

並稱if檢查,記錄器將記錄「未知」的源之前。經過一番研究,我在if區塊中加入了這個嘗試。現在,記錄器將「mscorlib」記錄爲源(輸入程序集名稱)。

這是概述: 主機 - >控制器(應用程序域之內運行)

我怎樣才能獲得組件(包含控制器)域內運行的名字嗎?

注:我也試過這個(下同),但它給了我在日誌類所在的框架(未在該控制器應用領域中運行的組件的名稱)的名稱:

assembly = Assembly.GetExecutingAssembly(); 
+0

避免尋找後門來獲取由代碼輕鬆準確提供的信息。添加一個屬性。 –

+0

那麼基本上傳遞一個字符串到日誌方法? Logger.Log(「MyApp」,message);' –

+0

當業務邏輯層完成日誌記錄並且可以從多個使用者調用日誌時,該方法不起作用。消費者知道他們的名字,但每個人都必須將這些信息傳遞給邏輯方法。我不想像這樣傳遞信息,我真的很想在一個地方得到它。 –

回答

3

這也許是一種方法來做你想做的。我在這裏演示的是通過SetDataGetData方法傳遞和接收創建的AppDomain元數據,以便無視我如何創建實際的遠程類型。

using System; 
using System.Reflection; 

namespace ConsoleApplication13 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      AppDomain appDomain = AppDomain.CreateDomain("foo"); 

      appDomain.SetData(FooUtility.SourceKey, FooUtility.SourceValue); 

      IFoo foo = (IFoo)appDomain.CreateInstanceFromAndUnwrap(Assembly.GetEntryAssembly().Location, typeof(Foo).FullName); 

      foo.DoSomething(); 
     } 
    } 

    public static class FooUtility 
    { 
     public const string SourceKey = "Source"; 
     public const string SourceValue = "Foo Host"; 
    } 

    public interface IFoo 
    { 
     void DoSomething(); 
    } 

    public class Foo : MarshalByRefObject, IFoo 
    { 
     public void DoSomething() 
     { 
      string source = AppDomain.CurrentDomain.GetData(FooUtility.SourceKey) as string; 

      if (String.IsNullOrWhiteSpace(source)) 
       source = "some default"; 

      Console.WriteLine(source); 
     } 
    } 
} 

,輸出:

富主機
按任意鍵繼續......

所以你的情況,你可以通過任何來源的元數據,以在AppDomain:

this._appDomain = AppDomain.CreateDomain(this._appName, AppDomain.CurrentDomain.Evidence, appDomainSetup); 

this._appDomain.SetData("Source", "MyController"); 

this._startStopControllerToRun = (IStartStop)this._appDomain.CreateInstanceFromAndUnwrap(assemblyName, this._fullyQualifiedClassName); 
this._startStopControllerToRun.Start(); 

並在您的GetSource方法檢查它的存在。

private static string GetSource() 
{ 
    try 
    { 
     string source = AppDomain.CurrentDomain.GetData("Source") as string; 

     if (!String.IsNullOrWhiteSpace(source)) 
      return source; 

     var assembly = Assembly.GetEntryAssembly(); 

     // GetEntryAssembly() can return null when called in the context of a unit test project. 
     // That can also happen when called from an app hosted in IIS, or even a windows service. 
     if (assembly == null) 
     { 
      // From http://stackoverflow.com/a/14165787/279516: 
      assembly = new StackTrace().GetFrames().Last().GetMethod().Module.Assembly; 
     } 

     return assembly.GetName().Name; 
    } 
    catch 
    { 
     return "Unknown"; 
    } 
} 

UPDATE備選

你也可以聲明一個公共接口方法設置源在目標域靜態位置爲好。

using System; 
using System.Reflection; 

namespace ConsoleApplication13 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      AppDomain appDomain = AppDomain.CreateDomain("foo"); 

      IFoo foo = (IFoo)appDomain.CreateInstanceFromAndUnwrap(Assembly.GetEntryAssembly().Location, typeof(Foo).FullName); 

      foo.SetSource("Foo Host"); 

      foo.DoSomething(); 
     } 
    } 

    public interface IFoo 
    { 
     void DoSomething(); 
     void SetSource(string source); 
    } 

    public class Foo : MarshalByRefObject, IFoo 
    { 
     public void DoSomething() 
     { 
      string source = Foo.Source; 

      if (String.IsNullOrWhiteSpace(source)) 
       source = "some default"; 

      Console.WriteLine(source); 
     } 

     public static string Source{get; private set;} 

     public void SetSource(string source) 
     { 
      Foo.Source = source; 
     } 
    } 
} 
0

我跑到那裏某處埋在.NET代碼的情況下,它是依靠Assembly.GetEntryAssembly()。它需要返回的程序集並檢查它是否具有程序集級屬性。如果代碼位於應用程序域中,哪個會失敗。長期以來,我不得不解決同樣的問題。解決方案是醜陋的,我討厭我需要這樣做,但它的工作...

如果您在此處閱讀文檔 - Assembly.GetEntryAssembly() Method

它包含本節:

返回值

類型:System.Reflection.Assembly

大會,是在默認應用程序域中可執行的進程,或 由AppDomain.ExecuteAssembly執行的第一個可執行文件。從非託管代碼調用時, 可以返回null。

爲了解決這個問題,我在exe中添加了一些代碼,如果將「/ initializingappdomain」作爲參數傳遞,會使進程退出。

下面是一些代碼來做到這一點...

// 1. Create your new app domain... 
var newDomain = AppDomain.CreateDomain(...); 

// 2. call domain.ExecuteAssembly, passing in this process and the "/initializingappdomain" argument which will cause the process to exit right away 
newDomain.ExecuteAssembly(GetProcessName(), new[] { "/initializingappdomain" }); 

private static string GetProcessName() 
{ 
    return System.IO.Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName.Replace(".vshost", "")); 
} 

// 3. Use your app domain as you see fit, Assembly.GetEntryAssembly will now return this hosting .net exe. 

再次,這是很不理想。如果可以避免這種情況,有更好的解決方案,但是如果您發現自己處於不依賴於Assembly.GetEntryAssembly()的代碼的情況下,這會讓您不知所措。

相關問題