Geeks With Blogs
Łukasz Kuryło's blog

Suppose that you have a interface in your project

  1:  namespace Configuration.Logger
2: {
3: public interface ILogger
4: {
5: void Write();
6: }
7: }


and a few his implementations.

  1:      public class FileLogger : ILogger
2: {
3: public void Write()
4: {
5: Console.WriteLine("Writing to file");
6: }
7: }
8:
9: public class DatabaseLogger : ILogger
10: {
11: public void Write()
12: {
13: Console.WriteLine("Writing to the database");
14: }
15: }


Depending on the situation, you want use first of them, another time the second. But how (and where) change it? The simplest possibility is to change it in the source code, but this is associated with recompilation of the entire project. So what else we can do?

The .NET Framework comes to us with a System.Configuration namespace which is responsible for working with the configuration files (Machine.config, Web.config, App.config). Now I think, the answer is simple – create and work with own config file. Thanks to him we can change the concrete implementation of the interface without recompilation the entire project.

So let’s create one.

  1:  <?xml version="1.0" encoding="utf-8" ?>
2: <configuration>
3: <configSections>
4: <section name="loggerMappingsConfiguration"
5:
type="Configuration.Configuration.LoggerSettings,
6: Configuration,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null"
/>
7: </configSections>
8: <loggerMappingsConfiguration>
9: <loggerMappings>
10: <loggerMapping interfaceShortTypeName="ILogger"
11:
concreteFullTypeName="Configuration.Logger.DatabaseLogger,
12: Configuration,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null"
/>
13: </loggerMappings>
14: </loggerMappingsConfiguration>
15: </configuration>


This is a simple App.config with one section only. As I mentioned earlier, System.Configuration provides classes to work with it. What we have to do is inherit from them and create a new for this example. We need to create a three classes derived from :


The forth class this will be a helper class contains a string values for configuration element. Let’s start from her.

  1:      internal static class LoggerMappingConstants
2: {
3: public const string ConfigurationPropertyName = "loggerMappings";
4: public const string ConfigurationElementName = "loggerMapping";
5: public const string InterfaceShortTypeNameAttributeName = "interfaceShortTypeName";
6: public const string ConcreteFullTypeNameAttributeName = "concreteFullTypeName";
7: public const string LoggerMappingsConfigurationSectionName = "loggerMappingsConfiguration";
8: }


These values are used in other classes several times, so create a static class with them is a good idea. Class derived from ConfigurationElement is show below

  1:      public sealed class LoggerMappingElement : ConfigurationElement
2: {
3: [ConfigurationProperty(LoggerMappingConstants.InterfaceShortTypeNameAttributeName,
4: IsKey = true, IsRequired = true)]
5: public string InterfaceShortTypeName
6: {
7: get
8: {
9: return (string)this[
10: LoggerMappingConstants.InterfaceShortTypeNameAttributeName];
11: }
12: set
13: {
14: this[LoggerMappingConstants.InterfaceShortTypeNameAttributeName] = value;
15: }
16: }
17:
18: [ConfigurationProperty(LoggerMappingConstants.ConcreteFullTypeNameAttributeName,
19: IsRequired = true)]
20: public string ConcreteFullTypeName
21: {
22: get
23: {
24: return (string)this[LoggerMappingConstants.ConcreteFullTypeNameAttributeName];
25: }
26: set
27: {
28: this[LoggerMappingConstants.ConcreteFullTypeNameAttributeName] = value;
29: }
30: }
31: }


Contain a two methods mapping to the appropriate properties from config file. Class derived from ConfigurationElementCollection

  1:      public sealed class LoggerMappingCollection : ConfigurationElementCollection
2: {
3:
4: protected override ConfigurationElement CreateNewElement()
5: {
6: return new LoggerMappingElement();
7: }
8:
9: protected override object GetElementKey(ConfigurationElement element)
10: {
11: return ((LoggerMappingElement)element).InterfaceShortTypeName;
12: }
13:
14: public override ConfigurationElementCollectionType CollectionType
15: {
16: get
17: {
18: return ConfigurationElementCollectionType.BasicMap;
19: }
20: }
21:
22: protected override string ElementName
23: {
24: get
25: {
26: return LoggerMappingConstants.ConfigurationElementName;
27: }
28: }
29:
30: public new LoggerMappingElement this[string interfaceShortTypeName]
31: {
32: get
33: {
34: return
35:
(LoggerMappingElement)this.BaseGet(interfaceShortTypeName);
36: }
37: }
38: }
39:


And the last class:

  1:  public class LoggerSettings : ConfigurationSection
2: {
3: [ConfigurationProperty(LoggerMappingConstants.ConfigurationPropertyName,
4: IsDefaultCollection = true)]
5: public LoggerMappingCollection LoggerMappings
6: {
7: get
8: {
9: return
10:
(LoggerMappingCollection)base[LoggerMappingConstants.ConfigurationPropertyName];
11: }
12: }
13: }


To test these classes, we can build a factory that will create objects depending on the settings in the configuration file

  1:  public static class LoggerFactory
2: {
3: public static ILogger CreateLogger()
4: {
5: ILogger logger;
6: string interfaceShortName = typeof(ILogger).Name;
7:
8: LoggerSettings settings = (LoggerSettings)ConfigurationManager.GetSection(
9: LoggerMappingConstants.LoggerMappingsConfigurationSectionName);
10:
11: logger = Activator.CreateInstance(
12: Type.GetType(settings.LoggerMappings[interfaceShortName]
13: .ConcreteFullTypeName)) as ILogger;
14:
15: return logger;
16: }
17: }


And finally check the result

  1:  class Program
2: {
3: static void Main(string[] args)
4: {
5: ILogger logger = new DatabaseLogger();
6: ILogger loggerFromFactory = LoggerFactory.CreateLogger();
7:
8: Debug.Assert(loggerFromFactory.GetType() == logger.GetType());
9: }
10: }


Source code is available here (click the blue button called "Pobierz plik").


Posted on Tuesday, September 29, 2009 10:55 PM other | Back to top


Comments on this post: Using App.config and System.Configuration

Comments are closed.
Comments have been closed on this topic.
Copyright © Łukasz Kuryło | Powered by: GeeksWithBlogs.net