section net name mvc example custom create configsections asp c# configuration app-config configuration-files

c# - net - Cómo implementar una ConfigurationSection con una ConfigurationElementCollection



custom section name (5)

Este es un código genérico para la recopilación de configuraciones:

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

Después de que tenga GenericConfigurationElementCollection , puede usarlo simplemente en la sección de configuración (este es un ejemplo de mi 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"]; } } }

El elemento de configuración es config aquí:

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

El archivo de configuración se vería así:

<?xml version="1.0" encoding="utf-8" ?> <dispatcherConfigurationSection> <eventsDispatches> <add name="Log" ></add> <add name="Notification" ></add> <add name="tester" ></add> </eventsDispatches> </dispatcherConfigurationSection>

Espero que ayude!

Estoy tratando de implementar una sección de configuración personalizada en un proyecto y sigo corriendo contra excepciones que no entiendo. Espero que alguien pueda completar los espacios en blanco aquí.

Tengo App.config que se ve así:

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

Tengo un elemento ServiceConfig definido así:

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

Y tengo una ServiceCollection definida así:

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

La parte que me falta es qué hacer para el controlador. Originalmente, traté de implementar un IConfigurationSectionHandler pero encontré dos cosas:

  1. no funcionó
  2. está desaprobado.

Ahora estoy completamente perdido en lo que debo hacer para poder leer mis datos desde config. Cualquier ayuda por favor!


Intente heredar de ConfigurationSection . Esta publicación del blog de Phil Haack tiene un ejemplo.

Confirmado, según la documentación de IConfigurationSectionHandler :

En .NET Framework versión 2.0 y superior, en su lugar debe derivar de la clase ConfigurationSection para implementar el manejador de sección de configuración relacionado.


La respuesta anterior es correcta, pero también te daré todo el código.

Tu app.config debería verse así:

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

Sus clases ServiceConfig y ServiceCollection permanecen sin cambios.

Necesitas una nueva clase:

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

Y eso debería hacer el truco. Para consumirlo puedes usar:

ServiceConfigurationSection serviceConfigSection = ConfigurationManager.GetSection("ServicesSection") as ServiceConfigurationSection; ServiceConfig serviceConfig = serviceConfigSection.Services[0];


Si está buscando una sección de configuración personalizada como la siguiente

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

entonces puede usar mi implementación de la sección de configuración para comenzar agregue referencia de ensamblado de System.Configuration a su proyecto

Mira los elementos anidados que utilicé, el primero es Credenciales con dos atributos, así que vamos a agregarlo primero

Elemento de credenciales

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

PrimaryAgent y SecondaryAgent

Ambos tienen los mismos atributos y parecen una Dirección a un conjunto de servidores para una conmutación por error primaria y por lo que solo necesitas crear una clase de elemento para los siguientes:

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

Explicaré cómo usar dos elementos diferentes con una clase más adelante en esta publicación, omita el SiteId ya que no hay diferencia. Solo tiene que crear una clase igual que la anterior con una sola propiedad. veamos cómo implementar la colección Lanes

se divide en dos partes, primero debe crear una clase de implementación de elementos, luego debe crear una clase de elemento de colección

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 }

puede observar que un atributo de LanElement es una enumeración y si intenta utilizar cualquier otro valor en la configuración que no está definida en la aplicación Enumeration arrojará una System.Configuration.ConfigurationErrorsException al inicio. Ok, pasemos a la definición de colección

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

puede observar que he configurado AddItemName = "Lane" , puede elegir lo que quiera para su elemento de entrada de colección, prefiero usar "agregar" el predeterminado, pero lo cambié solo por el bien de esta publicación.

Ahora que todos nuestros Elementos anidados se han implementado, ahora debemos agregar todos aquellos en una clase que tiene que implementar 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; } } }

Ahora puede ver que tenemos dos propiedades con el nombre PrimaryAgent y SecondaryAgent Ambas tienen el mismo tipo. Ahora puede entender fácilmente por qué teníamos solo una clase de implementación contra estos dos elementos.

Antes de que pueda usar esta sección de configuración recientemente inventada en su app.config (o web.config) solo tiene que decirle a la aplicación que ha inventado su propia sección de configuración y darle un poco de respeto, para hacerlo debe agregar las siguientes líneas en app.config (puede ser justo después del inicio de la etiqueta raíz).

<configSections> <section name="CustomApplicationConfig" type="MyNameSpace.CustomApplicationConfigSection, MyAssemblyName" /> </configSections>

NOTA: MyAssemblyName debería estar sin .dll, por ejemplo, si el nombre del archivo de ensamblado es myDll.dll y luego usa myDll en lugar de myDll.dll

para recuperar esta configuración use la siguiente línea de código en cualquier lugar de su aplicación

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

Espero que la publicación anterior te ayude a comenzar con un tipo de secciones de configuración personalizada un poco complicadas.

Happy Coding :)

**** Editar **** Para habilitar LINQ en LaneConfigCollection , debe implementar IEnumerable<LaneConfigElement>

Y agregue la siguiente implementación de GetEnumerator

public new IEnumerator<LaneConfigElement> GetEnumerator() { int count = base.Count; for (int i = 0; i < count; i++) { yield return base.BaseGet(i) as LaneConfigElement; } }

para las personas que todavía están confundidas acerca de cómo funciona realmente el rendimiento, lee este bonito artículo

Dos puntos clave tomados del artículo anterior son

realmente no termina la ejecución del método. yield return pausa la ejecución del método y la próxima vez que lo llame (para el siguiente valor de enumeración), el método continuará ejecutándose a partir de la última llamada de devolución de rendimiento. Suena un poco confuso, creo ... (Shay Friedman)

El rendimiento no es una característica del tiempo de ejecución .Net. Es solo una característica del lenguaje C # que se compila en código IL simple mediante el compilador C #. (Lars Corneliussen)


Una alternativa más fácil para aquellos que prefieren no escribir todo el texto estándar de configuración manualmente ...

1) Instalar Nerdle.AutoConfig desde NuGet

2) Defina su tipo ServiceConfig (ya sea una clase concreta o solo una interfaz, cualquiera lo hará)

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

3) Necesitará un tipo para mantener la colección, por ejemplo

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

4) Agregue la sección de configuración de esa manera (note el nombramiento de camelCase)

<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) Mapa con AutoConfig

var services = AutoConfig.Map<IServiceCollectionConfiguration>();