MVC3自定义验证属性,用于比较有效的最小值和最大值

时间:2014-07-23 14:29:32

标签: c# asp.net-mvc-3 validation

我的模型有两个十进制参数,如下所示:

public class Range
{
     public decimal MinimumValue { get; set; }
     public decimal MaximumValue { get; set; }
}

是否可以对以下两个参数进行自定义验证:

  • 验证MinimmumValue(必须小于MaximumValue)
  • 验证MaximumValue(必须大于MinimumValue)

2 个答案:

答案 0 :(得分:2)

有很多关于创建自定义验证属性的文章,但这里有一个示例,说明它在您的案例中的外观:

public class GreaterThanAttribute : ValidationAttribute
{
    public string PropertyNameToCompare { get; set; }

    public GreaterThanAttribute(string propertyNameToCompare)
    {
        PropertyNameToCompare = propertyNameToCompare;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var propertyToCompare = validationContext.ObjectType.GetProperty(PropertyNameToCompare);
        if (propertyToCompare == null)
        {
            return new ValidationResult(
                string.Format("Invalid property name '{0}'", PropertyNameToCompare));
        }
        var valueToCompare = propertyToCompare.GetValue(validationContext.ObjectInstance, null);

        bool valid;

        if (value is decimal && valueToCompare is decimal)
        {
            valid = ((decimal) value) > ((decimal) valueToCompare);
        }
        //TODO: Other types
        else
        {
            return new ValidationResult("Compared properties should be numeric and of the same type.");
        }

        if (valid)
        {
            return ValidationResult.Success;
        }

        return new ValidationResult(
            string.Format("{0} must be greater than {1}",
                validationContext.DisplayName, PropertyNameToCompare));
    }
}

我不太喜欢我开始检查房产类型的地方,但我不知道是否有可能让它变得更好。

当然,您也需要实施GreaterThanAttribute

答案 1 :(得分:0)

如果选中复选框,我执行了自定义属性来验证字段。如果未选中复选框,则需要该字段,否则,该字段不是必需的。我可以使用此代码来调整并检查字段是否比其他字段更强。 您还可以使用数据注释扩展。有关数据注释扩展的更多信息here

public class RequiredIf : ConditionalValidationAttribute
{
    protected override string ValidationName
    {
        get { return "requiredif"; }
    }

    public RequiredIf(string dependentProperty, object targetValue)
        : base(new RequiredAttribute(), dependentProperty, targetValue)
    {
    }

    protected override IDictionary<string, object> GetExtraValidationParameters()
    {
        return new Dictionary<string, object> 
                    { 
                        { "rule", "required" }
                    };
    }
}


[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
public abstract class ConditionalValidationAttribute : ValidationAttribute, IClientValidatable
{
    protected readonly ValidationAttribute InnerAttribute;
    public string DependentProperty { get; set; }
    public object TargetValue { get; set; }
    protected abstract string ValidationName { get; }

    protected virtual IDictionary<string, object> GetExtraValidationParameters()
    {
        return new Dictionary<string, object>();
    }

    protected ConditionalValidationAttribute(ValidationAttribute innerAttribute, string dependentProperty, object targetValue)
    {
        this.InnerAttribute = innerAttribute;
        this.DependentProperty = dependentProperty;
        this.TargetValue = targetValue;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        // get a reference to the property this validation depends upon
        var containerType = validationContext.ObjectInstance.GetType();
        var field = containerType.GetProperty(this.DependentProperty);
        if (field != null)
        {
            // get the value of the dependent property
            var dependentvalue = field.GetValue(validationContext.ObjectInstance, null);

            // compare the value against the target value
            if ((dependentvalue == null && this.TargetValue == null) || (dependentvalue != null && dependentvalue.Equals(this.TargetValue)))
            {
                // match => means we should try validating this field
                if (!InnerAttribute.IsValid(value))
                {
                    // validation failed - return an error
                    return new ValidationResult(this.ErrorMessage, new[] { validationContext.MemberName });
                }
            }
        }
        return ValidationResult.Success;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule()
        {
            ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
            ValidationType = ValidationName,
        };
        string depProp = BuildDependentPropertyId(metadata, context as ViewContext);
        // find the value on the control we depend on; if it's a bool, format it javascript style
        string targetValue = (this.TargetValue ?? "").ToString();
        if (this.TargetValue.GetType() == typeof(bool))
        {
            targetValue = targetValue.ToLower();
        }
        rule.ValidationParameters.Add("dependentproperty", depProp);
        rule.ValidationParameters.Add("targetvalue", targetValue);
        // Add the extra params, if any
        foreach (var param in GetExtraValidationParameters())
        {
            rule.ValidationParameters.Add(param);
        }
        yield return rule;
    }

    private string BuildDependentPropertyId(ModelMetadata metadata, ViewContext viewContext)
    {
        string depProp = viewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(this.DependentProperty);
        // This will have the name of the current field appended to the beginning, because the TemplateInfo's context has had this fieldname appended to it.
        var thisField = metadata.PropertyName + "_";
        if (depProp.StartsWith(thisField))
        {
            depProp = depProp.Substring(thisField.Length);
        }
        return depProp;
    }
}