Код, необходимый для использования foreach в моих собственных пользовательских настройках - PullRequest
2 голосов
/ 02 апреля 2010

Я искал сайт и не нашел именно то, что ищу. Близко, но без сигары.

В основном я хочу иметь раздел конфигурации, подобный этому:

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

Тогда я бы хотел, чтобы в моем коде, использующем appSettings, можно было написать что-то вроде этого (псевдокод):

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

Я провел достаточно исследований, чтобы понять, что мне, вероятно, нужно несколько моих собственных классов, которые реализуют и / или наследуют определенные классы конфигурации, чтобы сделать возможным приведенный выше код. Я просто не нашел ничего, что четко демонстрирует этот сценарий и как его кодировать - и когда я пытаюсь изучить весь мир конфигурации .NET, мой мозг начинает болеть. У кого-нибудь есть код, похожий на то, что я ищу, которым он может поделиться?

1 Ответ

5 голосов
/ 02 апреля 2010

Однажды я написал нечто подобное, например, для курса на 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
}

Надеюсь, это поможет.

...