Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to have arbitrary XML in a custom configuration section?

Tags:

.net

asp.net

Suppose I define a configuration section in an ASP.NET web.config like:

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

And suppose I define MySettings : System.Configuration.ConfigurationSection without unknownProperty:

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

Is there anyway to run the app without getting a Configuration Error complaining about the unrecognized attribute 'unknownProperty'?

Also I'd be fine with a way to catch that error and ignore it if that's possible.

In other words, I want the XML to have an attribute that is not defined in the matching type to which it's bound. Can it be done within the confines of the existing Configuration API?

like image 368
Jason Avatar asked Feb 03 '09 23:02

Jason


2 Answers

I'm pretty sure it is possible, since some built-in sections, like WCF and membership, do this with no error. Does OnDeserializeUnrecognizedAttribute do what you need?

protected override bool OnDeserializeUnrecognizedAttribute(string name, string value){
//don't call base to avoid error
}
like image 132
Daniel Avatar answered Oct 25 '22 16:10

Daniel


I'm using code below to successfully read any XML structure from my web.config ASP file. Note that only reading is supported.

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]__@__mail.domain.com:
        <RawXml><AnElement>Arbitrary string one</AnElement></RawXml>
        ************
        Custom XML for [email protected]__@__mail.domain.com:
         - none -
        ************
        Custom XML for [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 + "__@__" + 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; }
        }


    }
}
like image 45
jfburdet Avatar answered Oct 25 '22 15:10

jfburdet