Question

I'm trying to build a logging library that uses Enterprise Library 5.0 Logging Code Block and I've been able to create a CustomTraceListener that works when the configuration comes from the config file but when I try to configure it via the Configuration Source Builder I get the following error:

"Unable to find appropriate 0 argument constructor for CustomTraceListener"

When I try to find the error using the EL5.0 code base it is specifically having a problem building the construction string for CustomTraceListenerData.

Here is the code:

using System;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners;
using Microsoft.Practices.EnterpriseLibrary.Logging.Configuration;
using System.Diagnostics;
using Microsoft.Practices.EnterpriseLibrary.Logging.Formatters;

namespace AHCALoggerLibrary
{
[ConfigurationElementType(typeof(CustomTraceListenerData))]
public class ServiceTraceListener : CustomTraceListener
{
    public ServiceTraceListener()
        : base() {}

    public override void TraceData(System.Diagnostics.TraceEventCache eventCache, string source, System.Diagnostics.TraceEventType eventType, int id, object data)
    {
        base.TraceData(eventCache, source, eventType, id, data);
    }

    public override void TraceData(System.Diagnostics.TraceEventCache eventCache, string source, System.Diagnostics.TraceEventType eventType, int id, params object[] data)
    {
        base.TraceData(eventCache, source, eventType, id, data);
    }

    public override void Write(string message)
    {
        throw new NotImplementedException();
    }

    public override void WriteLine(string message)
    {
        throw new NotImplementedException();
    }
}

public class AHCALogger
{
    private static AHCALogger _logger = new AHCALogger();

    private LogWriter _Service = null; 

    public static LogWriter Service { get { return _logger._Service;} }

    private AHCALogger() { }

    public static void Init()
    {
        var builder = new ConfigurationSourceBuilder();

        builder.ConfigureLogging()
               .WithOptions
                 .DoNotRevertImpersonation()
               .LogToCategoryNamed("General")
                .WithOptions.SetAsDefaultCategory()
                    .SendTo.Custom<CustomTraceListener>("ServiceTraceListener")
                   .FormatWith(new FormatterBuilder()
                     .TextFormatterNamed("Text Formatter")
                       .UsingTemplate("Timestamp: {timestamp}...{newline})}"))
                 .SendTo.EventLog("Formatted EventLog TraceListener")
                    .FormatWithSharedFormatter("Text Formatter")
                      .ToLog("Application");

        var configSource = new DictionaryConfigurationSource();
        builder.UpdateConfigurationWithReplace(configSource);
        EnterpriseLibraryContainer.Current = EnterpriseLibraryContainer.CreateDefaultContainer(configSource);
        _logger._Service = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();
    }
}
}

Then to use the logger:

        AHCALogger.Init();
        AHCALogger.Service.Write("hello");

I suspect that I am configuring it wrong because it does work when I use the config file settings and call:

LogWriter ahcaLogger = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();
ahcaLogger.Write("hello");

I've tried to find more information on how to use the ConfigurationSourceBuilder but to no avail.

Can anyone help me with this?

Was it helpful?

Solution

You need to replace

.SendTo.Custom<CustomTraceListener>("ServiceTraceListener") 

with

 .SendTo.Custom<ServiceTraceListener>("ServiceTraceListener")

The error message tells you basically that you cannot instantiate an abstract class. You need to pass in the concrete class. You do not need [ConfigurationElementType(typeof(CustomTraceListenerData))] anyway because it has no effect.

To pass custom configuration data to your trace listener you need to be aware that the data is stored in the Attributes collection of the TraceListener base class. This means that you cannot initialize your listener in the ctor but at the first log call.

I have cleaned up your static logger stuff a bit to make it easier.

I noticed during debugging this annoying SynchronizationLockException

"Object synchronization method was called from an unsynchronized block of code."

which seem to be a bug in Entlib5 yuck. I have not yet found a way around this except to recompile unity by yourself and fix it.

Here is the code of the working logger with custom data.

using System;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners;
using System.Linq;
using System.Collections.Specialized;
using Microsoft.Practices.EnterpriseLibrary.Logging.Configuration;

class Program
{
    static void Main(string[] args)
    {
        AHCALogger.Service.Write(new LogEntry() { Message = "Hi" });
    }
}

public static class AHCALogger
{
    static Lazy<LogWriter> _Service = new Lazy<LogWriter>(Init);
    public static LogWriter Service
    {
        get { return _Service.Value; }
    }

    static LogWriter Init()
    {
        var builder = new ConfigurationSourceBuilder();
        var serviceConfig = new NameValueCollection();
        serviceConfig.Add("Key", "data");
        builder.ConfigureLogging()
            .LogToCategoryNamed("General")
            .WithOptions.SetAsDefaultCategory()
            .SendTo.Custom<ServiceTraceListener>("ServiceTraceListener", serviceConfig);

        var configSource = new DictionaryConfigurationSource();
        configSource.Add(LoggingSettings.SectionName, builder.Get(LoggingSettings.SectionName));
        var cont = EnterpriseLibraryContainer.CreateDefaultContainer(configSource);
        return cont.GetInstance<LogWriter>();
    }
}

public class ServiceTraceListener : CustomTraceListener
{
    public ServiceTraceListener() { }
    public override void Write(string message)
    {
        Console.WriteLine("Custom trace Listener Data {0}", 
            String.Join(Environment.NewLine, base.Attributes.Keys.OfType<string>().Select(key => "[" + key + "]: " + base.Attributes[key])));
        Console.WriteLine("message: {0}", message);
    }
    public override void WriteLine(string message) 
    {
        Write(message + Environment.NewLine);
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top