В чем разница между 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");
 }

Из Fiddle я действительно не видел различий между ними, поэтому в чем смысл использования HttpResponseException?

Ответ 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;
  }
}

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

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

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

Место, где вы можете использовать что-то вроде 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;
  }
}

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

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

Затем ответ возвращается и запрос продолжает обрабатываться.

Надеюсь, что это поможет

Ответ 2

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

  Foo Get(int id)

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

Помните, что HttpResponseMessage<T> уходит в следующей версии Web API.

Ответ 3

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

В классе, не относящемся к веб-интерфейсу, который выбрал клиента, вы, скорее всего, вернете нуль, а ваш код вызова проверяет нулевой ответ:

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

Ответ 4

HttpResponseException происходит от Exception и включает HttpResponseMessage. Поскольку он происходит от Exception, он может быть полезен в сценариях try - catch.

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

Ответ 5

Как утверждают исходные вопросы, в возвращаемом ответе нет реальной разницы.

Реальная цель HttpResponseException заключается в том, чтобы позволить вспомогательным методам создавать и "бросать" свои собственные 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 пузырится вверх по стеку вызовов действий, не попадает на обычные обработчики Exception и возвращает свой HttpResponseMessage, как и сам метод действий.