为什么我应该使用IHttpActionResult而不是HttpResponseMessage?

我一直在用WebApi开发,现在已经转移到WebApi2,微软在WebApi2中引入了一个新的IHttpActionResult接口,似乎建议使用它来返回HttpResponseMessage。我对这个新界面的优点感到困惑。它似乎只是提供了一个更简单的方法来创建HttpResponseMessage

我认为这是“为了抽象而抽象”。我遗漏了什么吗?除了节省一行代码之外,我从使用这个新接口中获得的实际优势是什么?

老方法(之前):

public HttpResponseMessage Delete(int id)
{
var status = _Repository.DeleteCustomer(id);
if (status)
{
return new HttpResponseMessage(HttpStatusCode.OK);
}
else
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}

新方法 (WebApi2):

public IHttpActionResult Delete(int id)
{
var status = _Repository.DeleteCustomer(id);
if (status)
{
//return new HttpResponseMessage(HttpStatusCode.OK);
return Ok();
}
else
{
//throw new HttpResponseException(HttpStatusCode.NotFound);
return NotFound();
}
}
241118 次浏览

你仍然可以使用HttpResponseMessage。这种能力不会消失。我和你有同样的感觉,并与团队进行了广泛的争论,认为没有必要进行额外的抽象。有一些争论试图证明它的存在,但没有什么能让我相信它是值得的。

直到我从布拉德•威尔逊中看到 sample。如果你以一种可以链接的方式构造IHttpActionResult类,你就能够创建一个“行动阈值”响应管道来生成HttpResponseMessage。在封面之下,这是ActionFilters是如何实现的,然而,当读取操作方法时,这些ActionFilters的顺序并不明显,这是我不喜欢操作过滤器的一个原因。

然而,通过创建一个IHttpActionResult,它可以显式地链接到action方法中,你可以组合各种不同的行为来生成响应。

这只是我个人的观点,来自web API团队的人可能会更好地表达它,但这里是我的2c。

首先,我认为这不是一个人胜过另一个人的问题。你可以使用它们,这取决于你想在你的动作方法中做什么,但为了理解IHttpActionResult的真正功能,你可能需要跳出那些方便的ApiController的帮助方法,如OkNotFound等。

基本上,我认为实现IHttpActionResult的类是HttpResponseMessage的工厂。有了这种心态,它现在就变成了一个需要返回的对象和一个生产它的工厂。在一般编程的意义上,您可以在某些情况下自己创建对象,在某些情况下,您需要一个工厂来做这件事。我也一样。

如果你想返回一个需要通过复杂逻辑构造的响应,比如许多响应头,等等,你可以将所有这些逻辑抽象到一个实现IHttpActionResult的操作结果类中,并在多个操作方法中使用它来返回响应。

使用IHttpActionResult作为返回类型的另一个优点是它使ASP。NET Web API动作方法类似MVC。您可以返回任何操作结果,而不会被媒体格式化程序捕获。

当然,正如Darrel所指出的,您可以将操作结果链接起来,并在API管道中创建一个类似于消息处理程序本身的强大微管道。这取决于您的操作方法的复杂性。

长话短说——它不是IHttpActionResultHttpResponseMessage。基本上,这是你想要创建响应的方式。你可以自己做,也可以去工厂做。

你可能决定不使用IHttpActionResult,因为你现有的代码构建了一个HttpResponseMessage,它不适合某个罐装响应。然而,你可以使用ResponseMessage的罐装响应使HttpResponseMessage适应IHttpActionResult。我花了一段时间来弄清楚这个问题,所以我想把它贴出来,让你不必非得选择其中之一:

public IHttpActionResult SomeAction()
{
IHttpActionResult response;
//we want a 303 with the ability to set location
HttpResponseMessage responseMsg = new HttpResponseMessage(HttpStatusCode.RedirectMethod);
responseMsg.Headers.Location = new Uri("http://customLocation.blah");
response = ResponseMessage(responseMsg);
return response;
}

注意,ResponseMessage是你的控制器应该继承的基类ApiController的一个方法。

// this will return HttpResponseMessage as IHttpActionResult
return ResponseMessage(httpResponseMessage);

我宁愿为IHttpActionResult实现TaskExecuteAsync接口函数。喜欢的东西:

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = _request.CreateResponse(HttpStatusCode.InternalServerError, _respContent);


switch ((Int32)_respContent.Code)
{
case 1:
case 6:
case 7:
response = _request.CreateResponse(HttpStatusCode.InternalServerError, _respContent);
break;
case 2:
case 3:
case 4:
response = _request.CreateResponse(HttpStatusCode.BadRequest, _respContent);
break;
}


return Task.FromResult(response);
}

,其中_request是HttpRequest, _respContent是有效负载。

Web API基本上返回4种类型的对象:voidHttpResponseMessageIHttpActionResult和其他强类型。Web API的第一个版本返回HttpResponseMessage,这是一个非常直接的HTTP响应消息。

IHttpActionResult是由WebAPI 2引入的,它是HttpResponseMessage的一种包装。它包含ExecuteAsync()方法,用于创建HttpResponseMessage。它简化了控制器的单元测试。

其他返回类型是一种强类型类,由Web API使用媒体格式化器序列化到响应体中。缺点是不能直接返回404之类的错误代码。你所能做的就是抛出HttpResponseException错误。

下面是在微软的ASP。网络文档中提到的IHttpActionResult相对于HttpResponseMessage的几个优点:

  • 简化控制器的单元测试。
  • 将用于创建HTTP响应的通用逻辑移动到单独的类中。
  • 通过隐藏构造响应的底层细节,使控制器动作的意图更加清晰。

但是这里有一些使用IHttpActionResult的其他优点值得一提:

  • 尊重单一责任原则:使动作方法有服务HTTP请求的责任,并且不涉及它们创建HTTP响应消息。
  • 有用的实现已经在system . web . http . result中定义:Ok NotFound Exception Unauthorized BadRequest Conflict Redirect InvalidModelState (链接到完整列表)
  • 默认使用异步和等待
  • 通过实现ExecuteAsync方法。
  • 你可以使用ResponseMessageResult ResponseMessage(HttpResponseMessage response)将HttpResponseMessage转换为IHttpActionResult

使用IHttpActionResult而不是HttpResponseMessage有以下好处:

  1. 通过使用IHttpActionResult,我们只关注要发送的数据,而不是状态码。所以这里的代码会更简洁,也更容易维护。
  2. 实现的控制器方法的单元测试将更容易。
  3. 默认使用asyncawait