App.config: вложенные разделы настраиваемой конфигурации

Я нашел отличный пример для обработчика пользовательской конфигурации и попытался использовать его. для моей собственной реализации.

Я настроил App.config следующим образом:

<configSections>
  <section name="DocumentationSettings" type="ConfigHandler.DocumentationSettings,Settings"/>
</configSections>

<DocumentationSettings>
  <DocumentationSections>
    <DocumentationSection Id="AAA">
      <SectionDescription Value="SectionDescriptionAAA"/>
    </DocumentationSection>
    <DocumentationSection Id="BBB">
      <SectionDescription Value="SectionDescriptionBBB"/>
    </DocumentationSection>
    <DocumentationSection Id="CCC">
      <SectionDescription Value="SectionDescriptionCCC"/>
    </DocumentationSection>
  </DocumentationSections>
</DocumentationSettings>

Я использую этот код для доступа к моей пользовательской конфигурации:

DocumentationSettings documentationSettings = ConfigurationManager.GetSection("DocumentationSettings") as DocumentationSettings;

foreach (DocumentationSectionConfigElement section in (documentationSettings.DocumentationSections.Sections))
{
    Console.WriteLine(section.Id);
    Console.WriteLine(section.SectionDescription.Properties.Value);
}

Первая «Console.WriteLine» работает отлично.

Итак, у меня есть следующие проблемы и вопросы, связанные с реализацией:

  1. Я получаю ошибку на втором «Console.WriteLine», ошибка: нераспознанный атрибут «Значение». Я поместил «public SectionDescription SectionDescription», поскольку класс «DocumentationSectionConfigElement» предоставляет доступ к свойствам, но я могу ошибаться, я сначала попытался поместить его в «DocumentationSectionCollection», но я не знаю, как его там реализовать, и мне кажется, что «DocumentationSectionCollection» реализует только логику «Коллекции».

  2. Я хочу получить доступ к «полям» либо так:

    section.Id section.SectionDescription.Value

или вот так:

section.Properties.Id
section.SectionDescription.Properties.Value

Я вижу, что «Коллекция» позволяет использовать эти свойства напрямую, используя такие методы индексатора:

public DocumentationSectionConfigElement this[int index]

Но я не могу реализовать метод индексатора в классе «SectionDescription», потому что это отдельный раздел, а не коллекция, поэтому это имя «Свойства» сохраняется, когда я обращаюсь к полям.

  1. Что мне нужно добавить, чтобы иметь возможность использовать LINQ для этих объектов конфигурации? Я имею в виду вот так:

    (DocumentationSettings.DocumentationSections.Sections) .Select (x => x.Id)

  2. Есть ли действительно хорошие примеры обработчика конфигурации сложной структуры XML? Из тех, что я обнаружил, в основном были такие простые структуры:

но нет никакого примера такой сложной структуры:

<section>
  <subSections>
    <subSection name="111">
      <Description Value="AAA"></Description>
      <Headers>
        <Header type="Main">
         <Properties>
           <Property name="Property1"/>
           <Property name="Property2"/>
           <Property name="Property3"/>
         </Properties>
        </Header>
      </Headers>
    </subSection>
  </subSections>
</section>

что ближе к реальным сценариям, когда нужно лучше организовать конфигурацию приложения.

  1. В чем смысл тега sectionGroup в configSections, если «Custom Configuration Handler» работает и достаточно одного зарегистрированного «раздела»?

  2. Почему все это так сложно? Я потратил так много времени на эти «нестандартные конфигурации», которые, как мне кажется, не должны быть такими сложными. Нет ли надстроек Visual Studio, которые обрабатывают эти вещи и генерируют код на основе структуры конфигурации XML?

Вот моя реализация обработчика конфигурации:

public class DocumentationSettings : ConfigurationSection
{
    [ConfigurationProperty("DocumentationSections")]
    public DocumentationSections DocumentationSections
    {
        get { return (DocumentationSections)base["DocumentationSections"]; }
    }
}

public class DocumentationSections : ConfigurationElement
{
    [ConfigurationProperty("", IsDefaultCollection = true)]
    public DocumentationSectionCollection Sections
    {
        get { return (DocumentationSectionCollection)base[""]; }
    }
}

public class SectionDescription : ConfigurationElement
{
    [ConfigurationProperty("SectionDescription")]
    public new SectionDescriptionConfigElement Properties
    {
        get { return (SectionDescriptionConfigElement)base["SectionDescription"]; }
    }
}

public class DocumentationSectionCollection : ConfigurationElementCollection
{
    public DocumentationSectionCollection()
    {
        DocumentationSectionConfigElement details = (DocumentationSectionConfigElement)CreateNewElement();
        if (details.Id != "")
        {
            Add(details);
        }
    }

    public override ConfigurationElementCollectionType CollectionType
    {
        get { return ConfigurationElementCollectionType.BasicMap; }
    }

    protected override ConfigurationElement CreateNewElement()
    {
        return new DocumentationSectionConfigElement();
    }

    protected override Object GetElementKey(ConfigurationElement element)
    {
        return ((DocumentationSectionConfigElement)element).Id;
    }

    public DocumentationSectionConfigElement this[int index]
    {
        get { return (DocumentationSectionConfigElement)BaseGet(index); }
        set
        {
            if (BaseGet(index) != null)
            {
                BaseRemoveAt(index);
            }
            BaseAdd(index, value);
        }
    }

    new public DocumentationSectionConfigElement this[string name]
    {
        get { return (DocumentationSectionConfigElement)BaseGet(name); }
    }

    public int IndexOf(DocumentationSectionConfigElement details)
    {
        return BaseIndexOf(details);
    }

    public void Add(DocumentationSectionConfigElement details)
    {
        BaseAdd(details);
    }
    protected override void BaseAdd(ConfigurationElement element)
    {
        BaseAdd(element, false);
    }

    public void Remove(DocumentationSectionConfigElement details)
    {
        if (BaseIndexOf(details) >= 0)
            BaseRemove(details.Id);
    }

    public void RemoveAt(int index)
    {
        BaseRemoveAt(index);
    }

    public void Remove(string name)
    {
        BaseRemove(name);
    }

    public void Clear()
    {
        BaseClear();
    }

    protected override string ElementName
    {
        get { return "DocumentationSection"; }
    }
}

public class DocumentationSectionConfigElement : ConfigurationElement
{
    [ConfigurationProperty("Id", IsRequired = true, IsKey = true)]
    [StringValidator(InvalidCharacters = "  ~!@#$%^&*()[]{}/;’\"|\\")]
    public string Id
    {
        get { return (string)this["Id"]; }
        set { this["Id"] = value; }
    }

    [ConfigurationProperty("Name", IsRequired = false)]
    public string Name
    {
        get { return (string)this["Name"]; }
        set { this["Name"] = value; }
    }

    [ConfigurationProperty("SectionDescription")]
    public SectionDescription SectionDescription
    {
        get { return ((SectionDescription)base["SectionDescription"]); }
    }
}

public class SectionDescriptionConfigElement : ConfigurationElement
{
    [ConfigurationProperty("Value", IsRequired = true)]
    public string Value
    {
        get { return (string)this["Value"]; }
        set { this["Value"] = value; }
    }
}

person Vadim K.    schedule 26.04.2015    source источник


Ответы (1)


Поскольку здесь нет активности, я постараюсь отвечать на свои вопросы один за другим:

  1. Нашел эту замечательную статью, в которой описывается много вещи и показывает довольно сложный пример реализации пользовательской конфигурации.

  2. Я нашел этот замечательный инструмент - «Генератор кода конфигурации .NET», который делает именно то, что я хотел - он требует XML. структура и генерирует пользовательский код конфигурации.

person Vadim K.    schedule 28.04.2015