C# FluentValidation LogOnFailure覆盖
在我的validator类中,我有两条规则。C# FluentValidation LogOnFailure覆盖,c#,asp.net-web-api,fluentvalidation,C#,Asp.net Web Api,Fluentvalidation,在我的validator类中,我有两条规则。 我需要将一些验证错误记录到数据库 以下是我的验证器: RuleFor(u => u.LastName) .Cascade(CascadeMode.StopOnFirstFailure) .NotEmpty().WithMessage("Last name is required") .Length(3, 20).WithMessage("Must have between 3 and 20 letters"); Rul
我需要将一些验证错误记录到数据库 以下是我的验证器:
RuleFor(u => u.LastName)
.Cascade(CascadeMode.StopOnFirstFailure)
.NotEmpty().WithMessage("Last name is required")
.Length(3, 20).WithMessage("Must have between 3 and 20 letters");
RuleFor(u => u.BirthDate)
.Cascade(CascadeMode.StopOnFirstFailure)
.NotNull().WithMessage("Birth date is required")
.Must(c => c > new DateTime(1920, 01, 01)).WithMessage("Too old");
RuleFor(u => u.Age)
.Cascade(CascadeMode.StopOnFirstFailure)
.NotNull().WithMessage("This is required")
.GreaterThan(18).WithMessage("Must be at least 18")
.Must((model, age, context) =>
{
DateTime today = DateTime.Today;
int ageToCompare = today.Year - model.BirthDate.Year;
return ageToCompare == age;
}).WithMessage("Invalid age");
对于以上规则,我只想记录特定的错误消息。
我知道我可以使用以下任何失败:
RuleFor(u => u.Age)
.Cascade(CascadeMode.StopOnFirstFailure)
.NotNull().WithMessage("This is required")
.GreaterThan(18).WithMessage("Must be at least 18").OnAnyFailure(LogOnFailure)
.Must((model, age, context) =>
{
DateTime today = DateTime.Today;
int ageToCompare = today.Year - model.BirthDate.Year;
return ageToCompare == age;
}).WithMessage("Invalid age").OnAnyFailure(LogOnFailure)
private void LogOnFailure(CreateAccountBindingModel obj))
{
Debug.WriteLine(obj);
}
但这样我将无法记录任何有用的内容,因为OnAnyFailure
将BindingModel作为参数,所以我将只获取用户输入的值,而不会显示错误消息
我曾尝试创建一个扩展方法,该方法可以作为OnAnyFailure的OnAnyFailure
,但由于我是FluentValidation新手,所以我甚至无法编译代码
下面是我的代码:
public static class IRuleBuilderOptionsExtensions
{
public static IRuleBuilderOptions<T, TProperty> OnAnyFailure<T, TProperty>(this IRuleBuilderOptions<T, TProperty> rule, Action<T, PropertyValidatorContext> onFailure)
{
return rule;
//return rule.Configure(config => {
// config.OnFailure = onFailure.CoerceToNonGeneric();
//});
}
}
基本上,我需要的是为
LogOnFailure
创建覆盖,该覆盖将能够访问PropertyValidatorContext。您可以再次验证模型以显示它:
public class MyValidator
{
public MyValidator()
{
// default behavior
Validate();
// works only when RuleSet specified explicitly as "Debug"
RuleSet("Debug", ()=> {
Validate();
FailAndLogErrors();
})
private void Validate()
{
RuleFor(u => u.Age)
//... set cascade mode, define rules with error messages
RuleFor(u => u.LastName)
//... set cascade mode, define rules with error messages
RuleFor(u => u.BirthDate)
//... set cascade mode, define rules with error messages
}
// force failing
private void FailAndLogErrors()
{
RuleFor(m => m)
.Must(m => false)
.WithName("_fakeProperty_")
.OnAnyFailure(m => LogIfFailed(this, m))
}
private void LogIfFailed(MyValidator validator, CreateAccountBindingModel obj))
{
var errors = validator.Validate(obj, "Debug").Errors;
if (errors.Count > 1) // prevent displaying valid model
{
var fakeError = errors.First(e => e.PropertyName == "_fakeProperty_");
errors.Remove(fakeError);
WriteErrors(errors);
}
}
private void WriteErrors(IList<ValidationFailure> errors)
{
foreach(var e in errors)
{
Debug.WriteLine(e);
}
Debug.WriteLine("");
}
}
}
公共类MyValidator
{
公共MyValidator()
{
//默认行为
验证();
//仅当规则集明确指定为“调试”时才起作用
规则集(“调试”,()=>{
验证();
FailAndLogErrors();
})
私有void Validate()
{
规则(u=>u.Age)
//…设置级联模式,定义带有错误消息的规则
规则(u=>u.LastName)
//…设置级联模式,定义带有错误消息的规则
规则(u=>u.生日)
//…设置级联模式,定义带有错误消息的规则
}
//强制失效
私有void FailAndLogErrors()
{
规则(m=>m)
.Must(m=>false)
.使用名称(“\u fakeProperty”)
.OnAnyFailure(m=>LogIfFailed(this,m))
}
私有void LogIfFailed(MyValidator验证器,CreateAccountBindingModel obj))
{
var errors=validator.Validate(obj,“Debug”).errors;
if(errors.Count>1)//阻止显示有效模型
{
var fakeError=errors.First(e=>e.PropertyName==“\u fakeProperty””;
错误。删除(fakeError);
写入错误(错误);
}
}
私有无效写入错误(IList错误)
{
foreach(错误中的变量e)
{
Debug.WriteLine(e);
}
Debug.WriteLine(“”);
}
}
}
创建覆盖将没有帮助,因为框架将使用单个参数(要验证的实例)调用PropertyRule.OnFailure
。@AlekseyL。那么还有别的办法吗?方法的名称可以不同,不必重写。我想在发生错误时获取我的模型和属性验证上下文,就像我不知道有这样的扩展点一样,但你可以在ActionFilter
检查模型状态并记录所有错误。如果你需要这个例子,请告诉我。@AlekseyL。我已经在FluentValidation repo(github.com/JeremySkinner/FluentValidation/issues/…)上发布了我当前的解决方案代码,我正在等待Jeremy的审核。我已经在我的项目中实现了这个解决方案,它工作得很好,但是我想在我发布它之前得到作者的评论。也许你可以看看它并分享你的想法?为什么不在特定的必须验证器中记录错误呢?谢谢,private void LogIfFailed(MyValidator validator,CreateAccountBindingModel obj)最后应该只有一个右括号
public class MyValidator
{
public MyValidator()
{
// default behavior
Validate();
// works only when RuleSet specified explicitly as "Debug"
RuleSet("Debug", ()=> {
Validate();
FailAndLogErrors();
})
private void Validate()
{
RuleFor(u => u.Age)
//... set cascade mode, define rules with error messages
RuleFor(u => u.LastName)
//... set cascade mode, define rules with error messages
RuleFor(u => u.BirthDate)
//... set cascade mode, define rules with error messages
}
// force failing
private void FailAndLogErrors()
{
RuleFor(m => m)
.Must(m => false)
.WithName("_fakeProperty_")
.OnAnyFailure(m => LogIfFailed(this, m))
}
private void LogIfFailed(MyValidator validator, CreateAccountBindingModel obj))
{
var errors = validator.Validate(obj, "Debug").Errors;
if (errors.Count > 1) // prevent displaying valid model
{
var fakeError = errors.First(e => e.PropertyName == "_fakeProperty_");
errors.Remove(fakeError);
WriteErrors(errors);
}
}
private void WriteErrors(IList<ValidationFailure> errors)
{
foreach(var e in errors)
{
Debug.WriteLine(e);
}
Debug.WriteLine("");
}
}
}