我正在尝试实现一个项目中的自定义配置节,但我总是遇到一些我不理解的异常。我希望有人能填补这里的空白。
我的App.config
看起来像这样:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="ServicesSection" type="RT.Core.Config.ServicesConfigurationSectionHandler, RT.Core"/>
</configSections>
<ServicesSection type="RT.Core.Config.ServicesSection, RT.Core">
<Services>
<AddService Port="6996" ReportType="File" />
<AddService Port="7001" ReportType="Other" />
</Services>
</ServicesSection>
</configuration>
我有一个定义如下的ServiceConfig
元素:
public class ServiceConfig : ConfigurationElement
{
public ServiceConfig() {}
public ServiceConfig(int port, string reportType)
{
Port = port;
ReportType = reportType;
}
[ConfigurationProperty("Port", DefaultValue = 0, IsRequired = true, IsKey = true)]
public int Port
{
get { return (int) this["Port"]; }
set { this["Port"] = value; }
}
[ConfigurationProperty("ReportType", DefaultValue = "File", IsRequired = true, IsKey = false)]
public string ReportType
{
get { return (string) this["ReportType"]; }
set { this["ReportType"] = value; }
}
}
我有一个定义如下的ServiceCollection
:
public class ServiceCollection : ConfigurationElementCollection
{
public ServiceCollection()
{
Console.WriteLine("ServiceCollection Constructor");
}
public ServiceConfig this[int index]
{
get { return (ServiceConfig)BaseGet(index); }
set
{
if (BaseGet(index) != null)
{
BaseRemoveAt(index);
}
BaseAdd(index, value);
}
}
public void Add(ServiceConfig serviceConfig)
{
BaseAdd(serviceConfig);
}
public void Clear()
{
BaseClear();
}
protected override ConfigurationElement CreateNewElement()
{
return new ServiceConfig();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((ServiceConfig) element).Port;
}
public void Remove(ServiceConfig serviceConfig)
{
BaseRemove(serviceConfig.Port);
}
public void RemoveAt(int index)
{
BaseRemoveAt(index);
}
public void Remove(string name)
{
BaseRemove(name);
}
}
我遗漏的部分是为处理程序做些什么。最初,我试图实现一个IConfigurationSectionHandler
,但发现了两件事:
我现在完全不知道该怎么做才能从config中读取我的数据。有什么需要帮忙的吗?
发布于 2010-10-15 02:12:15
前面的答案是正确的,但我也会给你所有的代码。
您的app.config应该如下所示:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="ServicesSection" type="RT.Core.Config.ServiceConfigurationSection, RT.Core"/>
</configSections>
<ServicesSection>
<Services>
<add Port="6996" ReportType="File" />
<add Port="7001" ReportType="Other" />
</Services>
</ServicesSection>
</configuration>
您的ServiceConfig
和ServiceCollection
类保持不变。
你需要一个新的类:
public class ServiceConfigurationSection : ConfigurationSection
{
[ConfigurationProperty("Services", IsDefaultCollection = false)]
[ConfigurationCollection(typeof(ServiceCollection),
AddItemName = "add",
ClearItemsName = "clear",
RemoveItemName = "remove")]
public ServiceCollection Services
{
get
{
return (ServiceCollection)base["Services"];
}
}
}
这应该能起到作用。要使用它,您可以使用:
ServiceConfigurationSection serviceConfigSection =
ConfigurationManager.GetSection("ServicesSection") as ServiceConfigurationSection;
ServiceConfig serviceConfig = serviceConfigSection.Services[0];
发布于 2013-10-10 07:38:47
如果您正在寻找如下所示的自定义配置节
<CustomApplicationConfig>
<Credentials Username="itsme" Password="mypassword"/>
<PrimaryAgent Address="10.5.64.26" Port="3560"/>
<SecondaryAgent Address="10.5.64.7" Port="3570"/>
<Site Id="123" />
<Lanes>
<Lane Id="1" PointId="north" Direction="Entry"/>
<Lane Id="2" PointId="south" Direction="Exit"/>
</Lanes>
</CustomApplicationConfig>
然后,您可以使用我的配置实现部分开始将System.Configuration
程序集引用添加到您的项目中
看看我使用的每个嵌套元素,第一个是具有两个属性的凭证,所以让我们先添加它
凭据元素
public class CredentialsConfigElement : System.Configuration.ConfigurationElement
{
[ConfigurationProperty("Username")]
public string Username
{
get
{
return base["Username"] as string;
}
}
[ConfigurationProperty("Password")]
public string Password
{
get
{
return base["Password"] as string;
}
}
}
PrimaryAgent和SecondaryAgent
两者具有相同的属性,并且看起来像是主服务器和故障转移的一组服务器的地址,因此您只需要为这两个服务器创建一个元素类,如下所示
public class ServerInfoConfigElement : ConfigurationElement
{
[ConfigurationProperty("Address")]
public string Address
{
get
{
return base["Address"] as string;
}
}
[ConfigurationProperty("Port")]
public int? Port
{
get
{
return base["Port"] as int?;
}
}
}
在这篇文章的后面,我将解释如何在一个类中使用两个不同的元素,让我们跳过SiteId,因为它没有区别。您只需创建一个与上面相同的类,并且只有一个属性。让我们来看看如何实现车道集合
它分为两部分,首先你必须创建一个元素实现类,然后你必须创建集合元素类
LaneConfigElement
public class LaneConfigElement : ConfigurationElement
{
[ConfigurationProperty("Id")]
public string Id
{
get
{
return base["Id"] as string;
}
}
[ConfigurationProperty("PointId")]
public string PointId
{
get
{
return base["PointId"] as string;
}
}
[ConfigurationProperty("Direction")]
public Direction? Direction
{
get
{
return base["Direction"] as Direction?;
}
}
}
public enum Direction
{
Entry,
Exit
}
您可以注意到,LanElement
的一个属性是枚举,如果您尝试在配置中使用枚举中未定义的任何其他值,应用程序将在启动时抛出System.Configuration.ConfigurationErrorsException
。好的,让我们来看看集合定义
[ConfigurationCollection(typeof(LaneConfigElement), AddItemName = "Lane", CollectionType = ConfigurationElementCollectionType.BasicMap)]
public class LaneConfigCollection : ConfigurationElementCollection
{
public LaneConfigElement this[int index]
{
get { return (LaneConfigElement)BaseGet(index); }
set
{
if (BaseGet(index) != null)
{
BaseRemoveAt(index);
}
BaseAdd(index, value);
}
}
public void Add(LaneConfigElement serviceConfig)
{
BaseAdd(serviceConfig);
}
public void Clear()
{
BaseClear();
}
protected override ConfigurationElement CreateNewElement()
{
return new LaneConfigElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((LaneConfigElement)element).Id;
}
public void Remove(LaneConfigElement serviceConfig)
{
BaseRemove(serviceConfig.Id);
}
public void RemoveAt(int index)
{
BaseRemoveAt(index);
}
public void Remove(String name)
{
BaseRemove(name);
}
}
你可以注意到,我已经设置了AddItemName = "Lane"
,你可以为你的集合条目选择任何你喜欢的东西,我更喜欢使用"add“默认的条目,但我只是为了这篇文章而修改了它。
现在我们所有的嵌套元素都已经实现了,现在我们应该将所有这些元素聚合到一个必须实现System.Configuration.ConfigurationSection
的类中
CustomApplicationConfigSection
public class CustomApplicationConfigSection : System.Configuration.ConfigurationSection
{
private static readonly ILog log = LogManager.GetLogger(typeof(CustomApplicationConfigSection));
public const string SECTION_NAME = "CustomApplicationConfig";
[ConfigurationProperty("Credentials")]
public CredentialsConfigElement Credentials
{
get
{
return base["Credentials"] as CredentialsConfigElement;
}
}
[ConfigurationProperty("PrimaryAgent")]
public ServerInfoConfigElement PrimaryAgent
{
get
{
return base["PrimaryAgent"] as ServerInfoConfigElement;
}
}
[ConfigurationProperty("SecondaryAgent")]
public ServerInfoConfigElement SecondaryAgent
{
get
{
return base["SecondaryAgent"] as ServerInfoConfigElement;
}
}
[ConfigurationProperty("Site")]
public SiteConfigElement Site
{
get
{
return base["Site"] as SiteConfigElement;
}
}
[ConfigurationProperty("Lanes")]
public LaneConfigCollection Lanes
{
get { return base["Lanes"] as LaneConfigCollection; }
}
}
现在您可以看到,我们有两个名为PrimaryAgent
和SecondaryAgent
的属性,它们都具有相同的类型。现在,您可以很容易地理解为什么我们对这两个元素只有一个实现类。
在你可以在你的app.config (或web.config)中使用这个新发明的配置节之前,你只需要告诉你的应用程序你已经发明了你自己的配置节,并给它一些尊重,要做到这一点,你必须在app.config中添加以下代码行(可能就在根标签的开始之后)。
<configSections>
<section name="CustomApplicationConfig" type="MyNameSpace.CustomApplicationConfigSection, MyAssemblyName" />
</configSections>
注意: MyAssemblyName应不带.dll,例如,如果汇编文件名为myDll.dll,则使用myDll而不是myDll.dll
要检索此配置,请在应用程序中的任何位置使用以下代码行
CustomApplicationConfigSection config = System.Configuration.ConfigurationManager.GetSection(CustomApplicationConfigSection.SECTION_NAME) as CustomApplicationConfigSection;
我希望上面的帖子能帮助你开始学习一些复杂的自定义配置节。
快乐编码:)
*编辑*要在LaneConfigCollection
上启用LINQ,您必须实现IEnumerable<LaneConfigElement>
并添加以下GetEnumerator
实现
public new IEnumerator<LaneConfigElement> GetEnumerator()
{
int count = base.Count;
for (int i = 0; i < count; i++)
{
yield return base.BaseGet(i) as LaneConfigElement;
}
}
对于那些仍然对read的工作原理感到困惑的人,请阅读this nice article
取自上述文章的两个要点是
它并不真正结束方法的执行。yield暂停方法执行,下一次调用它(对于下一个枚举值)时,该方法将从上一次yield调用开始继续执行。这听起来有点令人困惑,我认为…(Shay Friedman)
让步不是.Net运行时的一个特性。它只是一个由C#编译器编译成简单IL代码的C#语言特性。(Lars Corneliussen)
发布于 2010-10-17 13:47:09
这是配置集合的通用代码:
public class GenericConfigurationElementCollection<T> : ConfigurationElementCollection, IEnumerable<T> where T : ConfigurationElement, new()
{
List<T> _elements = new List<T>();
protected override ConfigurationElement CreateNewElement()
{
T newElement = new T();
_elements.Add(newElement);
return newElement;
}
protected override object GetElementKey(ConfigurationElement element)
{
return _elements.Find(e => e.Equals(element));
}
public new IEnumerator<T> GetEnumerator()
{
return _elements.GetEnumerator();
}
}
拥有GenericConfigurationElementCollection
之后,您可以在配置部分中简单地使用它(这是我的Dispatcher中的一个示例):
public class DispatcherConfigurationSection: ConfigurationSection
{
[ConfigurationProperty("maxRetry", IsRequired = false, DefaultValue = 5)]
public int MaxRetry
{
get
{
return (int)this["maxRetry"];
}
set
{
this["maxRetry"] = value;
}
}
[ConfigurationProperty("eventsDispatches", IsRequired = true)]
[ConfigurationCollection(typeof(EventsDispatchConfigurationElement), AddItemName = "add", ClearItemsName = "clear", RemoveItemName = "remove")]
public GenericConfigurationElementCollection<EventsDispatchConfigurationElement> EventsDispatches
{
get { return (GenericConfigurationElementCollection<EventsDispatchConfigurationElement>)this["eventsDispatches"]; }
}
}
Config元素的配置如下:
public class EventsDispatchConfigurationElement : ConfigurationElement
{
[ConfigurationProperty("name", IsRequired = true)]
public string Name
{
get
{
return (string) this["name"];
}
set
{
this["name"] = value;
}
}
}
配置文件将如下所示:
<?xml version="1.0" encoding="utf-8" ?>
<dispatcherConfigurationSection>
<eventsDispatches>
<add name="Log" ></add>
<add name="Notification" ></add>
<add name="tester" ></add>
</eventsDispatches>
</dispatcherConfigurationSection>
希望它能帮上忙!
https://stackoverflow.com/questions/3935331
复制相似问题