Monday, August 30, 2010

Enterprise Library 5.0 – Configuration Services Part - III

The previous two posts on Configuration Services showed how we can use an external configuration file and how we can use a specific section from an external config source.

In the final post of the Configuration Sources series, we will look at what I personally think is one of the most useful features of Configuration Services. We will see how we can have the application configuration file inherit from another configuration file and override or add only sections that are application specific. I will give you a scenario where this can be very useful.

In one of my recent projects we were developing a number of websites. Except for some application specific key value pairs a lot of the other environmental configurations were the same across most of these websites. With this feature, it will be very easy to isolate the environmental specific values in a separate configuration file, inherit the same and add key value pairs to store application specific values.

To show how this works, I have a shared config file that looks like the below.

   1: <configuration>
   2:     <configSections>
   3:         <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
   4:     </configSections>
   5:   <connectionStrings configSource="">
   6:     
   7:   </connectionStrings>
   8:     <loggingConfiguration name="" tracingEnabled="true" defaultCategory="General">
   9:         <listeners>
  10:             <add name="EntLIbTestListener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
  11:                 listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
  12:                 source="Enterprise Library Logging" formatter="Text Formatter"
  13:                 log="" machineName="." traceOutputOptions="None" />
  14:         </listeners>
  15:         <formatters>
  16:             <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
  17:                 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})}"
  18:                 name="Text Formatter" />
  19:         </formatters>
  20:         <categorySources>
  21:             <add switchValue="All" name="General">
  22:                 <listeners>
  23:                     <add name="EntLIbTestListener" />
  24:                 </listeners>
  25:             </add>
  26:         </categorySources>
  27:         <specialSources>
  28:             <allEvents switchValue="All" name="All Events" />
  29:             <notProcessed switchValue="All" name="Unprocessed Category" />
  30:             <errors switchValue="All" name="Logging Errors &amp; Warnings">
  31:                 <listeners>
  32:                     <add name="EntLIbTestListener" />
  33:                 </listeners>
  34:             </errors>
  35:         </specialSources>
  36:     </loggingConfiguration>
  37: </configuration>

This is the same configuration as I have used in Part I and II with the logging settings. To use this as my parent configuration, I have to set a couple of properties. I have to set the Parent Source of my config file to the common config file I have created above. The settings are shown in the screenshot below. I have also changed the configuration source to be System Configuration which means my local app.config is being used.

Parentconfig

Notice how this configuration file does not have any logging settings. After these changes, my config file now looks like



   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3:     <configSections>
   4:         <section name="enterpriseLibrary.ConfigurationSource" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ConfigurationSourceSection, Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
   5:     </configSections>
   6:     <enterpriseLibrary.ConfigurationSource selectedSource="System Configuration Source"
   7:         parentSource="Shared Config">
   8:         <sources>
   9:             <add name="System Configuration Source" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.SystemConfigurationSource, Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  10:             <add name="Shared Config" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.FileConfigurationSource, Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
  11:                 filePath="C:\Users\r.vaideeswaran\Documents\Visual Studio 2010\Projects\EntLibTest\EntLibTest\CommonConfig.config" />
  12:         </sources>
  13:     </enterpriseLibrary.ConfigurationSource>
  14: </configuration>


Notice how there are now two sources added; one is the system configuration source and the other points to the shared configuration file.

As a first step, let me now test the logging code I wrote in the previous two parts. For re-cap, here is the code



   1: namespace EntLibTest1
   2: {
   3:     class Program
   4:     {
   5:         static void Main(string[] args)
   6:         {
   7:             LogWriter textWriter = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();
   8:             LogEntry testEntry = new LogEntry();
   9:             testEntry.Message = "Logging the loading of EntLibTest1";
  10:             testEntry.Priority = 2;
  11:             testEntry.Categories.Add("General");
  12:             textWriter.Write(testEntry);
  13:  
  14:             Console.WriteLine("Message Logged");
  15:             Console.ReadLine();
  16:         }
  17:     }
  18: }

This does indeed produce a “Message Logged” output on the console though there are no logging sections directly in my config. This tells me that my parent source is working. The next step is now to add a specific section and see if that works.

I add a new key value pair in the appSettings section through enterprise library. The screenshot for the same is as below.

image


This is our good old appSettings key value pair. Unsurprisingly, the config is now changed to reflect the above settings.


   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3:     <configSections>
   4:         <section name="enterpriseLibrary.ConfigurationSource" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ConfigurationSourceSection, Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
   5:     </configSections>
   6:     <appSettings>
   7:         <add key="ConnectionString" value="TestConnectionString" />
   8:     </appSettings>
   9:     <enterpriseLibrary.ConfigurationSource selectedSource="System Configuration Source"
  10:         parentSource="Shared Config">
  11:         <sources>
  12:             <add name="System Configuration Source" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.SystemConfigurationSource, Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  13:             <add name="Shared Config" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.FileConfigurationSource, Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
  14:                 filePath="C:\Users\r.vaideeswaran\Documents\Visual Studio 2010\Projects\EntLibTest\EntLibTest\CommonConfig.config" />
  15:         </sources>
  16:     </enterpriseLibrary.ConfigurationSource>
  17: </configuration>


To make sure my app can retrieve the appSettings value, I add the following three lines of codev(Do not forget the usings at the top)


  1: AppSettingsReader connReader = new AppSettingsReader();
  2: var connString = connReader.GetValue("ConnectionString", typeof(string));
  3: Console.WriteLine(connString.ToString());



Nothing fancy. Now when I run the application, you will see that the application picks up both the logging configuration and the appSettings key. This happens because at run time the Enterprise library merges the two configuration files so that they act as one. The above example did not specifically override a section but if I were to override, the value in the local configuration will take precedence over the shared configuration.

That concludes my three part starter posts on Configuration Services. The Configuration Services is no where near perfect yet but as with anything else, I am sure this will evolve over multiple releases. Happy Coding!!!

Thursday, August 19, 2010

Enterprise Library 5.0 – Configuration Services Part -II

Last week, we saw how to use the same configuration file for two different applications. If you have not read the post yet, you can read it here. This week, we will look at how configuration services can help you use a section from a shared configuration file. For the sake of continuity, I will use the same example we used in the previous post.

In the previous post, we added a separate logging section, the change here is that we will just add a redirected section in the Configuration Sources element itself. To enable section redirection, the following has to be done

  • Change the configuration source to System Configuration Source. This will enable the application to use its default app.config
  • Add a redirected section. You can do this by expanding the Configuration Sources section and then add a redirected section. The source of the configuration section should now point to the section in the external file. The screenshot below shows how to add a redirected section

image

The configuration file now looks like the below

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3:     <configSections>
   4:         <section name="enterpriseLibrary.ConfigurationSource" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ConfigurationSourceSection, Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
   5:     </configSections>
   6:     <enterpriseLibrary.ConfigurationSource selectedSource="System Configuration Source">
   7:         <sources>
   8:             <add name="System Configuration Source" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.SystemConfigurationSource, Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
   9:             <add name="Shared Config" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.FileConfigurationSource, Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
  10:                 filePath="C:\Users\r.vaideeswaran\Documents\Visual Studio 2010\Projects\EntLibTest\logging.config" />
  11:         </sources>
  12:         <redirectSections>
  13:             <add sourceName="Shared Config" name="loggingConfiguration" />
  14:         </redirectSections>
  15:     </enterpriseLibrary.ConfigurationSource>
  16: </configuration>




Note how the logging is now configured as a redirectSection. This will ensure that the logging section is picked up from the shared config file. The code in the previous post will now work with this configuration as well without any changes. For the sake of reference, below is the code




   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         LogWriter textWriter = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();
   6:         LogEntry testEntry = new LogEntry();
   7:         testEntry.Message = "Logging the loading of EntLibTest1";
   8:         testEntry.Priority = 2;
   9:         testEntry.Categories.Add("General");
  10:         textWriter.Write(testEntry);
  11:  
  12:         Console.WriteLine("Message Logged");
  13:         Console.ReadLine();
  14:     }
  15: }



While in theory, this is the same as using the configSource for a particular setting, one of the advantages is that configSource doesnt permit you to use absolute paths (except for appSettings where you can use the file attribute instead of configSource). Sometimes, this can be a real pain. The Ent Lib Configuration Sources solves that problem.



Hope I was able to give you an idea of how to use a redirected section with Ent Lib 5.0. Happy Coding!!!!

Sunday, August 8, 2010

Enterprise Library 5.0 – Configuration Services Part - I

Microsoft recently released Ent Lib 5.0. While most of the application blocks are the same as 4.1, one of the new kids on the block is Configuration Services. Hence, I will start off this series on Ent Lib 5.0 by taking a closer look at the Configuration Services.

The configuration services provides three capabilities when it comes to managing config files

  • Ability for multiple applications to use the same config file
  • Ability to use of a specific section from a shared config file
  • Ability for a configuration file to inherit from another config file

In this post, we will see how to enable multiple applications to share the same config file.

Multiple Applications using the Same Config File

I will start off by creating a simple console application. For first timers, right click on the config and you should see a context menu to edit enterprise library configuration.

Clicking on the menu brings up the Ent Lib configuration console. The console has been re-designed in the latest version of enterprise library. To add a configuration source section, there is a menu called “Add Configuration Settings” under Blocks menu. Click on it and you should see a Configuration Section now added. Click on the image icon to expand the section and add a File Based Configuration Source.

Provide the values of the config name and the path of the config file. In the selected source dropdown, select the shared source that we have just configured. Save the settings and right click on the Configuration Sources section and click on Validate. You will get the list of warnings and errors, if any. Let us take a moment to look at the changes in the config. The following section has been added under the <configuration> section

<configSections>
<section name="enterpriseLibrary.ConfigurationSource" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ConfigurationSourceSection, Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
</configSections>

<enterpriseLibrary.ConfigurationSource selectedSource="Common Config">
<sources>
<add name="System Configuration Source" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.SystemConfigurationSource, Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add name="Common Config" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.FileConfigurationSource, Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
filePath="CommonConfig" />
</sources>
</enterpriseLibrary.ConfigurationSource>

When you close the enterprise library console, you should now see a commonconfig.config file in your project path. Right click and include the same in your project. Make sure you change the property of the file to copy over to the output path. This will now be the configuration that your application now uses.

To test this, I have added a logging application block and used the following code to log an entry into the event log.

   1: LogWriter textWriter = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();
   2: LogEntry testEntry = new LogEntry();
   3: testEntry.Message = "Logging the loading of EntLibTest";
   4: testEntry.Priority = 2;
   5: testEntry.Categories.Add("General");
   6: textWriter.Write(testEntry);
   7:  
   8: Console.WriteLine("Message Logged");
   9: Console.ReadLine();


Do remember to make the appropriate configuration changes to ensure logging is enabled. Running the application creates an entry in the event log. I now add another project to the same solution and update the configuration source to point to the commonconfig.config of the first project. Below is a snapshot of how my config for the second project looks like.

image

You should be able to run the application without making any other changes and ensure that messages are logged from the second console application as well.

Before all you web developers get excited, please remember that this feature does not work with web applications just yet. You can see the details of why in this blog.

That concludes our first look at Configuration Services in Enterprise Library 5.0. I will dig into the other two aspects in subsequent posts. Happy Coding!!!