web-dev-qa-db-ja.com

ネストされたコレクションを持つカスタム構成セクションの正しい実装?

Webアプリケーションでは、次のような構成セクションを使用してマッピングを定義できるようにしたいと思います。

<configuration>
    <configSections>
        <sectionGroup name="MyCustomer">
            <section name="CatalogMappings" type="MyCustom.MyConfigSection" />
        </sectionGroup>
    </configSections>
    <MyCustomer>
        <catalogMappings>
            <catalog name="toto">
                <mapping value="1" displayText="titi" />
                <mapping value="2" displayText="tata" />
            </catalog>
            <catalog name="toto2">
                <mapping value="1" displayText="titi2" />
                <mapping value="2" displayText="tata2" />
            </catalog>
        </catalogMappings>
    </MyCustomer>
</configuration>

コレクションのコレクションを定義するときは特に、この目標を達成するのに苦労しています。これを達成するために実装する必要があるクラスは何ですか?

現在、私は持っています:

public class CatalogMappingSection : System.Configuration.ConfigurationSection
{
    public class Mapping : ConfigurationElement
    {
        [ConfigurationProperty("externalKey")]
        public string ExternalKey { get; set; }
        [ConfigurationProperty("displayText", IsRequired=true)]
        public string DisplayText { get; set; }
        [ConfigurationProperty("value", IsRequired=true, IsKey=true)]
        public int Value { get; set; }
    }

    public class Catalog : ConfigurationElementCollection
    {
        [ConfigurationProperty("name", IsRequired=true, IsKey=true)]
        public string Name { get; set; }

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

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((Mapping)element).Value;
        }
    }

    public class CatalogCollection : ConfigurationElementCollection
    {
        [ConfigurationProperty("catalog")]
        [ConfigurationCollection(typeof(Catalog))]
        public Catalog CatalogMappingCollection
        {
            get
            {
                return (Catalog)base["catalog"];
            }
        }

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

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((Catalog)element).Name;
        }
    }

    [ConfigurationProperty("catalogMappings")]
    [ConfigurationCollection(typeof(CatalogCollection))]
    public CatalogCollection CatalogMappings
    {
        get
        {
            return (CatalogCollection)base["catalogMappings"];
        }
    }
}

しかし、これは期待どおりに機能していません。

44
Steve B

私はついにこの男の例を見つけました。コード化され、すぐに使用できました。

http://manyrootsofallevilrants.blogspot.com/2011/07/nested-custom-configuration-collections.html

ここにコードを貼り付けます......誰かが「あなたの答えはここにあります」と言って、リンクが切れているときに我慢できないからです。

彼のウェブサイトを最初に試してみて、それが機能する場合は「ありがとう」を残してください。

using System;
using System.Configuration;

namespace SSHTunnelWF
{
    public class TunnelSection : ConfigurationSection
    {
        [ConfigurationProperty("", IsDefaultCollection = true)]  
        public HostCollection Tunnels
        {
            get
            {
                HostCollection hostCollection = (HostCollection)base[""];
                return hostCollection;                
            }
        }
    }

    public class HostCollection : ConfigurationElementCollection
    {
        public HostCollection()
        {
            HostConfigElement details = (HostConfigElement)CreateNewElement();
            if (details.SSHServerHostname != "")
            {
                Add(details);
            }
        }

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

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

        protected override Object GetElementKey(ConfigurationElement element)
        {
            return ((HostConfigElement)element).SSHServerHostname;
        }

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

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

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

        public void Add(HostConfigElement details)
        {
            BaseAdd(details);
        }

        protected override void BaseAdd(ConfigurationElement element)
        {
            BaseAdd(element, false);
        }

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

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

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

        public void Clear()
        {
            BaseClear();
        }

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

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

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

        [ConfigurationProperty("SSHport", IsRequired = true, DefaultValue = 22)]
        [IntegerValidator(MinValue = 1, MaxValue = 65536)]
        public int SSHPort
        {
            get { return (int)this["SSHport"]; }
            set { this["SSHport"] = value; }
        }

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

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

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

        [ConfigurationProperty("tunnels", IsDefaultCollection = false)]
        public TunnelCollection Tunnels
        {
            get { return (TunnelCollection)base["tunnels"]; }
        }
    }

    public class TunnelCollection : ConfigurationElementCollection
    {
        public new TunnelConfigElement this[string name]
        {
            get
            {
                if (IndexOf(name) < 0) return null;
                return (TunnelConfigElement)BaseGet(name);
            }
        }

        public TunnelConfigElement this[int index]
        {
            get { return (TunnelConfigElement)BaseGet(index); }
        }

        public int IndexOf(string name)
        {
            name = name.ToLower();

            for (int idx = 0; idx < base.Count; idx++)
            {
                if (this[idx].Name.ToLower() == name)
                    return idx;
            }
            return -1;
        }

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

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

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((TunnelConfigElement)element).Name;
        }

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

    public class TunnelConfigElement : ConfigurationElement
    {        
        public TunnelConfigElement()
        {
        }

        public TunnelConfigElement(string name, int localport, int remoteport, string destinationserver)
        {
            this.DestinationServer = destinationserver;
            this.RemotePort = remoteport;
            this.LocalPort = localport;            
            this.Name = name;
        }

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

        [ConfigurationProperty("localport", IsRequired = true, DefaultValue =1)]
        [IntegerValidator(MinValue = 1, MaxValue = 65536)]
        public int LocalPort
        {
            get { return (int)this["localport"]; }
            set { this["localport"] = value; }
        }

        [ConfigurationProperty("remoteport", IsRequired = true, DefaultValue =1)]
        [IntegerValidator(MinValue = 1, MaxValue = 65536)]
        public int RemotePort
        {
            get { return (int)this["remoteport"]; }
            set { this["remoteport"] = value; }
        }

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

そして構成コード

 <?xml version="1.0"?>
 <configuration>
   <configSections>
     <section name="TunnelSection" type="SSHTunnelWF.TunnelSection,SSHTunnelWF" />
   </configSections>
   <TunnelSection>
     <Host SSHServerHostname="tsg.edssdn.net" username="user" SSHport="22" password="pass" privatekey="" privatekeypassphrase="">
       <tunnels>
         <tunnel name="tfs" localport="8081"  remoteport="8080" destinationserver="tfs2010.dev.com"  />
         <tunnel name="sql" localport="14331"  remoteport="1433" destinationserver="sql2008.dev.com"  />
         <tunnel name="crm2011app" localport="81"  remoteport="80" destinationserver="crm2011betaapp.dev.com"  />
       </tunnels>
     </Host>
     <Host SSHServerHostname="blade16" username="root" SSHport="22"  password="pass" privatekey="" privatekeypassphrase="">
      <tunnels>
        <tunnel name="vnc" localport="5902"  remoteport="5902" destinationserver="blade1.dev.com" />
      </tunnels>
     </Host>
   </TunnelSection>
 </configuration>

そして、「呼び出し」

TunnelSection tunnels = ConfigurationManager.GetSection("TunnelSection") as TunnelSection
65
granadaCoder

私の他の回答の人気のため、Usa-StatesとUsa-Countiesを使用してカスタム例を作成しました。従うのが少し簡単な例。

また、いくつかのインターフェイスを追加しました。これにより、この元の答えを書いたときに気づかなかったユニットテストのモックができます。

また、独自のファイルに設定を追加するため、app.configファイルには10億ものものが含まれていません。

コレクション内の特定のアイテムの検索をカプセル化する「Finder」も追加しました。

カスタムEnumも追加しました。

「UsaStatesSettings.config」(必ず「copy-always」としてマークしてください)

<?xml version="1.0" encoding="utf-8" ?>
<UsaStateDefinitionConfigurationSectionName>
  <usaStateDefinition usaStateFullName="Virginia" usaStateAbbreviation="VA" countyLabelName="County" usaStateDefinitionUniqueIdentifier="111" isContenential="true" >
    <usaCounties>
      <usaCounty usaCountyValue="Bath" />
      <usaCounty usaCountyValue="Bedford" />
      <usaCounty usaCountyValue="Bland" />
    </usaCounties>
  </usaStateDefinition>
  <!-- -->
  <usaStateDefinition usaStateFullName="North Carolina" usaStateAbbreviation="NC" countyLabelName="County" usaStateDefinitionUniqueIdentifier="222" isContenential="true" >
    <usaCounties>
      <usaCounty usaCountyValue="Catawba" />
      <usaCounty usaCountyValue="Chatham" />
      <usaCounty usaCountyValue="Chowan" />
    </usaCounties>
  </usaStateDefinition>
  <!-- -->
  <usaStateDefinition usaStateFullName="Alaska" usaStateAbbreviation="AK" countyLabelName="Borough" usaStateDefinitionUniqueIdentifier="333" isContenential="false" >
    <usaCounties>
      <usaCounty usaCountyValue="Aleutians East" />
    </usaCounties>
  </usaStateDefinition>
  <!-- -->
  <usaStateDefinition usaStateFullName="Lousiania" usaStateAbbreviation="LA" countyLabelName="Parish" usaStateDefinitionUniqueIdentifier="444" isContenential="true" >
    <usaCounties>
      <usaCounty usaCountyValue="Acadia" />
    </usaCounties>
  </usaStateDefinition>
</UsaStateDefinitionConfigurationSectionName>

「app.config」

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <configSections>

    <section name="UsaStateDefinitionConfigurationSectionName" type="GranadaCoder.CustomConfigurationExample.Configuration.UsaStateDefinitionConfigurationSection,GranadaCoder.CustomConfigurationExample.Configuration" />
  </configSections>


  <UsaStateDefinitionConfigurationSectionName configSource="UsaStatesSettings.config" />

  <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
</configuration>

そして今、「コード」

/**/

// file="CaseInsensitiveEnumConfigurationValueConverter.cs"

using System;
using System.ComponentModel;
using System.Configuration;
using System.Globalization;

namespace GranadaCoder.CustomConfigurationExample.Configuration
{
    public class CaseInsensitiveEnumConfigurationValueConverter<T> : ConfigurationConverterBase
    {
        public override object ConvertFrom(ITypeDescriptorContext ctx, CultureInfo ci, object data)
        {
            return Enum.Parse(typeof(T), (string)data, true);
        }
    }
}


/**/


// file="UsaCountyCollection.cs"


using System.Collections.Generic;
using System.Configuration;

namespace GranadaCoder.CustomConfigurationExample.Configuration
{
    [ConfigurationCollection(typeof(UsaCountyConfigurationElement))]
    public class UsaCountyCollection : ConfigurationElementCollection, IEnumerable<UsaCountyConfigurationElement>
    {
        public override ConfigurationElementCollectionType CollectionType
        {
            get { return ConfigurationElementCollectionType.BasicMap; }
        }

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

        public UsaCountyConfigurationElement this[int index]
        {
            get { return (UsaCountyConfigurationElement)BaseGet(index); }
        }

        public new UsaCountyConfigurationElement this[string name]
        {
            get
            {
                if (this.IndexOf(name) < 0)
                {
                    return null;
                }

                return (UsaCountyConfigurationElement)BaseGet(name);
            }
        }

        public void Add(UsaCountyConfigurationElement newItem)
        {
            this.BaseAdd(newItem);
        }

        public int IndexOf(string usaCountyValue)
        {
            for (int idx = 0; idx < this.Count; idx++)
            {
                if (this[idx].UsaCountyValue.ToLower(System.Globalization.CultureInfo.CurrentCulture) == usaCountyValue.ToLower(System.Globalization.CultureInfo.CurrentCulture))
                {
                    return idx;
                }
            }

            return -1;
        }

        public new IEnumerator<UsaCountyConfigurationElement> GetEnumerator()
        {
            int count = this.Count;

            for (int i = 0; i < count; i++)
            {
                yield return this.BaseGet(i) as UsaCountyConfigurationElement;
            }
        }

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

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((UsaCountyConfigurationElement)element).UsaCountyValue;
        }
    }
}



/**/




// file="UsaCountyConfigurationElement.cs"




using System.ComponentModel;
using System.Configuration;

namespace GranadaCoder.CustomConfigurationExample.Configuration
{
    [System.Diagnostics.DebuggerDisplay("UsaCountyValue='{UsaCountyValue}'")]
    public class UsaCountyConfigurationElement : ConfigurationElement
    {
        private const string UsaCountyValuePropertyName = "usaCountyValue";

        public UsaCountyConfigurationElement()
        {
        }

        public UsaCountyConfigurationElement(string usaCountyValue)
        {
            this.UsaCountyValue = usaCountyValue;
        }

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


/**/




// file="UsaCountyLabelEnum.cs"




namespace GranadaCoder.CustomConfigurationExample.Configuration
{
    public enum UsaCountyLabelEnum
    {
        Unknown,
        County,
        Parish,
        Borough
    }
}


/**/




// file="UsaStateDefinitionCollection.cs"




using System;
using System.Collections.Generic;
using System.Configuration;

using GranadaCoder.CustomConfigurationExample.Configuration.Interfaces;

namespace GranadaCoder.CustomConfigurationExample.Configuration
{
    [ConfigurationCollection(typeof(UsaStateDefinitionConfigurationElement))]
    public class UsaStateDefinitionCollection : ConfigurationElementCollection, IUsaStateDefinitionCollection
    {
        public UsaStateDefinitionCollection()
        {
            UsaStateDefinitionConfigurationElement details = (UsaStateDefinitionConfigurationElement)this.CreateNewElement();
            if (!string.IsNullOrEmpty(details.UsaStateFullName))
            {
                this.Add(details);
            }
        }

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

        bool ICollection<UsaStateDefinitionConfigurationElement>.IsReadOnly
        {
            get
            {
                return false;
            }
        }

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

        public UsaStateDefinitionConfigurationElement this[int index]
        {
            get
            {
                return (UsaStateDefinitionConfigurationElement)BaseGet(index);
            }

            set
            {
                if (this.BaseGet(index) != null)
                {
                    this.BaseRemoveAt(index);
                }

                this.BaseAdd(index, value);
            }
        }

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

        public int IndexOf(UsaStateDefinitionConfigurationElement details)
        {
            return this.BaseIndexOf(details);
        }

        public void Add(UsaStateDefinitionConfigurationElement newItem)
        {
            this.BaseAdd(newItem);
        }

        public bool Remove(UsaStateDefinitionConfigurationElement details)
        {
            if (this.BaseIndexOf(details) >= 0)
            {
                this.BaseRemove(details.UsaStateFullName);
                return true;
            }

            return false;
        }

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

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

        public void Clear()
        {
            this.BaseClear();
        }

        public bool Contains(UsaStateDefinitionConfigurationElement item)
        {
            if (this.IndexOf(item) >= 0)
            {
                return true;
            }

            return false;
        }

        public void CopyTo(UsaStateDefinitionConfigurationElement[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }

        public void Insert(int index, UsaStateDefinitionConfigurationElement item)
        {
            this.BaseAdd(index, item);
        }

        public new IEnumerator<UsaStateDefinitionConfigurationElement> GetEnumerator()
        {
            int count = this.Count;

            for (int i = 0; i < count; i++)
            {
                yield return this.BaseGet(i) as UsaStateDefinitionConfigurationElement;
            }
        }

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

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((UsaStateDefinitionConfigurationElement)element).UsaStateFullName;
        }

        protected override void BaseAdd(ConfigurationElement element)
        {
            this.BaseAdd(element, false);
        }
    }
}


/**/




// file="UsaStateDefinitionConfigurationElement.cs"




using System;
using System.ComponentModel;
using System.Configuration;

namespace GranadaCoder.CustomConfigurationExample.Configuration
{
    [System.Diagnostics.DebuggerDisplay("UsaStateFullName = '{UsaStateFullName}'")]
    public class UsaStateDefinitionConfigurationElement : ConfigurationElement
    {
        private const string UsaStateFullNamePropertyName = "usaStateFullName";
        private const string UsaStateAbbreviationPropertyName = "usaStateAbbreviation";
        private const string UsaStateDefinitionUniqueIdentifierPropertyName = "usaStateDefinitionUniqueIdentifier";
        private const string IsContenentialPropertyName = "isContenential";
        private const string CountyLabelNamePropertyName = "countyLabelName";

        private const string UsaCountiesPropertyName = "usaCounties";
        private const string ServiceBusQueuesPropertyName = "serviceBusQueues";

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

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

        [ConfigurationProperty(UsaStateDefinitionUniqueIdentifierPropertyName, IsRequired = true)]
        public int UsaStateDefinitionUniqueIdentifier
        {
            get { return (int)this[UsaStateDefinitionUniqueIdentifierPropertyName]; }
            set { this[UsaStateDefinitionUniqueIdentifierPropertyName] = value; }
        }

        [ConfigurationProperty(IsContenentialPropertyName, IsRequired = true)]
        public bool IsContenential
        {
            get { return (bool)this[IsContenentialPropertyName]; }
            set { this[IsContenentialPropertyName] = value; }
        }

        [ConfigurationProperty(UsaCountiesPropertyName, IsDefaultCollection = false)]
        public UsaCountyCollection UsaCounties
        {
            get { return (UsaCountyCollection)base[UsaCountiesPropertyName]; }
            set { this[UsaCountiesPropertyName] = value; } /* set is here for UnitTests */
        }

        [ConfigurationProperty(CountyLabelNamePropertyName, DefaultValue = UsaCountyLabelEnum.Unknown)]
        [TypeConverter(typeof(CaseInsensitiveEnumConfigurationValueConverter<UsaCountyLabelEnum>))]
        public UsaCountyLabelEnum CountyLabelType
        {
            get
            {
                return (UsaCountyLabelEnum)this[CountyLabelNamePropertyName];
            }

            set
            {
                base[CountyLabelNamePropertyName] = value;
            }
        }
    }
}



/**/




// file="UsaStateDefinitionConfigurationRetriever.cs"




using System;
using System.Configuration;
using System.Linq;

using GranadaCoder.CustomConfigurationExample.Configuration.Interfaces;

namespace GranadaCoder.CustomConfigurationExample.Configuration
{
    public class UsaStateDefinitionConfigurationRetriever : IUsaStateDefinitionConfigurationSectionRetriever
    {
        public static readonly string ConfigurationSectionName = "UsaStateDefinitionConfigurationSectionName";

        public IUsaStateDefinitionConfigurationSection GetIUsaStateDefinitionConfigurationSection()
        {
            UsaStateDefinitionConfigurationSection returnSection = (UsaStateDefinitionConfigurationSection)ConfigurationManager.GetSection(ConfigurationSectionName);
            if (returnSection != null)
            {
                var duplicates = returnSection.IUsaStateDefinitions.GroupBy(i => new { i.UsaStateDefinitionUniqueIdentifier })
                  .Where(g => g.Count() > 1)
                  .Select(g => g.Key);

                if (duplicates.Count() > 1)
                {
                    throw new ArgumentOutOfRangeException("Duplicate UsaStateDefinitionUniqueIdentifier values.", Convert.ToString(duplicates.First().UsaStateDefinitionUniqueIdentifier));
                }

                return returnSection;
            }

            return null;
        }
    }
}


/**/




// file="UsaStateDefinitionConfigurationSection.cs"




using System.Configuration;

using GranadaCoder.CustomConfigurationExample.Configuration.Interfaces;

namespace GranadaCoder.CustomConfigurationExample.Configuration
{
    public class UsaStateDefinitionConfigurationSection : ConfigurationSection, IUsaStateDefinitionConfigurationSection
    {
        [ConfigurationProperty("", IsDefaultCollection = true)]
        public UsaStateDefinitionCollection UsaStateDefinitions
        {
            get
            {
                UsaStateDefinitionCollection coll = (UsaStateDefinitionCollection)base[string.Empty];
                return coll;
            }
        }

        /* Here is the interface property that simply returns the non-interface property from above.  This allows System.Configuration to hydrate the non-interface property, but allows the code to be written (and unit test mocks to be written) against the interface property. */
        public IUsaStateDefinitionCollection IUsaStateDefinitions
        {
            get { return this.UsaStateDefinitions; }
        }
    }
}



/**/




// file="UsaStateDefinitionFinder.cs"




using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;

using GranadaCoder.CustomConfigurationExample.Configuration.Interfaces;

namespace GranadaCoder.CustomConfigurationExample.Configuration
{
    public class UsaStateDefinitionFinder : IUsaStateDefinitionFinder
    {
        private const string ErrorMessageMoreThanOneMatch = "More than item was found with the selection criteria. ({0})";

        private const string ErrorMessageNoMatch = "No item was found with the selection criteria. ({0})";

        public UsaStateDefinitionConfigurationElement FindUsaStateDefinitionConfigurationElement(IUsaStateDefinitionConfigurationSection settings, string usaStateFullName)
        {
            UsaStateDefinitionConfigurationElement returnItem = null;

            if (null != settings && null != settings.IUsaStateDefinitions)
            {
                ICollection<UsaStateDefinitionConfigurationElement> matchingFarmItems;
                matchingFarmItems = settings.IUsaStateDefinitions.Where(ele => usaStateFullName.Equals(ele.UsaStateFullName, StringComparison.OrdinalIgnoreCase)).ToList();

                if (matchingFarmItems.Count > 1)
                {
                    string errorDetails = this.BuildErrorDetails(matchingFarmItems);
                    throw new IndexOutOfRangeException(string.Format(ErrorMessageMoreThanOneMatch, errorDetails));
                }

                returnItem = matchingFarmItems.FirstOrDefault();
            }

            return returnItem;
        }

        public UsaStateDefinitionConfigurationElement FindUsaStateDefinitionConfigurationElement(string usaStateFullName)
        {
            IUsaStateDefinitionConfigurationSection settings = new UsaStateDefinitionConfigurationRetriever().GetIUsaStateDefinitionConfigurationSection();
            return this.FindUsaStateDefinitionConfigurationElement(settings, usaStateFullName);
        }

        public UsaStateDefinitionConfigurationElement FindUsaStateDefinitionConfigurationElementByUniqueId(int id)
        {
            IUsaStateDefinitionConfigurationSection settings = new UsaStateDefinitionConfigurationRetriever().GetIUsaStateDefinitionConfigurationSection();
            return this.FindUsaStateDefinitionConfigurationElementByUniqueId(settings, id);
        }

        public UsaStateDefinitionConfigurationElement FindUsaStateDefinitionConfigurationElementByUniqueId(IUsaStateDefinitionConfigurationSection settings, int id)
        {
            UsaStateDefinitionConfigurationElement returnItem = null;

            if (null != settings && null != settings.IUsaStateDefinitions)
            {
                ICollection<UsaStateDefinitionConfigurationElement> matchingFarmItems;
                matchingFarmItems = settings.IUsaStateDefinitions.Where(ele => id == ele.UsaStateDefinitionUniqueIdentifier).ToList();

                if (matchingFarmItems.Count > 1)
                {
                    string errorDetails = this.BuildErrorDetails(matchingFarmItems);
                    throw new IndexOutOfRangeException(string.Format(ErrorMessageMoreThanOneMatch, errorDetails));
                }

                returnItem = matchingFarmItems.FirstOrDefault();
            }

            return returnItem;
        }

        private string BuildErrorDetails(ICollection<UsaStateDefinitionConfigurationElement> items)
        {
            string returnValue;

            StringBuilder sb = new StringBuilder();

            if (null != items)
            {
                foreach (UsaStateDefinitionConfigurationElement item in items)
                {
                    sb.Append(string.Format("UsaStateFullName='{0}'.", item.UsaStateFullName));
                }
            }

            returnValue = sb.ToString();

            return returnValue;
        }
    }
}



/**/




// file="IUsaStateDefinitionCollection.cs"




using System;
using System.Collections.Generic;

namespace GranadaCoder.CustomConfigurationExample.Configuration.Interfaces
{
    public interface IUsaStateDefinitionCollection : IList<UsaStateDefinitionConfigurationElement>, IEnumerable<UsaStateDefinitionConfigurationElement> /* Implement IEnumerable to allow Linq queries */
    {
        UsaStateDefinitionConfigurationElement this[string name] { get; }

        void Remove(string name);
    }
}



/**/




// file="IUsaStateDefinitionConfigurationSection.cs"




using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace GranadaCoder.CustomConfigurationExample.Configuration.Interfaces
{
    public interface IUsaStateDefinitionConfigurationSection
    {
        IUsaStateDefinitionCollection IUsaStateDefinitions { get; }
    }
}


/**/




// file="IUsaStateDefinitionConfigurationSectionRetriever.cs"




namespace GranadaCoder.CustomConfigurationExample.Configuration.Interfaces
{
    public interface IUsaStateDefinitionConfigurationSectionRetriever
    {
        IUsaStateDefinitionConfigurationSection GetIUsaStateDefinitionConfigurationSection();
    }
}



/**/




// file="IUsaStateDefinitionFinder.cs"




using System;

namespace GranadaCoder.CustomConfigurationExample.Configuration.Interfaces
{
    public interface IUsaStateDefinitionFinder
    {
        UsaStateDefinitionConfigurationElement FindUsaStateDefinitionConfigurationElement(IUsaStateDefinitionConfigurationSection settings, string usaStateFullName);

        UsaStateDefinitionConfigurationElement FindUsaStateDefinitionConfigurationElement(string usaStateFullName);

        UsaStateDefinitionConfigurationElement FindUsaStateDefinitionConfigurationElementByUniqueId(int id);

        UsaStateDefinitionConfigurationElement FindUsaStateDefinitionConfigurationElementByUniqueId(IUsaStateDefinitionConfigurationSection settings, int id);
  }
}



/**/




// file="Program.cs"

using System;
using System.Text;

using GranadaCoder.CustomConfigurationExample.Configuration;
using GranadaCoder.CustomConfigurationExample.Configuration.Interfaces;

using log4net;
using Microsoft.Practices.Unity;

namespace GranadaCoder.CustomConfigurationExample.ConsoleAppOne
{
    public static class Program
    {
        public const int UnhandledExceptionErrorCode = 1;

        private static readonly ILog TheLogger = LogManager.GetLogger(typeof(Program));

        public static int Main(string[] args)
        {
            int returnValue = 0;
            string logMsg = string.Empty;

            try
            {
                //// For future //log4net.Config.XmlConfigurator.Configure();
                //// For future //IUnityContainer container = new UnityContainer();
                //// For future //container.RegisterType<ILog>(new InjectionFactory(x => LogManager.GetLogger(typeof(GranadaCoder.CustomConfigurationExample.ConsoleAppOne.Program))));

                IUsaStateDefinitionConfigurationSectionRetriever retr = new UsaStateDefinitionConfigurationRetriever();
                IUsaStateDefinitionConfigurationSection section = retr.GetIUsaStateDefinitionConfigurationSection();

                IUsaStateDefinitionFinder Finder = new UsaStateDefinitionFinder();
                UsaStateDefinitionConfigurationElement foundElement = Finder.FindUsaStateDefinitionConfigurationElement("Virginia");

                if (null != section)
                {
                    foreach (UsaStateDefinitionConfigurationElement state in section.IUsaStateDefinitions)
                    {
                        Console.WriteLine("state.UsaStateFullName='{0}', state.UsaStateAbbreviation='{1}', state.IsContenential='{2}', state.CountyLabelType='{3}'", state.UsaStateFullName, state.UsaStateAbbreviation, state.IsContenential, state.CountyLabelType);
                        foreach (UsaCountyConfigurationElement county in state.UsaCounties)
                        {
                            Console.WriteLine("county.UsaCountyValue='{0}'", county.UsaCountyValue);
                        }

                        Console.WriteLine("--------------------");
                    }
                }
            }
            catch (Exception e)
            {
                TheLogger.Error(e.Message, e);
                Console.WriteLine("Unexpected Exception : {0}", e.Message);
                returnValue = UnhandledExceptionErrorCode;
            }

            Console.WriteLine("END : {0}", System.Diagnostics.Process.GetCurrentProcess().ProcessName);
            Console.WriteLine(string.Empty);

            Console.WriteLine("Press ENTER to exit");
            Console.ReadLine();

            return returnValue;
        }
    }
}
7
granadaCoder