Click here to Skip to main content
15,885,985 members
Articles / Programming Languages / XML

A Useful Custom Configuration Section for Inline Unconstrained XML

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
20 Aug 2012CPOL1 min read 8.4K  
A useful custom configuration section for inline unconstrained XML

As I was writing a small TCP server for serving a Silverlight local TCP policy, I came across a certain need. Inspired by Dan Wahlin’s server implementation, I chose to write a simplified version for myself. I needed to keep some XML in the App.config without constraining it with a schema.

The normal solution in this case is a custom section, sibling to appSettings if you wish. So my App.Config looked at first like this:

XML
<configuration>
  <appSettings>
    <add key="ipAddress" value="127.0.0.1"/>
  </appSettings>
  <access-policy>
    <cross-domain-access>
      <policy>
        <allow-from>
          <domain uri="*" />
        </allow-from>
        <grant-to>
          <socket-resource port="4502" protocol="tcp" />
        </grant-to>
      </policy>
    </cross-domain-access>
  </access-policy>
</configuration>

Upon running the program, even addressing the “ipAddress” key in the appSettings section throws an exception like:

System.Configuration.ConfigurationErrorsException was unhandled
  Message="Configuration system failed to initialize"
  Source="System.Configuration"
  BareMessage="Configuration system failed to initialize"
  Line=0
  StackTrace:
       at System.Configuration.ConfigurationManager.PrepareConfigSystem()
       at System.Configuration.ConfigurationManager.GetSection(String sectionName)
       at System.Configuration.ConfigurationManager.get_AppSettings()
       at ConsoleApplication1.Program.Main(String[] args) in C:\Users\Andrei\Documents\
            Visual Studio 2008\Projects\ConsoleApplication1\ConsoleApplication1\Program.cs:line 21
       at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly
                  (String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, 
                                                ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: System.Configuration.ConfigurationErrorsException
       Message="Unrecognized configuration section access-policy.
               (C:\\Users\\Andrei\\Documents\\Visual Studio 2008\\Projects\\
                ConsoleApplication1\\ConsoleApplication1\\bin\\Debug\\
                ConsoleApplication1.vshost.exe.config line 8)"
       Source="System.Configuration"
       BareMessage="Unrecognized configuration section access-policy."
       Filename="C:\\Users\\Andrei\\Documents\\Visual Studio 2008\\Projects\\
         ConsoleApplication1\\ConsoleApplication1\\bin\\Debug\\ConsoleApplication1.vshost.exe.config"
       Line=8
       StackTrace:
            at System.Configuration.ConfigurationSchemaErrors.ThrowIfErrors(Boolean ignoreLocal)
            at System.Configuration.BaseConfigurationRecord.ThrowIfParseErrors
                             (ConfigurationSchemaErrors schemaErrors)
            at System.Configuration.BaseConfigurationRecord.ThrowIfInitErrors()
            at System.Configuration.ClientConfigurationSystem.EnsureInit(String configKey)
       InnerException:

So something is wrong. We need to tell the runtime that the “access-policy” section is allowed.

XML
<configuration>
  <strong>
   <configSections>
    <section name="access-policy" 
    type="CustomSections.InlineXmlSection, CustomSections"/>
   </configSections>
  </strong>
  ...

At first, I didn’t place the type attribute in the “section” element, but it turned out it had to be specified and not be empty. Moreover, it must contain the fully-qualified class name and the assembly which contains it. The class must inherit from System.Configuration.ConfigurationSection.

So, I created an assembly called CustomSections, and added references to the System.Configuration assembly and the System.Xml assembly.

All you need to do is override the DeserializeSection method and load the XML document in there:

C#
using System.Configuration;
using System.Xml;

namespace CustomSections
{
  public class InlineXmlSection : ConfigurationSection
  {
    public XmlDocument Content { get; private set; }

    protected override void DeserializeSection(XmlReader reader)
    {
      (this.Content = new XmlDocument()).Load(reader);
    }
  }
}

The code is pretty self-explanatory: we instantiate a new XmlDocument and load it from the XmlReader provided to us by the configuration infrastructure. If anything goes bad, the exception handling will be the responsibility of the caller. In this case, the first call to ConfigurationManager.

Now, let’s put the code to use:

C#
private static void Main(string[] args)
{
  expectedRequestBytes = Encoding.UTF8.GetBytes("<policy-file-request/>");
  listener = new TcpListener(IPAddress.Parse(ConfigurationManager.AppSettings["ipAddress"]), 943);
  var policySection = (InlineXmlSection)ConfigurationManager.GetSection("access-policy");
  policyBytes = Encoding.UTF8.GetBytes(policySection.Content.OuterXml);
  ...
}

The underlined code is the relevant portion (the rest is provided for context). We get the section via ConfigurationManager.GetSection, and we have to cast the result to the desired section type. Then, we use the section as we see fit.

This article was originally posted at http://blog.andrei.rinea.ro?p=230

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) IBM, Business Analytics
Romania Romania
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --