Как реализовать ConfigurationSection с помощью коллекции ConfigurationElementCollection
Я пытаюсь реализовать пользовательский раздел конфигурации в проекте, и я продолжаю работать с исключениями, которые я не понимаю. Я надеялся, что кто-то может заполнить пробелы.
Я 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 но нашел две вещи:
- не получилось
- это устаревшие.
я полностью потерял теперь о том, что делать, чтобы я мог читать мои данные из конфигурации. Любая помощь, пожалуйста!
5 ответов:
предыдущий ответ правильный, но я дам вам весь код, а также.
приложение.конфигурация должна выглядеть так:
<?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];
если вы ищете пользовательский раздел конфигурации, как показано ниже
<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; } } }первичный агент и 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"вы можете выбрать, что вам нравится для вашей коллекции элемент, я предпочитаю использовать "добавить" по умолчанию, но я изменил его только ради этого поста.теперь все наши вложенные элементы были реализованы теперь мы должны объединить все те, в классе, который должен реализовать
System.Configuration.ConfigurationSectionCustomApplicationConfigSection
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оба имеют одинаковый тип теперь вы можете легко понять, почему у нас был только один класс реализации этих двух элементов.прежде чем вы сможете использовать этот недавно изобретенный раздел конфигурации в своем приложении.config (или web.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;Я надеюсь, что выше сообщение поможет вам начать работу с немного сложным видом пользовательских разделов конфигурации.
Удачи В Кодировании :)
****редактирование**** Чтобы включить LINQ on
LaneConfigCollectionвы должны реализоватьIEnumerable<LaneConfigElement>и добавить следующую реализацию
GetEnumeratorpublic new IEnumerator<LaneConfigElement> GetEnumerator() { int count = base.Count; for (int i = 0; i < count; i++) { yield return base.BaseGet(i) as LaneConfigElement; } }для людей, которые все еще путают о том, как выход действительно работает читать это хорошая статья
два ключевых момента, которые изъяты из вышеуказанной статьи
на самом деле это не конец выполнения метода. возврата приостанавливает выполнение метода и в следующий раз вы называете это (для следующего значение перечисления), метод будет продолжать выполняться с последнего дайте обратный звонок. Это звучит немного запутанно, я думаю...(Шай Фридман)
Yield не является функцией среды выполнения .Net. Это просто язык C# функция, которая компилируется в простой код IL компилятором C#. (Ларс Корнелиуссен)
это общий код для коллекции конфигураций:
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, вы можете просто использовать его в разделе конфигурации (это пример из моего диспетчера):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>надеюсь, что это поможет !
более легкая альтернатива для тех, кто предпочел бы не писать все, что шаблон конфигурации вручную...
1) установить ботаник.Автонастройка от NuGet
2) Определите свой тип ServiceConfig (либо конкретный класс, либо просто интерфейс, либо будет делать)
public interface IServiceConfiguration { int Port { get; } ReportType ReportType { get; } }3) вам понадобится тип для хранения коллекции, например
public interface IServiceCollectionConfiguration { IEnumerable<IServiceConfiguration> Services { get; } }4) Добавьте раздел конфигурации вот так (Примечание camelCase именование)
<configSections> <section name="serviceCollection" type="Nerdle.AutoConfig.Section, Nerdle.AutoConfig"/> </configSections> <serviceCollection> <services> <service port="6996" reportType="File" /> <service port="7001" reportType="Other" /> </services> </serviceCollection>5) карта с автонастройки
var services = AutoConfig.Map<IServiceCollectionConfiguration>();
попробуйте наследовать от ConfigurationSection. Это блоге у Фила Хаака есть пример.
подтверждено, согласно документации для IConfigurationSectionHandler:
в .NET Framework версии 2.0 и выше вместо этого необходимо наследовать от класса ConfigurationSection для реализации соответствующего обработчика раздела конфигурации.
Comments