3

I've searched the site and haven't found exactly what I'm looking for. Close, but no cigar.

Basically I want to have a config section like this:

<configSections>
    <section name="PhoneNotificationsSection" type="Alerts.PhoneAlertConfigSection,Alerts,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null"/>    
</configSections>
<PhoneNotificationsSection>
  <phones>
    <add phone="MyMobile" value="1234567890@vtext.com" />
    <add phone="OtherMobile" value="1234567890@txt.att.com" />
  </phones>
</PhoneNotificationsSection>

Then I'd like to, in my appSettings consuming code, be able to write something like this (pseudo code):

foreach (phone p in phones)
{
   //'phone' attribute is just helpful/descriptive
   DoSomething(p.value);
}

I've done enough research to know I probably need a few of my own classes that implement and/or inherit from certain Configuration classes to make the above code possible. I just haven't found anything that clearly demonstrates this scenario and how to code for it - and when I try to learn the whole .NET configuration world my brain starts to hurt. Anyone have some code like what I'm looking for that they can share?

4

1 回答 1

6

我曾经写过类似的东西,作为 C# 课程的一个例子。在我看来,它主要展示了 .NET 配置子系统是多么糟糕,尽管代码确实有效。我没有根据您的设置对其进行调整,因为很容易引入错误,并且到目前为止 SO 编辑器不验证发布的代码示例;)

一、配置节声明:

    <configSections>
        <section name="passwordSafe"
                 type="Codeworks.PasswordSafe.Model.Configuration.PasswordSafeSection, Codeworks.PasswordSafe.Model, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </configSections>

    <passwordSafe hashAlgorithm="SHA256">
        <users>
            <user name="mm" password="Jok2eyBcFs4y7UIAlCuLix4mLfxw2byfvHfElpmk8d8=" />
            <user name="joe" password="Jok2eyBcFs4y7UIAlCuLix4mLfxw2byfvHfElpmk8d8=" />
        </users>
    </passwordSafe>

为了匹配上面的代码片段,我们首先需要配置部分:

    public class PasswordSafeSection : ConfigurationSection
    {
        #region Static Accessors
        /// <summary>
        /// Gets the configuration section using the default element name.
        /// </summary>
        public static PasswordSafeSection GetSection()
        {
            return GetSection( "passwordSafe" );
        }
        
        /// <summary>
        /// Gets the configuration section using the specified element name.
        /// </summary>
        public static PasswordSafeSection GetSection( string sectionName )
        {
            PasswordSafeSection section = ConfigurationManager.GetSection( sectionName ) as PasswordSafeSection;
            if( section == null )
            {
                string message = string.Format( "The specified configuration section (<{0}>) was not found.", sectionName );
                throw new ConfigurationErrorsException( message );
            }    
            return section;
        }
        #endregion

        #region Configuration Properties
        [ConfigurationProperty( "hashAlgorithm" )]
        public string HashAlgorithm
        {
            get { return (string) this[ "hashAlgorithm" ]; }
            set { this[ "hashAlgorithm" ] = value; }
        }

        [ConfigurationProperty( "users", IsDefaultCollection=true )]
        public UserElementCollection Users
        {
            get { return (UserElementCollection) this[ "users" ]; }
            set { this[ "users" ] = value; }
        }

        public override bool IsReadOnly()
        {
            return false;
        }
        #endregion
    }

我们正在使用一个自定义元素集合,所以让我们也声明一下:

    [ConfigurationCollection( typeof(UserElement), CollectionType = ConfigurationElementCollectionType.BasicMap )]
    public class UserElementCollection : ConfigurationElementCollection
    {
        protected override ConfigurationElement CreateNewElement()
        {
            return new UserElement();
        }

        protected override string ElementName
        {
            get { return "user"; }
        }
        public override ConfigurationElementCollectionType CollectionType
        {
            get { return ConfigurationElementCollectionType.BasicMap; }
        }

        public override bool IsReadOnly()
        {
            return false;
        }

        #region Indexers
        public UserElement this[ int index ]
        {
            get { return BaseGet( index ) as UserElement; }
            set
            {
                if( BaseGet( index ) != null )
                {
                    BaseRemoveAt( index );
                }
                BaseAdd( index, value );
            }
        }

        public new UserElement this[ string name ]
        {
            get { return BaseGet( name ) as UserElement; }
        }
        #endregion

        #region Lookup Methods
        protected override object GetElementKey( ConfigurationElement element )
        {
            UserElement user = element as UserElement;
            return user != null ? user.UserName : "error";
        }

        public string GetKey( int index )
        {
            return (string) BaseGetKey( index );
        }
        #endregion

        #region Add/Remove/Clear Methods
        public void Add( UserElement item )
        {
            BaseAdd( item );
        }

        public void Remove( string name )
        {
            BaseRemove( name );
        }

        public void Remove( UserElement item )
        {
            BaseRemove( GetElementKey( item ) );
        }

        public void RemoveAt( int index )
        {
            BaseRemoveAt( index );
        }

        public void Clear()
        {
            BaseClear();
        }
        #endregion
    }

最后我们需要声明元素集合中使用的自定义元素:

    public class UserElement : ConfigurationElement
    {
        #region Constructors
        public UserElement()
        {
        }

        public UserElement( string userName, string passwordHash )
        {
            UserName = userName;
            PasswordHash = passwordHash;
        }
        #endregion

        #region Configuration Properties
        [ConfigurationProperty( "name", IsKey = true )]
        public string UserName
        {
            get { return (string) this[ "name" ]; }
            set { this[ "name" ] = value; }
        }

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

        public override bool IsReadOnly()
        {
            return false;
        }
        #endregion
    }

现在,所有这些都准备就绪,我们就可以访问配置文件了。我正在使用 Configurator 辅助类来使这稍微不那么麻烦:

    public static class Configurator
    {
        #region AppSettings Helpers
        public static int SplashScreenDisplayTime
        {
            get { return Convert.ToInt32( ConfigurationManager.AppSettings[ "splash.display.msecs" ] ); }
        }
        #endregion

        #region User Helpers
        public static bool TryGetUserPasswordHash( string userName, out string passwordHash )
        {
            UserElement user = GetUser( userName );
            passwordHash = user != null ? user.PasswordHash : null;
            return ! string.IsNullOrEmpty( passwordHash );
        }

        private static UserElement GetUser( string userName )
        {
            SystemConfiguration config = GetConfiguration( ConfigurationUserLevel.PerUserRoamingAndLocal );
            PasswordSafeSection section = config.Sections[ "passwordSafe" ] as PasswordSafeSection;
            return section.Users[ userName ];
        }
        public static void AddUser( string userName, string passwordHash, string encryptionKey )
        {
            SystemConfiguration config = GetConfiguration( ConfigurationUserLevel.PerUserRoamingAndLocal );
            PasswordSafeSection section = config.Sections[ "passwordSafe" ] as PasswordSafeSection;
            UserElement user = section.Users[ userName ];
            if( user == null )
            {
                user = new UserElement( userName, passwordHash, encryptionKey );
                section.Users.Add( user );
                config.Save( ConfigurationSaveMode.Modified );
            }
        }
        public static void RemoveUser( string userName )
        {
            SystemConfiguration config = GetConfiguration( ConfigurationUserLevel.PerUserRoamingAndLocal );
            PasswordSafeSection section = config.Sections[ "passwordSafe" ] as PasswordSafeSection;
            section.Users.Remove( userName );
            config.Save( ConfigurationSaveMode.Modified );
        }
        public static void UpdateUser( string userName, string passwordHash )
        {
            SystemConfiguration config = GetConfiguration( ConfigurationUserLevel.PerUserRoamingAndLocal );
            PasswordSafeSection section = config.Sections[ "passwordSafe" ] as PasswordSafeSection;
            UserElement user = section.Users[ userName ];
            if( user != null )
            {
                user.PasswordHash = passwordHash;
                config.Save( ConfigurationSaveMode.Modified );
            }
        }
        #endregion

        #region Configuration Helpers
        private static SystemConfiguration GetConfiguration( ConfigurationUserLevel userLevel )
        {
            SystemConfiguration config = InitializeConfiguration( userLevel );
            return config;
        }

        private static SystemConfiguration InitializeConfiguration( ConfigurationUserLevel userLevel )
        {    
            SystemConfiguration config = ConfigurationManager.OpenExeConfiguration( userLevel );
            PasswordSafeSection section = config.Sections[ "passwordSafe" ] as PasswordSafeSection;
            if( section == null )
            {
                section = new PasswordSafeSection();
                section.SectionInformation.AllowExeDefinition = ConfigurationAllowExeDefinition.MachineToLocalUser;
                section.SectionInformation.ForceSave = true;
                config.Sections.Add( "passwordSafe", section );
                config.Save( ConfigurationSaveMode.Full );
            }
            return config;
        }
        #endregion
    }

希望这可以帮助。

于 2010-04-02T19:37:21.087 回答