Entlib 5 does have the ability to do this. I'm guessing you've got a [ConfigurationElementType(typeof(CustomTraceListenerData)] on your listener class, right?
Entlib 5 is designed to be container independent. As such, we can't rely on any kind of auto-wiring semantics because each container does it differently. So you need to tell Entlib which constructor to call, and what dependencies should be injected. This is done through your configuration data class.
I slapped together a quick example. Here's the trace listener - not much special:
[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);
}
}
The interesting part is in the GuiTraceListenerData class:
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>());
}
}
In particular, look at that GetCreationExpression method. that's telling entlib that to create the object represented by this config new, call that constructor, and resolve the formatter (if one is specified) and the IGuiController.
Then, in my test app (I used Winforms just to be quick) I initialized my container and app like this:
static void Main()
{
var container = new UnityContainer()
.AddNewExtension<EnterpriseLibraryCoreExtension>()
.RegisterType<IGuiController, MessageBoxGuiController>();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(container.Resolve<Form1>());
}
My Form1 class takes a LogWriter as a constructor parameter.
The nice thing about how Entlib 5 is built is that you get almost automatic config tool support when doing this - no need to write a separate config node. Your runtime config element is all you need - just copy the DLL into the same directory with the config tool and it'll just pick it up.
Anyway, from here on it just works.
Hope this helps. If you want more details, drop me a line and I can send you the entire working project.
-Chris