Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Custom Validation Attribute – Contains

0.00/5 (No votes)
3 Aug 2015 1  
Custom validation attribute - contains

Situation

I needed to create a custom validation attribute. More specifically, contains attribute.

I have a a few properties where I need to know if input value is valid and valid = value is contained in a list of allowed values.

For example:

property: title

allowed values: Mr, Mrs, Miss, Dr, etc.

So I created my own custom validation attribute:

public class ContainsValidatorAttribute : ValidationAttribute
{
    public string[] AcceptedValues { get; set; }
    public override bool IsValid(object value)
    {
        string strValue = value as string;
        if (!AcceptedValues.Contains(strValue))
        {
            return false;
        }
        return true;
    }
}
 
//Usage:
[ContainsValidator(AcceptedValues = new[] { "Mr", "Mrs", "Miss", "Ms", "Dr" }, 
ErrorMessage = "Not a valid title")]
public string Title { get; set; }

This works great, but then I thought it would be much better to have all the values in one place rather than write them right into an attribute.

So I created a static helper class with all allowed values:

public static class ValidatorHelper
{
    public static readonly string[] Titles = { "Mr", "Mrs", "Miss", "Ms", "Dr" };
    public static readonly string[] SmokerStatus = { "Yes", "No", "Ex"};
}

However, this will not work, because you cannot pass a static value into an attribute like this:

[ContainsValidator([__strong__]AcceptedValues = ValidatorHelper.Titles, ErrorMessage = "Not a valid title")]
public string Title { get; set; }

This will end with error even if you make string[] AcceptedValues static.

My Solution

public class ContainsValidatorAttribute : ValidationAttribute
{
    public string AcceptedValuesKey { get; set; }
    public override bool IsValid(object value)
    {
        var strValue = (string) value;
        string[] values;
        ValidatorHelper.Dictionary.TryGetValue(AcceptedValuesKey, out values);
        return values != null && values.Contains(strValue);
    }
}

and store values in a dictionary:

public static class ValidatorHelper
{
    public static readonly string[] Titles = { "Mr", "Mrs", "Miss", "Ms", "Dr" };
    public static readonly string[] SmokerStatus = { "Yes", "No", "Ex"};

    public const string TitleKey = "Title";
    public const string SmokerStatusKey = "Smoke";

    public static Dictionary<string, string[]> Dictionary = new Dictionary<string, string[]>()
    {
        {TitleKey, Titles},
        {SmokerStatusKey, SmokerStatus},
    };
}

Now you can store all values in one place and use dictionary to get allowed values.

[ContainsValidator(AcceptedValuesKey = ValidatorHelper.TitleKey, ErrorMessage = "Not a valid title")]
public string Title { get; set; }

And here is the unit test.

[TestClass]
    public class ContainsAttributeTest
    {
        [TestMethod]
        public void TestContainsAttribute()
        {
            var attr = new ContainsValidatorAttribute();
            attr.AcceptedValuesKey = ValidatorHelper.TitleKey;
            var result = attr.IsValid("Mr");

            Assert.AreEqual(true, result);
        }

        [TestMethod]
        public void TestContainsAttributeFailNull()
        {
            var attr = new ContainsValidatorAttribute();
            attr.AcceptedValuesKey = "invalid key";
            var result = attr.IsValid("Mr");

            Assert.AreEqual(false, result);
        }

        [TestMethod]
        public void TestContainsAttributeFailInvalidValue()
        {
            var attr = new ContainsValidatorAttribute();
            attr.AcceptedValuesKey = ValidatorHelper.TitleKey;
            var result = attr.IsValid("invalid");

            Assert.AreEqual(false, result);
        }
    }

Summary

This is not an ideal solution, but it is the only one I was able to come up with.

If you have any ideas on how to improve this solution, I would be grateful if you could share it with us in the comments.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here