在MVC 3.0中运行时条件验证(必填字段)

时间:2012-09-24 08:11:53

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

我的Model类中有几个Address line字段,它根据所选的国家/语言更改其行为(Required / not Required)。

例如,UK应该有3个地址行作为必填输入字段,而在美国的情况下,它应该只有2个必填字段。

我尝试使用自定义验证器“RequiredIf”&根据另一个可以为空的布尔属性打开或关闭它;但它不起作用。

我的模型的关注属性被称为floows:

public bool? IsAddressLine3Mandatory { get; set; }

[RequiredIf("IsAddressline3Mandatory", true, ErrorMessage = "Address line 3 is mandatory for UK")]
    public string AddressLine3 { get; set; }

我从我们的数据库&中获取国家/地区信息。在该视图的HTTPGet Action方法中设置IsAddressline3Mandatory字段。

我正在努力实现客户端和服务器端验证发生。

RequiredIf的代码如下:

    public class RequiredIfAttribute : ValidationAttribute, IClientValidatable
{
    private RequiredAttribute _innerAttribute = new RequiredAttribute();

    public string DependentProperty { get; set; }
    public object TargetValue { get; set; }

    public RequiredIfAttribute(string dependentProperty, object targetValue)
    {
        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 = "requiredif",
        };

        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 
        // (the default is True or False!)
        string targetValue = (this.TargetValue ?? "").ToString();
        if (this.TargetValue.GetType() == typeof(bool))
            targetValue = targetValue.ToLower();

        rule.ValidationParameters.Add("dependentproperty", depProp);
        rule.ValidationParameters.Add("targetvalue", targetValue);

        yield return rule;
    }

    private string BuildDependentPropertyId(ModelMetadata metadata, ViewContext viewContext)
    {
        // build the ID of the property
        string depProp = viewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(this.DependentProperty);
        // unfortunately 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. Instead, we
        // want to get the context as though it was one level higher (i.e. outside the current property,
        // which is the containing object (our Person), and hence the same level as the dependent property.
        var thisField = metadata.PropertyName + "_";
        if (depProp.StartsWith(thisField))
            // strip it off again
            depProp = depProp.Substring(thisField.Length);
        return depProp;
    }
}

0 个答案:

没有答案