Click here to Skip to main content
15,867,453 members
Articles / Web Development / ASP.NET
Article

Problems and solutions to Microsoft Configuration Management Application Block's "XmlFileStorage" in Web Applications

Rate me:
Please Sign up or sign in to vote.
4.08/5 (11 votes)
9 May 20043 min read 106.6K   27   17
MCMAB's XmlFileStorage has a known bug for which it does not work in Web Applications. When you need to use external XML file for storing configuration, you have to do some tweaking yourself.

Introduction

In a web application, the most common requirement for storing configuration is like this:

  • You have a static singleton class (e.g. MyConfiguration) which stored the configuration data. It has properties like "DatabaseConnectionString" to store configuration settings
  • You need to store it in a XML file.
  • You do not want to store it in web.config because whenever you change the values, your web application restarts
  • You want to programmatically modify the configuration from some administrative page and make it effective throughout the application immediately

If you have this requirement, Microsoft Configuration Management Application Block (MCMAB) provides the solution according to Microsoft (pbui) in "Patterns & Practices" section. MCMAB has a XMLFileStorage class which allows you to do this. However, you will be surprised because:

It does not work at all!

Microsoft Configuration Management Application Block's XMLFileStorage class has some problem with external XML file's path handling. It cannot read nor write into external XML files when you use it from a web application. However, for desktop application, it works smoothly. This article shows you a work-around how to solve this problem and use external XML files to store configurations in web applications.

Problem 1. Does not load XML file

You will be surprised to know, without modifying the code of MCMAB, you cannot use its XMLFileStorage to read/write configuration in external XML file.

According to the documentation, the configuration should be like this in web.config

XML
<configuration>
  <configsections>
      <section type="Microsoft.ApplicationBlocks.ConfigurationManagement.
ConfigurationManagerSectionHandler,Microsoft.ApplicationBlocks.
ConfigurationManagement, Version=1.0.0.0,Culture=neutral,
PublicKeyToken=null" name="applicationConfigurationManagement" />
  </CONFIGSECTIONS>  
  <applicationconfigurationmanagement defaultSection="MyConfigSection">
    <configsection name="MyConfigSection">
      <configprovider type="Microsoft.ApplicationBlocks.
ConfigurationManagement.Storage.XmlFileStorage" refreshOnChange="true" 
encrypted="false" signed="false" path="MyConfig.xml" 
assembly="Microsoft.ApplicationBlocks.ConfigurationManagement,
Version=1.0.0.0,Culture=neutral,PublicKeyToken=null" />
    </CONFIGSECTION>
  </APPLICATIONCONFIGURATIONMANAGEMENT>  

The above configuration file configures the following:

  • An external XML file for storing configuration
  • XML File name is "MyConfig.xml" which should be in the virtual directory folder where the web.config file is.
  • The configuration should be reloaded as the file is changed without restarting the web application

This is extremely helpful as you change the configuration file, your web application is not restarted. However it does not work

Why?

In the XMLFileStorage class, you will find the following code in the Init method:

C#
if( _applicationDocumentPath == null )
  _applicationDocumentPath = 
 AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
else
  _applicationDocumentPath = Path.GetFullPath( 
  _applicationDocumentPath );    

Q. In a webapp what do you think "Path.GetFullPath" is going to return for relative paths?

A. Definitely not the location "c:\inetpub\wwwroot\mysweetapp" but like "C:\windows\system32\..."

Solution

Solution is to modify those lines like this:

C#
if( _applicationDocumentPath == null ) 
{ 
  _applicationDocumentPath = 
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; 
} 
else if ( _applicationDocumentPath.IndexOf( "{base.dir}" ) > -1 ) 
{ 
  _applicationDocumentPath = _applicationDocumentPath.Replace( 
  "{base.dir}", AppDomain.CurrentDomain.BaseDirectory ); 
} 
else 
{ 
  _applicationDocumentPath = Path.GetFullPath( 
  _applicationDocumentPath ); 
}

Source: http://www.gotdotnet.com/community/workspaces/BugDetails.aspx?bugid=9524

Now it works! However, you have to modify the section in web.config as follows:

XML
 <applicationconfigurationmanagement defaultSection="MyConfigSection">
    <configsection name="MyConfigSection">
      <configprovider 
type="Microsoft.ApplicationBlocks.ConfigurationManagement.
Storage.XmlFileStorage" refreshOnChange="true" encrypted="false" 
signed="false" path="<B>{base.dir}</b>MyConfig.xml" 
assembly="Microsoft.ApplicationBlocks.ConfigurationManagement,
Version=1.0.0.0,Culture=neutral,PublicKeyToken=null" />
    </CONFIGSECTION>
  </APPLICATIONCONFIGURATIONMANAGEMENT> 

Now it really works!

Problem 2: Cannot write configuration

But you cannot invoke "ConfigurationManager.Write", it does not work.

Why?

The default behavior of the section handler implementation is, it tries to look for a "<section>" node having "name" equal to the name of the section you are trying to save.

For example, for the following line:

C#
ConfigurationManager.Write( "MyConfigSection", 
  Configurations.Instance );

It will look for a section declaration under the "configSections" in web.config.

Solution

You have to declare a section like this in web.config:

XML
<section type="Microsoft.ApplicationBlocks.ConfigurationManagement.
  XmlSerializerSectionHandler,Microsoft.ApplicationBlocks.
  ConfigurationManagement,Version=1.0.0.0,
  Culture=neutral,PublicKeyToken=null" name="MyConfigSection" />      

Now it works!

Problem 3: Not MCMAB, my problem, cannot use singleton

I cannot use singleton for storing the configuration because in order to serialize/deserialize any class, there must be a public default constructor.

How do we write singleton classes? Isn't it like this:

C#
public class Configurations
{

  private static raedonly Configurations _Instance =
     new Configurations();

  private Configurations()
  {
  }

  public static Configurations Instance
  {
    get
    {
      return _Instance;
    }
  }

There goes out Design Patterns. I had to do this, don't blame me:

C#
public class Configurations
{
  private static Configurations _Instance = new Configurations();

  // Please do not call these, my good fellow developers
  public Configurations()
  {
  }

  public static Configurations Instance
  {
    get
    {
      if( null == _Instance )
      {
        _Instance = new Configurations();
      }

      return _Instance;
    }
    set
    {
      lock( _Instance )
      {
        _Instance = value;
      }
    }
  }

  public int CurrentSemesterID;
  public string CurrentSemesterTitle;

Oh by the way, in Application_Start I'm doing this:

C#
Configurations.Instance = (Configurations) 
  ConfigurationManager.Items["MyConfigSection"];

An idiot's guide to MCMAB

I admit, I was an idiot. I had to spend an hour fixing things up in order to make MCMAB work for my web app.

Here's a step-by-step guide that you can follow to create a configuration class which is persisted in an external XML file.

Step 1

Change the code for Init method in XmlFileStorage class as explained above. Build the binaries. Copy the latest binaries to the "bin" folder of the web app.

Step 2

Create a web.config like this:

XML
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configsections>
      <section type="Microsoft.ApplicationBlocks.
ConfigurationManagement.ConfigurationManagerSectionHandler,
Microsoft.ApplicationBlocks.ConfigurationManagement, 
Version=1.0.0.0,Culture=neutral,PublicKeyToken=null" 
name="applicationConfigurationManagement" />

      <section type="Microsoft.ApplicationBlocks.
ConfigurationManagement.XmlSerializerSectionHandler,
Microsoft.ApplicationBlocks.ConfigurationManagement,Version=1.0.0.0,
Culture=neutral,PublicKeyToken=null" name="MyConfigSection" />   
  </configsections>

  
  <applicationconfigurationmanagement defaultSection="MyConfigSection">
  
    <configsection name="MyConfigSection">
      <configprovider type="Microsoft.ApplicationBlocks.
ConfigurationManagement.Storage.XmlFileStorage" refreshOnChange="true" 
encrypted="false" signed="false" path="{base.dir}Config.xml" 
assembly="Microsoft.ApplicationBlocks.ConfigurationManagement,
Version=1.0.0.0,Culture=neutral,PublicKeyToken=null" />
    </configsection>
  </applicationconfigurationmanagement>
  
  <system.web>
    ...
  </system.web>
</configuration>

Step 3

Create a blank XML file named "MyConfig.xml" in the folder where web.config is:

XML
<configuration>
  <myconfigsection>
  </myconfigsection>
</configuration>  

That's all.

Please use MCMAB. Besides this tiny problem, it's extremely powerful. Do not come up with your own implementation. Whatever you will do in your lifetime, all of them are already done in MCMAB. Thanks.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Architect BT, UK (ex British Telecom)
United Kingdom United Kingdom

Comments and Discussions

 
GeneralMy vote of 1 Pin
Member 37555813-Mar-09 2:35
Member 37555813-Mar-09 2:35 
GeneralEncrypting other custom config sections in the CMAB Pin
smartindi20-Feb-07 6:01
smartindi20-Feb-07 6:01 
GeneralRe: Encrypting other custom config sections in the CMAB Pin
RickyPena22-Feb-07 12:06
RickyPena22-Feb-07 12:06 
GeneralRe: Encrypting other custom config sections in the CMAB Pin
smartindi23-Feb-07 4:54
smartindi23-Feb-07 4:54 
GeneralRe: Encrypting other custom config sections in the CMAB Pin
RickyPena27-Feb-07 11:38
RickyPena27-Feb-07 11:38 
Questionhow use (path.getfullpath) Pin
syriast30-Jul-06 1:49
syriast30-Jul-06 1:49 
GeneralStill a better way Pin
jdn49298-Nov-05 5:23
jdn49298-Nov-05 5:23 
GeneralConfiguration Pin
VlastaH27-Sep-05 11:31
VlastaH27-Sep-05 11:31 
QuestionI have My Web Application Problem Can you Help me? Pin
Ahmed Erarslan6-Jun-05 10:56
Ahmed Erarslan6-Jun-05 10:56 
AnswerRe: I have My Web Application Problem Can you Help me? Pin
Omar Al Zabir7-Jun-05 18:55
Omar Al Zabir7-Jun-05 18:55 
GeneralNull Reference Exception in the Application_Start Pin
Member 6491795-Jul-04 1:44
Member 6491795-Jul-04 1:44 
GeneralRe: Null Reference Exception in the Application_Start Pin
spriet200014-Jan-05 7:50
spriet200014-Jan-05 7:50 
GeneralRe: Null Reference Exception in the Application_Start Pin
Anonymous14-Jan-05 19:21
Anonymous14-Jan-05 19:21 
GeneralRe: Null Reference Exception in the Application_Start Pin
spriet200014-Jan-05 23:14
spriet200014-Jan-05 23:14 
GeneralA better fix to the XmlFileStorage path Pin
hdelahitte18-May-04 10:26
hdelahitte18-May-04 10:26 
GeneralSingleton Pin
Anonymous11-May-04 9:44
Anonymous11-May-04 9:44 
GeneralSerialize/Deserialize a Singleton Pin
torsten_rendelmann10-May-04 7:28
torsten_rendelmann10-May-04 7:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.