这不是一个新问题,但我已经研究了两天,我能找到的所有答案都已过时或无益。我想要做的是将一个对象放入App.config,然后在程序启动时加载它。
我有一个名为" Person"有三个autoproperties :(字符串)FirstName,(字符串)LastName和(int)年龄。这是我的App.config文件:
<?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>
这是我的计划:
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);
}
}
}
目前它因ConfigurationErrorsException而崩溃。任何帮助将非常感激。令人难以置信的是,当App.config更容易做到这一点时,这是非常困难的。
答案 0 :(得分:7)
鉴于Person POCO课程:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
首先,您需要创建一个继承System.Configuration.ConfigurationElement的类,如下所示:
public class PersonElement : ConfigurationElement
{
public string InnerText { get; private set; }
protected override void DeserializeElement(XmlReader reader, bool serializeCollectionKey)
{
InnerText = reader.ReadElementContentAsString();
}
}
这是必需的,因此您可以使用内部文本等<FirstName>Jimmy</FirstName>
配置元素。
接下来,您需要一个继承System.Configuration.ConfigurationSection的类,如下所示:
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)
};
}
}
您的app.config应如下所示:
<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>
最后在代码中的某处执行此操作:
PersonSection config = (PersonSection)ConfigurationManager.GetSection("People/Person");
Person guy = config.CreatePersonFromConfig();
答案 1 :(得分:1)
您的实施存在一些问题,其中包括:
<configSections>
元素必须是App.config
文件type
元素的section
属性中描述的类型)必须从ConfigurationSection继承。 <configSections>
元素必须是App.config
文件中的第一个元素
正在抛出的ConfigurationErrorsException
包含以下详细信息:
只有一个&lt; configSections&gt;每个配置文件允许的元素,如果存在,则必须是根&lt; configuration&gt;的第一个子元素。元件。
这就是说你必须将<configSections>
元素移到文件的顶部。我想这是处理配置文件的代码可以在读取配置文件的每个部分之前为每个部分加载适当的处理程序。
配置部分处理程序(type
元素的section
属性中描述的类型)必须从ConfigurationSection
继承
不幸的是,配置系统的工作方式意味着您不能只放下POCO并让它为您完成所有连接。有creating a custom configuration section on MSDN的教程。
完全限定您所指的类型
我不确定这实际上是否会给您造成问题,但要精确避免它导致问题并没有什么坏处。以下内容:
<section name="Person" type="Person.Person" />
可能含糊不清。假设您的项目编译为名为“MyProjectThatContainsPerson”的DLL / EXE,您应该考虑将其更改为:
<section name="Person" type="Person.Person, MyProjectThatContainsPerson" />
这使得配置系统不仅清楚了类型的名称(Person.Person
),还清楚它应该尝试从(MyProjectThatContainsPerson
)加载它的程序集。
使用内置区域处理程序
的示例自定义区域如果您想添加具有自定义名称的配置部分(例如“MySection”),但行为与appSettings
的行为相同,则可以:
<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>