2012-05-18 14 views
56

ho cercato di capire entrambi e scrivere il codice di esempio:Qual è la differenza tra HttpResponseMessage e HttpResponseException

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

    throw new HttpResponseException(response); 
} 

E:

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

Da Fiddle, io davvero non ho visto alcuna differenza tra di loro , quindi qual è lo scopo dell'utilizzo di HttpResponseException?

+0

possibile duplicato del [Gettare HttpResponseException o tornare Request.CreateErrorResponse?] (Http://stackoverflow.com/questions/12519561/throw-httpresponseexception-or-return-request-createerrorresponse) –

risposta

66

La differenza principale tra i due è questa. L'eccezione è utile per interrompere immediatamente l'elaborazione e l'uscita. Per esempio assumere Ho il seguente codice

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

Se questo esegue il codice e passare un id che non è presente, viene immediatamente interrotta e restituire un codice di stato 404.

Se invece torno HttpResponseMessage, la richiesta continuerà felicemente il resto della sua elaborazione e restituirà un 404. La differenza principale è che termina la richiesta o meno.

Come ha detto Darrel, l'eccezione è utile nei casi in cui in alcuni casi voglio che l'elaborazione continui (come quando il cliente viene trovato) e in altri no.

Il luogo in cui è possibile utilizzare qualcosa come HttpResponseMessage si trova in un Http POST per restituire un codice di stato di 201 e impostare l'intestazione della posizione. In tal caso, desidero che l'elaborazione continui. Ciò farebbe con questo codice *

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:. Se si utilizzano i bit beta è necessario creare un nuovo HttpResponseMessage. Sto usando i bit successivi che tuttavia richiedono l'utilizzo del metodo di estensione CreateResponse al di fuori della richiesta.

Sopra, sto creando una risposta che imposta il codice di stato su 201, passa nel cliente e quindi imposta l'intestazione della posizione.

La risposta viene quindi restituita e la richiesta continua l'elaborazione.

Spero che questo aiuti

+3

Aggiungo che la gestione delle eccezioni/registrazione è un'altra ragione. Si consiglia di lanciare per registrare un 404 ma non lanciare e non registrare un 412. –

+5

Sono davvero confuso da cosa intendi con "la richiesta continua l'elaborazione". La richiesta non è finita nel momento in cui ritorni? – Stijn

+1

@Stijn - ci sono alcuni commenti sul blog di Glenn (http://goo.gl/ErSG9h) che lo rendono un po 'più chiaro. Sembra che Glenn si riferisca all'elaborazione di Web.Api dopo che il controller è tornato come Message Handlers. Tuttavia, Steven Solomon si chiede se sia così o no. – Iain

2

HttpResponseException deriva da Exception e incorpora HttpResponseMessage. Dal momento che deriva da Exception può essere utile negli scenari try - catch.

Il codice di stato predefinito restituito da HttpResponseException è HttpStatusCode.InternalServerError.

28

HttpResponseException è utile quando la tua firma azione di controllo si presenta come

Foo Get(int id) 

In questo caso, non è possibile tornare facilmente codice di stato come 400.

essere consapevoli del fatto che HttpResponseMessage<T> sta andando via nella prossima release di API Web.

+0

Grazie per la risposta, ha senso a me –

+4

Solo il generico HttpResponseMessage sta andando via – ozba

+0

@ozba Grazie, non avevo notato che la sintassi del markup impediva la visualizzazione delle parentesi angolari. –

13

Supponendo che si desidera unit test le risposte, non ha senso per restituire sempre un HttpResponseMessage? Non mi piace particolarmente l'idea di restituire un tipo diretto da un ApiController poiché non segue i tipici schemi di sviluppo.

In una classe API non-Web, che andò a prendere un cliente, si sarebbe probabilmente restituire null, con il vostro codice chiamante il controllo di una risposta nulla:

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

Ma in API Web, non si sta andando per restituire null, devi restituire qualcosa, anche se quel qualcosa viene creato dopo aver lanciato una HttpResponseException. In tal caso, per facilitare i test, perché non restituire sempre un messaggio HttpResponseMessage e rendere la tua firma?

+1

Sono d'accordo, Brian. Questo rende anche un percorso di apprendimento migliore per la restituzione di oggetti e codici di stato. Quando il modello imposta un tipo di ritorno come oggetto business, ti chiedi quale sia il modo corretto per gestire le altre risposte. –

+5

@Brian è una cosa di stile. Alcune persone vogliono entrare in ginocchio in HTTP e sentirsi parte del loro design dell'applicazione. Altri ritengono che HTTP sia un dettaglio di implementazione e preferirebbe astrarre l'HTTPness usando ActionFilters e HttpMessageHandlers. Nessuno dei due approcci è sbagliato se sai cosa stai facendo. Tendo a prendere il tuo approccio perché sento che nascondere l'HTTP fa sembrare le cose troppo simili a RPC. –

+0

Questo è il modo in cui naturalmente sono caduto nel farlo. Si chiama WebAPI - quindi per me rende perfetta la scena che dovrebbe sempre restituire una risposta HTTP valida - e quella risposta dice al chiamante cosa è successo. – Morvael

0

Come afferma la domanda originale, non vi è alcuna differenza reale nella risposta restituita.

Il vero scopo di HttpResponseException è quello di consentire ai metodi secondari di creare e "lanciare" i propri messaggi HttpResponseMessages che ritornano allo stack di chiamate e vengono restituiti al client.

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

Perdere eventuali errori, codice scritto al volo. L'HttpResponseException generata esplode attraverso lo stack delle chiamate delle azioni, non viene catturata dai normali gestori di eccezioni e restituisce HttpResponseMessage come il metodo di azione stesso.

Problemi correlati