Configuration을 Custom으로 사용해 보자 - 두번째

현재 주소 복사
트랙백 주소 복사
방실이님의 글 (1/2/2008 6:01:15 PM) Viewing : 4070

앞서 언급했던 2가지 방식중 같은 속성을 가진 Element를 가지고 있는 Section을 구성해 보도록 하겠다.
(첨부 파일이 없기에 모든 코드를 제시한다..보기에 불편 하더라도..이해를..^^)

    ///

    /// 최상위 섹션 그룹 클래스 Ver 1.0

    ///

    ///

    /// http://www.bangsil.net

    /// 07.12.14 - Prototype - 방실

    /// 07.12.31 - VideoSettings 추가 - 민성욱

    ///

    public class AncestorSectionGroup : ConfigurationSectionGroup

    {

        ///

        /// 개체를 가져옵니다.

        ///

        /// 사용하지 않습니다.

        [ConfigurationProperty("IPSettings", IsRequired = true)]

        public IPSettingsSection IPSettingsSection

        {

            get

            {

                return (IPSettingsSection)base.Sections["IPSettings"];

            }

        }

        ///

        /// 개체를 가져옵니다.

        ///

        /// 사용하지 않습니다.

        [ConfigurationProperty("VideoSettings", IsRequired = true)]

        public VideoSettingsSection VideoSettingsSection

        {

            get

            {

                return (VideoSettingsSection)base.Sections["VideoSettings"];

            }

        }

    }

먼저 SectionGroup을 구성해 보겠다.
SectionGroup클래스는 ConfigurationSectionGroup 클래스를 상속 받아야 한다.
이 클래스에서 정의된 부분은 이 그룹에 속한 Section 개체를 얻어 오는 프라퍼트 뿐이다.

이는 Sections라는 인덱서에서 섹션 이름으로 조회해서 가져오는 방식이다.

ConfigurationProperty 라는 어트리뷰트는 실제 xml 파일에서 표현되는 속성의 이릅이다, 이는 대소문자를 구분한다.

이제 Section 클래스를 구성해 보자.

    ///

    /// IP세팅을 위한 섹션 클래스 Ver 1.0

    ///

    ///

    /// http://www.bangsil.net

    /// 07.12.14 - Prototype - 방실

    ///

    public class IPSettingsSection : ConfigurationSection

    {

        ///

        /// 개체를 가져옵니다.

        ///

        /// 개체입니다

        [ConfigurationProperty("ServerSettings")]

        public ServerElementCollection ServerSettings

        {

            get

            {

                return (ServerElementCollection)base["ServerSettings"];

            }

        }

 

        ///

        /// 개체를 가져옵니다.

        ///

        /// 개체입니다.

        [ConfigurationProperty("ClientSettings")]

        public ClientElementCollection ClientSettings

        {

            get

            {

                return (ClientElementCollection)base["ClientSettings"];

            }

        }

 

        ///

        ///    name 값으로 클래스의 컬렉션에서 개체를 얻어 옵니다.

        ///

        /// 검색할 이름(키)입니다.

        /// 개체입니다.

        public ClientElement GetClientElement(string name)

        {

            IEnumerator enumerator = this.ClientSettings.GetEnumerator();

            while (enumerator.MoveNext())

            {

                if (name == ((ClientElement)enumerator.Current).Name)

                {

                    return (ClientElement)enumerator.Current;

                }

            }

            return null;

        }

 

        ///

        ///    name 값으로 클래스의 컬렉션에서 개체를 얻어 옵니다.

        ///

        /// 검색할 이름(키)입니다.

        /// 개체입니다.

        public ServerElement GetServerElement(string name)

        {

            IEnumerator enumerator = this.ServerSettings.GetEnumerator();

            while (enumerator.MoveNext())

            {

                if (name == ((ServerElement)enumerator.Current).Name)

                {

                    return (ServerElement)enumerator.Current;

                }

            }

            return null;

        }

    }

Section 클래스 또한 ConfigurationSection 클래스를 상속 받아야 한다.
마찬 가지로 하위 노드의 개체를 얻을 수 있는 속성을 가지고 있어야 한다.
ServetSettings와 ClientSettings 가 그것이다.

그리고 마지막으로 클라이언트(UI 단계)에서 Element 클래스에 접근 할 수 있도록 Get~ Element 메서드를 생성한다.
이 메서드는 ElementCollection의 Enumerator에서 이름속성의 값으로 조회한다.

이제 다음은 ElementCollection 클래스를 정의 한다.

    ///

    /// 클래스의 컬렉션 클래스 Ver 1.0

    ///

    ///

    /// http://www.bangsil.net

    /// 07.12.14 - Prototype - 방실

    ///

    public class ClientElementCollection : ConfigurationElementCollection

    {

        ///

        /// 파생 클래스에서 재정의할 때 새 를 만듭니다.

        ///

        ///

        ///입니다.

        ///

        protected override ConfigurationElement CreateNewElement()

        {

            return new ClientElement();

        }

 

        ///

        /// 파생 클래스에서 재정의될 때 지정된 구성 요소의 요소 키를 가져옵니다.

        ///

        /// 키를 반환할 입니다.

        ///

        /// 지정된 의 키로 사용되는 입니다.

        ///

        protected override object GetElementKey(ConfigurationElement element)

        {

            return ((ClientElement)element).Name;

        }

    }

이 ElementCollection 클래스 역시 ConfigurationElementCollectoin 클래스를 상속 받으며 2개의 메서드를 재정의 해야 한다.
이 메서드는 실제 사용자 코드에서는 사용되지 않지만, 내부적으로 호출 되는 메서드이며 반드시 정의하여야 한다.

이제 마지막으로 Element 클래스만이 남았다.

    ///

    /// ClientSettings 요소의 클래스 Ver 1.0

    ///

    ///

    /// http://www.bangsil.net

    /// 07.12.14 - Prototype - 방실

    /// 07.12.17 - portForVideo 속성 추가 - 민성욱

    /// 08.01.01 - 구조수정 - 민성욱

    ///

    public class ClientElement : ConfigurationElement

    {

        private static ConfigurationPropertyCollection properties;

        private static readonly ConfigurationProperty name;

        private static readonly ConfigurationProperty ipAddress;

        private static readonly ConfigurationProperty portForFileSharing;

        private static readonly ConfigurationProperty portForVideo;

 

        ///

        /// 클래스의 정적 생성자입니다.

        ///

        static ClientElement()

        {

            name = new ConfigurationProperty("name", typeof(string), string.Empty, ConfigurationPropertyOptions.IsKey | ConfigurationPropertyOptions.IsRequired);

            ipAddress = new ConfigurationProperty("ipAddress", typeof(string), string.Empty, ConfigurationPropertyOptions.IsRequired);

            portForFileSharing = new ConfigurationProperty("portForFileSharing", typeof(Int32), 9098, ConfigurationPropertyOptions.IsKey | ConfigurationPropertyOptions.IsRequired);

            portForVideo = new ConfigurationProperty("portForVideo", typeof(Int32), 6050, ConfigurationPropertyOptions.IsKey | ConfigurationPropertyOptions.IsRequired);

            properties = new ConfigurationPropertyCollection();

            properties.Add(name);

            properties.Add(ipAddress);

            properties.Add(portForFileSharing);

            properties.Add(portForVideo);

        }

 

        ///

        /// 클래스의 생성자입니다.

        ///

        internal ClientElement() { }

 

        ///

        /// 해당 요소의 이름(키)를 가져옵니다.

        ///

        /// 이름(키)입니다.

        [ConfigurationProperty("name", IsRequired = true, IsKey = true)]

        [StringValidator(InvalidCharacters = "[a-zA-Z]*", MinLength = 1, MaxLength = 255)]

        public string Name

        {

            get

            {

                return (string)base[name];

            }

        }

 

        ///

        /// 해당 요소의 아이피 주소를 가져오거나 설정합니다.

        ///

        /// 아이피 주소입니다.

        [ConfigurationProperty("ipAddress", IsRequired = true)]

        [StringValidator(InvalidCharacters = @"[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*", MinLength = 1, MaxLength = 255)]

        public string IPAddress

        {

            get

            {

                return ((string)base[ipAddress]).Trim();

            }

            set

            {

                base[ipAddress] = value.Trim();

            }

        }

 

        ///

        /// 해당 요소의 파일 공유를 위한 포트 번호를 가져오거나 설정합니다.

        ///

        /// 파일 공유를 위한 포트 번호입니다.

        [ConfigurationProperty("portForFileSharing", IsRequired = true, IsKey = true)]

        [IntegerValidator(ExcludeRange = true, MinValue = 0, MaxValue = 65535)]

        public Int32 PortForFileSharing

        {

            get

            {

                return (Int32)base[portForFileSharing];

            }

            set

            {

                base[portForFileSharing] = value;

            }

        }

 

        ///

        /// 해당 요소의 비디오를 위한 포트 번호를 가져오거나 설정합니다.

        ///

        /// 비디오를 위한 포트 번호입니다.

        [ConfigurationProperty("portForVideo", IsRequired = true, IsKey = true)]

        [IntegerValidator(ExcludeRange = true, MinValue = 0, MaxValue = 65535)]

        public Int32 PortForVideo

        {

            get

            {

                return (Int32)base[portForVideo];

            }

            set

            {

                base[portForVideo] = value;

            }

        }

 

        ///

        /// 속성 컬렉션을 가져옵니다.

        ///

        ///

        /// 요소에 대한 속성의 컬렉션입니다.

        protected override ConfigurationPropertyCollection Properties

        {

            get

            {

                return properties;

            }

        }

 

        ///

        /// Configuration 요소의 속성 Value를 가져옵니다

        ///

        /// 속성(Property)의 이름입니다

        /// 해당 속성의 값입니다

        public object GetValue(string propertyName)

        {

            return base[propertyName];

        }

 

        ///

        /// Configuration 속성 Value값을 설정합니다

        ///

        /// 속성(Property)의 이름입니다

        /// 요소에 들어갈 값(Value)입니다

        public void SetValue(string propertyName, object value)

        {

            base[propertyName] = value;

        }

    }

마지막으로 정의해야 할 Element 클래스 역시 ConfigurationElement 클래스를 상속 받아야 한다.
앞서와 마찬가지로 사용되는 속성에 대하여 Property를 정의 해야 한다.
속성을 정의 함에 있어 사용된 IntegerValidator와 StringValidator 등의 어트리뷰트는 속성의 입력값에 대한 검증을 해준다.

정적 변수 및 정적 생성자를 이용한 이유는...이유없다..그냥..이랄까..다음 강좌에서는 Field 로 정의 한것을 보여 주도록 하겠다.

잘 살펴 보아야 하는 개체는 ConfigurationPropertyCollection 형의 properties 라는 개체이다.
이 개체는 정의된 속성들을 담고 있는 컬렉션이 되겠다.
이 컬렉션은 Properties 라는 속성을 재정의 하여 properties 라는 값을 가져온다.
이 속성 역시 내부적으로 사용되는 속성이면 반드시 재정의 하여야 하겠다.

마지막으로 Element의 값을 가져오기위한 GetValue와 SetValue 메서드를 만들어 놓았다.

자 이제 사용하기 위한 모든 조건이 완성 되었다. 이 설정을 코드에서 가져오고 새로운 값으로 저장해 보도록 하자.
바로 사용하여도 되지만..^^;
이것을 사용하기 쉽게 하기 위해 Helper 클래스를 하나 만들어 보자..어렵지 않다.

    ///

    /// 환경 설정 파일 도우미 클래스 Ver 1.0

    ///

    ///

    /// http://www.bangsil.net

    /// 07.12.14 - Prototype - 방실

    /// 07.12.31 - VideoSettingsSection, Save 메소드 추가 - 민성욱

    ///

    public class ConfigurationHelper

    {

        private static AncestorSectionGroup ancestor;

        private static Configuration config;

 

        ///

        /// 클래스의 정적 생성자입니다.

        ///

        static ConfigurationHelper()

        {

            config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

            ancestor = (AncestorSectionGroup)(config.GetSectionGroup("BIT.TM.DreamCare"));

        }

 

        ///

        /// IPSettings 섹션요소의 값을 가져옵니다

        ///

        /// IP에 관련된 값의 섹션입니다

        public static IPSettingsSection IPSettingsSection

        {

            get

            {

                return ancestor.IPSettingsSection;

            }

        }

 

        ///

        /// VideoSettings 섹션요소의 값을 가져옵니다

        ///

        /// Video에 관련된 값의 섹션입니다

        public static VideoSettingsSection VideoSettingsSection

        {

            get

            {

                return ancestor.VideoSettingsSection;

            }

        }

 

        ///

        /// 변경된 Configuration의 값을 저장합니다

        ///

        public static void Save()

        {

            config.Save();

        }

    }

Helper 클래스의 정적 생성자를 보면 ConfigurationManager 클래스를 이용해서 config 파일을 읽어 오는 모습을 볼수 있다.
만약 사용자의 config 파일 depth의 구조가 SectionGroup 이 없는 즉, 상위 레벨의 노드가 Section이라면 GetSection 이라는 메서드를 통해서 해당 섹션을 가져 올 수 있다.
그러나 위 예시의 경우에는 SectionGroup을 사용하였기에 GetSectionGroup 메서드를 이용하여 SectionGroup 개체를 만들도록 하였다.
그리고 2개의 프라퍼티는 이 SectionGroup이 자식으로 가지고 있는 Section을 리턴하는 구조이다.
마지막으로 Save메서드는 사용자의 코드에 의해 변경된 config 값을 config 파일에 쓰도록 하는 메서드이다. 이 메서드를 호출하지 않으면 사용자가 새로운 값을 할당하였을때 메모리 상에서만 이 값이 반영되어 프로그램이 Reset 되었을 때는 다시 원래의 값을 읽혀 지게 되겠다.

자 이제 이렇게 구성한 파일들은 어떻게 사용하는지 살펴 보도록 하자.

Convert.ToInt32(ConfigurationHelper.IPSettingsSection.GetClientElement("MainServer").GetValue("ipAddress"));

ConfigurationHelper.IPSettingsSection.GetClientElement("MainServer").IPAddress;

위 처럼 2가지 방식으로 사용할 수 있다.
첫번째 방식은 Element에서 만들었던 GetValue() 메서드를 사용해서 문자열로 입력되는 속성이름을 넣고 값을 가져오는 방식이며 object형으로 리턴된다.
일반적으로는 2번째 방식을 사용하게 될 터이다.
Element 클래스에서 정의 했던 Property를 사용하는 방법이다..물론 Property를 사용하기 때문에 형도 엄격하게 정해 진다.

굳이 GetValue 라는 메서드를 만든 이유는 다음 강좌에서 살펴볼 속성의 종류가 다른 Element 일때에도 같은 메서드를 사용하여 코드의 일관성을 유지 하고 싶어서이다...@.@
값을 변경하고 저장하는 방법도 쉽다.

ConfigurationHelper.IPSettingsSection.GetClientElement("MainServer").SetValue("ipAddress","127.0.0.1");

ConfigurationHelper.Save();

SerValue() 메서드로 키과 값을 입력 하고 단순히 Save() 메서드만 호출 하면 되겠다...

자..설명이 어설픈면이 없잖아 있지만..

오늘 아티클을 이해해야 다음 아티클을 이해 할 수 있겠다...


마지막 업데이트 : (10/5/2010 12:49:30 PM)

TAG : Configuration 



Trackback 보기 (0)
댓글 보기 (0)
댓글 쓰기