user11680003
user11680003

Reputation:

use IModelValidator to Create a Custom Property Validation Attribute

Below is a custom property validation from my textbook

public class MustBeTrueAttribute : Attribute, IModelValidator
{
    public bool IsRequired => true;

    public string ErrorMessage { get; set; }

    public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
    {
        bool? value = context.Model as bool?;
        if (!value.HasValue || value.Value == false)
        {
            return new List<ModelValidationResult> {
                    new ModelValidationResult("", ErrorMessage) // why first argument has to be empty?
                };
        }
        else
        {
            return Enumerable.Empty<ModelValidationResult>();
        }
    }
}

public class Appointment
{  
    public DateTime Date { get; set; }

    [MustBeTrue(ErrorMessage = "You must accept the terms")]
    public bool TermsAccepted { get; set; }
}

I have two questions:

Q1- IModelValidator interface doesn't define the IsRequired property, where it comes from and how this property is going to be used?

Q2- why the first argument(memberName) in the ModelValidationResult's constructor has to be empty "", under what circumstances we need to specify a value

Upvotes: 0

Views: 1250

Answers (1)

Allen Chen
Allen Chen

Reputation: 226

Q1: IModelValidator interface doesn't define the IsRequired property, where it comes from and how this property is going to be used?

Ans: In this case, the property IsRequired is useless, because it isn't used in your code.

Q2: why the first argument(memberName) in the ModelValidationResult's constructor has to be empty "", under what circumstances we need to specify a value

Ans: Actually, it doesn’t have to be empty. It depends on what level you'd like to validate. Once you registered your custom validator, you might call it in your Controller to validate your model. So if this validator is only for one model, you can validate all the properties with a Switch...Case statement and give those properties a specific name. On the other hand, if this validator will be used to validate many different models. You may need to consider whether it is suitable to specify a value.

public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
{
    if (context != null)
    {
        switch (context.ModelMetadata.PropertyName)
        {
            case "TermsAccepted":
                if (!context.Model.TermsAccepted) {
                    return new ModelValidationResult[]
                    {
                        new ModelValidationResult 
                        {
                            MemberName = "TermsAccepted",
                            Message = "You must accept the terms"
                        }
                    };
                }
                break; 
            default:
        }
        return new List<ModelValidationResult> 
        {
            new ModelValidationResult("", ErrorMessage)
        };
    }

    return Enumerable.Empty<ModelValidationResult>();
}

Upvotes: 1

Related Questions