用.NET 2.0 Enterprise Library庫讀寫App.config文件(3)

Enterprise Library Configuration Helpers

The Enterprise Library for .NET 2.0 has made it a lot easier to use the System.Configuration classes.More info how to configure the new application blocks you can  be found in another article. Lets suppose you want to store a collection of strongly typed named objects in our App.Config file. In this example it is a plugin configuration file where a list of plugins can be added and the selected plugin be started. The config file could look like this:

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

<configuration>

  <configSections>

    <section name="PluginConfiguration" type="EntlibInjection.PluginManagerConfiguration, EntlibInjection, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />

  </configSections>

 

  <PluginConfiguration name="Configured Plugins" SelectedPlugin="2D">

    <Plugins>

      <!-- type="EntlibInjection.PluginData, EntlibInjection, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" -->

      <add name="2D" cfgfile="2D.config" plugintype="EntlibInjection.TwoD, EntlibInjection, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" type=""/>

      <add name="3D" plugintype="ThreeDPlugin.ThreeD, ThreeDPlugin, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" type=""/>

    </Plugins>

  </PluginConfiguration>

 

</configuration>


We want a PluginConfiguration class which selects a plugin and contains a list of plugins. To make it work we first need to define the PluginManagerConfiguration class. We need the Enterprise Library  only for the 
IConfigurationSource interface to load our config from other files than App.config or even an SQL server.

PluginManagerConfiguration.cs

using System;

using System.Configuration;

using System.ComponentModel;

using System.Collections.Generic;

using System.Text;

using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;

 

namespace EntlibInjection

{

    public class PluginManagerConfiguration : SerializableConfigurationSection

    {

            private const string selectedPlugin = "SelectedPlugin";

            private const string PluginCollectionProperty = "Plugins";

            private const string nameProperty = "name";

 

 

            /// <summary>

            /// Configuration section name for Plugin Configuration

            /// </summary>

            public const string SectionName = "PluginConfiguration";

 

 

            public PluginManagerConfiguration()

            {

 

            }

 

            /// <summary>

            /// Gets the configured plugin settings section in the configuration source.

            /// </summary>

            /// <param >The <see cref="IConfigurationSource"/> to get the section from.</param>

            /// <returns>The plugin configuration.</returns>

            public static PluginManagerConfiguration GetPluginSettings(IConfigurationSource configurationSource)

            {

               return (PluginManagerConfiguration)configurationSource.GetSection(PluginManagerConfiguration.SectionName);

            }

 

            /// <summary>

            /// Get/Set the selected plugin

            /// </summary>

           [ConfigurationProperty(selectedPlugin, IsRequired = true)]

            public string SelectedPlugin

            {

                  get

                  {

                     return (string)this[selectedPlugin];

                  }

                  set

                  {

                     this[selectedPlugin] = value;

                  }

            }

 

        /// <summary>

        /// Name of the configuration node.

        /// </summary>

        [ConfigurationProperty(nameProperty)]

        [EditorBrowsable(EditorBrowsableState.Never)]

        public string Name

        {

            get

            {

                return (string)this[nameProperty];

            }

            set

            {

                this[nameProperty] = value;

            }

        }

 

            /// <summary>

            /// This property contains a list of plugins

            /// </summary>

            [ConfigurationProperty(PluginCollectionProperty)]

            public PluginDataCollection Plugins

            {

                  get

                  {

                      return (PluginDataCollection)base[PluginCollectionProperty];

                  }

            }

 

    }

}


After the definition of the Configuration Section we need the collection class which contains a list of elements. If you want a list of strongly typed data elements in the config file you can use the PolymorphicConfigurationElementCollection<T> generic which is introduced by the Enterprise Library. This class was specifically designed to store lists of the following form:
<SectionName>

      <add name="blah" type="PluginData strongly typed " xxx="xxxx" xxx="xxxx" .../>

</SectionName>


You have to derive from
PolymorphicConfigurationElementCollection and implement the RetrieveElementConfigurationElementType where you retrieve the data type which is responsible for the ser/deserialization of the other attributes of this node. Error handling code has been omitted. Please have a look at e.g. the Logging Application Block of Entlib to see the correct error handling.
 
PluginDataCollection.cs

using System;

using System.Collections.Generic;

using System.Text;

using System.Xml;

using System.Configuration;

using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;

 

 

namespace EntlibInjection

{

    public class PluginDataCollection : PolymorphicConfigurationElementCollection<PluginData>

    {

            /// <summary>

            /// Returns the <see cref="ConfigurationElement"/> type to created for the current xml node.

            /// </summary>

            /// <remarks>

            /// The <see cref="PluginData"/> include the configuration object type as a serialized attribute.

            /// </remarks>

            /// <param >

            protected override Type RetrieveConfigurationElementType(XmlReader reader)

            {

                 return typeof(PluginData);

            }

 

    }

}

I have simplified the RetrieveConfigurationElementType a lot compared to the normally used strongly typed name which should be specified to allow versioning of you configuration node data types. Please do NOT use this shortcut in production environments. If you do not want strong names for your data types then the PolymorphicConfigurationElementCollection<xxx> is not the right choice for your problem. Instead a direct derivate of ConfigurationElementCollection is the better alternative for you. Do not ask me how to figure out with which version of PluginData you App.Config was created when you do not use strong names for your data types.This can be an important issue if you plan e.g. to create configuration converters from one version to the next. Please have a look at the Logging Block code e.g. TraceListenerDataCollection how the PolymorphicConfigurationElementCollection<xxx> is correctly implemented. Ok so much for versioning. Now we can create our PluginData class which contains the plugin data type and an external config file which contains the plugin configuration. If it is not specified we assume the the plugin configuration is located in the App.config file. This can be  implemented by switching from SystemConfigurationSource to FileConfiguratonSource and put the plugin config file into it.

 PluginData.cs

using System;

using System.ComponentModel;

using System.Collections.Generic;

using System.Text;

using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;

using System.Configuration;

 

 

namespace EntlibInjection

{

    public class PluginData : NameTypeConfigurationElement

    {

        public const string PluginTypeProperty = "plugintype";

        public const string PluginConfigProperty = "cfgfile";

 

 

          private static IDictionary<string, string> emptyAttributes = new Dictionary<string, string>(0);

 

     

            public PluginData()

            {

            }

 

            protected PluginData(string name, Type PluginType)

                  : base(name, PluginType)

            {

                this.PluginType = this.GetType();

            }

 

 

 

            [ConfigurationProperty(PluginConfigProperty, DefaultValue="", IsRequired = false)]

            public string ConfigFile

            {

                  get

                  {

                     return (string)this[PluginConfigProperty];

                  }

                  set

                  {

                     this[PluginConfigProperty] = value;

                  }

            }

 

 

            [ConfigurationProperty(PluginTypeProperty, IsRequired= true)]

            [TypeConverter(typeof(AssemblyQualifiedTypeNameConverter))]

            public Type PluginType

            {

                  get

                  {

                        return (Type)this[PluginTypeProperty];

                  }

                  set

                  {

                        this[PluginTypeProperty] = value;

                  }

            }

    }

}

 

To load the configuration form a config file you can use the FileConfigurationSource from the Enterprise Library and you are ready to rockn roll.

         FileConfigurationSource configurationSource = new FileConfigurationSource(“2D.config”);

         PluginManagerConfiguration.GetPluginSettings(configurationSource);

There are many new things within the System.Configuration namespace which this article tries to show you how the can be used. I hope this article gives you enough starting points to jump up on the .NET 2.0 wagon and the new Enterprise Library. One last thing: User settings are not supported by the Enterprise Library. But you can fake this by creating a config file in %APPDATA%\MyEntlibApp\<MyEntlibApp Assembly Version>\User.config and load it from there. To make this work you need a loaded user profile which is not always present e.g.  System Service. In this case you need to load some trusted user profile to make it work.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章