visual studio microsoft español descargar community c# configuration configuration-files configurationsection

c# - microsoft - visual studio installer



¿Implementación correcta de una sección de configuración personalizada con colecciones anidadas? (2)

En una aplicación web, quiero poder definir alguna asignación usando una sección de configuración como esta:

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

Estoy luchando para lograr este objetivo, especialmente al definir mi colección de colecciones. ¿Cuáles son las clases que necesito implementar para lograr esto?

Actualmente, tengo:

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

Pero, esto no está funcionando como se esperaba.


Debido a la popularidad de mi otra respuesta, escribí un ejemplo personalizado usando Usa-States y Usa-Counties. Un ejemplo que es un poco más fácil de seguir.

También agregué algunas interfaces, lo que permite burlas para las pruebas unitarias, algo de lo que no era plenamente consciente cuando escribí esta respuesta original.

También agregué poner la configuración en su propio archivo, por lo que su archivo app.config no tiene mil millones de elementos.

También agregué un "Finder" para encapsular la búsqueda de un elemento específico en la colección.

También agregué un Enum personalizado.

"UsaStatesSettings.config" (asegúrese de marcar esto como "copiar siempre")

<?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>

El "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>

y ahora el "código"

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


Finalmente encontré el ejemplo de este tipo. Fue codificado y funcionó desde el primer momento.

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

Voy a pegar el código aquí ... solo porque no puedo soportarlo cuando alguien dice "Tu respuesta está aquí", y el enlace está muerto.

Primero prueba su sitio web y deja un "gracias" si funciona.

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

Y el código de configuración

<?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>

Y luego la "llamada"

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