C# 属性是否丢失表达式x=>;中的元数据;x、 AccountNumber.ToString()是否使用FlientValidation?
我正在为一个个人项目构建一个web应用程序,在.NET 5.0的RESTful API中使用FlientValidation时遇到了一个不寻常的行为。总之,直截了当地说: 这是我的DTO:C# 属性是否丢失表达式x=>;中的元数据;x、 AccountNumber.ToString()是否使用FlientValidation?,c#,asp.net-core,.net-5,fluentvalidation,C#,Asp.net Core,.net 5,Fluentvalidation,我正在为一个个人项目构建一个web应用程序,在.NET 5.0的RESTful API中使用FlientValidation时遇到了一个不寻常的行为。总之,直截了当地说: 这是我的DTO: public class ClientDto { public string ClientName { get; set; } public int? AccountNumber { get; set; } public int InitialFunds { get; set; }
public class ClientDto
{
public string ClientName { get; set; }
public int? AccountNumber { get; set; }
public int InitialFunds { get; set; }
}
A有一个验证器,对于AccountNumber
public class ClientDtoValidator : AbstractValidator<ClientDto>
{
public ClientDtoValidator()
{
RuleFor(x => x.ClientName).NotNull().NotEmpty();
RuleFor(x => x.AccountNumber.ToString()).MaximumLength(5).When(x => x.AccountNumber != null);
}
}
酒店的名字在哪里?这是我刚才尝试发送的JSON请求:
{
"ClientName" : "Mike",
"AccountNumber" : 123456
}
如果尝试一个AccountNumber
,比如12345,服务器返回200。ClientName还正确验证:
{
"ClientName" : "",
"AccountNumber" : 12345
}
答复:
{
{
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"": [
"The length of '' must be 5 characters or fewer. You entered 6 characters."
]
}
}
{
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"ClientName": [
"'Client Name' must not be empty."
]
}
}
回到验证器,如果我把规则换成简单的东西
//RuleFor(x => x.AccountNumber.ToString()).MaximumLength(5).When(x => x.AccountNumber != null);
RuleFor(x => x.AccountNumber).NotNull().NotEmpty();
这样的要求
{
"ClientName" : null,
"AccountNumber" : null
}
将显示这两个字段的名称来自.NET管道的某个位置:
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"ClientName": [
"'Client Name' must not be empty."
],
"AccountNumber": [
"'Account Number' must not be empty."
]
}
我的赌注是在
RuleFor(x=>x.AccountNumber.ToString())
中调用.ToString()
,但我不是CLR专家。也不是这方面的“FluentValidator专家”。想法?事实证明,自定义验证非常简单。对于这个特殊的案例,我把这个
RuleFor(x => x.AccountNumber)
.When(x => x.AccountNumber.HasValue == false)
.WithMessage("Account Number' must not be empty.");
RuleFor(x => x.AccountNumber.ToString()).MaximumLength(5).When(x => x.AccountNumber != null);
进入这个
RuleFor(x => x.AccountNumber).Custom((accountNumber, context) =>
{
if (accountNumber.ToString().Length > 5)
context.AddFailure(@$"The length of 'AccountNumber' must be 5 characters or fewer.
You entered {accountNumber.ToString().Length} characters.");
}).When(x => x.AccountNumber != null);
它绕过了框架找不到属性名的整个问题。即使消息是可自定义的,但我将其保留为默认值:
{
"ClientName" : "Joe",
"AccountNumber" : 123456
}
回应
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-276c77469c6acd4a9bf6f353a5606327-d956a33f62c9eb46-00",
"errors": {
"AccountNumber": [
"The length of 'AccountNumber' must be 5 characters or fewer. You entered 6 characters."
]
}
好东西
编辑
使其通用(我使用了一个静态类,因为我看不出不这样做的原因):
公共静态类CustomValidationRules
{
公共静态无效检查MaxLengthValidationFailure(int-length,int-maxLength,
字符串属性名称,FluentValidation.ValidationContext ValidationContext)
{
如果(长度>最大长度)
validationContext.AddFailure(@$“{propertyName}的长度必须为{maxLength}
字符或更少。您输入了{length}个字符。“);
}
}
这样使用:
public class ClientDtoValidator : AbstractValidator<ClientDto>
{
public ClientDtoValidator()
{
RuleFor(x => x.ClientName).NotNull().NotEmpty();
RuleFor(x => x.CreditCardNumber).Custom((creditCardNumber, context) =>
{
CustomValidationRules.CheckMaxLengthValidationFailure(creditCardNumber.ToString().Length, 16, "CreditCardNumber", context);
}).When(x => x.CreditCardNumber != null);
RuleFor(x => x.AccountNumber).Custom((accountNumber, context) =>
{
CustomValidationRules.CheckMaxLengthValidationFailure(accountNumber.ToString().Length, 5, "AccountNumber", context);
}).When(x => x.AccountNumber != null);
}
}
公共类ClientDtoValidator:AbstractValidator
{
公共客户端Tovalidator()
{
RuleFor(x=>x.ClientName).NotNull().NotEmpty();
规则(x=>x.CreditCardNumber)。自定义((CreditCardNumber,上下文)=>
{
CustomValidationRules.CheckMaxLengthValidationFailure(creditCardNumber.ToString().Length,16,“creditCardNumber”,上下文);
}).When(x=>x.CreditCardNumber!=null);
RuleFor(x=>x.AccountNumber).Custom((AccountNumber,context)=>
{
CustomValidationRules.CheckMaxLengthValidationFailure(accountNumber.ToString().Length,5,“accountNumber”,上下文);
}).When(x=>x.AccountNumber!=null);
}
}
事实证明,自定义验证非常简单。对于这个特殊的案例,我把这个
RuleFor(x => x.AccountNumber.ToString()).MaximumLength(5).When(x => x.AccountNumber != null);
进入这个
RuleFor(x => x.AccountNumber).Custom((accountNumber, context) =>
{
if (accountNumber.ToString().Length > 5)
context.AddFailure(@$"The length of 'AccountNumber' must be 5 characters or fewer.
You entered {accountNumber.ToString().Length} characters.");
}).When(x => x.AccountNumber != null);
它绕过了框架找不到属性名的整个问题。即使消息是可自定义的,但我将其保留为默认值:
{
"ClientName" : "Joe",
"AccountNumber" : 123456
}
回应
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-276c77469c6acd4a9bf6f353a5606327-d956a33f62c9eb46-00",
"errors": {
"AccountNumber": [
"The length of 'AccountNumber' must be 5 characters or fewer. You entered 6 characters."
]
}
好东西
编辑
使其通用(我使用了一个静态类,因为我看不出不这样做的原因):
公共静态类CustomValidationRules
{
公共静态无效检查MaxLengthValidationFailure(int-length,int-maxLength,
字符串属性名称,FluentValidation.ValidationContext ValidationContext)
{
如果(长度>最大长度)
validationContext.AddFailure(@$“{propertyName}的长度必须为{maxLength}
字符或更少。您输入了{length}个字符。“);
}
}
这样使用:
public class ClientDtoValidator : AbstractValidator<ClientDto>
{
public ClientDtoValidator()
{
RuleFor(x => x.ClientName).NotNull().NotEmpty();
RuleFor(x => x.CreditCardNumber).Custom((creditCardNumber, context) =>
{
CustomValidationRules.CheckMaxLengthValidationFailure(creditCardNumber.ToString().Length, 16, "CreditCardNumber", context);
}).When(x => x.CreditCardNumber != null);
RuleFor(x => x.AccountNumber).Custom((accountNumber, context) =>
{
CustomValidationRules.CheckMaxLengthValidationFailure(accountNumber.ToString().Length, 5, "AccountNumber", context);
}).When(x => x.AccountNumber != null);
}
}
公共类ClientDtoValidator:AbstractValidator
{
公共客户端Tovalidator()
{
RuleFor(x=>x.ClientName).NotNull().NotEmpty();
规则(x=>x.CreditCardNumber)。自定义((CreditCardNumber,上下文)=>
{
CustomValidationRules.CheckMaxLengthValidationFailure(creditCardNumber.ToString().Length,16,“creditCardNumber”,上下文);
}).When(x=>x.CreditCardNumber!=null);
RuleFor(x=>x.AccountNumber).Custom((AccountNumber,context)=>
{
CustomValidationRules.CheckMaxLengthValidationFailure(accountNumber.ToString().Length,5,“accountNumber”,上下文);
}).When(x=>x.AccountNumber!=null);
}
}
在RuleFor(x=>x.AccountNumber.ToString())
中使用ToString()是个问题,它不再是DTO属性的成员表达式/规则,而是字符串表达式
您不需要编写自定义代码来处理此问题
Transform(x=>x.AccountNumber,x=>x.ToString())。最大长度(5)。当(x=>x.AccountNumber!=null)代码>将是一种方法(注意:)
另一种方式
RuleFor(x=>x.AccountNumber).inclusivebeween(199999).When(x=>x.AccountNumber!=null)代码>
因为您在使用时总是在服务器端对其进行评估,必须是另一个选项。如果有更多选项可用,主要的问题是如果不需要自定义代码,就避免使用它。在RuleFor(x=>x.AccountNumber.ToString())中使用ToString()
是问题所在,它不再是DTO属性的成员表达式/规则,而是字符串表达式
您不需要编写自定义代码来处理此问题
Transform(x=>x.AccountNumber,x=>x.ToString())。最大长度(5)。当(x=>x.AccountNumber!=null)代码>将是一种方法(注意:)
另一种方式
RuleFor(x=>x.AccountNumber).inclusivebeween(199999).When(x=>x.AccountNumber!=null)代码>
因为您在使用时总是在服务器端对其进行评估,必须是另一个选项。如果有更多的选项可用,主要的是避免使用不需要的自定义代码。它使用的是反编译的表达式。它正在寻找一个成员表达式,以获取其名称(属性或字段),但它没有得到该名称,而是得到一个方法调用表达式。所以它默认为空白。对我来说有道理。你的帐号是真的吗