Search code examples
c#attributesblazorvalidationattribute

Customs validation attribute with multiple value for Blazor EditForm validations


I want to check if the combination of column A and column B is unique in my blazor app. To check if column A is unique is quite simple using a ValidationAttribute

public class MyClass
{
    [IsUnique(ErrorMessage = "The entered value exists.")]
    public string Code {get; set;}
}
public class IsUniqueAttribute : ValidationAttribute
{

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var service = (DbService)validationContext.GetService(typeof(DbService))
        bool exists = service.IsUnique((String)value);
        if(exists == false)
        {
            return ValidationResult.Success;
        }
        return new ValidationResult(ErrorMessage, new[] { validationContext.MemberName });
    }
}

However, I do not know how to do the same thing when there are multiple values involved. Say that I want to check if Code + Name is unique in the database for the following MyClass2.

public class MyClass2
{
    public string Code {get; set;}
    public string Name {get;set;}
}

I have tried using custom parameters:

public class IsCodeNameCombinationUniqueAttribute : ValidationAttribute
{
    public string Name{ get; set; }

    public override bool IsValid(object value)
    {

        //Validate
    }
}

public class MyClass2
{
    [IsCodeNameCombinationUnique(ErrorMessage = "The combination of Code and Name exists.", Name = Name)]
    public string Code {get; set;}
    public string Name {get;set;}
}

But it seems that I can only pass constants into the Name parameter.

Is there any way to make a custom ValidationAttribute to achieve what I want to?

Or should I be using custom validators instead? ( https://learn.microsoft.com/en-us/aspnet/core/blazor/forms-validation?view=aspnetcore-5.0#validator-components)


Solution

  • The thing you are trying can be achieved using "Class-Level" Validation.

    This can be done by implementing "IValidatableObject" in your model class and provide your validation logic in "Validate" method which is provided by "IValidatableObject".

    In your case,

    public class MyClass2 : IValidatableObject
    {
        public string Code {get; set;}
        public string Name {get;set;}
    
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            var service = (DbService)validationContext.GetService(typeof(DbService))
            
            bool exists = service.IsUniqueCombination(this.Code,this.Name);
    
            if(exists)
            {
                yield return new ValidationResult("The combination of Code and Name exists.");
            }
        }
    }