Invalid TraceListenerData type in configuration - Logging block

Topics: Logging Application Block
Jul 31, 2008 at 10:59 AM


I'm hoping someone can explain some (seemingly) weird behaviour in the Logging App Block 3.1. Here's my scenario:

I have an executing assembly (winform) that references another assembly (midtier). Both these assemblies reference a third assembly which wraps the logging app block and exposes static log methods. All built-in trace listeners work fine except the database trace listener; as soon as i call Logger.Write I get exception:


Invalid TraceListenerData type in configuration 'listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Database.Configuration.FormattedDatabaseTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging.Database, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"'.

After much playing around, I got it to work by referencing Microsoft.Practices.EnterpriseLibrary.Logging.Database in the executing assembly (the form) as well as my wrapper assembly, which i don't necessarily want to do as i'll never access the library directly from the form, instead i'll always use the wrapper. What confuses me is that it's only Logging.Database.dll that's needs to be referenced and not just Logging.dll, let alone the fact that the wrapper is the only assembly that accesses the logging library. Does anyone know if this is normal behaviour and if not what might be causing this? Does it have something to do with reading the .config file?

Thanks, dave

Here's app.config:

<?xml version="1.0" encoding="utf-8"?>
<section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<loggingConfiguration name="Logging Application Block" tracingEnabled="true"
defaultCategory="Debug" logWarningsWhenNoCategoriesMatch="true">
<add databaseInstanceName="LogConnectionString" writeLogStoredProcName="WriteLog"
addCategoryStoredProcName="AddCategory" formatter="Text Formatter"
listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Database.Configuration.FormattedDatabaseTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging.Database, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
traceOutputOptions="None" type="Microsoft.Practices.EnterpriseLibrary.Logging.Database.FormattedDatabaseTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging.Database, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
name="Database Trace Listener" />
<add toAddress="" fromAddress=""
subjectLineStarter="" subjectLineEnder="" smtpServer=""
smtpPort="25" formatter="Text Formatter" listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.EmailTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
traceOutputOptions="None" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.EmailTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
name="EmailTraceListener" />
<add source="OASVendSource" formatter="Text Formatter" log="OASVend"
machineName="" listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
traceOutputOptions="None" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
name="EventLogTraceListener" />
<add fileName="trace.log" header="" footer="" formatter="DebugLogFormatter"
listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
traceOutputOptions="None" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
name="FlatFileTraceListener" />
<add template="{timestamp}: [{category}] {message}" type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
name="DebugLogFormatter" />
<add template="Timestamp: {timestamp}&#xD;&#xA;Message: {message}&#xD;&#xA;Category: {category}&#xD;&#xA;Priority: {priority}&#xD;&#xA;EventId: {eventid}&#xD;&#xA;Severity: {severity}&#xD;&#xA;Title:{title}&#xD;&#xA;Machine: {machine}&#xD;&#xA;Application Domain: {appDomain}&#xD;&#xA;Process Id: {processId}&#xD;&#xA;Process Name: {processName}&#xD;&#xA;Win32 Thread Id: {win32ThreadId}&#xD;&#xA;Thread Name: {threadName}&#xD;&#xA;Extended Properties: {dictionary({key} - {value}&#xD;&#xA;)}"
type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
name="Text Formatter" />
<add switchValue="All" name="Debug">
<add name="EmailTraceListener" />
<add name="EventLogTraceListener" />
<add name="FlatFileTraceListener" />
<add name="Database Trace Listener" />
<add switchValue="Error" name="Email" />
<add switchValue="Warning" name="EventLog" />
<add switchValue="All" name="General" />
<add switchValue="Information" name="SqlLog" />
<allEvents switchValue="All" name="All Events" />
<notProcessed switchValue="All" name="Unprocessed Category" />
<errors switchValue="All" name="Logging Errors &amp; Warnings" />
<dataConfiguration defaultDatabase="LogConnectionString" />
<add name="LogConnectionString" connectionString="Data Source=OASVendSql;Initial Catalog=Logging;Integrated Security=True"
providerName="System.Data.SqlClient" />

Jul 31, 2008 at 2:04 PM


The Logging.Database assembly is required at runtime; adding a reference copies the assembly to the output folder, thus making it available to the app. This previous thread should clarify this situation


Aug 1, 2008 at 9:59 AM
Edited Aug 1, 2008 at 12:28 PM
hmm... but the problem is that it is referenced, but it isn't being copied.

In an effort to understand exactly what the issue is I've spent some time watching what assemblies get deployed whenever anything is referenced. The confusion comes in thus: I have a wrapper assembly that references ...EnterpriseLibrary.Logging.dll, EnterpriseLibrary.Logging.Database.dll and EnterpriseLibrary.Data.dll, and an winform assembly that references the wrapper only. After build, the Debug folder of the winform assembly contains only a copy of Logging.dll and not Database.dll or Data.dll. If I reference Logging.Database in the winform, it works as expected, because it copies Database into the executing folder. If I remove the reference and manually copy Logging.Database.dll and Data.dll into the folder, it also works, as expected. If I reference Logging.Database again then remove it, then build, the Logging.Database.dll and the Data.dll disappear from my executing folder, being winformapp\bin\Debug, and the app breaks. I had assumed that a build, no matter how complex the reference chain, will always contain a copy of every single referenced assembly, obviously, otherwise the app can't function.

So my question should probably be rephrased thus: why is it that when building an application, the IDE copies some referenced assemblies and not others, and if so, what determines what gets copied and what doesn't? All references are Copy Local = True. Is it the assemblies themselves that specify whether they get deployed or not (which makes absolutely no sense to me whatsoever) or is there some other reason that an assembly that I need for a certain component in my solution to work is not copied to the running folder of the executing assembly? What am i missing? This is what I'm trying to understand.

Any thoughts?
Aug 1, 2008 at 4:17 PM

Here's how it works. The build process, which can be triggered by the IDE but is really msbuild doing the work, will copy to the output folder of a project all the "copy local" project references + all the assemblies the copy-local-referenced assemblies reference in their metadata that are located in the folder where each copy-local-referenced assembly resides. When this transitive reference chain is calculated, the roots are the copy-local-referenced assemblies but from then on metadata references are followed; project references are no longer considered (or even available). Adding a reference to an assembly in a project will not ensure you have a metadata reference in the resulting assembly; you need to actually have a code reference to a type in the assembly to get a metadata reference, otherwise the reference in the project will just be ignored. Since you won't directly use the types on a provider assembly directly, no metadata reference is added (which is a good thing) so it's not copied along with the copy-local project reference.

In your experiment try adding code that references a type in the logging.database assembly (a simple typeof() will do): you'll see it copied along with your winform app, and if you use ildasm on the wrapper assembly you will see a metadata reference that wasn't there before. Of course, this doesn't solve the problem as such code and the metadata reference it causes don't belong in the wrapper assembly. You will have to make the logging.database assembly available to the winforms app by either referencing it (not necessary to build the assembly, just for the side effect of copying it), copy it yourself (either manually or through a custom build step), or GAC it.

Hope this helps,
Aug 5, 2008 at 7:47 AM
Edited Aug 6, 2008 at 5:54 AM
Okay, I think I'm starting to get the hang of this. What I did was the following:

1. Removed the reference to Logging.Database in my winform and reproduced the error I originally posted.
2. Checked the wrapper assembly manifest in Ildasm and saw it indeed only contained a ref to Logging.dll, despite the fact that Logging.Database and Logging.Data were referenced.
3. Checked the output folder of the wrapper and saw it contained Logging.dll, Logging.Database.dll and Logging.Data.dll, as expectected as they are directly referenced by that assembly and Copy Local = True. Then checked the output folder of the winform and confirmed that it only contained Logging.dll, as expected since the app broke.
4. As suggested, added a Type t = typeof(Microsoft.Practices.EnterpriseLibrary.Logging.Database.FormattedDatabaseTraceListener) to a method in the wrapper assembly, rebuild.
5. Checked the wrapper manifest, hey presto, an extra reference in the metadata to Logging.Database.
6. Checked the winform output folder and indeed there were now copies of Logging.Database.dll and Data.dll, and the spike now works as expected.
7. Then, to check, referenced another random dll (entlib.Security) in the wrapper with copy local=true, built, wrapper output folder now contains Security.dll, winform output folder doesn't, and no Security reference in the wrapper manifest, as it's not used in the code.
8. Added the line Type t2 = typeof(Microsoft.Practices.EnterpriseLibrary.Security.AuthorizationProvider) to the wrapper, built, and now the winform (executing) output folder contains Security.dll, and the wrapper manifest contains a reference to Security.

So, just to be sure i understand (and for the benifit of anyone who was as confused as i was three days ago) it works like this: Any directly referenced assembly with copy local = true will be copied into the output folder but it's manifest will not contain a reference to it if it's not used in the code. Any indirectly referenced assembly (a reference of a reference) will only be copied if the directly referenced assembly contains the reference to it in it's assembly manifest. So I guess the best way to make sure the dll's travel right down to the executing assembly is to make sure you use the types in the references, which in this case slipped by since the object (FormattedDatabaseTraceListener) was created in the app.config of the winform and not in code. Adding Type t = typeof(...) solved the problem. Am I on the right track? Hope I got the terminology right...

One other q about the Logging block, I noticed that time stamps are always GMT, in my case (i'm GMT+2) the times are always two hours behind. Is this behaviour by design and how do I get around it? (my app will always be local time)

Fernando, thanks for your help, you rock.
Aug 5, 2008 at 3:20 PM

Hi Dave,

I'm glad this was helpful.

Just to clarify, the suggestion of adding code with hard references to types in the provider assemblies was just part of the experiment to understand how the build works; you don't need the code to build your app and in fact it's impossible to add references to each possible provider assembly you may reference through configuration. The most convenient approach is to add the references in your app's project, or copy the binaries through a post-build event.

Regarding timestamps, yes they are GMT by design. You can use the {timestamp} token to indicate local timestamps when you use a formatter to generate the log message as described in As for the timestamp property logged to the database, you will need to add code to convert it from GMT to your local TZ; it's probably easier if you do it on the stored procedure, so you can keep using the signed binaries.


Aug 6, 2008 at 5:59 AM
Understood. Thanks again.
Dec 18, 2009 at 2:45 PM
fsimonazzi wrote:

Just to clarify, the suggestion of adding code with hard references to types in the provider assemblies was just part of the experiment to understand how the build works; you don't need the code to build your app and in fact it's impossible to add references to each possible provider assembly you may reference through configuration. The most convenient approach is to add the references in your app's project, or copy the binaries through a post-build event.


 I know this is an old post, but I recently came across this post and it was very helpful.  For the moment I have taken Dave's approach to get it working without adding a reference to the .exe project.  However, I would love to know how to get the child logging project to copy the assembly to the parent.  I don't want the parent (.exe) assembly to have to know anything about this "feature."  I want any new project to be able to just add my Logging project and work.

Thanks in advance!

Dec 21, 2009 at 2:38 AM

Altonymous, if your child logging project contains the Logging assembly, your "parent" assembly must be able to locate that assembly.  And as the discussion already mentioned, it should somehow, referenced or unreferenced, be in the output folder of your "parent" assembly.  This is how .NET works.  The other way around it I think is to have your child logging project reference the logging assembly from GAC by setting the Copy Local  property of the reference to False.  So in your machine, the Logging assembly should be in GAC


Sarah Urmeneta
Global Technology & Solutions
Avanade, Inc.


Jan 18, 2010 at 8:50 PM

I too ran into this problem, and this post also in the end was the solution to my issue (thanks fsimonazzi !). After a little reflection, it makes sense that an assembly that gets loaded dynamically through configuration would not automatically get put into the runtime directory. I also agree that you won't be able to include each and every assembly that might get loaded into configuration through the trick of directly referencing it (as in using the typeof trick described above).

However, in this case I would suggest if you're going to use database logging but this won't be known until after deployment and/or might change due to operations teams decisions that you use the trick of directly referencing the assembly. In my case I have a support project (strangely named support) that includes overall functionality like logging and other helper functionality. It gets called all over the place and really I can't be sure of each and every potential referencer of the project. What's worse, any ommisions in the direct references in the calling projects will work just fine until the configuration is changed to include database logging - then a less then useful exception will get raised that the operations folks will not understand and quite frankly even I will likely have to take pause and reflect on by the time this actually happens (could be months; years?). Then we'll have to dig up the right version of the assembly and/or rebuild the calling project.

This needs to be looked at with some discretion - as soon as the typeof method gets called that assembly will be loaded and that clearly may not be desirable in all cases. But at least in my case the loading of a 38+ kilobyte assembly won't have a material impact, and it is the only assembly that I have that in this case will by dynamic (in this context). All of my custom tracers are also in the support assembly so will get included by default.

Of course your mileage may vary...

Dave Remmer

Oct 5, 2011 at 1:08 PM
Edited Oct 5, 2011 at 1:10 PM

Thanks fsimonazzi. It was of great help.

Apr 18, 2012 at 12:51 PM

I had the exact same problem.

The typeof() did not work for me, however, as soon as I instantiated it in the constructor of my unit test, the file got copied.

FormattedDatabaseTraceListenerData fdtl = new FormattedDatabaseTraceListenerData();

Oct 10, 2012 at 8:17 PM

I think this I am seeing this issue...

In my case, the Logging is being done in a class libarary with a LogHelper class that is referenced in many different applications.  In VS2010 I have a test console app project that calls the static WriteLogEntry() method.  My initial tests with the Event  Log were fine, but things went south as soon as I made the leap to try logging to a SQL Database.

Invalid TraceListenerData type in configuration

I believe the issue is that my test program does not include any references (or code) for Microsoft.Practices.EnterpriseLibrary.Logging.Database, therefore the DLL is not copied to the output BIN folder, correct?

I am really stuggling to understand why this would be even be needed.  My utitlity class library even loads it's own EntLib.config file programatically so there should be no reference to ANY Enterprise Library DLLs in the test project / app.  Why should the app care how MyUtils.WriteLogEntry() is implemeted and where it logs to?

Is the workaround to add references to Microsoft.Practices.EnterpriseLibrary.Logging.Database along with a unused lined of code to call the FormattedDatabaseTraceListenerData() constructor?  YIKES!!

Any input would be appreciated.... thanks!

Oct 10, 2012 at 8:38 PM
Edited Oct 10, 2012 at 8:50 PM

You need to ensure that the Microsoft.Practices.EnterpriseLibrary.Logging.Database.dll assembly can be located by the .NET Framework  at run time.  How you do that is up to you.  For example, you could place it in the GAC or have a deployment step to copy the appropriate assemblies, add a probing path, etc.

The reason why the compiler does not copy the assembly is that it is not used by any code.  Just adding some code that references the assembly will cause the assembly to be copied:


    private static Type dbType = typeof(FormattedDatabaseTraceListener);

That's probably the easiest workaround.  

Also note that if you are testing with a console application it will need to target the .NET Framework and not .NET Framework Client Profile.

Randy Levy
Enterprise Library support engineer