I'm currently trying to work through MVC validation, and am coming up against some problems where a field is required depending on the value of another field. An example is below (that I haven't figured out yet) - If the PaymentMethod == "Cheque", then the ChequeName should be required, otherwise it can be let through.
我目前正在尝试通过MVC验证,并且遇到了一些需要字段的问题,具体取决于另一个字段的值。下面是一个例子(我还没想到) - 如果PaymentMethod ==“Check”,则需要ChequeName,否则可以通过。
[Required(ErrorMessage = "Payment Method must be selected")]
public override string PaymentMethod
{ get; set; }
[Required(ErrorMessage = "ChequeName is required")]
public override string ChequeName
{ get; set; }
I'm using the System.ComponentModel.DataAnnotations for the [Required], and have also extended a ValidationAttribute to try and get this working, but I can't pass a variable through to do the validation (extension below)
我正在为[Required]使用System.ComponentModel.DataAnnotations,并且还扩展了ValidationAttribute以尝试使其工作,但我无法通过变量来进行验证(下面的扩展名)
public class JEPaymentDetailRequired : ValidationAttribute
{
public string PaymentSelected { get; set; }
public string PaymentType { get; set; }
public override bool IsValid(object value)
{
if (PaymentSelected != PaymentType)
return true;
var stringDetail = (string) value;
if (stringDetail.Length == 0)
return false;
return true;
}
}
Implementation:
执行:
[JEPaymentDetailRequired(PaymentSelected = PaymentMethod, PaymentType = "Cheque", ErrorMessage = "Cheque name must be completed when payment type of cheque")]
Has anyone had experience with this sort of validation? Would it just be better to write it into the controller?
有没有人有这种验证的经验?将它写入控制器会更好吗?
Thanks for your help.
谢谢你的帮助。
4 个解决方案
#1
3
I would write the validation logic in the model, not the controller. The controller should only handle interaction between the view and the model. Since it's the model that requires validation, I think it's widely regarded as the place for validation logic.
我会在模型中编写验证逻辑,而不是控制器。控制器应该只处理视图和模型之间的交互。由于它是需要验证的模型,我认为它被广泛认为是验证逻辑的地方。
For validation that depends on the value of another property or field, I (unfortunately) don't see how to completely avoid writing some code for that in the model, such as shown in the Wrox ASP.NET MVC book, sort of like:
对于依赖于另一个属性或字段的值的验证,我(遗憾的是)没有看到如何完全避免在模型中为其编写一些代码,如Wrox ASP.NET MVC书中所示,有点像:
public bool IsValid
{
get
{
SetRuleViolations();
return (RuleViolations.Count == 0);
}
}
public void SetRuleViolations()
{
if (this.PaymentMethod == "Cheque" && String.IsNullOrEmpty(this.ChequeName))
{
RuleViolations.Add("Cheque name is required", "ChequeName");
}
}
Doing all validation declaratively would be great. I'm sure you could make a RequiredDependentAttribute
, but that would only handle this one type of logic. Stuff that is even slightly more complex would require yet another pretty specific attribute, etc. which gets crazy quickly.
以声明方式进行所有验证会很棒。我确信你可以创建一个RequiredDependentAttribute,但那只能处理这种逻辑。甚至稍微复杂一点的东西需要另一个非常具体的属性,等等,它会很快变得疯狂。
#2
4
If you want client side validation in addition to model validation on the server, I think the best way to go is a custom validation attribute (like Jaroslaw suggested). I'm including the source here of the one I use.
如果除了服务器上的模型验证之外还需要客户端验证,我认为最好的方法是自定义验证属性(如Jaroslaw建议的那样)。我在这里包含了我使用的源码。
Custom attribute:
自定义属性:
public class RequiredIfAttribute : DependentPropertyAttribute
{
private readonly RequiredAttribute innerAttribute = new RequiredAttribute();
public object TargetValue { get; set; }
public RequiredIfAttribute(string dependentProperty, object targetValue) : base(dependentProperty)
{
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(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 && TargetValue == null) ||
(dependentvalue != null && dependentvalue.Equals(TargetValue)))
{
// match => means we should try validating this field
if (!innerAttribute.IsValid(value))
// validation failed - return an error
return new ValidationResult(ErrorMessage, new[] { validationContext.MemberName });
}
}
return ValidationResult.Success;
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule
{
ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
ValidationType = "requiredif"
};
var depProp = BuildDependentPropertyId(DependentProperty, 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!)
var targetValue = (TargetValue ?? "").ToString();
if (TargetValue != null)
if (TargetValue is bool)
targetValue = targetValue.ToLower();
rule.ValidationParameters.Add("dependentproperty", depProp);
rule.ValidationParameters.Add("targetvalue", targetValue);
yield return rule;
}
}
Jquery validation extension:
Jquery验证扩展:
$.validator.unobtrusive.adapters.add('requiredif', ['dependentproperty', 'targetvalue'], function (options) {
options.rules['requiredif'] = {
dependentproperty: options.params['dependentproperty'],
targetvalue: options.params['targetvalue']
};
options.messages['requiredif'] = options.message;
});
$.validator.addMethod('requiredif',
function (value, element, parameters) {
var id = '#' + parameters['dependentproperty'];
// get the target value (as a string,
// as that's what actual value will be)
var targetvalue = parameters['targetvalue'];
targetvalue = (targetvalue == null ? '' : targetvalue).toString();
// get the actual value of the target control
var actualvalue = getControlValue(id);
// if the condition is true, reuse the existing
// required field validator functionality
if (targetvalue === actualvalue) {
return $.validator.methods.required.call(this, value, element, parameters);
}
return true;
}
);
Decorating a property with the attribute:
使用属性装饰属性:
[Required]
public bool IsEmailGiftCertificate { get; set; }
[RequiredIf("IsEmailGiftCertificate", true, ErrorMessage = "Please provide Your Email.")]
public string YourEmail { get; set; }
#3
4
Just use the Foolproof validation library that is available on Codeplex: https://foolproof.codeplex.com/
只需使用Codeplex上提供的Foolproof验证库:https://foolproof.codeplex.com/
It supports the following "requiredif" validation attributes / decorations:
它支持以下“requiredif”验证属性/装饰:
[RequiredIf]
[RequiredIfNot]
[RequiredIfTrue]
[RequiredIfFalse]
[RequiredIfEmpty]
[RequiredIfNotEmpty]
[RequiredIfRegExMatch]
[RequiredIfNotRegExMatch]
To get started is easy:
开始很容易:
- Download the package from the provided link
- 从提供的链接下载包
- Add a reference to the included .dll file
- 添加对包含的.dll文件的引用
- Import the included javascript files
- 导入包含的javascript文件
- Ensure that your views references the included javascript files from within its HTML for unobtrusive javascript and jquery validation.
- 确保您的视图引用其HTML中包含的javascript文件,以进行不引人注目的javascript和jquery验证。
#4
2
Your problem can be solved relatively simply by the usage of conditional validation attribute e.g.
通过使用条件验证属性,可以相对简单地解决您的问题,例如
[RequiredIf("PaymentMethod == 'Cheque'")]
public string ChequeName { get; set; }
#1
3
I would write the validation logic in the model, not the controller. The controller should only handle interaction between the view and the model. Since it's the model that requires validation, I think it's widely regarded as the place for validation logic.
我会在模型中编写验证逻辑,而不是控制器。控制器应该只处理视图和模型之间的交互。由于它是需要验证的模型,我认为它被广泛认为是验证逻辑的地方。
For validation that depends on the value of another property or field, I (unfortunately) don't see how to completely avoid writing some code for that in the model, such as shown in the Wrox ASP.NET MVC book, sort of like:
对于依赖于另一个属性或字段的值的验证,我(遗憾的是)没有看到如何完全避免在模型中为其编写一些代码,如Wrox ASP.NET MVC书中所示,有点像:
public bool IsValid
{
get
{
SetRuleViolations();
return (RuleViolations.Count == 0);
}
}
public void SetRuleViolations()
{
if (this.PaymentMethod == "Cheque" && String.IsNullOrEmpty(this.ChequeName))
{
RuleViolations.Add("Cheque name is required", "ChequeName");
}
}
Doing all validation declaratively would be great. I'm sure you could make a RequiredDependentAttribute
, but that would only handle this one type of logic. Stuff that is even slightly more complex would require yet another pretty specific attribute, etc. which gets crazy quickly.
以声明方式进行所有验证会很棒。我确信你可以创建一个RequiredDependentAttribute,但那只能处理这种逻辑。甚至稍微复杂一点的东西需要另一个非常具体的属性,等等,它会很快变得疯狂。
#2
4
If you want client side validation in addition to model validation on the server, I think the best way to go is a custom validation attribute (like Jaroslaw suggested). I'm including the source here of the one I use.
如果除了服务器上的模型验证之外还需要客户端验证,我认为最好的方法是自定义验证属性(如Jaroslaw建议的那样)。我在这里包含了我使用的源码。
Custom attribute:
自定义属性:
public class RequiredIfAttribute : DependentPropertyAttribute
{
private readonly RequiredAttribute innerAttribute = new RequiredAttribute();
public object TargetValue { get; set; }
public RequiredIfAttribute(string dependentProperty, object targetValue) : base(dependentProperty)
{
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(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 && TargetValue == null) ||
(dependentvalue != null && dependentvalue.Equals(TargetValue)))
{
// match => means we should try validating this field
if (!innerAttribute.IsValid(value))
// validation failed - return an error
return new ValidationResult(ErrorMessage, new[] { validationContext.MemberName });
}
}
return ValidationResult.Success;
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule
{
ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
ValidationType = "requiredif"
};
var depProp = BuildDependentPropertyId(DependentProperty, 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!)
var targetValue = (TargetValue ?? "").ToString();
if (TargetValue != null)
if (TargetValue is bool)
targetValue = targetValue.ToLower();
rule.ValidationParameters.Add("dependentproperty", depProp);
rule.ValidationParameters.Add("targetvalue", targetValue);
yield return rule;
}
}
Jquery validation extension:
Jquery验证扩展:
$.validator.unobtrusive.adapters.add('requiredif', ['dependentproperty', 'targetvalue'], function (options) {
options.rules['requiredif'] = {
dependentproperty: options.params['dependentproperty'],
targetvalue: options.params['targetvalue']
};
options.messages['requiredif'] = options.message;
});
$.validator.addMethod('requiredif',
function (value, element, parameters) {
var id = '#' + parameters['dependentproperty'];
// get the target value (as a string,
// as that's what actual value will be)
var targetvalue = parameters['targetvalue'];
targetvalue = (targetvalue == null ? '' : targetvalue).toString();
// get the actual value of the target control
var actualvalue = getControlValue(id);
// if the condition is true, reuse the existing
// required field validator functionality
if (targetvalue === actualvalue) {
return $.validator.methods.required.call(this, value, element, parameters);
}
return true;
}
);
Decorating a property with the attribute:
使用属性装饰属性:
[Required]
public bool IsEmailGiftCertificate { get; set; }
[RequiredIf("IsEmailGiftCertificate", true, ErrorMessage = "Please provide Your Email.")]
public string YourEmail { get; set; }
#3
4
Just use the Foolproof validation library that is available on Codeplex: https://foolproof.codeplex.com/
只需使用Codeplex上提供的Foolproof验证库:https://foolproof.codeplex.com/
It supports the following "requiredif" validation attributes / decorations:
它支持以下“requiredif”验证属性/装饰:
[RequiredIf]
[RequiredIfNot]
[RequiredIfTrue]
[RequiredIfFalse]
[RequiredIfEmpty]
[RequiredIfNotEmpty]
[RequiredIfRegExMatch]
[RequiredIfNotRegExMatch]
To get started is easy:
开始很容易:
- Download the package from the provided link
- 从提供的链接下载包
- Add a reference to the included .dll file
- 添加对包含的.dll文件的引用
- Import the included javascript files
- 导入包含的javascript文件
- Ensure that your views references the included javascript files from within its HTML for unobtrusive javascript and jquery validation.
- 确保您的视图引用其HTML中包含的javascript文件,以进行不引人注目的javascript和jquery验证。
#4
2
Your problem can be solved relatively simply by the usage of conditional validation attribute e.g.
通过使用条件验证属性,可以相对简单地解决您的问题,例如
[RequiredIf("PaymentMethod == 'Cheque'")]
public string ChequeName { get; set; }