В чем разница между HttpResponseMessage и HttpResponseException


Я попытался понять оба и написать пример кода:

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

от скрипки, я действительно не видел никаких различий между ними, так какова цель использования HttpResponseException?

5 56

5 ответов:

основное различие между ними заключается в следующем. Исключение полезно для немедленного прекращения обработки и выхода. Например, предположим, что у меня есть следующий код

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

Если этот код выполняется, и я передаю идентификатор, которого нет, он немедленно прекратит обработку и вернет код состояния 404.

если вместо этого я возвращаю HttpResponseMessage, запрос с радостью продолжит остальную часть своей обработки и вернет 404. Главным образом разница быть концом запрос или не.

Как сказал Даррел, исключение полезно в тех случаях, когда в некоторых случаях я хочу, чтобы обработка продолжалась (например, когда клиент найден), а в других-нет.

место, где вы можете использовать что-то вроде HttpResponseMessage, находится в HTTP-сообщении, чтобы вернуть код состояния 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;
  }
}

*Примечание: Если вы используете бета-бит вы создаст новый HttpResponseMessage. Однако я использую более поздние биты, которые требуют, чтобы вы использовали метод расширения CreateResponse от запроса.

выше, я создаю ответ, который устанавливает код состояния на 201, передает клиенту, а затем устанавливает заголовок местоположения.

затем возвращается ответ и запрос продолжает обработку.

надеюсь, что это помогает

HttpResponseException полезно, когда ваша подпись действия контроллера выглядит как

  Foo Get(int id)

в этом случае, вы не сможете вернуть код состояния 400.

имейте в виду, что HttpResponseMessage<T> уходит в следующем выпуске веб-API.

предполагая, что вы хотите модульного тестирования ответов, разве не имеет смысла всегда возвращать HttpResponseMessage? Мне не особенно нравится идея возвращения прямого типа из ApiController, так как он не соответствует типичным шаблонам развития.

в классе не-Web API, который получил клиента, вы, вероятно, вернете 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);
}

HttpResponseException происходит от Exception и встраивает HttpResponseMessage. Так как это происходит от Exception это может быть полезно в try -catch сценарии.

код состояния по умолчанию возвращается HttpResponseException и HttpStatusCode.InternalServerError.

как говорится в исходных вопросах, нет никакой реальной разницы в возвращенном ответе.

реальная цель HttpResponseException состоит в том, чтобы позволить sub-методам создавать и "бросать" свои собственные HttpResponseMessages, которые возвращаются в стек вызовов и возвращаются клиенту.

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 как сам метод действия будет иметь.