Help converting web.config into fluent config

Topics: Logging Application Block
Oct 3, 2011 at 8:20 PM
Edited Oct 3, 2011 at 8:36 PM

I have an application that is using the logging application block with it's configuration stored in web.config. However, we now need to move the connection string information outside of web.config so I will need to configure the EntLib logging block using the Fluent API. I have not done this before and it seems to be taking a lot longer than I would think it should. Can someone help me to migrate the following into the proper fluent calls?

 

 

<loggingConfiguration name="" tracingEnabled="true" defaultCategory="General">
	<listeners>
		<add name="Event Log Listener"
			type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
			listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
			source="MyPortal"
			formatter="Text Formatter"
			log=""
			machineName="."
			traceOutputOptions="LogicalOperationStack, Callstack"
			filter="Error" />
		<add name="Database Trace Listener"
			type="Microsoft.Practices.EnterpriseLibrary.Logging.Database.FormattedDatabaseTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging.Database, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
			listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Database.Configuration.FormattedDatabaseTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging.Database, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
			databaseInstanceName="PortalSqlServer"
			writeLogStoredProcName="WriteTraceLog"
			addCategoryStoredProcName="AddTraceCategory" />
	</listeners>
	<formatters>
		<add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
			 template="Timestamp: {timestamp}{newline}&#xA;Message: {message}{newline}&#xA;Category: {category}{newline}&#xA;Priority: {priority}{newline}&#xA;EventId: {eventid}{newline}&#xA;Severity: {severity}{newline}&#xA;Title:{title}{newline}&#xA;Machine: {localMachine}{newline}&#xA;App Domain: {localAppDomain}{newline}&#xA;ProcessId: {localProcessId}{newline}&#xA;Process Name: {localProcessName}{newline}&#xA;Thread Name: {threadName}{newline}&#xA;Win32 ThreadId:{win32ThreadId}{newline}&#xA;Extended Properties: {dictionary({key} - {value}{newline})}"
			 name="Text Formatter" />
	</formatters>
	<categorySources>
		<add switchValue="All"
			 name="General">
			<listeners>
				<add name="Event Log Listener" />
				<add name="Database Trace Listener" />
			</listeners>
		</add>
		<add switchValue="All"
			name="User Interface">
			<listeners>
				<add name="Event Log Listener" />
				<add name="Database Trace Listener" />
			</listeners>
		</add>
		<add switchValue="All"
			name="Persistence">
			<listeners>
				<add name="Event Log Listener" />
				<add name="Database Trace Listener" />
			</listeners>
		</add>
	</categorySources>
	<specialSources>
		<allEvents switchValue="All"
			name="All Events">
			<listeners>
				<add name="Database Trace Listener" />
				<add name="Event Log Listener" />
			</listeners>
		</allEvents>
		<notProcessed switchValue="All"
			name="Unprocessed Category">
			<listeners>
				<add name="Database Trace Listener" />
				<add name="Event Log Listener" />
			</listeners>
		</notProcessed>
		<errors switchValue="All"
			name="Logging Errors &amp; Warnings">
			<listeners>
				<add name="Event Log Listener" />
				<add name="Database Trace Listener" />
			</listeners>
		</errors>
	</specialSources>
</loggingConfiguration>

 

Update:  Also, I am currently using the unity container within my application and was loading the configuration using the following:

var _container = new UnityContainer();

_container.AddNewExtension<EnterpriseLibraryCoreExtension>();

_container.RegisterType<IType, Type>();
// etc

 

How would I continue to use the Unity Container with the Fluent API?

Oct 4, 2011 at 2:43 AM

Hi,

Just to clarify - when you say you will need to move the connection string info outside of the web.config, do you mean you will move it to another configuration file (possibly another XML file), or that you will now store the connection string info to the class files?

 

Oct 4, 2011 at 7:02 AM

Hi,

What specific challanges are you facing with Fluent Config API? You can refer to the Fluent Config API documentation for logging here. Regarding with your second concern, yes you can use the Fluent Config API along with Unity. Here is a simple sample code that writes to a flat file named "MyFile.txt":

 var myConfig = new ConfigurationSourceBuilder();
                myConfig.ConfigureLogging().WithOptions
                    .DoNotRevertImpersonation()
                    .LogToCategoryNamed("MyCategory").WithOptions.SetAsDefaultCategory()
                    .SendTo.FlatFile("Flat File")
                    .FormatWith(new FormatterBuilder().TextFormatterNamed("MyFormatter")
                    .UsingTemplate("Timestamp: {timestamp}...{newline}) Message: {message}")).WithHeader("----------- The Beginning -------------")
                    .WithFooter("----------- The End -------------")
                    .ToFile("MyFile.txt");

var configSource = new DictionaryConfigurationSource();
                myConfig.UpdateConfigurationWithReplace(configSource);

    UnityContainer myContainer = new UnityContainer();
                myContainer.AddExtension(new EnterpriseLibraryCoreExtension(configSource));

     LogWriter writer
                 //= EnterpriseLibraryContainer.CreateDefaultContainer(configSource).GetInstance<LogWriter>();
                = myContainer.Resolve<LogWriter>();

Hope this helps.

 

Noel Angelo Bolasoc
Avanade Software and Cloud Services
Avanade, Inc.
Contact 

 

Oct 4, 2011 at 12:46 PM

CodeTrainer - The connection string would be stored outside web.config as an encrypted value in the registry and would be retrieved by code at runtime.

AvandeSupport -

My main issue with the Fluent API seems to be not knowing which methods to use when to produce the same results as the configuration file
(which was created using the EntLib v5 Configuration Tool; MUCH easier to use than previous versions by the way). For instance, when/where do
I create the trace listeners and then refer to them elsewhere? Does the database configuration have to be defined prior to the Logging, etc. I have
been looking over the documentation for the Fluent API, but the samples are very specific/basic and don't give more detailed information on each of the
methods. I'm sure it will all make sense once I've figured it all out, but getting there is taking more time than I would have anticipated.

The sample for using Unity as the container helps, so hopefully I can start small and keep building on it.

Oct 5, 2011 at 3:27 AM

Would this help?

http://msdn.microsoft.com/en-us/library/ff953193%28PandP.50%29.aspx

Oct 5, 2011 at 8:51 AM

Yes, the documentation seems too basic. However, you may find the words used on the fluent config api identical to its config version.  I tried migrating your config and here's what I've got:

var myConfig = new ConfigurationSourceBuilder(); 
                

                myConfig.ConfigureLogging().WithOptions
                    .DoNotRevertImpersonation()
                    .LogToCategoryNamed("General").WithOptions.SetAsDefaultCategory().ToSourceLevels(SourceLevels.All)
                    .SendTo.EventLog("Event Log Listener").UsingEventLogSource("MyPortal").FormatWith(new FormatterBuilder
                                                                                                          ().
                                                                                                          TextFormatterNamed
                                                                                                          ("Text Formatter")
                                                                                                          .UsingTemplate
                                                                                                          ("Timestamp: {timestamp}{newline}&#xA;Message: {message}{newline}&#xA;Category: {category}{newline}&#xA;Priority: {priority}{newline}&#xA;EventId: {eventid}{newline}&#xA;Severity: {severity}{newline}&#xA;Title:{title}{newline}&#xA;Machine: {localMachine}{newline}&#xA;App Domain: {localAppDomain}{newline}&#xA;ProcessId: {localProcessId}{newline}&#xA;Process Name: {localProcessName}{newline}&#xA;Thread Name: {threadName}{newline}&#xA;Win32 ThreadId:{win32ThreadId}{newline}&#xA;Extended Properties: {dictionary({key} - {value}{newline})}")
                    )

                    .ToLog("")
                    .ToMachine(".")
                    .WithTraceOptions(TraceOptions.LogicalOperationStack & TraceOptions.Callstack)
                    .Filter(SourceLevels.Error)

                    .SendTo.Database("Database Trace Listener")
                    .UseDatabase("MyDatabaseInstance")
                    .WithWriteLogStoredProcedure("WriteTraceLog")
                    .WithAddCategoryStoredProcedure("AddTraceCategory")

                    .LogToCategoryNamed("User Interface").WithOptions.ToSourceLevels(SourceLevels.All).SendTo.EventLog(
                        "Event Log").SendTo.Database("Database Trace Listener")

                    .LogToCategoryNamed("Persistence").WithOptions.ToSourceLevels(SourceLevels.All).SendTo.EventLog(
                        "Event Log").SendTo.Database("Database Trace Listener")

                    .SpecialSources.AllEventsCategory.WithOptions.ToSourceLevels(SourceLevels.All).LogToCategoryNamed("All Events").SendTo.EventLog(
                        "Event Log").SendTo.Database(
                            "Database Trace Listener")

                    .SpecialSources.UnprocessedCategory.WithOptions.ToSourceLevels(SourceLevels.All).LogToCategoryNamed("Unprocessed Category").SendTo.
                    EventLog("Event Log").SendTo.Database(
                        "Database Trace Listener")

                    .SpecialSources.LoggingErrorsAndWarningsCategory.WithOptions.ToSourceLevels(SourceLevels.All).LogToCategoryNamed("Logging Errors and Warnings").
                    SendTo.EventLog("Event Log").SendTo.Database(
                        "Database Trace Listener");
                     
                    
myConfig.ConfigureData().ForDatabaseNamed("MyDatabaseInstance").ThatIs.ASqlDatabase().WithConnectionString(@"Data Source=.;Initial Catalog=LoggingDB;Integrated Security=true");

I haven't tested this yet but I hope this would give you an idea. Hope this helps! :)

 

Noel Angelo Bolasoc
Avanade Software and Cloud Services
Avanade, Inc.
Contact 

Oct 5, 2011 at 1:26 PM

Yes, that is basically what I ended up with yesterday after reading the links supplied above. I started very basic (logging to a file) and
then gradually started tweaking it and adding new layers (event log, filters, etc.) until I got what I wanted. Some of the configuration methods
did match the names from the config file and/or the Visual Config tool, but not always. After a little while, things started making more sense.

A better walk through of the code that talks about what is being done instead of just a code dump would greatly help make the transition from code to Fluent.

Thanks to all that assisted.

This is what I ended up with that seems to be working:

/// <summary>Logging format string</summary>
private static string FormatterTemplate =
	"Timestamp: {timestamp}{newline}\n" +
	"Message: {message}{newline}\n" +
	"Category: {category}{newline}\n" +
	"Priority: {priority}{newline}\n" +
	"EventId: {eventid}{newline}\n" +
	"Severity: {severity}{newline}\n" +
	"Title:{title}{newline}\n" +
	"Machine: {localMachine}{newline}\n" +
	"App Domain: {localAppDomain}{newline}\n" +
	"ProcessId: {localProcessId}{newline}\n" +
	"Process Name: {localProcessName}{newline}\n" +
	"Thread Name: {threadName}{newline}\n" +
	"Win32 ThreadId:{win32ThreadId}{newline}\n" +
	"Extended Properties: {dictionary({key} - {value}{newline})}";


var builder = new ConfigurationSourceBuilder();
var connectionString = GetConnectionString();


// configure database
builder.ConfigureData()
	.ForDatabaseNamed( "CmcsSqlServer" )
	.ThatIs.ASqlDatabase()
	.WithConnectionString( connectionString )
	.AsDefault();

// configure logging
builder.ConfigureLogging()
	.WithOptions.DoNotRevertImpersonation()

	// Categories
	.LogToCategoryNamed( "General" )
		.WithOptions
			.SetAsDefaultCategory()

		// Event Log Listener
		.SendTo
			.EventLog( "Event Log Listener" )
				.UsingEventLogSource( "CMCS Portal" )
				.FormatWith(
					new FormatterBuilder()
						.TextFormatterNamed( "Text Formatter" )
						.UsingTemplate( FormatterTemplate ) )
				.Filter( SourceLevels.Error )
				.ToLog( "Application" )

		// Database Trace Listener
		.SendTo
			.Database( "Database Trace Listener" )
				.UseDatabase( "CmcsSqlServer" )
				.WithAddCategoryStoredProcedure( "AddTraceCategory" )
				.WithWriteLogStoredProcedure( "WriteTraceLog" )

	.LogToCategoryNamed( "User Interface" )
		.SendTo.SharedListenerNamed( "Event Log Listener" )
		.SendTo.SharedListenerNamed( "Database Trace Listener" )

	.LogToCategoryNamed( "Persistence" )
		.SendTo.SharedListenerNamed( "Event Log Listener" )
		.SendTo.SharedListenerNamed( "Database Trace Listener" )

	// Special Categories
	.SpecialSources
		.AllEventsCategory
			.SendTo.SharedListenerNamed( "Event Log Listener" )
			.SendTo.SharedListenerNamed( "Database Trace Listener" )
	.SpecialSources
		.UnprocessedCategory
			.SendTo.SharedListenerNamed( "Event Log Listener" )
			.SendTo.SharedListenerNamed( "Database Trace Listener" )
	.SpecialSources
		.LoggingErrorsAndWarningsCategory
			.SendTo.SharedListenerNamed( "Event Log Listener" )
			.SendTo.SharedListenerNamed( "Database Trace Listener" )
;

// assign & register with the container
var configSource = new DictionaryConfigurationSource();
builder.UpdateConfigurationWithReplace( configSource );

var mContainer = new UnityContainer();
mContainer.AddExtension( new EnterpriseLibraryCoreExtension( configSource ) );