2012-05-18 23 views
56

Próbowałem zrozumieć zarówno i napisać przykładowy kod:Jaka jest różnica między HttpResponseMessage i HttpResponseException

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

    throw new HttpResponseException(response); 
} 

oraz:

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

Od Fiddle, ja naprawdę nie widzę żadnych różnic między nimi , więc jaki jest cel używania HttpResponseException?

+0

możliwe duplikat [Rzut HttpResponseException lub powrót Request.CreateErrorResponse?] (Http://stackoverflow.com/questions/12519561/throw-httpresponseexception-or-return-request-createerrorresponse) –

Odpowiedz

66

Główna różnica między tymi dwoma jest taka. Wyjątek jest przydatny do natychmiastowego przerwania przetwarzania i zakończenia. Na przykład założyć, mam następujący kod

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

Jeśli ten kod działa i mogę przekazać identyfikator, który nie jest obecny, będzie natychmiast zatrzymać przetwarzanie i zwraca kod statusu 404.

Jeśli zamiast wrócić HttpResponseMessage, żądanie z przyjemnością kontynuuje pozostałą część przetwarzania i zwraca 404. Główną różnicą jest zakończenie żądania lub nie.

Jak Darrel powiedział, że wyjątek jest przydatny w przypadkach, w których w niektórych przypadkach chcę kontynuować przetwarzanie (jak w przypadku znalezienia klienta), aw innych nie.

Miejsce, w którym możesz chcieć użyć czegoś takiego jak HttpResponseMessage, znajduje się w HST POST, aby zwrócić kod stanu 201 i ustawić nagłówek lokalizacji. W takim przypadku chcę, aby przetwarzanie było kontynuowane. Że zrobi z tym kodem *

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

*. Uwaga: Jeżeli używasz bity beta chcesz utworzyć nowy HttpResponseMessage. Używam późniejszych bitów, które jednak wymagają użycia metody rozszerzenia CreateResponse z Żądania.

Powyżej tworzę odpowiedź, która ustawia kod statusu na 201, przechodzi w kliencie, a następnie ustawia nagłówek lokalizacji.

Odpowiedź jest zwracana, a żądanie kontynuuje przetwarzanie.

Nadzieja to pomaga

+3

Dodam, że obsługa wyjątków/rejestrowanie to kolejny powód. Możesz rzucić, aby zalogować 404, ale nie rzucać i nie rejestrować 412. –

+5

Jestem naprawdę zdezorientowany przez to, co masz na myśli, mówiąc, że "żądanie kontynuuje przetwarzanie". Czy prośba nie została zakończona w momencie "powrotu"? – Stijn

+1

@Stijn - jest kilka komentarzy na blogu Glenna (http://goo.gl/ErSG9h), które czynią go trochę jaśniejszym. Wygląda na to, że Glenn odnosi się do przetwarzania, które Web.Api robi po zwróceniu kontrolera, takim jak Message Handlers. Jednak Steven Solomon pyta, czy tak jest, czy nie. – Iain

2

wywodzi się z Exception i osadza HttpResponseMessage. Ponieważ pochodzi od Exception, może być przydatny w scenariuszach try - catch.

Domyślny kod stanu zwrócony przez HttpResponseException to HttpStatusCode.InternalServerError.

28

HttpResponseException jest przydatna, gdy podpis Action Controller wygląda

Foo Get(int id) 

W tym przypadku nie można łatwo powrócić kod stanu jak 400.

Należy pamiętać, że HttpResponseMessage<T> zniknie w następnym wydaniu Web API.

+0

Dzięki za odpowiedź, ma sens dla mnie –

+4

Tylko ogólny HttpResponseMessage odchodzi – ozba

+0

@ozba Dzięki, nie zauważyłem, że składnia znaczników uniemożliwiła pojawienie się nawiasów trójkątnych. –

13

Zakładając chcesz testów jednostkowych odpowiedzi, nie jest sens, aby zawsze zwracać HttpResponseMessage? Nie podoba mi się zwłaszcza pomysł zwrócenia prostego typu z ApiController, ponieważ nie podąża za typowymi wzorami rozwoju.

W klasie non-Web API, które naciągane Klient, to prawdopodobnie zwróci null, a Twój kod wywołujący sprawdzanie null odpowiedzi:

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

Ale w Web API, nie zamierzamy aby zwrócić wartość null, musisz zwrócić coś, nawet jeśli coś jest tworzone po wyrzuceniu wyjątku HttpResponseException. W takim przypadku, aby ułatwić testowanie, dlaczego nie zawsze zwracasz HttpResponseMessage i tworzysz swój podpis?

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

Zgadzam się, Brian. Zapewnia to także lepszą ścieżkę uczenia się dla zwracanych obiektów i kodów stanu. Kiedy szablon ustawia typ zwracany jako obiekt biznesowy, sprawia, że ​​zastanawiasz się, jaki jest właściwy sposób postępowania z innymi odpowiedziami. –

+5

@Brian to rzecz stylu. Niektórzy ludzie chcą się połknąć w HTTP i czuć, że jest to część ich projektu aplikacji. Inni uważają, że HTTP jest szczegółem implementacji i raczej odciągnie HTTPness za pomocą ActionFilters i HttpMessageHandlers. Żadne podejście nie jest złe, jeśli wiesz, co robisz. Mam tendencję do podejścia, ponieważ czuję, że ukrywanie HTTP sprawia, że ​​rzeczy wyglądają zbyt podobnie do RPC. –

+0

W ten sposób naturalnie wpadłem na to. Nazywa się WebAPI - więc dla mnie tworzy idealną scenę, która powinna zawsze zwracać prawidłową odpowiedź HTTP - i ta odpowiedź mówi dzwoniącemu, co się stało. – Morvael

0

Zgodnie z pierwotnymi pytaniami, w zwróconej odpowiedzi nie ma rzeczywistej różnicy.

Prawdziwym celem wyjątku HttpResponseException jest umożliwienie metodom podrzędnym tworzenia i "wyrzucania" własnych HttpResponseMessages, które powracają do stosu wywołań i są zwracane do klienta.

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

Przebaczyć ewentualne błędy, kod napisany w locie. Wyrzucony wyjątek HttpResponseException przepływa przez stos wywołań akcji, nie jest przechwytywany przez normalne procedury obsługi wyjątków i zwraca jego HttpResponseMessage, tak jak ma to miejsce w przypadku metody akcji.

Powiązane problemy