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


326

我一直在使用WebApi进行开发,然后转到了WebApi2,Microsoft在其中引入了一个新的IHttpActionResult接口,似乎建议将其用于返回a的接口HttpResponseMessage。我对这个新界面的优势感到困惑。它似乎主要只是提供了一种稍微容易些的创建方式HttpResponseMessage

我认为这是“抽象的抽象”。我想念什么吗?除了节省一行代码之外,使用此新接口还能给我带来什么现实世界的好处?

旧方法(WebApi):

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();
    }
}

我刚刚发现了一些有趣的东西。我不确定这些结果是否可以被其他人验证。但是通过执行一些调用,性能有了很大提高:*通过使用一个示例,HttpResponseMessage我在9545 ms内返回了响应。*使用IHttpActionResult我在同一个响应返回294毫秒
克里斯·莱斯格

@chrislesage 9545毫秒几乎是10秒。甚至294ms也有点慢。如果您花费的时间超过100毫秒,那么那里还有其他工作。这个故事不仅仅满足于期待。
AaronLS

Answers:


305

您可能会决定不使用它,IHttpActionResult因为您现有的代码所生成的a HttpResponseMessage不适合罐装响应之一。但是,您可以适应HttpResponseMessageIHttpActionResult使用的罐头回应ResponseMessage。我花了一些时间才弄清楚这一点,因此我想发布它,以表明您不必选择其中一个:

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;
}

注意,ResponseMessageApiController您的控制器应继承的基类的方法。


1
花了我一段时间才发现ResponseMessage现在是ResponseMessageResult。也许它最近已重命名?附注:您在答案中也错过了一个新关键字,非常感谢您的建议:)
Ilya Chernomordik

10
@IlyaChernomordik ResponseMessageResponseMessageResult是两个不同的东西。 ResponseMessage()是一种方法ApiController,你的控制器应继承的,因此只是一个方法调用。因此new,那里不需要关键字。您可能没有继承,ApiController或者您处于静态方法内。 ResponseMessageResult是的返回类型ResponseMessage()
AaronLS 2015年

3
@IlyaChernomordik我可以写得response = base.ResponseMessage(responseMsg)更清楚一些,它是基类ApiController的方法
AaronLS 2015年

谢谢,我确实有一个服务没有从ApiController继承,这就是为什么要花一些时间才能找到它的原因。
Ilya Chernomordik

3
@pootzko您是对的,我提到了一个事实,即OP似乎暗示他们认为这两种方法是互斥的,将它们称为“旧方法”与“新方法”,而实际上并非如此。我认为Darrel的答案很好地解释了返回IHttpActionResult的一些好处,而我的答案演示了如何将旧的HttpResponseMessage转换为IHttpActionResult,从而可以兼得两者。
AaronLS 2015年

84

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

也就是说,直到我看到Brad Wilson的这个样本。如果以可以链接的方式构造类,则可以创建“操作级”响应管道以生成的能力。在幕后,这是实现方式,但是,在阅读action方法时,它们的顺序并不明显,这是我不喜欢action filter的原因之一。IHttpActionResultHttpResponseMessageActionFiltersActionFilters

但是,通过创建IHttpActionResult可以在您的操作方法中显式链接的,您可以组成各种不同的行为来生成响应。


62

这是Microsoft ASP.Net文档IHttpActionResultover HttpResponseMessage提到的一些好处:

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

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

  • 遵守单一责任原则:导致操作方法负责服务HTTP请求,并且不将其包含在创建HTTP响应消息中。
  • 有用的实现中即System.Web.Http.Results已经定义:Ok NotFound Exception Unauthorized BadRequest Conflict Redirect InvalidModelState链接到完整名单
  • 默认情况下使用“ 异步”和“等待”
  • 只需实施即可轻松创建自己的ActionResultExecuteAsync方法即可。
  • 您可以ResponseMessageResult ResponseMessage(HttpResponseMessage response)用来将HttpResponseMessage转换为IHttpActionResult

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

18

这只是我的个人观点,来自Web API团队的人们可能可以更好地表达出来,但这是我的2c。

首先,我认为这不是一个一个又一个的问题。您可以使用这两个取决于你想要在你的操作方法做什么,但为了了解真正的力量IHttpActionResult,你可能会需要一步的那些方便的helper方法之外ApiController,例如OkNotFound等等。

基本上,我认为一个实现IHttpActionResultHttpResponseMessage。有了这种思路,它现在变成需要返回的对象,并由工厂生产它。在一般的编程意义上,您可以在某些情况下自己创建对象,并且在某些情况下,您需要工厂来执行此操作。同样在这里。

如果要返回需要通过复杂的逻辑构造的响应(例如,许多响应标头等),则可以将所有这些逻辑抽象为实现的动作结果类IHttpActionResult,并在多种动作方法中使用它来返回响应。

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

当然,正如Darrel所述,您可以链接操作结果并创建一个功能强大的微管道,类似于API管道中的消息处理程序本身。根据您的操作方法的复杂性,您将需要此功能。

长话短说-它不是IHttpActionResult对立的HttpResponseMessage。基本上,这就是您要如何创建响应。自己或通过工厂进行。


我在工厂调整中遇到的问题是,我可以轻松地创建ResponseFactory.CreateOkResponse()返回HttpResponseMessage之类的静态方法,并且在创建响应时不必处理异步内容。一位团队成员确实提到了以下事实:如果您需要执行I / O来生成标头值,那么异步可能会很有用。不知道这种情况多久发生一次。
Darrel Miller

我认为这与说为什么我们需要工厂方法模式相同。为什么不只是使用静态方法来创建对象。当然,这是可行的-每个对象创建都不具有适当的工厂模式。但是恕我直言,这取决于您要如何对类进行建模。您是否想要逻辑来创建不同类型的响应,这些响应都以多种静态方法的形式塞入一个类,或者基于接口具有不同的类?同样,没有好与坏。一切取决于。无论如何,我的观点是,这不是一个接一个的过程,我个人更喜欢工厂的事情:)
Badri

6

在Web API基本上回到4类型的对象:voidHttpResponseMessageIHttpActionResult,等强类型。Web API的第一个版本返回HttpResponseMessage,这是非常简单的HTTP响应消息。

IHttpActionResult通过的WebAPI 2,其是一种包裹物引入HttpResponseMessage。它包含ExecuteAsync()创建的方法HttpResponseMessage。它简化了控制器的单元测试。

其他返回类型是由Web API使用媒体格式化程序序列化到响应主体中的强类型类。缺点是您不能直接返回错误代码(例如404)。您所能做的就是抛出HttpResponseException错误。


3

我宁愿为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是有效负载。


2

使用IHttpActionResultover 有以下好处HttpResponseMessage

  1. 通过使用,IHttpActionResult我们只专注于要发送的数据,而不关注状态码。因此,这里的代码将更加简洁并且易于维护。
  2. 实施的控制器方法的单元测试将更加容易。
  3. 默认情况下使用asyncawait
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.