4

I'm implementing a custom .NET ConfigurationSection and need to validate that either one of two conditions are met in the configuration, but I'm not sure how to approach validation against multiple fields.

Basically the condition is, given three KVPs (A, B, and C) either A is required or B and C are required.

Because they realistically are independently optional, I can't mark them as being required, however one of the two conditions is required for a valid configuration.

I've read about writing custom validators on Jon Rista's Decoding the Mysteries of .NET 2.0 Configuration, but these only validate a value of a single field.

Should I just nest these three settings as their own ConfigurationElement and write a validator (or use a CallbackValidator) for the property exposing this section? Or is there a better way to validate against multiple properties?

2 Answers 2

2

How about using the PostDeserialize method?

protected override void PostDeserialize()
{
    base.PostDeserialize();

    if (A == null && (B == null || C == null))
    {
        throw new ConfigurationErrorsException("...");
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

I ended up shoving those three configuration properties into a custom ConfigurationElement and using a CallbackValidator on a property:

public class AlphabetElement : ConfigurationElement
{
    private static ConfigurationPropertyCollection _properties;

    private static ConfigurationProperty _a;
    [ConfigurationProperty("A")]
    public Letter A
    {
        get { return (Letter)base[_a]; }
    }

    private static ConfigurationProperty _b;
    [ConfigurationProperty("B")]
    public Letter B
    {
        get { return (Letter)base[_b]; }
    }

    private static ConfigurationProperty _c;
    [ConfigurationProperty("C")]
    public Letter C
    {
        get { return (Letter)base[_c]; }
    }

    static AlphabetElement()
    {
        // Initialize the ConfigurationProperty settings here...
    }

    public static void Validate(object value)
    {
        AlphabetElement element = value as AlphabetElement;
        if (element == null)
            throw new ArgumentException(
                "The method was called on an invalid object.", "value");

        if (A == null && (B == null || C == null))
            throw new ArgumentException(
                "Big A, little a, bouncing beh... " +
                "The system might have got you but it won't get me.");
    }
}

public class BestBefore : ConfigurationSection
{
    private static ConfigurationPropertyCollection _properties;

    private static ConfigurationProperty _alphabetElement;
    [ConfigurationProperty("alphabet", IsRequired = true)]
    public AlphabetElement Alphabet
    {
        get { return (AlphabetElement)base[_alphabetElement]; }
    }

    static BestBefore()
    {
        _properties = new ConfigurationPropertyCollection();

        _alphabetElement = new ConfigurationProperty(
            "alphabet",
            typeof(AlphabetElement),
            null,
            null,
            new CallbackValidator(
                typeof(AlphabetElement),
                new ValidatorCallback(AlphabetElement.Validate)),
            ConfigurationPropertyOptions.IsRequired);
        _properties.Add(_alphabetElement);
    }
}

And then in the config it would look like:

<bestBefore ...>
    <alphabet B="B" C="C"/>
</bestBefore>

I'll leave this here for posterity.

Crass approves.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.