Programing

ConfigurationElementCollection을 사용하여 ConfigurationSection을 구현하는 방법

lottogame 2020. 6. 5. 08:00
반응형

ConfigurationElementCollection을 사용하여 ConfigurationSection을 구현하는 방법


프로젝트에서 사용자 정의 구성 섹션을 구현하려고하는데 이해하지 못하는 예외에 대비하여 계속 실행됩니다. 누군가가 빈칸을 채울 수 있기를 바랍니다.

나는 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했지만 두 가지를 발견했습니다.

  1. 작동하지 않았다
  2. 더 이상 사용되지 않습니다.

config에서 내 데이터를 읽을 수 있도록 지금해야 할 일이 완전히 없어졌습니다. 도와주세요!


이전 답변은 정확하지만 모든 코드를 알려 드리겠습니다.

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>

귀하 ServiceConfigServiceCollection수업은 변경되지 않습니다.

새로운 수업이 필요합니다 :

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;
            }
        }
    }

1 차 에이전트 및 2 차 에이전트

둘 다 동일한 속성을 가지며 기본 및 장애 조치를 위해 서버 세트에 대한 주소처럼 보입니다. 따라서 다음과 같은 두 요소에 대해 하나의 요소 클래스 만 작성하면됩니다.

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를 건너 뛰겠습니다. 하나의 속성만으로 위와 동일한 클래스를 하나만 작성하면됩니다. Lanes 컬렉션을 구현하는 방법을 보자

먼저 요소 구현 클래스를 만든 다음 컬렉션 요소 클래스를 만들어야합니다.

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시작시 발생합니다. Ok 컬렉션 정의로 넘어갑니다

[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.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.dll 대신 myDll을 사용하십시오.

이 구성을 검색하려면 응용 프로그램의 어느 곳에서나 다음 코드 줄을 사용하십시오.

CustomApplicationConfigSection config = System.Configuration.ConfigurationManager.GetSection(CustomApplicationConfigSection.SECTION_NAME) as CustomApplicationConfigSection;

위의 게시물이 약간 복잡한 종류의 사용자 정의 구성 섹션을 시작하는 데 도움이되기를 바랍니다.

행복한 코딩 :)

**** 편집 **** LINQ를 활성화하려면 LaneConfigCollection구현해야합니다.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;
            }
        }

수확량이 실제로 어떻게 작동하는지 아직도 혼란스러워하는 사람들을 위해이 좋은 기사를 읽으십시오

위 기사에서 취한 두 가지 핵심 사항은

실제로 메소드 실행을 종료하지는 않습니다. yield return은 메소드 실행을 일시 정지하고 다음에 메소드를 호출 할 때 (다음 열거 값에 대해) 마지막 수익률 리턴 호출부터 메소드가 계속 실행됩니다. 내가 생각하기에 약간 혼란스러워 ... (셰이 프리드먼)

수율은 .Net 런타임의 기능이 아닙니다. C # 컴파일러에 의해 간단한 IL 코드로 컴파일되는 C # 언어 기능 일뿐입니다. (Lars Corneliussen)


이것은 구성 컬렉션의 일반 코드입니다.

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();
    }
}

을 가지고 나면 GenericConfigurationElementCollectionconfig 섹션에서 간단하게 사용할 수 있습니다 (이것은 내 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"]; }
    }
}

구성 요소는 구성입니다.

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에서 Nerdle.AutoConfig 설치

2) ServiceConfig 유형을 정의하십시오 (구체적인 클래스 또는 인터페이스 중 하나)

public interface IServiceConfiguration
{
    int Port { get; }
    ReportType ReportType { get; }
}

3) 컬렉션을 보유 할 유형이 필요합니다. 예 :

public interface IServiceCollectionConfiguration
{
    IEnumerable<IServiceConfiguration> Services { get; } 
}

4) 구성 섹션을 다음과 같이 추가하십시오 (낙타 케이스 이름 지정에 유의하십시오)

<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 에서 상속을 시도하십시오 . Phil Haack 의이 블로그 게시물 에 예가 있습니다.

IConfigurationSectionHandler에 대한 설명서에 따라 확인되었습니다 .

.NET Framework 버전 2.0 이상에서는 ConfigurationSection 클래스에서 파생되어 관련 구성 섹션 처리기를 구현해야합니다.

참고 URL : https://stackoverflow.com/questions/3935331/how-to-implement-a-configurationsection-with-a-configurationelementcollection

반응형