WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

Beginnings of a Flexible .NET Architecture: A Simplified Config Service
Pages: 1, 2, 3

The Configuration Service In Practice

Let us be more clear by applying the configuration service to a practical example. Let's say we want to send an email for a Web application. Let's also consider that in your chest of copious libraries you have earlier penned an API that looks like this:




public static void sendMail(string from, string to, string subject, string body, string format);

Equipped with such an API, my client code could look like this:


    public static trivialMailExample()
    {
      string from="support@johndoeinc.com";
      string to = "johndoe2@customerinc.com";
      string subject = "Your order is ready";
      string body="You can pick it up at facility1";
      string format = "plain-text";

      sendMail(from,to,subject,body,format);
    }

As you can see, all of the parameters of the email are hard-coded into your Web site. What if we want to read some of these from a config file?

...
<SimpleConfiguration>
    <EmailInfo>
      <from>support@johhdoeinc.com
      <subject>Your order is ready. Order number {0}</subject>
      <body> <![[CDATA
<html>
<body>
    <p>Here are your order details</p>
    {0}
</body>
</html>
      ]]>
      </body>
      <format>html</format>
    </EmailInfo>
</SimpleConfiguration>

Ah ha! Once this configuration is in place, I can change my earlier method to the following:


    public static trivialMailExampleEnabledForConfig(string toCustomer, string orderId)
    {
      string from = AppServices.getValue("/SimpleConfiguration/from"); 
        // an error not to have it
      string subject = string.Format(AppServices.getValue("/SimpleConfiguration/from"), orderId);
      string body = string.Format(AppServices.getValue("/SimpleConfiguration/from"), orderId);
      string format = AppServices.getValue("/SimpleConfiguration/from","plain-text"); 
      // defaults to plain-text

      sendMail(from,toCustomer,subject,body,format);
    }

You can very easily change your config file to alter the look and feel of your emails. Notice how string.Format(...) is used to substitute dynamic values into a template read from the config file. Also notice how you can use CDATA sections to embed HTML inside of your XML sections.

Public Static Services Turned Into Interfaces

Before I tell you how to implement these methods, let me take a little detour and explain how I want to convert the static methods into an interface. Here is the reason: AppServices is a collection of interfaces, each of which represents a service. For example:

public AppServices
{
    public static IConfig getConfigurationService();
    pulbic static IFacgtory getFactoryService();
    public static ILog getLoggingService();
    ...any other application level services
}

Let us see what IConfig could be having:

public interface IConfig
{
    public static getValue(string key);
      // throws an exception if the key is not found or has an 
      // empty string
    public static getValueHonourWhiteSpace(string key)
      // throws an exception if the key is not found

    public static getValue(string key, string default);
      // returns the default if the key is not found or has an 
      // empty string
    public static getValueHonourWhiteSpace(string key, string default)
      // returns the default if the key is not found
}

We can have another interface for XPath support, as follows:


public interface IConfigXPath
{
    //Xpath support
    public static getXPathValue(string key);
      // throws an exception if the key is not found or has an 
     // empty string
    public static getXPathValueHonourWhiteSpace(string key)
      // throws an exception if the key is not found

    public static getXPathValue(string key, string default);
      // returns the default if the key is not found or has an 
      // empty string
    public static getXPathValueHonourWhiteSpace(string key, string default)
      // returns the default if the key is not found
}

Now I can proceed to have an implementation of these as follows:


public class DefaultConfig : IConfig, IXPathConfig
{
    ... Implements all the methods
}

Now one can code AppServices as follows:


public class AppServices
{
    private IConfig m_config = new DefaultConfig(); 
      // Potentially one can get this from a factory

    public static getIConfig() { return m_config; }
    ... and others
}

Why convert static methods to an interface? Because for some tastes, case sensitivity is a good thing and for others, case insensitivity is desirable. Having an interface will allow for both.


public class CaseSensitiveConfig : IConfig
{
    //... implement your keys with case sensitive
}

public class CaseInsensitiveConfig : IConfig
{
    //... implement your keys with case insensitive
}

And your app services can return a suitable implementation at run time. If you want to know how, you may have to wait until I publish on the topic of factory services. Or you can read about in one of the references at the end of the article. Let us demonstrate one more nicety before moving on.


public class CaseInsensitiveMultiFileConfig : IConfig
{
    // Implement your keys with case insensitivity and 
    // read from multiple config files
}

As we start placing emphasis on config files, it won't be long before the idea proliferates and your XML config file will grow as long as the phone book. In a team environment, it is more desirable to break up configuration into multiple files. The above class could implement one such implementation, thereby increasing the team collaboration.

So far we have talked about benefits and how to use a configuration service. I could perhaps leave it as an exercise for the inquisitive to implement it. For the eager audience, nevertheless, I would like to help out by providing some basic code to get started.

Pages: 1, 2, 3

Next Pagearrow