我一直在用WebApi开发,已经转移到WebApi2,微软已经引入了一个新的IHttpActionResult接口,似乎建议用于返回一个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。这种能力不会消失。我和你有同样的感觉,并与团队进行了广泛的争论,认为没有必要进行额外的抽象。有一些争论试图证明它的存在,但没有什么能让我相信它是值得的。

直到我看到布拉德·威尔逊的这个样本。如果您以一种可以链接的方式构造IHttpActionResult类,您将获得创建一个“操作级”响应管道以生成HttpResponseMessage的能力。在封面下,这是ActionFilters是如何实现的,然而,当阅读动作方法时,这些ActionFilters的顺序并不明显,这是我不喜欢动作过滤器的一个原因。

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

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

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

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

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

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

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

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

您可能决定不使用IHttpActionResult,因为您现有的代码构建了一个HttpResponseMessage,该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种类型的对象:void、HttpResponseMessage、IHttpActionResult和其他强类型。Web API的第一个版本返回HttpResponseMessage,这是一个非常直接的HTTP响应消息。

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

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

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

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

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

Respecting single responsibility principle: cause action methods to have the responsibility of serving the HTTP requests and does not involve them in creating the HTTP response messages. Useful implementations already defined in the System.Web.Http.Results namely: Ok NotFound Exception Unauthorized BadRequest Conflict Redirect InvalidModelState (link to full list) Uses Async and Await by default. Easy to create own ActionResult just by implementing ExecuteAsync method. you can use ResponseMessageResult ResponseMessage(HttpResponseMessage response) to convert HttpResponseMessage to IHttpActionResult.

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

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