No Configuration Enterprise Library

From time to time I end up starting a new C# project and bumping into the same old infrastructure requirements like exception handling, logging, caching, etc.

At that point I always get back to Microsoft Enterprise Library... :)

I really like EntLib but this time I had other requirements that prevented me from having a configuration file.

So how the heck can you use EntLib without configuration? It turns out that it’s relatively easy but not so well documented, so that even Google had trouble finding me the solution. :)

I’ll leave it here also for future reference...

Scenario 1 – No Configuration Caching Block

Using the caching block with configuration is very simple. You create the configuration and then simply use the CacheFactory to create the manager. Something like this:

   1: ICacheManager productsCache = CacheFactory.GetCacheManager();
   2: productsCache.Add(product.ProductID, product)

To use it without configuration is a little harder.

First you need to use the CacheManagerFactory to create a factory passing in the configuration settings. Then you use that factory to create the manager.

The magic happens when you create your own class implementing the IConfigurationSource interface (available in Microsoft.Practices.EnterpriseLibrary.Common).

The final code is as follows:

   1: using Microsoft.Practices.EnterpriseLibrary.Caching.Configuration;
   2: using Microsoft.Practices.EnterpriseLibrary.Caching.BackingStoreImplementations;
   3:  
   4: namespace MyApplication
   5: {
   6:     internal class CacheServiceConfigurationSource : IConfigurationSource
   7:     {
   8:         #region Members
   9:  
  10:         private int expirationFrequencyInSeconds;
  11:         private int maximumElementsBeforeScavenging;
  12:  
  13:         #endregion
  14:  
  15:         #region Constructors
  16:  
  17:         private CacheServiceConfigurationSource()
  18:         {
  19:         }
  20:  
  21:         public CacheServiceConfigurationSource(int expirationFrequencyInSeconds, int maximumElementsBeforeScavenging)
  22:             : this()
  23:         {
  24:             this.expirationFrequencyInSeconds = expirationFrequencyInSeconds;
  25:             this.maximumElementsBeforeScavenging = maximumElementsBeforeScavenging;
  26:         }
  27:  
  28:         #endregion
  29:  
  30:         #region Public Methods
  31:  
  32:         public void Add(IConfigurationParameter saveParameter, string sectionName, ConfigurationSection configurationSection)
  33:         {
  34:         }
  35:  
  36:         public void AddSectionChangeHandler(string sectionName, ConfigurationChangedEventHandler handler)
  37:         {
  38:         }
  39:  
  40:         public ConfigurationSection GetSection(string sectionName)
  41:         {
  42:             if (sectionName.Equals("cachingConfiguration", StringComparison.CurrentCulture))
  43:             {
  44:                 CacheManagerSettings result = new CacheManagerSettings();
  45:                 result.DefaultCacheManager = "DefaultCacheManager";
  46:  
  47:                 CacheStorageData storage = new CacheStorageData();
  48:                 storage.StorageEncryption = string.Empty;
  49:                 storage.Name = "NullStorage";
  50:                 storage.Type = typeof(NullBackingStore);
  51:                 result.BackingStores.Add(storage);
  52:  
  53:                 CacheManagerData manager = new CacheManagerData();
  54:                 manager.Name = "DefaultCacheManager";
  55:                 manager.NumberToRemoveWhenScavenging = 10;
  56:                 manager.MaximumElementsInCacheBeforeScavenging = this.maximumElementsBeforeScavenging;
  57:                 manager.ExpirationPollFrequencyInSeconds = this.expirationFrequencyInSeconds;
  58:                 manager.CacheStorage = "NullStorage";
  59:                 result.CacheManagers.Add(manager);
  60:  
  61:                 return result;
  62:             }
  63:  
  64:             return null;
  65:         }
  66:  
  67:         public void Remove(IConfigurationParameter removeParameter, string sectionName)
  68:         {
  69:         }
  70:  
  71:         public void RemoveSectionChangeHandler(string sectionName, ConfigurationChangedEventHandler handler)
  72:         {
  73:         }
  74:  
  75:         #endregion
  76:     }
  77: }
  78:  
  79: using System;
  80: using System.Configuration;
  81: using System.Text;
  82: using Microsoft.Practices.EnterpriseLibrary.Caching;
  83: using Microsoft.Practices.EnterpriseLibrary.Caching.Expirations;
  84:  
  85: namespace MyApplication
  86: {
  87:     public static class CacheService
  88:     {
  89:         #region Members
  90:  
  91:         private static ICacheManager manager;
  92:  
  93:         #endregion
  94:  
  95:         #region Properties
  96:  
  97:         private static ICacheManager Manager
  98:         {
  99:             get
 100:             {
 101:                 if (manager == null)
 102:                 {
 103:                     CacheManagerFactory factory = new CacheManagerFactory(new CacheServiceConfigurationSource(Context.Current.Settings.Cache.ExpirationFrequencyInSeconds, Context.Current.Settings.Cache.MaximumElementsBeforeScavenging));
 104:                     manager = factory.CreateDefault();
 105:                 }
 106:  
 107:                 return manager;
 108:             }
 109:         }
 110:  
 111:         #endregion
 112:  
 113:         #region Public Methods
 114:  
 115:         public static void AddData<T>(string key, T value)
 116:         {
 117:             AddData<T>(key, value, Context.Current.Settings.Cache.ExpirationTimeInSeconds);
 118:         }
 119:  
 120:         internal static void AddData<T>(string key, T value, int expirationInSeconds)
 121:         {
 122:             // Expiration handler
 123:  
 124:             SlidingTime expirationHandler = new SlidingTime(new TimeSpan(0, 0, expirationInSeconds), DateTime.Now);
 125:  
 126:             // Add it
 127:  
 128:             Manager.Add(key, value, CacheItemPriority.Low, null, expirationHandler);
 129:         }
 130:  
 131:         #endregion
 132:     }
 133: }

Notice the GetSection method in CacheServiceConfigurationSource and the Manager property in the CacheService class.

Scenario 2 – No Configuration Logging Block

The logging application block is similar.

With configuration you use the Logger class.

Without configuration you must create a LogWriter using your own IConfigurationSource also.

   1: using System;
   2: using System.Configuration;
   3: using System.Text;
   4: using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
   5: using Microsoft.Practices.EnterpriseLibrary.Logging.Configuration;
   6: using Microsoft.Practices.EnterpriseLibrary.Logging.Formatters;
   7: using Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners;
   8:  
   9: namespace MyApplication
  10: {
  11:     internal class LoggingConfigurationSource : IConfigurationSource
  12:     {
  13:         #region Public Methods
  14:  
  15:         public void Add(IConfigurationParameter saveParameter, string sectionName, ConfigurationSection configurationSection)
  16:         {
  17:         }
  18:  
  19:         public void AddSectionChangeHandler(string sectionName, ConfigurationChangedEventHandler handler)
  20:         {
  21:         }
  22:  
  23:         public ConfigurationSection GetSection(string sectionName)
  24:         {
  25:             if (sectionName.Equals("loggingConfiguration", StringComparison.CurrentCulture))
  26:             {
  27:                 // Logging configuration
  28:  
  29:                 LoggingSettings result = new LoggingSettings();
  30:                 result.DefaultCategory = "General";
  31:                 result.TracingEnabled = true;
  32:                 result.LogWarningWhenNoCategoriesMatch = true;
  33:  
  34:                 // Listners
  35:  
  36:                 FormattedEventLogTraceListenerData listener = new FormattedEventLogTraceListenerData();
  37:                 listener.Name = "EventLogListener";
  38:                 listener.Source = "Office Extensions";
  39:                 listener.Formatter = "TextFormatter";
  40:                 listener.Log = "MyApplication";
  41:                 listener.MachineName = string.Empty;
  42:                 listener.TraceOutputOptions = System.Diagnostics.TraceOptions.None;
  43:                 listener.Filter = System.Diagnostics.SourceLevels.All;
  44:                 listener.ListenerDataType = typeof(FormattedEventLogTraceListenerData);
  45:                 listener.Type = typeof(FormattedEventLogTraceListener);
  46:                 result.TraceListeners.Add(listener);
  47:  
  48:                 TraceListenerReferenceData listenerReference = new TraceListenerReferenceData();
  49:                 listenerReference.Name = "EventLogListener";
  50:  
  51:                 // Formatters
  52:  
  53:                 StringBuilder template = new StringBuilder();
  54:                 template.AppendLine("Timestamp: {timestamp}");
  55:                 template.AppendLine("Message: {message}");
  56:                 template.AppendLine("Category: {category}");
  57:                 template.AppendLine("Priority: {priority}");
  58:                 template.AppendLine("EventId: {eventid}");
  59:                 template.AppendLine("Severity: {severity}");
  60:                 template.AppendLine("Title:{title}");
  61:                 template.AppendLine("Machine: {machine}");
  62:                 template.AppendLine("Application Domain: {appDomain}");
  63:                 template.AppendLine("Process Id: {processId}");
  64:                 template.AppendLine("Process Name: {processName}");
  65:                 template.AppendLine("Win32 Thread Id: {win32ThreadId}");
  66:                 template.AppendLine("Thread Name: {threadName}");
  67:                 template.AppendLine("Extended Properties: {dictionary({key} - {value})}");
  68:  
  69:                 TextFormatterData formatter = new TextFormatterData();
  70:                 formatter.Name = "TextFormatter";
  71:                 formatter.Type = typeof(TextFormatter);
  72:                 formatter.Template = template.ToString();
  73:                 result.Formatters.Add(formatter);
  74:  
  75:                 // Category Sources
  76:  
  77:                 TraceSourceData exceptionsSource = new TraceSourceData();
  78:                 exceptionsSource.TraceListeners.Add(listenerReference);
  79:                 exceptionsSource.Name = "Exceptions";
  80:                 exceptionsSource.DefaultLevel = System.Diagnostics.SourceLevels.All;
  81:                 result.TraceSources.Add(exceptionsSource);
  82:  
  83:                 TraceSourceData traceSource = new TraceSourceData();
  84:                 traceSource.TraceListeners.Add(listenerReference);
  85:                 traceSource.Name = "Trace";
  86:                 traceSource.DefaultLevel = System.Diagnostics.SourceLevels.All;
  87:                 result.TraceSources.Add(traceSource);
  88:  
  89:                 TraceSourceData generalSource = new TraceSourceData();
  90:                 generalSource.TraceListeners.Add(listenerReference);
  91:                 generalSource.Name = "General";
  92:                 generalSource.DefaultLevel = System.Diagnostics.SourceLevels.All;
  93:                 result.TraceSources.Add(generalSource);
  94:  
  95:                 // Special Sources
  96:  
  97:                 result.SpecialTraceSources.AllEventsTraceSource.Name = "AllEvents";
  98:                 result.SpecialTraceSources.AllEventsTraceSource.DefaultLevel = System.Diagnostics.SourceLevels.All;
  99:  
 100:                 result.SpecialTraceSources.NotProcessedTraceSource.Name = "NotProcessed";
 101:                 result.SpecialTraceSources.NotProcessedTraceSource.DefaultLevel = System.Diagnostics.SourceLevels.All;
 102:  
 103:                 result.SpecialTraceSources.ErrorsTraceSource.Name = "LoggingErrorsAndWarnings";
 104:                 result.SpecialTraceSources.ErrorsTraceSource.DefaultLevel = System.Diagnostics.SourceLevels.All;
 105:                 result.SpecialTraceSources.ErrorsTraceSource.TraceListeners.Clear();
 106:                 result.SpecialTraceSources.ErrorsTraceSource.TraceListeners.Add(listenerReference);
 107:  
 108:                 // Return
 109:  
 110:                 return result;
 111:             }
 112:  
 113:             return null;
 114:         }
 115:  
 116:         public void Remove(IConfigurationParameter removeParameter, string sectionName)
 117:         {
 118:         }
 119:  
 120:         public void RemoveSectionChangeHandler(string sectionName, ConfigurationChangedEventHandler handler)
 121:         {
 122:         }
 123:  
 124:         #endregion
 125:     }
 126: }
 127:  
 128: using System;
 129: using System.Diagnostics;
 130: using System.Globalization;
 131: using Microsoft.Practices.EnterpriseLibrary.Logging;
 132:  
 133: namespace MyApplication
 134: {
 135:     public static class LoggingHandler
 136:     {
 137:         #region Constants
 138:  
 139:         private const string CategoryExceptions = "Exceptions";
 140:         private const int PriorityExceptions = 1000;
 141:         private const int EventIdExceptions = 1000;
 142:         private const string TitleExceptions = "Errors Log";
 143:         private const TraceEventType SeverityExceptions = TraceEventType.Error;
 144:  
 145:         #endregion
 146:  
 147:         #region Members
 148:  
 149:         private static LogWriter writer;
 150:  
 151:         #endregion
 152:  
 153:         #region Properties
 154:  
 155:         internal static LogWriter Writer
 156:         {
 157:             get
 158:             {
 159:                 if (writer == null)
 160:                 {
 161:                     writer = CreateWriter();
 162:                 }
 163:  
 164:                 return writer;
 165:             }
 166:         }
 167:  
 168:         #endregion
 169:  
 170:         #region Public Methods
 171:  
 172:         public static void Exception(Exception ex)
 173:         {
 174:             // Validation
 175:  
 176:             if (ex == null)
 177:             {
 178:                 throw new ArgumentNullException();
 179:             }
 180:  
 181:             // Log
 182:  
 183:             WriteEntry(CategoryExceptions, TitleExceptions, ex.ToString(), PriorityExceptions, EventIdExceptions, SeverityExceptions);
 184:         }
 185:  
 186:         #endregion
 187:  
 188:         #region Private Methods
 189:  
 190:         private static void WriteEntry(string category, string title, string message, int priority, int eventId, TraceEventType severity)
 191:         {
 192:             LogEntry entry = new LogEntry();
 193:             entry.Categories.Add(category);
 194:             entry.TimeStamp = DateTime.Now;
 195:             entry.EventId = eventId;
 196:             entry.Message = message;
 197:             entry.Priority = priority;
 198:             entry.Severity = severity;
 199:             entry.Title = title;
 200:  
 201:             Writer.Write(entry);
 202:         }
 203:  
 204:         private static LogWriter CreateWriter()
 205:         {
 206:             LogWriterFactory factory = new LogWriterFactory(new LoggingConfigurationSource());
 207:             return factory.Create();
 208:         }
 209:  
 210:         #endregion
 211:     }
 212: }

I hope this helps someone in the future.

It turns out that the greater strength of EntLib – configuration – is also, at least in my opinion, its greater weakness. Just think of how many “real-world applications” would you want to have the user messing with the configuration file to setup event viewer listeners and things like that. :)

Published 15 May 09 12:53 by hgr

Comments

No Comments
Anonymous comments are disabled