我一直在尝试创建一个FluentValidation规则,该规则在验证它的属性之前检查它正在验证的对象的实例是否为null。
我宁愿在验证器中封装这个空验证,而不是在调用代码中进行验证。
请参阅下面的示例代码,其中包含需要所需逻辑的注释:
namespace MyNamespace
{
using FluentValidation;
public class Customer
{
public string Surname { get; set; }
}
public class CustomerValidator: AbstractValidator<Customer>
{
public CustomerValidator()
{
// Rule to check the customer instance is not null.
// Don't continue validating.
RuleFor(c => c.Surname).NotEmpty();
}
}
public class MyClass
{
public void DoCustomerWork(int id)
{
var customer = GetCustomer(id);
var validator = new CustomerValidator();
var results = validator.Validate(customer);
var validationSucceeded = results.IsValid;
}
public Customer GetCustomer(int id)
{
return null;
}
}
}
所以我的问题是我如何在CustomerValidator()构造函数中检查当前客户实例是否为空而如果它为空则中止进一步的规则处理?
提前致谢。
答案 0 :(得分:28)
您应该能够覆盖Validate
课程中的CustomerValidator
方法。
public class CustomerValidator: AbstractValidator<Customer>
{
// constructor...
public override ValidationResult Validate(Customer instance)
{
return instance == null
? new ValidationResult(new [] { new ValidationFailure("Customer", "Customer cannot be null") })
: base.Validate(instance);
}
}
答案 1 :(得分:14)
我现在无法真正测试,但您可以尝试覆盖Validate
,或在When
块中包含规则:
public CustomerValidator()
{
When(x => x != null, () => {
RuleFor(x => x.Surname).NotEmpty();
//etc.
});
}
答案 2 :(得分:6)
对于使用版本&gt; 6.2.1的用户,您需要覆盖此签名,以实现与@chrispr相同的功能:
public override ValidationResult Validate(ValidationContext<T> context)
{
return (context.InstanceToValidate == null)
? new ValidationResult(new[] { new ValidationFailure("Property", "Error Message") })
: base.Validate(context);
}
答案 3 :(得分:2)
我从流畅的AbstractValidator继承并创建了一个NullReferenceAbstractValidator类:
public class NullReferenceAbstractValidator<T> : AbstractValidator<T>
{
public override ValidationResult Validate(T instance)
{
return instance == null
? new ValidationResult(new[] { new ValidationFailure(instance.ToString(), "response cannot be null","Error") })
: base.Validate(instance);
}
}
然后从该类继承,每个验证程序需要一个空引用检查:
public class UserValidator : NullReferenceAbstractValidator<User>
答案 4 :(得分:1)
由于上述解决方案对我不起作用(FluentValidation,Net45版本= 6.2.1.0),我发布的是我所做的。
这只是ValidateAndThrow
扩展方法的简单替换/包装。
public static class ValidatorExtensions
{
public static void ValidateAndThrowNotNull<T>(this IValidator<T> validator, T instance)
{
if (instance == null)
{
var validationResult = new ValidationResult(new[] { new ValidationFailure("", "Instance cannot be null") });
throw new ValidationException(validationResult.Errors);
}
validator.ValidateAndThrow(instance);
}
}
答案 5 :(得分:1)
使用级联模式。
以下是documentation。
中的示例 query_posts( array(
...
)
),
'posts_per_page' => 100
)
);
?>
<table style="border:1px solid black" cellpadding="1.5" cellspacing="5">
<tbody>
<tr>
<th><strong>NAME\SUBJECT</strong></th>
<th align='center'><strong>French</strong></th>
<th align='center'><strong>Business Education</strong></th>
<th align='center'><strong>Total</strong></th>
<th align='center'><strong>Average</strong></th>
<th align='center'><strong>Position</strong></th>
</tr>
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<!-- Initializing count and sum -->
<?php
$subject_count=0;
$subject_sum_total=0;
$subject_french_exam_total= get_post_meta(get_the_ID(),'_ts_subject_french_exam_total',true );
if($subject_french_exam_total):
$subject_count++;
$subject_sum_total+=$subject_french_exam_total;
endif;
$subject_business_edu_exam_total= get_post_meta(get_the_ID(),'_ts_subject_business_edu_exam_total',true );
if($subject_business_edu_exam_total):
$subject_count++;
$subject_sum_total+=$subject_business_edu_exam_total;
endif;
$store_student_avg=array();
if($subject_sum_total>0.1):
$subject_avg_total= $subject_sum_total/$subject_count;
array_push($store_student_avg,$subject_avg_total);
endif;
?>
<tr>
<td><?php the_title(); ?></td>
<td><?php echo $subject_french_exam_total ;?></td>
<td><?php echo $subject_business_edu_exam_total ;?></td>
<td><?php echo $subject_sum_total ;?></td>
<td><?php echo $subject_avg_total ;?></td>
<?php
rsort($store_student_avg);
$arrlength = count($store_student_avg);
$rank = 1;
$prev_rank = $rank;
for($x = 0; $x < $arrlength; $x++)
if ($x==0): ?>
<td><?php echo $rank; ?></td>
<?php elseif ($numbers[$x] != $numbers[$x-1]):
$rank++;
$prev_rank = $rank;
?>
<td><?php echo $rank; ?></td>
<?php else:
$rank++;
?>
<td><?php echo $prev_rank; ?></td>
<?php endif; ?>
</tr>
<?php endwhile;endif; ?>
</tbody>
</table>
同样来自文档:
如果NotNull验证器失败,那么NotEqual验证器将不会 执行。如果您有一个复杂的链,这将特别有用 其中每个验证器依赖于先前的验证器来成功。
答案 6 :(得分:1)
覆盖EnsureInstanceNotNull,如下所示
protected override void EnsureInstanceNotNull(object instanceToValidate)
{
if(instanceToValidate==null)
throw new ValidationException("Customer can not be null");
}
答案 7 :(得分:1)
通过Custom()。当另一个字段的验证基于您当前字段的验证时,它也会非常有用。
ruleBuilder.Custom((obj, context) =>
{
if (obj != null)
{
var propertyName = <field where should be validation>;
context.AddFailure(propertyName, "'Your field name' Your validation message.");
}
});
答案 8 :(得分:1)
这是一篇较旧的文章,但希望更新答案以包括FluentValidation文档中的以下内容:
使用PreValidate
如果每次调用验证程序时都需要运行特定的代码,则可以通过重写PreValidate方法来执行此操作。此方法采用ValidationContext和ValidationResult,可用于自定义验证过程。
float bluee = float.Parse(blue, fmt); //default float of string3