9

I want to read the custom XML section from the app.config of a C# windows service.

How do I go about it?

The XML is below:

<Books>
<Book name="name1" title="title1"/>
<Book name="name2" title="title2"/>
</Books>
George Stocker
  • 57,289
  • 29
  • 176
  • 237
Jimmy
  • 2,106
  • 12
  • 39
  • 53

4 Answers4

14

In a project I developed I use something similar for configuration that I found. I believe the article was called the last configuration section handler I'll ever need (I can't find a working link, maybe someone can link it for me).

This method takes what you want to do one step further, and actually de-serializes the object into memory. I'm just copying code from my project, but it should be fairly simple to take a step backwards if all you want is the XML.

First, you need to define a class that handles your configuration settings.

using System;
using System.Configuration;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.XPath;


namespace Ariel.config
{
    class XmlSerializerSectionHandler : IConfigurationSectionHandler
    {

        #region IConfigurationSectionHandler Members

        public object Create(object parent, object configContext, XmlNode section)
        {
            XPathNavigator nav = section.CreateNavigator();
            string typename = (string)nav.Evaluate("string(@type)");
            Type t = Type.GetType(typename);
            XmlSerializer ser = new XmlSerializer(t);
            return ser.Deserialize(new XmlNodeReader(section));
        }

        #endregion
    }
}

Now, say you want to load a section of configuration... super easy, cast to the type of object you're expecting to XML Serialize to, and pass the section you're looking for (in this case SearchSettings.

try
{
  config = (Eagle.Search.SearchSettings)ConfigurationSettings.GetConfig("SearchSettings");
}
catch (System.Configuration.ConfigurationException ex)
{
  syslog.FatalException("Loading search configuration failed, you likely have an error", ex);
  return;
}

Now, all you need is your App.config file. I chose to split mine into separate files (1 file per section) just to make managing the config a little easier. You define a section, give it a name, and define the type (whatever you called the class listed above) and the assembly's name.

App.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="SearchSettings" type="Ariel.config.XmlSerializerSectionHandler, Ariel"/>
  </configSections>
  <SearchSettings configSource="Config\Search.config" />
</configuration>

Now, all that's left is the config file to be de-serialized. What's important here is that the block matches your section name, and your type is whatever object it should de-serialize to, and the Assembly name.

<?xml version="1.0" encoding="utf-8" ?>
<SearchSettings type="Eagle.Search.SearchSettings, Eagle">
  <NumThreads>4</NumThreads>
</SearchSettings>

If you just want the pure raw XML, all you should need to do is modify the Object that handles the section to return the XML or do whatever you need to do.

George Stocker
  • 57,289
  • 29
  • 176
  • 237
Kevin Nisbet
  • 2,239
  • 16
  • 14
  • 1
    This looks like a stable link: http://sites.google.com/site/craigandera/craigs-stuff/clr-workings/the-last-configuration-section-handler-i-ll-ever-need . The only problem I see with his approach is if you have a ton of such sections, it will get littered with type declarations. But you could get around this disadvantage by gluing them together into one section, and making one larger type. As such, it seems pretty viable, and a pretty elegant hack. – Merlyn Morgan-Graham Mar 29 '11 at 08:21
  • Phil Haack did an updated version based on Craig's approach that supports reloading the config if the file changes. The formatting's all broken in the move to his new blog, but the link is http://haacked.com/archive/2004/06/24/verylastconfigurationsectionhandler.aspx/ – piers7 Sep 09 '14 at 02:00
  • `IConfigurationSectionHandler` as stated at https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(System.Configuration.IConfigurationSectionHandler);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5.2);k(DevLang-csharp)&rd=true has been deprecated for a long time. – Tamir Daniely Oct 19 '15 at 14:12
5

What you want to do is read up on Custom Configuration Sections.

Colin Mackay
  • 18,736
  • 7
  • 61
  • 88
  • 2
    And good luck to noobs who are brave enough to do this! They can be very confusing for a new developer. –  Jul 18 '09 at 21:55
  • 2
    True, the .NET 1.x way where you implemented an interface and got to play with the XML was much easier to understand, IMO. – Colin Mackay Jul 18 '09 at 22:03
  • 2
    I found this article series on codeproject (http://www.codeproject.com/KB/dotnet/mysteriesofconfiguration.aspx) to be a good explaination on the topic. – Christian.K Sep 17 '09 at 05:06
5

Since IConfigurationSectionHandler is deprecated I thought it's worth mentioning that you can still implement a pure serialized section just by overriding ConfigurationSection.DeserializeSection and not calling the base implementation.

Here is a very basic example that I reuse a lot. A simple configuration section that loads an object graph from inline XAML. (Naturally you can implement with XmlSerializer instead)

using System.Configuration;
using System.Xaml;
using System.Xml;

...

public class XamlConfigurationSection<T> : ConfigurationSection
{
    public static XamlConfigurationSection<T> Get(string sectionName)
    {
        return (XamlConfigurationSection<T>)ConfigurationManager.GetSection(sectionName);
    }

    public T Content { get; set; }

    protected override void DeserializeSection(XmlReader xmlReader)
    {
        xmlReader.Read();
        using (var xamlReader = new XamlXmlReader(xmlReader))
            Content = (T)XamlServices.Load(xamlReader);
    }
}
Tamir Daniely
  • 1,659
  • 1
  • 20
  • 24
  • +1 `ConfigurationSection.DeserializeSection` is a life saver since its easier iterating over the relevant XML cfg node instead of dealing w/ System.Configuration various annotations, and still exposing static/strongly safe configuration items – Shmil The Cat Oct 19 '17 at 17:14
0

I use custom xml in my config.app. file and create a app.XSD from it. The XSD file includes the schema of the config.app file. Then XSD file can be translated to a vb class or a C# class file using 'xsd.exe'. Now all you have to do is deserialize the configfile to the class.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section name="CustomConfig" type="Object" />
    </configSections>

    <CustomConfig>
        <ActiveEnvironment>QAS</ActiveEnvironment>
        <Environments>
            <Environment name ="PRD" log="Y">
            </Environment>
            <Environment name ="QAS" log="N">
            </Environment>
            <Environment name ="DEV" log="Y">
            </Environment>
        </Environments>
    </CustomConfig>

</configuration>
Pieter
  • 1
  • 2
    Laying out your type in Xml then auto-generating a class from it seems pretty compelling. How do you "create a app.XSD from it"? +1 when you add those instructions to your answer ;) – Merlyn Morgan-Graham Mar 29 '11 at 08:29
  • You can create the XSD from within VS. Create a sample XML file, then on the toolbar in VS2017, there's an 'XML' menu with a "Create Schema" option. More information on MSDN at https://msdn.microsoft.com/en-us/library/ms255829.aspx – Chris J Sep 10 '17 at 12:21