简体   繁体   中英

How to read an object from app.config?

This is not a new question, but I've been researching this for two days and all the answers I can find are outdated or unhelpful. What I want to do is put an object into App.config and then load it when the program starts.

I've got a basic class called "Person" with three autoproperties: (string) FirstName, (string) LastName, and (int) Age. Here's my App.config file:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/></startup>
  <configSections>
    <sectionGroup name="People">
      <section 
        name="Person" 
        type="Person.Person"
      />
    </sectionGroup>
  </configSections>
  <People>
    <Person>
      <Person type="Person.Person, Person">
        <FirstName>Jimmy</FirstName>
        <LastName>Dean</LastName>
        <Age>2</Age>
      </Person>
    </Person>
  </People>
</configuration>

And here is my program:

using System;
using System.Configuration;

namespace AppConfigTest
{
    class AppConfigTester
    {
        public static void Main(string[] args)
        {
            var guy = (Person.Person) ConfigurationManager.GetSection("People/Person");
            Console.WriteLine(guy.FirstName);
            Console.WriteLine(guy.LastName);
            Console.WriteLine(guy.Age);
        }
    }
}

At the moment it crashes with a ConfigurationErrorsException. Any help would be very appreciated. It's boggling my mind that this is so difficult, when App.config is supposed to make doing this sort of thing easier.

Given a Person POCO class:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
}

First you need to create a class that inherits System.Configuration.ConfigurationElement like this:

public class PersonElement : ConfigurationElement
{
    public string InnerText { get; private set; }

    protected override void DeserializeElement(XmlReader reader, bool serializeCollectionKey)
    {
        InnerText = reader.ReadElementContentAsString();
    }
}

This is needed so you can have config elements like <FirstName>Jimmy</FirstName> with inner text.

Next you need a class that inherits System.Configuration.ConfigurationSection like this:

public class PersonSection : ConfigurationSection
{
    [ConfigurationProperty("FirstName")]
    public PersonElement FirstName
    {
        get { return this["FirstName"] as PersonElement; }
        set { this["FirstName"] = value; }
    }

    [ConfigurationProperty("LastName")]
    public PersonElement LastName
    {
        get { return this["LastName"] as PersonElement; }
        set { this["LastName"] = value; }
    }

    [ConfigurationProperty("Age")]
    public PersonElement Age
    {
        get { return this["Age"] as PersonElement; }
        set { this["Age"] = value; }
    }

    public Person CreatePersonFromConfig()
    {
        return new Person()
        {
            FirstName = this.FirstName.InnerText,
            LastName = this.LastName.InnerText,
            Age = Convert.ToInt32(this.Age.InnerText)
        };
    }
}

Your app.config should look like this:

<configuration>
    <configSections>
        <sectionGroup name="People">
            <section name="Person" type="Example.PersonSection, Example" />
        </sectionGroup>
    </configSections>
    <People>
        <Person>
            <FirstName>Jimmy</FirstName>
            <LastName>Dean</LastName>
            <Age>2</Age>
        </Person>
    </People>
</configuration>

Finally somewhere in your code do this:

PersonSection config = (PersonSection)ConfigurationManager.GetSection("People/Person");
Person guy = config.CreatePersonFromConfig();

There are a couple of issues with your implementation, these are:

  1. The <configSections> element must be the first element in your App.config file
  2. The configuration section handler (the type that is described in the type attribute of the section element) must inherit from ConfigurationSection .
  3. Fully qualifying the types that you're referring to

The <configSections> element must be the first element in your App.config file

The ConfigurationErrorsException that is being thrown contains the following detail:

Only one <configSections> element allowed per config file and if present must be the first child of the root <configuration> element.

This is calling out the fact that you have to move the <configSections> element to the top of the file. I guess this is so the code that processes the configuration file can load the appropriate handlers for each section before it reads each section of the config file.

The configuration section handler (the type that is described in the type attribute of the section element) must inherit from ConfigurationSection

Unfortunately the way the configuration system works means that you can't just drop a POCO in and have it take care of wiring it all up for you. There is a tutorial for creating a custom configuration section on MSDN .

Fully qualifying the types that you're referring to

I'm not sure that this is actually causing an issue for you, but it doesn't hurt to be precise to avoid it causing a problem. The following:

<section name="Person" type="Person.Person" />

Is potentially ambiguous. Assuming that your project compiles to a DLL/EXE called "MyProjectThatContainsPerson", you should consider changing it to:

<section name="Person" type="Person.Person, MyProjectThatContainsPerson" /> 

This makes it clear to the configuration system not only what the name of the type is ( Person.Person ) but also what assembly it should attempt to load it from ( MyProjectThatContainsPerson ).

An example custom section using a built in Section Handler

If you wanted to add a configuration section that had a custom name (eg "MySection") but otherwise behaved the same as appSettings , you could have:

<configSections>
    <section name="MySection" 
             type="System.Configuration.NameValueSectionHandler, system, 
                   Version=1.0.3300.0, Culture=neutral, 
                   PublicKeyToken=b77a5c561934e089, Custom=null" />
</configSections>
<MySection>
    <add key="MySetting" value="MyValue" />
</MySection>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM