我正在使用.Net 4.5.1创建一个使用MVC 6的ASP.Net 5应用程序。我有一个POST方法,它使用FromBody参数自动获取对象。
[HttpPost]
public IActionResult Insert([FromBody]Agent agent)
{
try
{
var id = service.Insert(agent);
return Ok(id);
}
catch (Exception ex)
{
return HttpBadRequest(ex);
}
}
这只是一个证明一个概念,我不会只返回成功时的id或错误时的完整异常。
当发送有效的JSON时,一切正常。但是,当发送无效的JSON时,我在调试期间收到异常:
抛出异常:'Newtonsoft.Json.JsonReaderException'中 Newtonsoft.Json.dll
其他信息:在解析值后出现意外字符 遇到了:l。路径'名称',第2行,第20位。
问题是在此错误之后,该方法被正常调用,但是使用null参数,并且异常不会传播。
我可以检查null并返回一条通用消息,但这并不像原始消息那样有用,它包含重要信息,例如标记名称和无效字符的位置。
所以我想捕获此异常并将其返回给HTTP调用者。我怎么做?像这样:
{"error": "After parsing a value an unexpected character was encountered: l. Path 'Name', line 2, position 20"}
我知道我可以在try / catch块中手动捕获和反序列化JSON,但这对我来说是不可接受的。我想这样做并继续使用FromBody,我觉得非常高效。
答案 0 :(得分:10)
默认JsonInputFormatter
在遇到错误时实际上会返回空模型 - 但它会填充ModelState
所有例外。
通过挖掘ModelState
:
[HttpPost]
public IActionResult Insert([FromBody]Agent agent)
{
if (!ModelState.IsValid)
{
var errors = ModelState
.SelectMany(x => x.Value.Errors, (y, z) => z.Exception.Message);
return BadRequest(errors);
}
// Model is valid, do stuff.
}
上面的输出是所有异常消息的数组,例如:
[
"After parsing a value an unexpected character was encountered: l. Path 'Name', line 2, position 20",
"Another exception message..."
]
答案 1 :(得分:5)
我发现自己遇到了完全相同的问题,但能够找到不同的解决方案。 我将在这里分享我的解决方案,作为@ ypsilo0n答案的替代方案。
而不是检查每个控制器if (!ModelState.IsValid)
我们可以使用此中间件过滤器:
public class FooFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var modelState = context.ModelState;
if (modelState != null && modelState.IsValid == false)
{
// this class takes the model state and parses
// it into a dictionary with all the errors
var errorModel = new SerializableError(modelState);
context.Result = new BadRequestObjectResult(errorModel);
}
}
}
现在,控制器永远不会被调用,因为此中间件在请求之前运行并结束请求。 (阅读docs了解更多信息)。
当我们设置一个非空context.Result
时,它意味着“在这里结束HTTP请求”(文档) - 如果你问我但不是非常用户友好/直观,那么(希望返回值)
使用.net核心1.1