# &#8220;Is One Of&#8221; and &#8220;Is Not One Of&#8221; validation attributes

**Date:** 2019-12-23  
**Author:** Kees C. Bakker  
**Categories:** .NET Core / C#  
**Tags:** .NET Data Validation  
**Original:** https://keestalkstech.com/is-one-of-and-is-not-one-of-validation-attributes/

![A collection of red buttons that can be used for clothing.](https://keestalkstech.com/wp-content/uploads/2019/12/siora-photography-L06-OsgvNoM-unsplash-scaled.jpg)

---

I love attribute validation! They can be used for a myriad of things. In .NET Core MVC we use them to [validate models](https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-3.1) that come into our controllers. In one of our projects, we kept running into the same situation: we need to validate a value against an array of pre-defined values. That how our `IsOneOfValidationAttribute` was born.

[outline]

## Validation for the win!

Here we see a model with multiple validation attributes. `Required`, `EmailAddress` and `StringLength` are well known (I hope). But now I want to validate that the `Label` *is one a list of preset values from my config*. I also would like to validate that the `Name` is a new repository name.

```cs
using System;
using System.ComponentModel.DataAnnotations;

public class GitHubProvisioningRequest
{
    [Required, Label]
    public string Label { get; set; }

    [Required]
    public string Description { get; set; }

    [Required, TeamIdShouldExist]
    public int TeamId { get; set; }

    [Required]
    public string Tag { get; set; }

    [Required,
     StringLength(100, MinimumLength = 5), 
     ApplicationNameAvailable]
    public string Name { get; set; }

    [Required, EmailAddress]
    public string EmailAddress { get; set; }
}
```

## A base class for "Is One Of"

Our configuration has a string array with valid `Label` values. What if we could use that to validate our property? First we need to create a base class that is the bridge between the validation and the array of valid values. Then we only need to implement the retrieval of said array.

```
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = true)]
public abstract class IsOneOfValidationAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(
        object? value,
        ValidationContext validationContext)
    {
        var values = GetValidValues(validationContext);
        var exists = values.Contains(value);

        if (exists)
        {
            return ValidationResult.Success!;
        }

        var msg = GetInvalidValueMessage(value, values);
        string[] members = validationContext.MemberName is not null
            ? [validationContext.MemberName]
            : [];

        return new ValidationResult(msg, members);
    }

    protected abstract object[] GetValidValues(ValidationContext validationContext);

    protected virtual string GetInvalidValueMessage(
        object? invalidValue,
        object[] validValues
    )
    {
        var valid = string.Join(", ", validValues);
        return $"{invalidValue} is not valid or allowed. Options are: [{valid}]";
    }

    protected virtual TOption GetOption(ValidationContext validationContext)
        where TOption : class, new()
    {
        return validationContext.GetRequiredService().Value;
    }
}
```

Let's implement it for our label to get the values from our configuration:

```
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = true)]
public class LabelAttribute : IsOneOfValidationAttribute
{
    protected override object[] GetValidValues(ValidationContext validationContext) =>
        GetOption(validationContext).Labels;
}
```

## How about "Not One Of"?

What if you need something not to be on a list? You could build the inverse of the `IsOneOfValidationAttribute`, but would that make sense? *Only if you have a small list of items, it may work, and I'm not even sure if you want to show the list of items that are not allowed.* Most of my use cases involve a query to see if something *does not* exist.

Let's make our `ValidationAttribute` class a little nicer to work with:

```
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = true)]
public abstract class SimpleValidationAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(
        object? value,
        ValidationContext validationContext)
    {
        var valid = IsValidValue(value, validationContext);

        if (valid)
        {
            return ValidationResult.Success!;
        }

        var msg = GetInvalidValueMessage(value);
        string[] members = validationContext.MemberName is not null
        ? [validationContext.MemberName]
        : [];

        return new ValidationResult(msg, members);
    }

    protected abstract bool IsValidValue(object? value, ValidationContext validationContext);

    protected virtual string GetInvalidValueMessage(object? invalidValue)
    {
        return $"{invalidValue} is not valid or allowed.";
    }
}
```

Now we can easily implement the validator, without having to worry about messages and members:

```
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = true)]
public class ApplicationNameAvailableAttribute : SimpleValidationAttribute
{
    protected override bool IsValidValue(object? value, ValidationContext validationContext)
    {
        if (value is not string name || string.IsNullOrWhiteSpace(name))
        {
            return false;
        }

        var exists = validationContext
            .GetRequiredService()
            .Exists(name)
            .Result;

        return !exists;
    }
}
```

## Conclusion

With data annotation validations, .NET provides a powerful and extendable mechanism to influence the way objects are validated. But what if you want to use the validation in your business service? I've got you covered, check: [Data Annotation validation with dependency injection in a business service](https://keestalkstech.com/data-annotation-validation-in-a-business-service/).

The code is on GitHub, so check it out: [code gallery / 14. validation](https://github.com/KeesCBakker/keestalkstech-code-gallery/tree/main/14.validation)

## Changelog

- 2025-05-27: Rewrote the article to give a better implementation of the "is not" use case.
- 2025-04-06: Removed the "Validating objects with attributes" section and added it to its own article [Data Annotation validation with dependency injection in a business service](https://keestalkstech.com/data-annotation-validation-in-a-business-service/)
- 2019-09-23: Initial article.
