58 votes

Quelle est la différence entre HttpResponseMessage et HttpResponseException ?

J'ai essayé de comprendre les deux et d'écrire un exemple de code :

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

     throw new HttpResponseException(response);
 }

Et :

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

De Fiddle, je n'ai pas vraiment vu de différences entre eux, alors quel est l'intérêt d'utiliser HttpResponseException ?

0 votes

67voto

Glenn Block Points 7019

La principale différence entre les deux est la suivante. L'exception est utile pour arrêter immédiatement le traitement et sortir. Par exemple, supposons que j'ai le code suivant

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 ce code s'exécute et que je passe un identifiant qui n'est pas présent, il arrêtera immédiatement le traitement et renverra un code d'état 404.

Si, à la place, je renvoie HttpResponseMessage, la requête poursuivra joyeusement le reste de son traitement et renverra un 404. La principale différence étant de terminer la demande ou non.

Comme l'a dit Darrel, l'exception est utile dans les cas où, dans certains cas, je veux que le traitement continue (comme lorsque le client est trouvé) et dans d'autres, je ne le veux pas.

L'endroit où vous pourriez vouloir utiliser quelque chose comme HttpResponseMessage est dans un Http POST pour renvoyer un code d'état 201 et définir l'en-tête d'emplacement. Dans ce cas, je veux que le traitement se poursuive. Pour ce faire, il suffit d'utiliser ce code.

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 : Si vous utilisez les versions bêta, vous devez créer un nouveau HttpResponseMessage. J'utilise les versions ultérieures qui requièrent l'utilisation de la méthode d'extension CreateResponse à partir de la requête.

Ci-dessus, je crée une réponse qui définit le code d'état 201, transmet le client, puis définit l'en-tête d'emplacement.

La réponse est ensuite renvoyée et le traitement de la demande se poursuit.

J'espère que cela vous aidera

3 votes

J'ajouterais que la gestion et la journalisation des exceptions sont une autre raison. Vous pouvez vouloir lancer pour enregistrer un 404 mais ne pas lancer pour ne pas enregistrer un 412.

5 votes

Je ne comprends pas bien ce que vous voulez dire par "la demande continue à être traitée". La demande n'est-elle pas terminée au moment où vous return ?

1 votes

@Stijn - il y a des commentaires sur le blog de Glenn ( goo.gl/ErSG9h ) qui rendent les choses un peu plus claires. Il semble que Glenn fasse référence au traitement que Web.Api effectue après le retour du contrôleur, comme les gestionnaires de messages. Cependant, Steven Solomon se demande si c'est le cas ou non.

28voto

Darrel Miller Points 56797

HttpResponseException est utile lorsque la signature de votre action de contrôleur ressemble à ceci

  Foo Get(int id)

Dans ce cas, vous ne pouvez pas facilement renvoyer un code d'état comme 400.

Sachez que HttpResponseMessage<T> disparaîtra dans la prochaine version de l'API Web.

0 votes

Merci pour votre réponse, elle me semble logique.

4 votes

Seul le générique HttpResponseMessage<T> disparaît.

0 votes

@ozba Merci, je n'avais pas remarqué que la syntaxe du balisage empêchait l'apparition des crochets d'angle.

13voto

Brian Vallelunga Points 3209

En supposant que vous vouliez tester les réponses à l'unité, n'est-il pas logique de toujours renvoyer un HttpResponseMessage ? Je n'aime pas particulièrement l'idée de renvoyer un type direct à partir d'un ApiController car cela ne suit pas les modèles de développement typiques.

Dans une classe d'API non Web qui récupère un client, vous renverriez probablement null, et votre code d'appel vérifierait que la réponse est nulle :

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

Mais dans l'API Web, vous n'allez pas renvoyer null, vous devez renvoyer quelque chose, même si ce quelque chose est créé après avoir lancé une HttpResponseException. Dans ce cas, pour faciliter les tests, pourquoi ne pas toujours renvoyer un HttpResponseMessage et en faire votre signature ?

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 votes

Je suis d'accord, Brian. Cela permet également un meilleur apprentissage des objets de retour et des codes d'état. Lorsque le modèle définit un type de retour comme un objet de gestion, on se demande quelle est la bonne façon de traiter les autres réponses.

5 votes

@Brian, c'est une question de style. Certaines personnes veulent s'enfoncer jusqu'au genou dans HTTP et avoir l'impression que cela fait partie de la conception de leur application. D'autres estiment que HTTP est un détail de mise en œuvre et préfèrent s'abstraire de l'aspect HTTP en utilisant des ActionFilters et des HttpMessageHandlers. Aucune de ces approches n'est mauvaise si vous savez ce que vous faites. J'ai tendance à adopter votre approche car je pense que masquer le HTTP fait trop ressembler les choses à des RPC.

0 votes

C'est la façon dont j'ai été amené à le faire. Il s'agit d'une interface WebAPI. Il me semble donc logique qu'elle renvoie toujours une réponse HTTP valide, et que cette réponse indique à l'appelant ce qui s'est passé.

2voto

labilbe Points 1231

HttpResponseException provient de Exception et embarque HttpResponseMessage . Puisqu'il dérive de Exception il peut être utile dans try - catch scénarios.

Code d'état par défaut renvoyé par HttpResponseException est HttpStatusCode.InternalServerError .

0voto

Mikee Points 67

Comme l'indique la question originale, il n'y a pas de différence réelle dans la réponse renvoyée.

Le véritable objectif de HttpResponseException est de permettre aux sous-méthodes de créer et de "lancer" leurs propres HttpResponseMessages qui remontent la pile d'appels et sont renvoyés au 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)
}

Pardonnez toute erreur, le code a été écrit à la volée. L'exception HttpResponseException qui est lancée remonte dans la pile d'appels des actions, n'est pas prise en compte par les gestionnaires d'exceptions normaux et renvoie son HttpResponseMessage comme la méthode d'action elle-même l'aurait fait.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X