Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/256.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 自定义模型验证程序.NET核心中的格式化错误消息_C#_Asp.net Core_.net Core_Asp.net Core Mvc_Asp.net Core 3.1 - Fatal编程技术网

C# 自定义模型验证程序.NET核心中的格式化错误消息

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

在.NET Core 3.x应用程序中,我有一个如下的模型,其中使用了自定义验证属性
[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