2009-02-03 16 views
8

Supongamos que defino una sección de configuración en un web.config ASP.NET como:¿Es posible tener XML arbitrario en una sección de configuración personalizada?

<?xml version="1.0"?> 
<configuration> 
    <configSections> 
    <sectionGroup name="system.web"> 
     <section name="MySettings" type="MyCompany.MyProject.Configuration.MySettings" allowLocation="true" allowDefinition="Everywhere" restartOnExternalChanges="false" /> 
    </sectionGroup> 
    </configSections> 
    <system.web> 
    <MySettings knownProperty="some_value" unknownProperty="other_value" /> 
    </system.web> 
</configuration> 

Y supongo defino MySettings : System.Configuration.ConfigurationSectionsinunknownProperty:

using System.Configuration; 

namespace MyCompany.MyProject.Configuration 
{ 
    public class MySettings : ConfigurationSection 
    { 
     public MySettings() { } 

     [ConfigurationProperty("knownProperty", DefaultValue="default_value")] 
     public string KnownProperty 
     { 
     get { return (string)this["knownProperty"]; } 
     } 

     // I'm not defining unknownProperty here on purpose 
    } 
} 

¿Hay alguna forma de ejecutar la aplicación sin Obteniendo un Error de configuración quejándose del atributo no reconocido 'unknownProperty'?

También estaría bien con una forma de detectar ese error e ignorarlo si eso es posible.

En otras palabras, quiero que el XML tenga un atributo que no está definido en el tipo coincidente al que está vinculado. ¿Se puede hacer dentro de los límites de la API de configuración existente?

Respuesta

6

Estoy bastante seguro de que es posible, ya que algunas secciones integradas, como WCF y membresía, lo hacen sin ningún error. ¿OnDeserializeUnrecognizedAttribute hace lo que necesita?

protected override bool OnDeserializeUnrecognizedAttribute(string name, string value){ 
//don't call base to avoid error 
} 
2

Estoy utilizando el código de abajo para leer con éxito cualquier estructura XML de mi web.config archivo ASP. Tenga en cuenta que solo lectura es compatible.

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Configuration; 
using System.Xml; 

/* In this file, you'll find an example on how to store an custom section in an .Net 
* application configuration file that can contains arbitrary XML that can be retrieved 
* as a raw System.Xml.XmlNode. In the specific example below, I wanted to be able to 
* store arbitrary information about POP servers I retrieve email from, without having to 
* write specific Configuration data for each different case. This is usefull for quick 
* application development. 
*/ 

/* Config file sample : 
<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <configSections> 
     <sectionGroup name="MySection"> 
      <section name="MailRetrieve" type="ConsoleApplication1.MailRetrieveConfigurationSection, ConsoleApplication1"/> 
     </sectionGroup> 
    </configSections> 


    <MySection> 
     <MailRetrieve> 
      <Hosts> 
       <add username="[email protected]" popserver="mail.domain.com" password="1234"> 
        <RawXml> 
         <AnElement>Arbitrary string one</AnElement> 
        </RawXml> 
       </add> 
       <add username="[email protected]" popserver="mail.domain.com" password="1234"></add> 
       <add username="[email protected]" popserver="mail.domain.com" password="1234" > 
        <RawXml> 
         <OtherElement>Arbitrary string two</OtherElement> 
        </RawXml> 
       </add> 
      </Hosts> 
     </MailRetrieve> 
    </MySection> 
    </configuration> 
*/ 

/* Sample output : running the piece of code below, using config file above, gives : 

     Custom XML for [email protected][email protected]__mail.domain.com: 
     <RawXml><AnElement>Arbitrary string one</AnElement></RawXml> 
     ************ 
     Custom XML for [email protected][email protected]__mail.domain.com: 
     - none - 
     ************ 
     Custom XML for [email protected][email protected]__mail.domain.com: 
     <RawXml><OtherElement>Arbitrary string two</OtherElement></RawXml> 
     --> Found OtherElement ! 
     ************ 
     Hit a key to finish 

*/ 

namespace ConsoleApplication1 { 
    class Program { 
     static void Main(string[] args) { 

      MailRetrieveConfigurationSection config = (MailRetrieveConfigurationSection) 
        (System.Configuration.ConfigurationManager.GetSection("MySection/MailRetrieve")); 


      if (config != null) { 
       foreach (HostConfigElement cfg in config.Hosts) { 
        System.Console.WriteLine("Custom XML for " + cfg.PopMailboxID + ":"); 
        if (cfg.RawXml.Node != null) { 
         System.Console.WriteLine(cfg.RawXml.Node.OuterXml); 
         if (cfg.RawXml.Node.SelectSingleNode("OtherElement") != null) { 
          Console.WriteLine("--> Found OtherElement !"); 
         } 
        } 
        else { 
         System.Console.WriteLine(" - none -"); 
        } 
        System.Console.WriteLine("************");      
       } 
      } 
      System.Console.WriteLine("Hit a key to finish"); 
      System.Console.ReadKey(); 
     } 
    } 


    public class MailRetrieveConfigurationSection : ConfigurationSection { 
     [ConfigurationProperty("Hosts")] 
     public MailRetrieveHostsConfigCollection Hosts { 
      get { 
       return ((MailRetrieveHostsConfigCollection)(base["Hosts"])); 
      } 
     } 
    } 

    [ConfigurationCollectionAttribute(typeof(HostConfigElement))] 
    public class MailRetrieveHostsConfigCollection : ConfigurationElementCollection { 
     protected override ConfigurationElement CreateNewElement() { 
      return new HostConfigElement(); 
     } 

     /// <summary> 
     /// We want to have only one configuration per POP mailbox, wich key is host+username 
     /// If more configuration is wanted, one must introduce an "id" attribute. 
     /// </summary>   
     protected override object GetElementKey(ConfigurationElement element) { 
      return ((HostConfigElement)(element)).PopMailboxID; 
     } 

     public void Add(HostConfigElement element) { 
      this.BaseAdd(element); 
     } 

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

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


     public HostConfigElement this[int idx] { 
      get { return (HostConfigElement)this[idx]; } 
     } 
    } 


    public class MyCustomConfigurationElement : ConfigurationElement { 

     public XmlNode Node = null; 

     protected override void DeserializeElement(XmlReader reader, bool serializeCollectionKey) {      
      XmlDocument doc = new XmlDocument(); 
      doc.Load(reader.ReadSubtree()); 
      Node = doc.FirstChild; 
     }   
    } 

    public class HostConfigElement : ConfigurationElement { 

     /// <summary> 
     /// A POP3 mailbox is distinguished from another using the server name and user name. 
     /// </summary> 
     public string PopMailboxID { 
      get { 
       return Username + "[email protected]__" + PopServer; // 
      } 
     } 


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

     [ConfigurationProperty("username", IsRequired = true, Options = ConfigurationPropertyOptions.IsKey)] 
     public string Username { 
      get { return (string)this["username"]; } 
      set { this["username"] = value; } 
     } 

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


     [ConfigurationProperty("RawXml", IsRequired=false)] 
     public MyCustomConfigurationElement RawXml { 
      get { return (MyCustomConfigurationElement)this["RawXml"]; } 
      set { this["RawXml"] = value; } 
     } 


    } 
} 
1

A raíz de la respuesta de Daniel: -

protected override bool OnDeserializeUnrecognizedAttribute(string name, string value) { 
    try { 
     var lProperty = new ConfigurationProperty(name, typeof(String)); 
     Properties.Add(lProperty); 
     base[name] = value; 
     return true; 
    } catch { 
     return false; 
    } 
} 
Cuestiones relacionadas