2010-08-09 140 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