【问题标题】:What is the difference between HttpResponseMessage and HttpResponseExceptionHttpResponseMessage 和 HttpResponseException 有什么区别
【发布时间】:2012-05-26 12:08:05
【问题描述】:

我试图理解两者并编写示例代码:

 public HttpResponseMessage Get()
 {
     var response = ControllerContext.Request
                         .CreateResponse(HttpStatusCode.BadRequest, "abc");

     throw new HttpResponseException(response);
 }

还有:

 public HttpResponseMessage Get()
 {
     return ControllerContext.Request
                        .CreateResponse(HttpStatusCode.BadRequest, "abc");
 }

从Fiddle,我真的没看出他们有什么区别,那么使用HttpResponseException的目的是什么?

【问题讨论】:

标签: c# asp.net-web-api


【解决方案1】:

两者之间的主要区别在于。该异常对于立即停止处理并退出很有用。例如假设我有以下代码

public class CustomerController : ApiController {
  private ICustomerContext repo;

  public CustomerController(ICustomerContext repo) {
    this.repo = repo;
  }

  public Customer Get(int id) {
    var customer = repo.Customers.SingleOrDefault(c=>c.CustomerID == id);
    if (customer == null) {
      throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
    }
    return customer;
  }
}

如果此代码运行并且我传递了一个不存在的 id,它将立即停止处理并返回 404 状态代码。

如果我返回 HttpResponseMessage,请求将愉快地继续其其余处理并返回 404。主要区别在于是否结束请求。

正如 Darrel 所说,在某些情况下我希望继续处理(如找到客户时)而在其他情况下我不想继续处理时,异常很有用。

您可能想要使用类似 HttpResponseMessage 的地方是在 Http POST 中返回状态代码 201 并设置位置标头。在这种情况下,我确实希望继续处理。这将与此代码有关。*

public class CustomerController : ApiController {
  private ICustomerContext repo;

  public CustomerController(ICustomerContext repo) {
    this.repo = repo;
  }

  public HttpResponseMessage Post(Customer customer) {
    repo.Add(customer);
    repo.SaveChanges();
    var response = Request.CreateResponse(HttpStatusCode.Created, customer);
    response.Headers.Location = new Uri(Request.RequestUri, string.format("customer/{0}", customer.id));
    return response;
  }
}

*注意:如果您使用的是 beta 位,您将创建一个新的 HttpResponseMessage。我正在使用后面的位,但是这要求您使用请求之外的 CreateResponse 扩展方法。

在上面,我正在创建一个响应,它将状态代码设置为 201,传入客户,然后设置位置标头。

然后返回响应并继续处理请求。

希望对你有帮助

【讨论】:

  • 我要补充一点,异常处理/日志记录是另一个原因。您可能想 throw 以记录 404,但不想 throw 也不记录 412。
  • 我真的对“请求继续处理”的意思感到困惑。你return的那一刻请求不是结束了吗?
  • @Stijn - Glenn 的博客 (goo.gl/ErSG9h) 上有一些 cmets 使它更清晰一些。听起来 Glenn 指的是 Web.Api 在控制器返回后执行的处理,例如消息处理程序。然而,史蒂文所罗门质疑是否是这样。
  • @Iain 感谢您的链接,这是一个有趣的评论。不是我不相信格伦,但如果他能证明这一点,那就太好了。
  • @GlennBlock 我不确定这是正确的答案。 This answer 好像不一样
【解决方案2】:

当你的控制器动作签名看起来像这样时,HttpResponseException 很有用

  Foo Get(int id)

在这种情况下,你不能轻易返回 400 之类的状态码。

请注意,HttpResponseMessage<T> 将在 Web API 的下一个版本中消失。

【讨论】:

  • 感谢您的回答,这对我来说很有意义
  • 只有通用的 HttpResponseMessage 会消失
  • @ozba 谢谢,我没有注意到标记语法会阻止尖括号出现。
  • 这也是Professional ASP.Net MVC 4wrox.com/WileyCDA/WroxTitle/…中提到的情况。当您的 API 基于返回域类型(如 Foo)时,您不能在出现错误的情况下返回 HttpResponseMessage,但您可以返回/抛出 HttpResponseException,从而向消费者提供状态代码等。为什么要返回域类型?与这里的其他一些答案相比,他们说它简化了 UT 处理域对象而不是像 HttpResponseMessage 这样的低级框架对象。
  • @rism HttpResponseMessage 不是“低级框架”对象,它是代表您返回的 HTTP 消息的对象。 HTTP 是应用层协议。您不会通过 HTTP 返回对象,而是返回 HTTP 消息。从长远来看,试图假装您正在返回域对象会造成很大的痛苦。
【解决方案3】:

假设您想对响应进行单元测试,总是返回 HttpResponseMessage 是否有意义?我不太喜欢从 ApiController 返回直接类型的想法,因为它不遵循典型的开发模式。

在获取客户的非 Web API 类中,您可能会返回 null,而您的调用代码会检查 null 响应:

public Customer GetCustomer(int id)
{
    return db.Customers.Find(id);
}

但是在 Web API 中,你不会返回 null,你必须返回一些东西,即使那个东西是在你抛出 HttpResponseException 之后创建的。在这种情况下,为了简化测试,为什么不总是返回一个 HttpResponseMessage 并将其作为您的签名?

public HttpResponseMessage GetCustomer(int id)
{
    var customer = db.Customers.Find(id);
    if (customer == null)
    {
        return Request.CreateResponse(HttpStatusCode.NotFound);
    }

    return Request.CreateResponse(HttpStatusCode.OK, customer);
}

【讨论】:

  • 我同意,布赖恩。这也为返回对象和状态代码提供了更好的学习路径。当模板将返回类型设置为业务对象时,您会想知道处理其他响应的正确方法是什么。
  • @Brian 这是一种风格。有些人想深入了解 HTTP,并觉得它是他们应用程序设计的一部分。其他人认为 HTTP 是一个实现细节,宁愿使用 ActionFilters 和 HttpMessageHandlers 抽象出 HTTPness。如果您知道自己在做什么,那么这两种方法都不是错误的。我倾向于采用您的方法,因为我觉得隐藏 HTTP 会使事情看起来太像 RPC。
  • 这就是我自然而然地投入其中的方式。它调用了 WebAPI——所以对我来说它是一个完美的场景,它应该总是返回一个有效的 HTTP 响应——并且该响应告诉调用者发生了什么。
【解决方案4】:

HttpResponseException 派生自 Exception 并嵌入 HttpResponseMessage。 由于它源自Exception,因此在try-catch 场景中很有用。

HttpResponseException 返回的默认状态码是HttpStatusCode.InternalServerError

【讨论】:

    【解决方案5】:

    正如原始问题所述,返回的响应没有真正的区别。

    HttpResponseException 的真正目的是允许子方法创建和“抛出”它们自己的 HttpResponseMessage,这些 HttpResponseMessage 会流回调用堆栈的上层并返回给客户端。

    public class CustomerController : ApiController {
      private ICustomerContext repo;
      public CustomerController(ICustomerContext repo) {
        this.repo = repo;
      }
    
      public HttpResponseMessage Get(int id) {
    
        Customer customer = getCustomer(id);
    
        return Request.CreateResponse(customer);
      }
    
      private Customer getCustomer(int id){
        .....do some work
        .....we have a problem so throw exception
        throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.BadRequest, "Id out of range");
        return repo.Customers.SingleOrDefault(c=>c.CustomerID == id)
    }
    

    请原谅任何错误,即时编写的代码。抛出的 HttpResponseException 通过动作调用堆栈冒泡,不会被正常的异常处理程序捕获并返回其 HttpResponseMessage 就像动作方法本身一样。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-02
      • 2011-12-12
      • 2010-09-16
      • 2012-03-14
      • 2012-02-06
      • 2011-02-25
      • 2011-11-22
      • 2015-03-26
      相关资源
      最近更新 更多