我有一个简单的web,它使用验证属性执行一些基本的验证。如果请求不符合验证要求,那么我将从ModelStateDictionary中提取错误消息,并将这些消息作为字典返回给调用方,其中键是指向有错误的属性的路径,该消息指示问题所在。
问题是,给定某些输入,ModelStateDictionary中的错误消息通常包含我不希望返回到客户端的信息(例如转换器试图将JSON映射到的对象的全名(包括命名空间))。
是否有可能区分验证错误(由验证属性/ IValidatableObject实现生成)和试图将无效的JSON映射到特定对象时生成的错误?
例如:
My models
public class Order
{
[Required]
public Customer Customer { get; set; }
}
public class Customer
{
[Required]
public string Name { get; set; }
}我的行动方法
public IActionResult Post(Order order)
{
if (!ModelState.IsValid)
{
var errors = GetErrors(ModelState);
return BadRequest(errors);
}
return Ok();
}
private Dictionary<string, string> GetErrors(ModelStateDictionary modelState)
{
var errors = new Dictionary<string, string>();
foreach (var error in modelState)
{
string message = null;
if (error.Value.Errors.Any(e => e.Exception != null))
{
message = "Unable to interpret JSON value.";
}
else
{
message = string.Join(". ", string.Join(". ", error.Value.Errors.Select(e => e.ErrorMessage)));
}
errors.Add(error.Key, message);
}
return errors;
}我的示例输入:
缺少必需数据的
{
"Customer": {
"Name": null // name is required
}
}由于Customer.Name是用RequiredAttribute修饰的,因此将生成以下错误消息:
{
"Customer.Name": "The Name field is required."
}这是可以返回给调用者的东西,所以这里没有问题。
{
"Customer": 123 // deserializing will fail to map this value to a Customer object
}由于将值123反序列化为Customer对象失败,因此将生成以下错误消息:
{
"Customer": "Error converting value 123 to type 'MyProject.Models.Customer'. Path 'Customer', line 2, position 19."
}返回到调用方是不行的,因为它包含要映射到的对象的完整命名空间路径。在本例中,一些是通用的(例如"Bad JSON值“)。应该用作错误消息。
有人能帮我找到隐藏这些错误信息的解决方案吗?这些错误消息包含不应该返回给调用者的信息。
正如在上面的代码中所看到的,我想我可以检查ModelEntry.Exception属性并使用它来确定是否需要屏蔽错误消息,但是在我的两个示例中,这都是空的。
解决方案可能是检查错误消息是否以Error converting value开头,如果是的话,请屏蔽该消息不受调用方的影响。这看起来不太可靠,我也不确定这在现实世界的例子中会有多可靠。
发布于 2021-02-09 09:20:35
HTTP 400响应的默认响应类型是ValidationProblemDetails类。因此,我们将创建一个继承ValidationProblemDetails类的自定义类,并定义自定义错误消息。
public class CustomBadRequest : ValidationProblemDetails
{
public CustomBadRequest(ActionContext context)
{
ConstructErrorMessages(context);
Type = context.HttpContext.TraceIdentifier;
}
private void ConstructErrorMessages(ActionContext context)
{
//this is the error message you get...
var myerror = "Error converting value";
foreach (var keyModelStatePair in context.ModelState)
{
var key = keyModelStatePair.Key;
var errors = keyModelStatePair.Value.Errors;
if (errors != null && errors.Count > 0)
{
if (errors.Count == 1)
{
var errorMessage = GetErrorMessage(errors[0]);
if (errorMessage.StartsWith(myerror))
{
Errors.Add(key, new[] { "Cannot deserialize" });
}
else
{
Errors.Add(key, new[] { errorMessage });
}
}
else
{
var errorMessages = new string[errors.Count];
for (var i = 0; i < errors.Count; i++)
{
errorMessages[i] = GetErrorMessage(errors[i]);
if (errorMessages[i] == myerror)
{
errorMessages[i] = "Cannot deserialize";
}
}
Errors.Add(key, errorMessages);
}
}
}
}
string GetErrorMessage(ModelError error)
{
return string.IsNullOrEmpty(error.ErrorMessage) ?
"The input was not valid." :
error.ErrorMessage;
}
}在Startup.cs中配置:
services.AddControllers().ConfigureApiBehaviorOptions(options =>
{
options.InvalidModelStateResponseFactory = context =>
{
var problems = new CustomBadRequest(context);
return new BadRequestObjectResult(problems);
};
});确保您的控制器包含[ApiController]属性。
结果:

发布于 2021-02-08 16:53:09
通常,当由于JSON有效负载没有正确格式化而导致模型绑定失败时,传入的模型对象(在您的示例中为“order”)将是null。只需输入一个简单的null检查,并返回带有泛型错误消息的BadRequest。
if (order == null)
return BadRequest("Invalid JSON");https://stackoverflow.com/questions/66104418
复制相似问题