views:

48

answers:

1

I have several applications that need to read and write application settings. Since one of the apps is a legacy c++ app with hundreds of settings in the registry (and that isn't bound to change) and there are also some settings stored in a proprietary database format I'm wondering how the architecture could be setup to allow a single interface in for reading and or writing the settings.
One idea is for there to be a giant enum with every possible setting and a split that directs the read/write request, based on a giant case statement, to the correct reader or writer. In the case of the registry this would then have to further parse the enum possibilities to find the key's location (if its an Http setting its here, if its a Setup setting its located at this key). This whole idea makes me think non-OOP and too much manual testing. Keep in mind that there are about 30 DB settings, and maybe 70 registry settings.

public class SettingsTest
{
    public enum ESetting
    {
        HttpUserName, HttpPassword, SetupAllowPublic,  //db server stored
        HttpProxyUsername, HttpProxyPassword, PublicOrPrivate //registry stored
    }

    public string GetSetting(ESetting setting)
    {
        if (IsSettingInRegistry(setting)
            return RegHandler.GetFromRegistry(setting);
        else
            return DBHandler.GetFromDB(setting);
    }
}
+2  A: 

I think the "big" enum might be a bit nasty - why don't you break them up using namespaces; to quote MSDN:

Usually it is best to define an enum directly within a namespace so that all classes in the namespace can access it with equal convenience. However, an enum can also be nested within a class or struct

So you could have:

RediVider.EnterpriseApp.DataAccess.ESettingsKeys
RediVider.EnterpriseApp.BusinessLogic.ESettingsKeys
RediVider.EnterpriseApp.ComponentXXX.ESettingsKeys

Also - would you be declaring enums, or static readonly fields? (where the value is the key, and working on the assumption that when you define a key you explicity define where it's coming from - hence the vale of the key).

A better idea would be to not define a repository specific key, but a key which mapped back to an AppSetting key - and that's where you defined the actual respository specific Key. This would allow you to change where to get the "setting" from - via config, and without having to re-deploy the app.

So, you have:

namespace RediVider.EnterpriseApp.DataAccess
{
  Public class ESettingsKeys
  {
    // Note - AppSetting Keys are "namespaced" to match: 
    public readonly string SetupAllowPublic = "RediVider.EnterpriseApp.DataAccess.SetupAllowPublic";
  }
} 

Then in your config (psuedo code):

<AppSetting Key="RediVider.EnterpriseApp.DataAccess.SetupAllowPublic" value="/System/Settings/Blah/SetupAllowPublic">

The only snag is that this only helps break-up the keys into more logical and easier to deal with areas - you stil have the issue of resolving the repository. If you really wanted to abstract that out you'd need to serialize a simple class that had

  • Key
  • Value
  • Repository

The idea of the switch statement isn't so bad, but you could take the same approach here too, using a sort of Facade or Factory pattern based approach:

  • Have various concrete methods that get the settings from storage repository.
  • In each namespace (as per the ESetting enums) have a "GetSettings" method that does what you've described - but only for the settings defined in that namespace.
Adrian K