I’ve played a bit now with the .NET configuration model and while I can certainly see some elements in there to like, it seems to me that it falls short in a number of different ways.
First off, it doesn’t really have any concept of “multi-level configuration.” In fact, it’s basically a single level XML file (granted, you could create a hierarchical organization within that single xml file, but there’s other issues with that). .NET does help a bit with the concept of a machine config file, but from what I can tell that’s about as far as it goes.
Second, the default behavior is to locate the application config file in the same path as the application itself. That’s great if your user is running as administrator, but not so great in more locked-down situations where users do not have full admin rights. In those cases, configuration that’s writable needs to be stored somewhere within the user’s profile directory structure. This is just going to get worse with Vista, too.
Ok, sounds good but what, you may be asking, is a multi-level configuration scheme, and why would I want one? Almost every app I’ve ever worked on, short of the trivial utilities I’ve built, has required this sort of configuration scheme (or at the very least greatly benefited from having it). It almost always follows along this line:
- Administrator specified User specific configuration (rarely used, the user cannot change this configuration)
- User specific configuration (that the user can change dynamically)
- Group specific configuration (typically set by a system administrator or group admin and read only to users)
- Machine specific configuration (typically set by a system admin, and rarely used, read only to users)
- Application global configuration (typically set by the system admin, read only to users)
- OEM defaults (typically set by the app developers to provide default config values, generally readonly by everyone except the developers)
At each level, the system provides for an essentially unlimited number of name value pairs that can be cordoned off into groups (or sections as they used to be called in INI files). Some may argue that a section-name-value system like this is too limiting and you should always accomodate full hierarchical structures, but I’ve found the extra functionality rarely necessary.
Of course, the type of value (string, int, date, etc) for a particular setting is defined within the application, but value types might also be defined as OEM default settings. Should sysadmins really be able to change setting X from a string to a date? I’d imagine not usually.
The trick and the real beauty of the system is in the way that setting values are resolved. The resolution logic basically says that if the app can find a setting at a higher level in the hierarchy, it uses that value. Otherwise it searches down the hierarchy till it either finds a value, or till it drops to the OEM defaults. If no setting is specified at the OEM level, the system defaults to blanks, or 0’s depending on the data type.
So, for instance, the code might ask for the setting “AskOnExit” from the “Prompts” section. The config handler needs to look first at the “level of most significance” which, in the above list of levels, would be the Administrator specified user specific settings (ie those settings that are set on a per user basis, but that the user himself doesn’t have the authority to change.
If the setting isn’t found there, the code continues down the hierarchy, looking at each level in turn until eventually in run through them all and returns the default or a blank or 0.
And, of course, you also have to provide a means to retrieving and writing a setting at a specific level in the hierarchy, for those settings that are always application level or machine level or what not.
Obviously, such a scheme requires a little more work up front, but the configuration flexibility (especially when you’re talking about major, multi user systems with lots of configuration options, typically off-the-shelf, reseller-friendly applications like accounting systems or CRM packages), is a huge selling point to admins and users alike.
Why, then does configuration handling in .NET seem so archaically primitive?
Could you roll all these levels into that singular .config file? Sure, when where would you put it? In the Application path? No, users won’t typically have write rights there. Under the user’s Application Data folder in the Profile? No, can’t put app wide settings somewhere that only a single user can access it. How about that machine config file. Again, not writable by typical users.
It’s funny that Windows already has a rights system that is very stable, quite flexible and easy to work with, both manually and from within code and yet it often goes completely unused by larger apps. I’m talking, of course, of the file system.
These days, though, web apps are de rigueur and you can’t go assigning file system rights to web users. There’s no way that would fly with most web developers (you weren’t really thinking of something like that, right?). So, roll it up into a simple table, with a getSetting and a setSetting stored procedure to simplify the coding. With proper indexing, and a little intelligent caching, it’ll be every big as fast as using the .NET configuration functions, and whole lot more flexible.
Long story short. If your sideline utility needs to save a few settings, use the .NET configuration. It’s fast, relatively easy and convenient. But for just about everything else, take a little time and do it right.
Your users and their sysadmins will thank you.