【发布时间】:2014-07-31 16:32:55
【问题描述】:
我正在尝试创建在 ASP.NET 中有条件地验证模型的能力。我让它用于服务器端验证,但我不知道如何让它用于客户端验证。
例如,
public class Student
{
[Required]
public string Name { get; set; }
public bool RequiresAddress { get; set; }
[RequiredIf("RequiresAddress", true)]
public string Address { get; set; }
}
这是我的RequiredIf 属性(创建以下this post):
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public sealed class RequiredIfAttribute : ValidationAttribute
{
public string DependentName;
public object DependentValue;
public RequiredIfAttribute(string PropertyName, object PropertyValue, string ErrorMessage)
{
this.DependentName = PropertyName;
this.DependentValue = PropertyValue;
this.ErrorMessage = ErrorMessage;
}
public override bool IsValid(object value)
{
if (value == null) { return false; }
string ValueString = value as string;
if (ValueString != null) { return (ValueString.Trim().Length != 0); }
return true;
}
}
然后我有了这个验证器(我使用 DataAnnotationsModelValidatorProvider 在 Global.asax.cs 中注册):
public class RequiredIfValidator : DataAnnotationsModelValidator<RequiredIfAttribute>
{
public RequiredIfValidator(ModelMetadata metadata, ControllerContext context, RequiredIfAttribute attribute)
: base(metadata, context, attribute)
{
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
var Rule = new ModelClientValidationRule
{
ErrorMessage = ErrorMessage,
ValidationType = "requiredif",
};
var viewContext = (ControllerContext as ViewContext);
string depProp = viewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(Attribute.DependentName);
Rule.ValidationParameters.Add("dependentname", depProp);
Rule.ValidationParameters.Add("dependentvalue", Attribute.DependentValue);
yield return Rule;
}
public override IEnumerable<ModelValidationResult> Validate(object container)
{
var Field = Metadata.ContainerType.GetProperty(Attribute.DependentName);
if (Field != null)
{
var Value = Field.GetValue(container, null);
if ((Value == null && Attribute.DependentValue == null) || (Value != null && Value.Equals(Attribute.DependentValue)))
{
if (!Attribute.IsValid(Metadata.Model))
{
yield return new ModelValidationResult { Message = ErrorMessage };
}
}
}
}
}
最后,在我看来,我尝试用 jQuery 注册客户端验证器:
if (typeof (jQuery) !== "undefined" && typeof (jQuery.validator) !== "undefined") {
(function ($) {
$.validator.addMethod('requiredif', function (value, element, parameters) {
var id = '#' + parameters['dependentname'];
var dependentvalue = parameters['dependentvalue'];
dependentvalue = (dependentvalue == null ? '' : dependentvalue).toString();
var actualvalue = $(id).val();
if (dependentvalue === actualvalue) {
return $.validator.methods.required.call(this, value, element, parameters);
}
else {
return true;
}
});
})(jQuery);
}
就像我说的,服务器端验证完美无缺,但客户端似乎根本没有工作。我对 JavaScript 有点不了解,所以我不确定如何解决这个问题 - 我在这里错过了什么?
更新
我摆脱了 Validator 类,并在自定义属性上实现了 IClientValidatable。这是我的新RequiredIfAttribute。同样,服务器端的一切似乎都按预期工作,但客户端却不工作。
从我看来,我正在使用 DevExpress 构建表单。
附言The zipped solution can be found here.
public class RequiredIfAttribute : ValidationAttribute, IClientValidatable
{
public string DependentName { get; set; }
public object DependentValue { get; set; }
public RequiredIfAttribute(string DependentName, object DependentValue)
{
this.DependentName = DependentName;
this.DependentValue = DependentValue;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata Metadata, ControllerContext Context)
{
var rule = new ModelClientValidationRule();
rule.ErrorMessage = FormatErrorMessage(Metadata.GetDisplayName());
rule.ValidationParameters.Add("dependentname", DependentName);
rule.ValidationParameters.Add("dependentvalue", DependentValue);
rule.ValidationType = "requiredif";
yield return rule;
}
public override bool IsValid(object value)
{
if (value == null) { return false; }
string ValueString = value as string;
if (ValueString != null) { return (ValueString.Trim().Length != 0); }
return true;
}
protected override ValidationResult IsValid(object Value, ValidationContext Context)
{
var ContainerType = Context.ObjectInstance.GetType();
var Field = ContainerType.GetProperty(this.DependentName);
if (Field != null)
{
var DependentValue = Field.GetValue(Context.ObjectInstance, null);
if ((DependentValue == null && DependentValue == null) ||
(DependentValue != null && DependentValue.Equals(this.DependentValue)))
{
if (!IsValid(Value))
{
//return new ValidationResult(ErrorMessage, new[] { Context.MemberName });
return new ValidationResult(FormatErrorMessage(Context.DisplayName));
}
}
}
return ValidationResult.Success;
}
public string GetPropertyID(ModelMetadata Metadata, ViewContext Context)
{
string DependentID = Context.ViewData.TemplateInfo.GetFullHtmlFieldId(this.DependentName);
var Fie1ldID = Metadata.PropertyName + "_";
return (DependentID.StartsWith(FieldID))
? DependentID.Substring(FieldID.Length)
: DependentID;
}
}
然后这是我的带有相关 JavaScript 的 View 类:
<script type="text/javascript">
function OnValueChanged(s, e) {
var Result = ASPxClientCheckBox.Cast(s).GetValue();
StudentForm.GetItemByName("Address").SetVisible(!Result);
}
</script>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(false)
@Html.DevExpress().FormLayout(Form =>
{
Form.Name = "StudentForm";
Form.Items.Add(x => x.Name, Item =>
{
(Item.NestedExtensionSettings as TextBoxSettings).ShowModelErrors = true;
(Item.NestedExtensionSettings as TextBoxSettings).Properties.ValidationSettings.ErrorDisplayMode = ErrorDisplayMode.ImageWithTooltip;
(Item.NestedExtensionSettings as TextBoxSettings).Properties.ValidationSettings.Display = Display.Dynamic;
});
Form.Items.Add(x => x.Address, Item =>
{
Item.Name = "Address";
(Item.NestedExtensionSettings as TextBoxSettings).ShowModelErrors = true;
(Item.NestedExtensionSettings as TextBoxSettings).Properties.ValidationSettings.ErrorDisplayMode = ErrorDisplayMode.ImageWithTooltip;
(Item.NestedExtensionSettings as TextBoxSettings).Properties.ValidationSettings.Display = Display.Dynamic;
});
Form.Items.Add(x => x.AddressHidden, Item =>
{
Item.Name = "AddressHidden";
(Item.NestedExtensionSettings as CheckBoxSettings).Properties.ClientSideEvents.Init = "OnValueChanged";
(Item.NestedExtensionSettings as CheckBoxSettings).Properties.ClientSideEvents.ValueChanged = "OnValueChanged";
});
Form.Items.Add(x => x.AddressRequired);
Form.Items.Add(x =>
{
x.NestedExtensionType = FormLayoutNestedExtensionItemType.Button;
ButtonSettings Settings = (ButtonSettings)x.NestedExtensionSettings;
Settings.UseSubmitBehavior = true;
Settings.Text = "Submit";
Settings.Name = "SubmitButton";
});
}).Bind(Model).GetHtml()
}
<script type="text/javascript">
jQuery.validator.unobtrusive.adapters.add('requiredif', ['dependentname', 'dependentvalue'], function (options) {
options.rules["requiredif"] = true;
options.messages["requiredif"] = options.message;
});
$.validator.addMethod('requiredif', function (value, element, params) {
var id = '#' + $(element).attr("data-val-requiredif-dependentname");
var dependentvalue = $(element).attr("data-val-requiredif-dependentvalue");
var actualvalue = $(id).is(":checked");
if (dependentvalue == "True" && actualvalue && value.length <= 0) {
return false;
}
return true;
});
</script>
【问题讨论】:
标签: c# jquery asp.net-mvc jquery-validate unobtrusive-validation