Почему StringValidator всегда терпит неудачу для настраиваемого раздела конфигурации?

Я создал настраиваемый раздел конфигурации в библиотеке классов С#, наследуя от ConfigurationSection. Я ссылаюсь на библиотеку классов в своем веб-приложении (также С#, ASP.NET), заполняю соответствующие атрибуты, и все отлично работает. Проблема начинается, когда я начинаю добавлять валидаторы.

Например, это свойство:

    [ConfigurationProperty("appCode", IsRequired = true)]
    public string ApplicationCode
    {
        get
        {
            return (string)base["appCode"];
        }
        set
        {
            base["appCode"] = value;
        }
    }

Как это хорошо работает, но как только я добавляю это:

    [StringValidator(MinLength=1)]  

Он бомбит следующую ошибку:

Значение для свойства 'appCode' недопустимо. Ошибка: длина строки должна быть не менее 1 символа.

Я получаю эту ошибку, даже если действительное значение appCode находится в моем файле web.config. Если я удалю валидатор, он отлично работает. Кто-нибудь знает, как обойти это?

Ответ 1

Мне удалось обойти эту проблему, используя явный ConfigurationProperty как ключ к моей коллекции свойств, а не строку, так как в следующей реализации:

public class AssemblyElement : ConfigurationElement
{
    private static readonly ConfigurationProperty _propAssembly;
    private static readonly ConfigurationPropertyCollection _properties;

    static AssemblyElement()
    {
        _propAssembly = new ConfigurationProperty("assembly", typeof(string), null, null, new StringValidator(1), ConfigurationPropertyOptions.IsKey | ConfigurationPropertyOptions.IsRequired);
        _properties = new ConfigurationPropertyCollection();
        _properties.Add(_propAssembly);
    }

    internal AssemblyElement() { }
    public AssemblyElement(string assemblyName)
    {
        this.Assembly = assemblyName;
    }

    [ConfigurationProperty("assembly", IsRequired = true, IsKey = true, DefaultValue = "")]
    [StringValidator(MinLength = 1)]
    public string Assembly
    {
        get { return (string)base[_propAssembly]; }
        set { base[_propAssembly] = value; }
    }

    internal AssemblyName AssemblyName
    {
        get { return new AssemblyName(this.Assembly); }
    }

    protected override ConfigurationPropertyCollection Properties
    {
        get { return _properties; }
    }
}

(Этот код сильно моделируется после кода, отраженного от класса элементов AssemblyInfo. Мне все еще жаль, что мне не пришлось дублируйте мои проверки, но, по крайней мере, этот код позволяет мне указать пустое значение по умолчанию, в то же время требуя ввода значения.)

Ответ 2

Кажется, что ответ действительно есть, потому что у них нет значения по умолчанию. Кажется странным, поэтому, если у кого-то есть лучший ответ, дайте мне знать, и я приму их.

Ответ 3

У меня была эта проблема некоторое время, тогда я понял, что валидаторы не предназначены для создания атрибута или элементов, необходимых для их проверки.

Чтобы сделать требуемое свойство, вам нужно использовать IsRequired и ConfigrationPropertyOptions.IsRequired, например.

[ConfigurationProperty("casLogoutUrl", DefaultValue = null, IsRequired = true, Options = ConfigurationPropertyOptions.IsRequired)]
[StringValidator(MinLength=10)]

Или (если используется api)

ConfigurationProperty casLoginUrl = new ConfigurationProperty("casLoginUrl", typeof(string), null, null, new StringValidator(1), ConfigurationPropertyOptions.IsRequired);

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

Это также работает с элементами, чтобы сделать дочерние элементы требуемыми. Например. если вы создаете настраиваемый ConfigSection с дочерними элементами и вам нужен дочерний элемент. Однако, если вы создадите CustomValidator, который наследуется от ConfigurationValidatorBase, вам нужно использовать ElementInformation.IsPresent, например.

            public override void Validate(object value)
        {
            CredentialConfigurationElement element = (CredentialConfigurationElement)value;
            if (!element.ElementInformation.IsPresent)
                return; //IsRequired is handle by the framework, don't throw error here  only throw an error if the element is present and it fails validation.
            if (string.IsNullOrEmpty(element.UserName) || string.IsNullOrEmpty(element.Password))
                throw new ConfigurationErrorsException("The restCredentials element is missing one or more required Attribute: userName or password.");
        }

Короче говоря, вам не хватает части параметров вашего атрибута, чтобы сделать это необходимым, и не нужно использовать StringValidator (MinLength = 1), чтобы сделать это необходимым. Фактически StringValidator (MinLength = 1) полностью избыточен. Если вы сделаете так, чтобы MinLength = 1 завершилось с ошибкой без обязательного отказа, потому что если он присутствует, он должен иметь длину не менее 1 символа.

Измените свой валидатор на

[ConfigurationProperty("appCode", IsRequired = true, Options=ConfigurationPropertyOptions.IsRequired)]

Затем нажмите кнопку проверки строки.

Ответ 4

Решение StringValidator может быть выполнено любым из следующих способов:

  • Удаление аргумента MinLength
  • Настройка MinLength= 0
  • Удаление атрибута StringValidator
  • Добавление DefaultValue в атрибут ConfigurationProperty

Идеальное определение свойства похоже на:

[ConfigurationProperty("title", IsRequired = true, DefaultValue = "something")]
[StringValidator(InvalidCharacters = "[email protected]#$%^&*()[]{}/;’\"|\\"
  , MinLength = 1
  , MaxLength = 256)]
public string Title
{
    get { return this["title"] as string; }
    set { this["title"] = value; }
}