2010-08-09 234 views
2

對不起,這是一個相當特殊的主題,因此許多人可能不感興趣。 :-(Unity/EntLib:向CustomTraceListener注入依賴關係

不過,我需要做以下的事情:

  • 我有一個提供登錄到某種控制檯窗口(這是一個WPF窗口,因爲應用需求和因的應用應用程序需要顯得豔俗即使在這裏 - 我們的客戶的特殊要求這一點,談論它的每一次見面)

  • 提供線索 - 我創建了一個接口/實現對「IGUIController」 /「GUIController」

  • 不可知記錄

到目前爲止,這麼好。一切都很好。

但是:

  • 我需要我自己的自定義跟蹤監聽器(我稱之爲「GUITraceListener」),它採用了IGUIController - 接口編寫特定的日誌消息華而不實WPF - 窗口

到目前爲止,我的解決方案是在我的GUIController上有一個被黑客入侵的舊skool代碼,它具有獨立式風格的「Current」屬性(是的,而且我很慚愧,我知道這很糟糕),我這樣調用它:

GUIController.Current.Log(message); 

很明顯,這是一個不行。

所以,正確的方法是注入依賴關係(當然)。然而,當我這樣做的時候,我得到了投訴(運行時),我沒有爲我的GUITraceListener類提供一個帶有0(零)參數的構造函數。

由於事實上,我拿到這裏:

EnterpriseLibraryContainer.ConfigureContainer(configurator, 
ConfigurationSourceFactory.Create()); 

而抱怨是:

ArgumentException的是未處理 無法找到合適的0參數的構造函數用於GUITraceListener

這是特別糟糕。我的意思是,Unity是企業圖書館的一部分,爲什麼這些人只是增加了注入我的依賴的可能性?

澄清:

我想擁有的到底是:

/// <summary> 
    /// Constructor 
    /// </summary> 
    /// <param name="guiController"></param> 
    public GUITraceListener(IGUIController guiController) 
    { 
     // Store the dependencies 
     this.m_GUIController = guiController; 
    } 
+1

請問您可以展示可用於GUITraceListener的構造函數,以及如何解決類型GUITraceListener。 – 2010-08-09 08:28:27

+0

我沒有自己解決GUITraceListener,這是由企業庫本身通過app.config中的配置條目完成的。 但是,我將添加我爲GUITraceListener添加到我的職位的構造函數。等一下。 :-) – 2010-08-09 08:29:29

回答

6

Entlib 5 確實有能力做到這一點。我猜你的監聽器類中有一個[ConfigurationElementType(typeof(CustomTraceListenerData)],對吧?

Entlib 5被設計成獨立於容器,因此我們不能依賴任何類型的自動因爲每個容器都有不同的表現,所以你需要告訴Entlib調用哪個構造函數,以及應該注入哪些依賴關係,這是通過你的配置數據類來完成的。

我打了一個快速示例。這裏的跟蹤偵聽器 - 沒有太多特殊:

[ConfigurationElementType(typeof(GuiTraceListenerData))] 
public class GuiTraceListener : TraceListener 
{ 
    private readonly ILogFormatter formatter; 
    private readonly IGuiController guiController; 

    public GuiTraceListener() 
     : this(string.Empty, null, null) 
    { 
    } 

    public GuiTraceListener(string name) 
     : this(name, null, null) 
    { 
    } 

    public GuiTraceListener(string name, ILogFormatter formatter, IGuiController guiController) : base(name) 
    { 
     this.formatter = formatter; 
     this.guiController = guiController; 
    } 

    public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, 
     object data) 
    { 
     if ((Filter == null) || Filter.ShouldTrace(eventCache, source, eventType, id, null, null, data, null)) 
     { 
      if (data is LogEntry) 
      { 
       if (formatter != null) 
       { 
        Write(formatter.Format(data as LogEntry)); 
       } 
       else 
       { 
        base.TraceData(eventCache, source, eventType, id, data); 
       } 
      } 
      else 
      { 
       base.TraceData(eventCache, source, eventType, id, data); 
      } 
     } 
    } 

    public override void Write(string message) 
    { 
     guiController.Log(message); 
    } 

    public override void WriteLine(string message) 
    { 
     guiController.Log(message); 
    } 
} 

有趣的部分是在GuiTraceListenerData類:

public class GuiTraceListenerData : TraceListenerData 
{ 
    private const string formatterNameProperty = "formatter"; 

    public GuiTraceListenerData() 
     : this("unnamed", null, TraceOptions.None) 
    { 
    } 

    public GuiTraceListenerData(string name) 
     : this(name, null, TraceOptions.None) 
    { 
    } 

    public GuiTraceListenerData(string name, string formatterName) 
     : this(name, formatterName, TraceOptions.None) 
    { 
    } 

    protected GuiTraceListenerData(string name, string formatterName, TraceOptions traceOutputOptions) 
     : base(name, typeof (GuiTraceListener), traceOutputOptions, SourceLevels.All) 
    { 
     ListenerDataType = typeof (GuiTraceListenerData); 
     Formatter = formatterName; 
    } 

    [ConfigurationProperty(formatterNameProperty, IsRequired = false)] 
    [Reference(typeof(NameTypeConfigurationElementCollection<FormatterData, CustomFormatterData>), typeof(FormatterData))] 
    public string Formatter 
    { 
     get { return (string) base[formatterNameProperty]; } 
     set { base[formatterNameProperty] = value; } 
    } 

    protected override Expression<Func<TraceListener>> GetCreationExpression() 
    { 
     return() => 
      new GuiTraceListener(Name, 
       Container.ResolvedIfNotNull<ILogFormatter>(Formatter), 
       Container.Resolved<IGuiController>()); 
    } 
} 

特別是,看看那GetCreationExpression方法。這就是告訴entlib創建由這個config new代表的對象,調用該構造函數並解析格式化程序(如果指定了)和IGuiController。

然後,在我的測試程序(我用的WinForms只是要快)我初始化我的容器和應用程序是這樣的:

static void Main() 
{ 
    var container = new UnityContainer() 
     .AddNewExtension<EnterpriseLibraryCoreExtension>() 
     .RegisterType<IGuiController, MessageBoxGuiController>(); 

    Application.EnableVisualStyles(); 
    Application.SetCompatibleTextRenderingDefault(false); 
    Application.Run(container.Resolve<Form1>()); 
} 

我Form1類需要一個寫進程作爲構造函數的參數。

有關Entlib 5如何構建的好處是,您可以在執行此操作時獲得幾乎自動的配置工具支持 - 無需編寫單獨的配置節點。您的運行時配置元素是您所需要的 - 只需使用配置工具將該DLL複製到相同的目錄中,它就會將其提取出來。

無論如何,從這裏開始,它只是工作。

希望這會有所幫助。如果你想要更多的細節,請給我一個線路,我可以發送給你整個工作項目。

-Chris

+0

哇,這就是我一直在尋找的!非常感謝你! :-) – 2010-08-26 07:54:27

+0

但告訴我,你如何獲得「GetCreationExpression()」中的容器? – 2010-08-26 08:24:12

+1

啊,這是一個小竅門。 Container.Resolved <>不是對Unity或任何其他容器實例的調用。這裏的容器實際上是Entlib中的一個靜態類,如果你看到Resolved或ResolvedIfNotNull的實現,你會看到它們是noops。 – 2010-08-26 17:25:50