Custom validation attribute that compares the valu

2019-01-05 01:51发布

I want to create a custom validation attribute, in which I want to compare the value of my property with another property's value in my model class. For example I have in my model class:

...    
public string SourceCity { get; set; }
public string DestinationCity { get; set; }

And I want to create a custom attribute to use it like this:

[Custom("SourceCity", ErrorMessage = "the source and destination should not be equal")]
public string DestinationCity { get; set; }
//this wil lcompare SourceCity with DestinationCity

How can I get there?

3条回答
手持菜刀,她持情操
2楼-- · 2019-01-05 02:03

Here's how you could obtain the other property value:

public class CustomAttribute : ValidationAttribute
{
    private readonly string _other;
    public CustomAttribute(string other)
    {
        _other = other;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var property = validationContext.ObjectType.GetProperty(_other);
        if (property == null)
        {
            return new ValidationResult(
                string.Format("Unknown property: {0}", _other)
            );
        }
        var otherValue = property.GetValue(validationContext.ObjectInstance, null);

        // at this stage you have "value" and "otherValue" pointing
        // to the value of the property on which this attribute
        // is applied and the value of the other property respectively
        // => you could do some checks
        if (!object.Equals(value, otherValue))
        {
            // here we are verifying whether the 2 values are equal
            // but you could do any custom validation you like
            return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
        }
        return null;
    }
}
查看更多
We Are One
3楼-- · 2019-01-05 02:11

Please look below for my example:

Model class implements INotifyPropertyChanged

public class ModelClass : INotifyPropertyChanged
        {
            private string destinationCity;
            public string SourceCity { get; set; }

            public ModelClass()
            {
                PropertyChanged += CustomAttribute.ThrowIfNotEquals;
            }

            [Custom("SourceCity", ErrorMessage = "the source and destination should not be equal")]
            public string DestinationCity
            {
                get
                {
                    return this.destinationCity;
                }

                set
                {
                    if (value != this.destinationCity)
                    {
                        this.destinationCity = value;
                        NotifyPropertyChanged("DestinationCity");
                    }
                }
            }

            public event PropertyChangedEventHandler PropertyChanged;

            protected virtual void NotifyPropertyChanged(string info)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(info));
                }
            }
        }

Attribute class also contains event hendler.

internal sealed class CustomAttribute : Attribute
    {
        public CustomAttribute(string propertyName)
        {
            PropertyName = propertyName;
        }

        public string PropertyName { get; set; }

        public string ErrorMessage { get; set; }

        public static void ThrowIfNotEquals(object obj, PropertyChangedEventArgs eventArgs)
        {
            Type type = obj.GetType();
            var changedProperty = type.GetProperty(eventArgs.PropertyName);
            var attribute = (CustomAttribute)changedProperty
                                                 .GetCustomAttributes(typeof(CustomAttribute), false)
                                                 .FirstOrDefault();

            var valueToCompare = type.GetProperty(attribute.PropertyName).GetValue(obj, null);
            if (!valueToCompare.Equals(changedProperty.GetValue(obj, null)))
                throw new Exception("the source and destination should not be equal");
        }
    }

Usage

    var test = new ModelClass();
    test.SourceCity = "1";
    // Everything is ok
    test.DestinationCity = "1";
    // throws exception
    test.DestinationCity ="2";

To simplify code I decided to omit a validation.

查看更多
老娘就宠你
4楼-- · 2019-01-05 02:13

The best way to do this, is through of IValidatableObject. See http://msdn.microsoft.com/en-us/data/gg193959.aspx

查看更多
登录 后发表回答