C# 自定义模型验证程序.NET核心中的格式化错误消息
在.NET Core 3.x应用程序中,我有一个如下的模型,其中使用了自定义验证属性C# 自定义模型验证程序.NET核心中的格式化错误消息,c#,asp.net-core,.net-core,asp.net-core-mvc,asp.net-core-3.1,C#,Asp.net Core,.net Core,Asp.net Core Mvc,Asp.net Core 3.1,在.NET Core 3.x应用程序中,我有一个如下的模型,其中使用了自定义验证属性[CustomValidator]。为CustomValidator返回的错误消息没有$。前缀,而内置JSON验证器返回前缀。我希望它们保持一致(无论是否始终使用$。前缀)。你知道怎么做吗 示例模型: public class Dto { public float Price {get; set;} [CustomValidator] public int? EntityID {get; set
[CustomValidator]
。为CustomValidator
返回的错误消息没有$。
前缀,而内置JSON验证器返回前缀。我希望它们保持一致(无论是否始终使用$。
前缀)。你知道怎么做吗
示例模型:
public class Dto
{
public float Price {get; set;}
[CustomValidator] public int? EntityID {get; set;}
}
其中,[CustomValidator]
是一个自定义验证属性,其功能如下
public class CustomValidatorAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var isValid = CheckSomething(...);
return isValid
? ValidationResult.Success
: new ValidationResult($"Invalid value for Entity");
}
}
我在控制器中验证模型。使用
if (!ModelState.IsValid) return BadRequest(ModelState);
对于输入:
{
"Price" : "abc"
}
{
"Price" : 1.0,
"EntityID": -1,
}
它回来了
{
...
"errors": {
"$.price": [
"The JSON value could not be converted to System.Single. Path: $.price | LineNumber: 7 | BytePositionInLine: 21."
]
}
}
{
...
"errors": {
"EntityID": [
"Invalid value for Entity"
]
}
}
鉴于对于输入:
{
"Price" : "abc"
}
{
"Price" : 1.0,
"EntityID": -1,
}
它回来了
{
...
"errors": {
"$.price": [
"The JSON value could not be converted to System.Single. Path: $.price | LineNumber: 7 | BytePositionInLine: 21."
]
}
}
{
...
"errors": {
"EntityID": [
"Invalid value for Entity"
]
}
}
我希望错误总是具有一致的属性名称,例如Price
和EntityID
而不是$。Price
和EntityID
ASP.Net core 3.1使用自己的序列化程序System.Text.Json
您可以在ASP.NET core 3.1中使用Newtonsoft.JSON
步骤:
1:从NuGet软件包下载Microsoft.AspNetCore.Mvc.NewtonsoftJsonb 3.x
2:在Startup.cs中替换services.AddControllersWithViews()代码>带有服务。AddControllersWithViews().AddNewtonsoftJson()代码>
结果:
前缀是JsonException
中包含的json路径的一部分。您可以在这里的默认json输入格式化程序的源代码中看到它
因此,从技术上讲,要在将该路径传递给方法ModelState.TryAddModelError
之前对其进行规范化,您当然需要以某种方式修改该路径。那样很复杂。相反,您可以为最终的问题详细信息
结果配置自定义的InvalidModelStateResponseFactory
。尽管这样,您可能会在性能影响方面做出权衡,尤其是在验证错误频繁发生且涉及大量错误的情况下。但我认为这在现实中并不常见。这种方法的思想是修改ModelState
,方法是尝试交换掉所有键前缀为$的条目。
,并将它们替换为键前缀被修剪掉的条目
您可以通过配置apibhavioroptions
来配置该响应工厂,如下所示:
//inside Startup.ConfigureServices
services.Configure<ApiBehaviorOptions>(o => {
//we need to call this original factory inside our custom factory
var originalFactory = o.InvalidModelStateResponseFactory;
o.InvalidModelStateResponseFactory = context => {
//get all the keys prefixed with $. (which should be related to json errors)
var jsonPathKeys = context.ModelState.Keys.Where(e => e.StartsWith("$.")).ToList();
foreach(var key in jsonPathKeys)
{
var normalizedKey = key.Substring(2);
foreach (var error in context.ModelState[key].Errors)
{
if (error.Exception != null)
{
context.ModelState.TryAddModelException(normalizedKey, error.Exception);
}
context.ModelState.TryAddModelError(normalizedKey, error.ErrorMessage);
}
context.ModelState.Remove(key);
}
return originalFactory(context);
};
});
//内部Startup.ConfigureServices
服务配置(o=>{
//我们需要在我们的定制工厂内给这个原始工厂打电话
var originalFactory=o.InvalidModelStateResponseFactory;
o、 InvalidModelStateResponseFactory=上下文=>{
//获取所有以$为前缀的键(应该与json错误相关)
var jsonPathKeys=context.ModelState.Keys.Where(e=>e.StartsWith(“$”).ToList();
foreach(jsonPathKeys中的var键)
{
var normalizedKey=key.Substring(2);
foreach(上下文中的变量错误.ModelState[key].Errors)
{
if(error.Exception!=null)
{
context.ModelState.tryaddmodeleexception(normalizedKey,error.Exception);
}
context.ModelState.tryaddmodeleror(normalizedKey,error.ErrorMessage);
}
context.ModelState.Remove(键);
}
返回原始目录(上下文);
};
});
实际上我更喜欢使用System.Text.Json
。有没有办法自定义错误消息?还有.Hi@Yinqui,实际上我想继续使用system.text.json,而不是切换回newtonsoft