我正在开发基于MVC5 / Web API的应用程序。在一些文章中,我已阅读使用Contract.Requires
(System.Diagnostics.Contracts
命名空间的一部分)来验证传入数据。
这是验证传入数据的正确方法吗?此外,我无法调试Contract.Requires
行,因为调试器始终绕过此行。我正在使用Visual Studio 2013。
public async Task<UserInfo> Put(
[FromBody] UserInfo userInfo) {
Contract.Requires(userInfo != null);
..............
}
有人可以解释何时使用Contract.Requires
以及在哪里避免?
答案 0 :(得分:3)
您当然可以在控制器中使用代码合同,但这里有一些缺点和原因,您可能不需要合同。
API响应中错误详细信息丢失:代码合同失败将作为HTTP 500内部服务器错误返回给客户端,可能没有详细信息,这对客户端无效API。这是因为合同失败会导致抛出异常。您可能更愿意使用自己的详细信息抛出HttpResponseException
,或者自定义HttpResponseMessage
。在这种情况下(除非你滚动自己的全局异常处理)代码合同可能没有意义。
Contract.Requires可能是多余的:考虑Web API如何验证您的参数。例如,缺少参数可能导致无效路由,因此请求被拒绝,并且不会调用该方法。代码合同在这种方法中没用。
为什么需要合同?代码合同非常适合在编译时捕获合同失败。但除非您的API客户端也是.NET项目,否则您无法利用该功能。因此,请考虑您可能需要签订合同的其他内容以及是否证明其合理使用。
答案 1 :(得分:3)
为什么要签约?
你可以在api方法中使用HttpResponseMessage:
[HttpPost]
public HttpResponseMessage Put(UserInfo userInfo) {
if(ModelState.IsValid)
{
// your code
return Request.CreateResponse(HttpStatusCode.OK);
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest, new { msg = "invalid data" });
}
}
和或:
[HttpPost]
public async Task<ActionResult> Put(UserInfo userInfo) {
if(ModelState.IsValid)
{
// your code
return Request.CreateResponse(HttpStatusCode.OK);
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest, new { msg = "invalid data" });
}
}
答案 2 :(得分:2)
虽然Keith指出了在Web中使用代码契约的一些明显的缺点。我想分享一些关于它们可能有意义或派上用场的想法。
使用代码约定,您可以使用标准方法进行输入验证和参数验证(如断言甚至后置条件)。 这意味着您可以以相同的方式编码 - 无论您是在ApiController内还是在其他一些代码中(例如异步工作线程)。
当然,发送到客户端的一般HTTP 500消息没有用,因此我们将代码约定与标准Web.Api异常处理程序(HttpStatusExceptionFilterAttribute)结合使用。此异常处理程序将检查消息并将自定义HTTP错误代码发送回客户端(可选地连同失败的条件)以及它可以将完整堆栈跟踪记录到中央应用程序的日志工具。
通过利用这两个功能,您可以清理和简化代码,同时向客户端提供友好且有意义的错误信息,同时仍保留完整的错误信息以进行内部故障排除。
您可以查看本文,进一步解释它:Using CodeContracts with OData Controllers and Web.Api Exception Filters
希望这会有所帮助
问候,罗纳德