В чем разница между 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, как и сам метод действий.