VC++ Cures for .NET Configuration Change Headaches, Part 2

My previous article presented the various options for reloading changed configuration settings without restarting an application domain where covered. Although none of the solutions was a silver bullet, the article showed the Configuration Application Block from Microsoft's Enterprise Library to be a viable option. However, because the Configuration Application Block is not a simple replacement for the System.Configuration namespace's built-in configuration infrastructure, it imposes a lot of re-work on existing applications.

This article presents a Visual C++ assembly with a custom configuration handler that makes achieving reloadable configuration information much easier.

The .NET Framework has a highly extensible configuration system. You can nominate a custom type that will parse a section of XML in the configuration file and return an Object pointer that represents some form of configuration information. The application code that uses this information can then cast the Object pointer to the appropriate type and use it as required. This form of configuration extension is enabled through custom configuration file handlers, and it has many obvious advantages over rewriting an entire configuration system.

The .NET Framework Library ships with a number of custom configuration handlers, such as NameValueSectionHandler, which returns a NameValueCollection pointer as its configuration data, and DictionarySectionHandler, which returns a Hashtable pointer. Both of these types suffer from the same issue as ConfigurationSettings::AppSettings, in that data changes in the configuration file are not reloaded until an application domain is recycled. However, these built-in types can be leveraged to build a custom configuration handler that will reload configuration data when the underlying configuration file changes.

The most obvious form of extension would be to derive a new type from one of the built-in handlers that provides reload support. NameValueCollection is the most likely candidate for derivation because its usage pattern closely matches that of AppSettings. Unfortunately, the virtual method that needs to be overridden to hook in the reloading behavior is marked with the final method attribute, which means that you cannot derive from it. Rather than use derivation, you can store a NameValueCollection pointer as a member variable and build reloading on top of its XML-parsing functionality.

To implement a custom handler, you need to implement the IConfigurationSectionHandler interface. This interface has a single method—Create—that the configuration infrastructure uses to retrieve the configuration data from the custom handler and pass it to the application code that requires the data. A skeleton handler would look like the following code snippet:

public __gc class
Handler:
public
IConfigurationSectionHandler
{
   public:
   virtual Object* Create(Object* parent, Object* configContext,
                          XmlNode* section)
   {
      return 0;
   }
};

The handler would use the XmlNode pointer that is passed in as a parameter to parse the XML contained in this node and then return an Object pointer that represented the de-serialized form of this data. The reloading handler has no special requirements for the XML or the configuration data holder, and you can build the implementation entirely on top of the NameValueSectionHandler, as shown here:

public __gc class
Handler:
public IConfigurationSectionHandler
{
   private:
   NameValueSectionHandler* _handler;
   NameValueCollection* _configData;

   public:
   virtual Object* Create(Object* parent, Object* configContext,
                          XmlNode* section)
   {
      //load original config data;

      _handler = new NameValueSectionHandler();
      NameValueCollection* configData = 
         dynamic_cast<NameValueCollection*>
      (_handler->Create(parent, configContext, section));
      _configData = new NameValueCollection(configData);


      return _configData;
   }
};

This code simply passes on all the work to a NameValueSectionHandler member variable and returns whatever this object parses from the XML. On top of this functionality, the custom handler needs to monitor changes to the configuration file and get the NameValueSectionHandler member variable to reload its data when it detects a change. The FileSystemWatcher class can monitor the configuration file, and when the data is reloaded, it will need the original values passed in to the Create method and, hence, need to be stored in member variables. The handler now looks like this (new code in italics):

public __gc class
Handler: public IConfigurationSectionHandler
{
   private:
   NameValueSectionHandler* _handler;
   NameValueCollection* _configData;

   Object* _parent;
   Object* _configContext;
   XmlNode* _section;
   String* _configFileName;

   void watcher_Changed(Object* sender, FileSystemEventArgs* e)
   {
   }

   public:
   virtual Object* Create(Object* parent, Object* configContext,
                          XmlNode* section)
   {
      //setup config file watch
      _configFileName = AppDomain::CurrentDomain->
                        SetupInformation->ConfigurationFile;
      FileSystemWatcher* watcher = new
      FileSystemWatcher(Path::GetDirectoryName(_configFileName),
      Path::GetFileName(_configFileName));
      watcher->EnableRaisingEvents = true;
      watcher->Changed +=new FileSystemEventHandler(this,
         &Handler::watcher_Changed);

      //store values for re-read
      _parent = parent;
      _configContext = configContext;
      _section = section;

      //load original config data;

      _handler = new NameValueSectionHandler();
      NameValueCollection* configData = 
         dynamic_cast<NameValueCollection*>
         (_handler->Create(parent, configContext, section));

      _configData = new NameValueCollection(configData);
      return _configData;
   }
};

VC++ Cures for .NET Configuration Change Headaches, Part 2

Insert Article Text Here.


Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • A help desk is critical to the operations of an IT services business. As a centralized intake location for technical issues, it allows for a responsive and timely solution to get clients and their staff back to business as usual. In addition to handling immediate IT issues, a help desk performs several proactive tasks to ensure clients' IT systems remain operational and downtime is minimized. Thus, utilizing a help desk and following best practices can improve the productivity, efficiency and satisfaction of …

  • Live Event Date: May 6, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT While you likely have very good reasons for remaining on WinXP after end of support -- an estimated 20-30% of worldwide devices still are -- the bottom line is your security risk is now significant. In the absence of security patches, attackers will certainly turn their attention to this new opportunity. Join Lumension Vice President Paul Zimski in this one-hour webcast to discuss risk and, more importantly, 5 pragmatic risk mitigation techniques …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds