Creating a Server Side Data Annotations CustomValidator 
Tags: dotnet, csharp
Published: 2022-01-10 10:18:03

>This tutorial requires some previous knowledge of the Data Annotations Namespace , along with .NET applications. 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bt2n57qx4wcrqdrzczsj.gif)
##Data Annotations , an overview
Data Annotations allow you to configure class models and add various attributes that specify how the property it is applied to should be treated e.g.  
* Required
* MaxLength 
* MinLength
* Display (Name ,Order, Description etc)
* Range
* RegularExpression
* Compare

These are just a few of the options available. 
You can read more on Data Annotations [Here](https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations?view=net-6.0)

##Why Write Your Own ? 
Well its simple really - while the list of options is expansive we are often required to implement restrictions that don't exist.

Consider a common form to change passwords. It would require your existing password and the new password. Often you see a requirement that the new password is not the same as the current password. Or maybe just that the password is not the same as the Username. 
Data Annotations has an option to make sure that two properties are the same using `Compare` - you could verify a user enters a password and reenters to confirm. But it does not have the opposite to this to prevent two properties being the same. 

We will use a `CustomValidator` to build this option. 



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6r3gfqxx6nt2olwt10b1.png)

##Get Started
Create a new class file. Within this import the below namespaces to get started: 
```csharp
using System.Reflection;
using System.ComponentModel.DataAnnotations;
```

Next create a new class named NotEqualTo and inherit from `ValidationAttribute` and override the `IsValid` method with our own. We'll also need to create the constructor that will accept the __name__ of the form property we need to compare to. 

```csharp
   private readonly string _other;
   public NotEqualto (string other)
   {
      // This is the name of the property to compare to 
      _other = other;
   }

 protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        { 
    .... 
}
```

Now we need to implement the logic in the IsValid method. The method takes two parameters 
1. object value  -  This is the value entered by the user for that field.
2. ValidationContext validationContext - This is the instance object for our validation, and we can use this to access the other properties. 

The key to all this is the validationContext. We need to use it in conjunction with the string we pass to the constructor. 

```csharp
// Get the Other Property
var otherProperty = validationContext.ObjectType.GetProperty(_other);
//Now use it to get the Value 
var otherValue = otherProperty.GetValue(validationContext.ObjectInstance, null);
```   

Now this is all well and good but we should add in some checks in case the property doesn't exist and return an error message using the `ValidationResult` like so :
```csharp
// Get the Other Property
var otherProperty = validationContext.ObjectType.GetProperty(_other);
//Check if it exists
            if (otherProperty == null)
            {
                return new ValidationResult( string.Format("Property {0} not found", _other) );
            }
//Now use it to get the Value 
var otherValue = otherProperty.GetValue(validationContext.ObjectInstance, null);
```

Then all we need to do is compare the values of the two properties, and if they are equal then set the `ValidationResult` to return an error.

```csharp
if (object.Equals(value, otherValue))
            {
                // We can access the Display name like so 
                var otherDisplayAttribute = otherProperty.GetCustomAttribute(typeof(DisplayAttribute)) as DisplayAttribute;
                string otherName = "";
                if (otherDisplayAttribute != null)
                {
                    otherName = otherDisplayAttribute.Name;
                }
                else
                {
                    otherName = otherProperty.Name;
                }
                // Set the Error Message if the two values are the same.
                this.ErrorMessage = $"{validationContext.DisplayName} cannot be the same as {otherName}";
                return new ValidationResult(this.ErrorMessage);
            }
```

Simple enough. 

##Apply the Validator

You can apply the Custom validator like you would any other Data Annotation ! e.g. `[NotEqualto("name_of_other_property")]` . The name of the property to compare to must be passed in as well.

A more detailed example  :
```csharp
public class PasswordForm
{
[Required]
[Display(Name = "Current Password")]  
public string Password{get;set;}

[Required]
[NotEqualto("Password")]
[Display(Name = "New Password")] 
public string NewPassword{get;set;}

}
```

##The Final Code
By now you should have something similar to the below:
```csharp
using System.Reflection;
using System.ComponentModel.DataAnnotations;

namespace SampleProject.NotEqualsValidation
{
 
    public class NotEqualto : ValidationAttribute
    {
        private readonly string _other;
        public NotEqualto (string other)
        {
            // This is the name of the property to compare to 
            _other = other;
        }

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var otherProperty = validationContext.ObjectType.GetProperty(_other);
            if (otherProperty == null)
            {
                return new ValidationResult( string.Format("Property {0} not found", _other) );
            }
            var otherValue = otherProperty.GetValue(validationContext.ObjectInstance, null);
           
            if (object.Equals(value, otherValue))
            {
                var otherDisplayAttribute = otherProperty.GetCustomAttribute(typeof(DisplayAttribute)) as DisplayAttribute;
                string otherName = "";
                if (otherDisplayAttribute != null)
                {
                    otherName = otherDisplayAttribute.Name;
                }
                else
                {
                    otherName = otherProperty.Name;
                }
                this.ErrorMessage = $"{validationContext.DisplayName} cannot be the same as {otherName}";
                return new ValidationResult(this.ErrorMessage);
            }
            return null;
        }
    }
}

```

##Finito 
I hope you've found this useful and that it gets you out of any binds you may find yourself in !
See a full example Git project below 

{% github jamiemcmanus/customvalidator no-readme %}

If you feel generous enough feel free to [![Buy Me A Coffee](https://cdn.buymeacoffee.com/buttons/default-black.png)](https://www.buymeacoffee.com/SUKaQp9)