【问题标题】:Custom validation attribute that compares the value of my property with another property's value in my model class将我的属性值与模型类中另一个属性的值进行比较的自定义验证属性
【发布时间】:2012-08-11 03:58:26
【问题描述】:

我想创建一个自定义验证属性,我想在其中将我的属性值与模型类中另一个属性的值进行比较。 例如,我的模型类中有:

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

我想创建一个自定义属性来像这样使用它:

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

我怎样才能到达那里?

【问题讨论】:

  • @Joe,这适用于 ASP.NET MVC 2,不再适用于 MVC 3。此外,这篇博文也没有说明如何在验证器中检索依赖属性值,这就是 OP 的含义试图在这里实现。

标签: c# asp.net-mvc razor validationattribute


【解决方案1】:

请看下面我的例子:

模型类实现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));
        }
    }
}

属性类还包含事件处理程序。

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");
    }
}

用法

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

为了简化代码,我决定省略验证。

【讨论】:

    【解决方案2】:

    最好的方法是通过 IValidatableObject。见http://msdn.microsoft.com/en-us/data/gg193959.aspx

    【讨论】:

    • IValidatableObject 肯定是一个很好的解决方案,但基于潜在的可重用性,ValidationAttribute 会做得更多
    【解决方案3】:

    以下是获取其他属性值的方法:

    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;
        }
    }
    

    【讨论】:

    • 太好了,这正是我正在寻找的答案!除了我的验证上下文始终为空。有什么想法吗?
    • @GrimmTheOpiner 我知道这已经过时了,但对于任何想要尝试的人来说,请尝试在 CustomAttribute 中添加 public override bool RequiresValidationContext { get { return true; } }
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-12
    • 1970-01-01
    • 2013-01-17
    相关资源
    最近更新 更多