2012-05-18 11 views
56

traté de entender tanto y escribir código de ejemplo:¿Cuál es la diferencia entre HttpResponseMessage y HttpResponseException

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

    throw new HttpResponseException(response); 
} 

Y:

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

De violín, realmente no vi ninguna diferencia entre ellos , entonces, ¿cuál es el propósito de usar HttpResponseException?

+0

posible duplicado de [Lanza HttpResponseException o volver Request.CreateErrorResponse?] (Http://stackoverflow.com/questions/12519561/throw-httpresponseexception-or-return-request-createerrorresponse) –

Respuesta

66

La principal diferencia entre los dos es esto. La excepción es útil para detener el procesamiento y salir inmediatamente. Por ejemplo suponer que tengo el siguiente código

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

Si se ejecuta este código y pasar un identificador que no está presente, se detendrá inmediatamente el procesamiento y devolver un código de estado de 404.

Si en vez vuelvo HttpResponseMessage, la solicitud continuará felizmente el resto de su procesamiento y devolverá un 404. La principal diferencia es finalizar la solicitud o no.

Como dijo Darrel excepción es útil en casos en los que en algunos casos que quiero que continúe el procesamiento (como cuando se encuentra en el cliente) y en otros que no lo hacen.

El lugar donde es posible que desee utilizar algo como HttpResponseMessage está en un HTTP POST para devolver un código de estado de 201 y establecer el encabezado de ubicación. En ese caso, quiero que el procesamiento continúe. Eso haría con este código *

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

. * Nota: Si está utilizando los bits beta, se crearía un nuevo HttpResponseMessage. Sin embargo, estoy usando las últimas partes que requieren que uses el método de extensión CreateResponse fuera de la Solicitud.

Arriba, estoy creando una respuesta que establece el código de estado en 201, pasa al cliente y luego establece el encabezado de ubicación.

continuación, se devuelve la respuesta y la petición de seguir con el procesamiento.

Esperanza esto ayuda

+3

Agregaría que el manejo/registro de excepciones es otro motivo. Es posible que desee lanzar para registrar un 404 pero no tirar y no registrar un 412. –

+5

Estoy realmente confundido con lo que quiere decir con "la solicitud continúa procesando". ¿No ha terminado la solicitud en el momento en que 'regresas '? – Stijn

+1

@Stijn - hay algunos comentarios en el blog de Glenn (http://goo.gl/ErSG9h) que lo hacen un poco más claro. Parece que Glenn se refiere al procesamiento que hace Web.Api después de que el controlador regrese, como los manejadores de mensajes. Sin embargo, Steven Solomon pregunta si ese es el caso o no. – Iain

2

HttpResponseException deriva de Exception e integra HttpResponseMessage. Ya que deriva de Exception que puede ser útil en try - catch escenarios.

código de estado devuelto por defecto es HttpResponseExceptionHttpStatusCode.InternalServerError.

28

HttpResponseException es útil cuando su firma Acción controlador parece

Foo Get(int id) 

En este caso, no se puede volver fácilmente código de estado como 400.

Sé consciente de que HttpResponseMessage<T> se va en la próxima versión de API web

+0

Gracias por su respuesta, que tiene sentido para mí –

+4

Solo se va el genérico HttpResponseMessage ozba

+0

@ozba Gracias, no me había dado cuenta de que la sintaxis del marcado impidió que aparecieran los corchetes angulares. –

13

Suponiendo que deseas prueba de la unidad de las respuestas, no tiene sentido volver siempre una HttpResponseMessage? No me gusta particularmente la idea de devolver un tipo recto de un ApiController ya que no sigue los patrones de desarrollo típicos.

En una clase API no web que fue a buscar un cliente, usted es probable que vuelva nulo, con su código de llamada comprobar que existe una respuesta nula:

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

Pero en Web API, no vas para devolver nulo, debe devolver algo, incluso si ese algo se crea después de lanzar una HttpResponseException. En ese caso, para facilitar las pruebas, ¿por qué no siempre devuelve un HttpResponseMessage y lo convierte en su firma?

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

Estoy de acuerdo, Brian. Esto también contribuye a una mejor ruta de aprendizaje para devolver objetos y códigos de estado. Cuando la plantilla establece un tipo de devolución como un objeto comercial, hace que se pregunte cuál es la forma correcta de tratar otras respuestas. –

+5

@Brian es una cosa de estilo. Algunas personas quieren profundizar en HTTP y sentir que es parte del diseño de su aplicación. Otros piensan que HTTP es un detalle de implementación y prefieren abstraer el HTTPness usando ActionFilters y HttpMessageHandlers. Ningún enfoque es incorrecto si sabes lo que estás haciendo. Tiendo a tomar su enfoque porque me siento oculto que el HTTP hace que las cosas se parezcan demasiado a RPC. –

+0

Esta es la forma en que, naturalmente, caí en hacerlo. Llamaba a WebAPI, por lo que me parece perfecto que siempre devuelva una respuesta HTTP válida, y esa respuesta le dice a la persona que llama lo que sucedió. – Morvael

0

Como dice la pregunta original, no hay una diferencia real en la Respuesta devuelta.

El objetivo real de HttpResponseException es permitir que los submétodos creen y "arrojen" sus propios HttpResponseMessages que fluyen de vuelta a la pila de llamadas hacia arriba y se devuelven al cliente.

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

perdonareis errores, el código escrito sobre la marcha. La HttpResponseException lanzada surge a través de la pila de llamadas de acciones, no queda atrapada por los manejadores de Excepciones normales y devuelve su HttpResponseMessage como lo haría el método de acción en sí.

Cuestiones relacionadas