Asp.net mvc 3 使用FluentValidation/MVC 3在客户端上验证复选框
我正在尝试使用FluentValidation验证客户端上是否选中了复选框。我想不出这是我们的生活Asp.net mvc 3 使用FluentValidation/MVC 3在客户端上验证复选框,asp.net-mvc-3,fluentvalidation,Asp.net Mvc 3,Fluentvalidation,我正在尝试使用FluentValidation验证客户端上是否选中了复选框。我想不出这是我们的生活 可以使用不引人注目的验证来完成吗?假设您有以下模型: [Validator(typeof(MyViewModelValidator))] public class MyViewModel { public bool IsChecked { get; set; } } 使用以下验证器: public class MyViewModelValidator : AbstractValidato
可以使用不引人注目的验证来完成吗?假设您有以下模型:
[Validator(typeof(MyViewModelValidator))]
public class MyViewModel
{
public bool IsChecked { get; set; }
}
使用以下验证器:
public class MyViewModelValidator : AbstractValidator<MyViewModel>
{
public MyViewModelValidator()
{
RuleFor(x => x.IsChecked).Equal(true).WithMessage("Please check this checkbox");
}
}
以相应的观点:
@model MyViewModel
@using (Html.BeginForm())
{
@Html.LabelFor(x => x.IsChecked)
@Html.CheckBoxFor(x => x.IsChecked)
@Html.ValidationMessageFor(x => x.IsChecked)
<button type="submit">OK</button>
}
到目前为止,我们已经启动了服务器端验证并运行良好。那很好。这始终是我们必须设置的第一部分。我曾看到人们过于关注客户端验证,而忘记了服务器端验证,当你禁用javascript时(如果你无意中发现一个恶意用户,甚至更糟),糟糕的事情就会发生。
到目前为止,我们很有信心,因为我们知道,即使客户端出现问题,我们的域也会受到服务器端验证的保护
现在让我们关注一下客户端验证。现成的FluentValidation.NET支持对
EqualTo
验证器进行自动客户端验证,但与另一个属性值进行比较时,该属性值相当于[Compare]
数据注释
但在我们的例子中,我们是在与一个固定值进行比较。因此,我们不需要开箱即用的客户端可用性。当我们从盒子里拿不到东西时,我们需要把它放进盒子里
因此,我们首先定义自定义FluentValidationPropertyValidator:
public class EqualToValueFluentValidationPropertyValidator : FluentValidationPropertyValidator
{
public EqualToValueFluentValidationPropertyValidator(ModelMetadata metadata, ControllerContext controllerContext, PropertyRule rule, IPropertyValidator validator)
: base(metadata, controllerContext, rule, validator)
{
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
if (!this.ShouldGenerateClientSideRules())
{
yield break;
}
var validator = (EqualValidator)Validator;
var errorMessage = new MessageFormatter()
.AppendPropertyName(Rule.GetDisplayName())
.AppendArgument("ValueToCompare", validator.ValueToCompare)
.BuildMessage(validator.ErrorMessageSource.GetString());
var rule = new ModelClientValidationRule();
rule.ErrorMessage = errorMessage;
rule.ValidationType = "equaltovalue";
rule.ValidationParameters["valuetocompare"] = validator.ValueToCompare;
yield return rule;
}
}
到目前为止,我们已经将自定义FluentValidationPropertyValidator与EqualValidator相关联
最后一部分是编写自定义适配器:
(function ($) {
$.validator.unobtrusive.adapters.add('equaltovalue', ['valuetocompare'], function (options) {
options.rules['equaltovalue'] = options.params;
if (options.message != null) {
options.messages['equaltovalue'] = options.message;
}
});
$.validator.addMethod('equaltovalue', function (value, element, params) {
if ($(element).is(':checkbox')) {
if ($(element).is(':checked')) {
return value.toLowerCase() === 'true';
} else {
return value.toLowerCase() === 'false';
}
}
return params.valuetocompare.toLowerCase() === value.toLowerCase();
});
})(jQuery);
差不多就是这样。剩下的就是包括客户端脚本:
<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/customadapter.js")" type="text/javascript"></script>
我喜欢达林·迪米特罗夫的答案,但如果你想快速回答,这里是我的替代方法 在模型中创建其他属性,例如:
public bool ValidationTrue { get; set; }
并在模型的构造函数中将其值设置为true
在视图中使用它保存请求中的值:
@Html.HiddenFor(x => x.ValidationTrue)
现在添加如下验证规则:
public class MyViewModelValidator : AbstractValidator<MyViewModel>
{
public MyViewModelValidator()
{
RuleFor(x => x.ValidationTrue)
.Equal(true); // check it for security reasons, if someone has edited it in the source of the page
RuleFor(x => x.HasToBeChecked)
.Equal(x => x.ValidationTrue) // HasToBeChecked has to have the same value as ValidationTrue (which is always true)
.WithMessage("Required");
}
}
公共类MyViewModelValidator:AbstractValidator
{
公共MyViewModelValidator()
{
RuleFor(x=>x.ValidationTrue)
.Equal(true);//如果有人在页面源代码中编辑了它,请检查它是否安全
规则(x=>x.HasToBeChecked)
.Equal(x=>x.ValidationTrue)//HasToBeChecked必须具有与ValidationTrue相同的值(该值始终为true)
.WithMessage(“必需”);
}
}
该验证由开箱即用的不引人注目的验证器支持。我在ASP.NET MVC5中编码,Darin的代码在涉及复选框时引用value.ToLowerCase()的行上产生javascript错误。另一个问题是,此代码使两个属性之间的客户端相等性比较无效。它似乎只在与文字值进行比较时起作用……这可能是他的意图,但我需要它在两种情况下都起作用: 这里有一个可能的解决方法,它只涉及对Darin答案的两个更改: 首先,我用以下内容更新了javascript函数。
$.validator.addMethod('equaltovalue', function (value, element, params) {
if ($(element).is(':checkbox')) {
value = $(element).is(':checked') ? "true" : "false";
}
return params.valuetocompare.toLowerCase() === value.toLowerCase();
});
其次,我用以下内容更新了EqualToValueFluentValidationPropertyValidator:
public class EqualToValueFluentValidationPropertyValidator : FluentValidationPropertyValidator
{
EqualValidator EqualValidator
{
get { return (EqualValidator)Validator; }
}
public EqualToValueFluentValidationPropertyValidator(ModelMetadata metadata, ControllerContext controllerContext, PropertyRule rule, IPropertyValidator validator) : base(metadata, controllerContext, rule, validator) {
ShouldValidate = false;
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() {
if (!ShouldGenerateClientSideRules()) yield break;
var propertyToCompare = EqualValidator.MemberToCompare as PropertyInfo;
if(propertyToCompare != null) {
// If propertyToCompare is not null then we're comparing to another property.
// If propertyToCompare is null then we're either comparing against a literal value, a field or a method call.
// We only care about property comparisons in this case.
var comparisonDisplayName =
ValidatorOptions.DisplayNameResolver(Rule.TypeToValidate, propertyToCompare, null)
?? propertyToCompare.Name.SplitPascalCase();
var formatter = new MessageFormatter()
.AppendPropertyName(Rule.GetDisplayName())
.AppendArgument("ComparisonValue", comparisonDisplayName);
string message = formatter.BuildMessage(EqualValidator.ErrorMessageSource.GetString());
yield return new ModelClientValidationEqualToRule(message, CompareAttribute.FormatPropertyForClientValidation(propertyToCompare.Name)) ;
}
else
{
var validator = (EqualValidator)Validator;
var errorMessage = new MessageFormatter()
.AppendPropertyName(Rule.GetDisplayName())
.AppendArgument("ValueToCompare", validator.ValueToCompare)
.BuildMessage(validator.ErrorMessageSource.GetString());
var rule = new ModelClientValidationRule();
rule.ErrorMessage = errorMessage;
rule.ValidationType = "equaltovalue";
rule.ValidationParameters["valuetocompare"] = validator.ValueToCompare;
yield return rule;
}
}
}
公共类EqualToValueFluentValidationPropertyValidator:FluentValidationPropertyValidator
{
等速校准器等速校准器
{
获取{return(EqualValidator)验证器;}
}
公共EqualToValueFluentValidationPropertyValidator(ModelMetadata元数据、ControllerContext ControllerContext、PropertyRule规则、IPropertyValidator验证器):基本(元数据、ControllerContext、规则、验证器){
ShouldValidate=false;
}
公共重写IEnumerable GetClientValidationRules(){
如果(!ShouldGenerateClientSideRules())产生中断;
var propertyToCompare=EqualValidator.MemberToCompare as PropertyInfo;
if(propertyToCompare!=null){
//如果propertyToCompare不为null,则我们将与另一个属性进行比较。
//如果propertyToCompare为null,则我们将与文本值、字段或方法调用进行比较。
//在这种情况下,我们只关心财产比较。
变量comparisonDisplayName=
ValidatorOptions.DisplayNameResolver(Rule.TypeToValidate,propertyToCompare,null)
??propertyToCompare.Name.SplitPascalCase();
var formatter=new MessageFormatter()
.AppendPropertyName(规则.GetDisplayName())
.AppendArgument(“ComparisonValue”,comparisonDisplayName);
string message=formatter.BuildMessage(EqualValidator.ErrorMessageSource.GetString());
返回新的ModelClientValidationQualtoRule(消息,CompareAttribute.FormatPropertyForClientValidation(propertyToCompare.Name));
}
其他的
{
var验证器=(EqualValidator)验证器;
var errorMessage=new MessageFormatter()
.AppendPropertyName(规则.GetDisplayName())
.AppendArgument(“ValueToCompare”,validator.ValueToCompare)
.BuildMessage(validator.ErrorMessageSource.GetString());
var rule=new ModelClientValidationRule();
rule.ErrorMessage=ErrorMessage;
rule.ValidationType=“equaltovalue”;
rule.ValidationParameters[“valuetocompare”]=validator.valuetocompare;
收益率-收益率规则;
}
}
}
这段代码是从fluentvalidation源代码中的EqualToFluentValidationPropertyValidator
内部类复制的,我在else之后添加了Darin的逻辑。这允许客户端验证用于属性比较和值比较…我不确定这是否是一个好方法,因为您基本上覆盖了内置的平等验证器,它可能会在未来的fluent validation版本中中断…但是
public class MyViewModelValidator : AbstractValidator<MyViewModel>
{
public MyViewModelValidator()
{
RuleFor(x => x.ValidationTrue)
.Equal(true); // check it for security reasons, if someone has edited it in the source of the page
RuleFor(x => x.HasToBeChecked)
.Equal(x => x.ValidationTrue) // HasToBeChecked has to have the same value as ValidationTrue (which is always true)
.WithMessage("Required");
}
}
$.validator.addMethod('equaltovalue', function (value, element, params) {
if ($(element).is(':checkbox')) {
value = $(element).is(':checked') ? "true" : "false";
}
return params.valuetocompare.toLowerCase() === value.toLowerCase();
});
public class EqualToValueFluentValidationPropertyValidator : FluentValidationPropertyValidator
{
EqualValidator EqualValidator
{
get { return (EqualValidator)Validator; }
}
public EqualToValueFluentValidationPropertyValidator(ModelMetadata metadata, ControllerContext controllerContext, PropertyRule rule, IPropertyValidator validator) : base(metadata, controllerContext, rule, validator) {
ShouldValidate = false;
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() {
if (!ShouldGenerateClientSideRules()) yield break;
var propertyToCompare = EqualValidator.MemberToCompare as PropertyInfo;
if(propertyToCompare != null) {
// If propertyToCompare is not null then we're comparing to another property.
// If propertyToCompare is null then we're either comparing against a literal value, a field or a method call.
// We only care about property comparisons in this case.
var comparisonDisplayName =
ValidatorOptions.DisplayNameResolver(Rule.TypeToValidate, propertyToCompare, null)
?? propertyToCompare.Name.SplitPascalCase();
var formatter = new MessageFormatter()
.AppendPropertyName(Rule.GetDisplayName())
.AppendArgument("ComparisonValue", comparisonDisplayName);
string message = formatter.BuildMessage(EqualValidator.ErrorMessageSource.GetString());
yield return new ModelClientValidationEqualToRule(message, CompareAttribute.FormatPropertyForClientValidation(propertyToCompare.Name)) ;
}
else
{
var validator = (EqualValidator)Validator;
var errorMessage = new MessageFormatter()
.AppendPropertyName(Rule.GetDisplayName())
.AppendArgument("ValueToCompare", validator.ValueToCompare)
.BuildMessage(validator.ErrorMessageSource.GetString());
var rule = new ModelClientValidationRule();
rule.ErrorMessage = errorMessage;
rule.ValidationType = "equaltovalue";
rule.ValidationParameters["valuetocompare"] = validator.ValueToCompare;
yield return rule;
}
}
}
RuleFor(x => x.HasToBeChecked)
.Equal(x => true)
.WithMessage("Required");