web-dev-qa-db-fra.com

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 ne voyais vraiment aucune différence entre eux. Quel est donc le but d'utiliser HttpResponseException?

57
cuongle

La principale différence entre les deux est la suivante. L'exception est utile pour arrêter immédiatement le traitement et quitter. 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 est exécuté et que je passe un identifiant non présent, il arrêtera immédiatement le traitement et renverra un code d'état de 404.

Si, au lieu de cela, je retourne HttpResponseMessage, la requête poursuivra volontiers le reste de son traitement et renverra un 404. La différence principale étant la fin ou non de la requête.

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

L'endroit où vous pouvez utiliser quelque chose comme HttpResponseMessage se trouve dans un Http POST pour renvoyer un code d'état de 201 et définir l'en-tête d'emplacement. Dans ce cas, je souhaite que le traitement continue. Cela ferait avec 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;
  }
}

* Remarque: Si vous utilisez les bits bêta, vous créerez un nouveau HttpResponseMessage. J'utilise les derniers bits cependant qui vous obligent à utiliser la méthode d'extension CreateResponse en dehors de la demande.

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

La réponse est ensuite renvoyée et la demande poursuit son traitement.

J'espère que cela t'aides

66
Glenn Block

HttpResponseException est utile lorsque votre signature Action du contrôleur ressemble à

  Foo Get(int id)

Dans ce cas, vous ne pouvez pas facilement renvoyer un code de statut tel que 400. 

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

28
Darrel Miller

En supposant que vous souhaitiez 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 d'un ApiController car il ne suit pas les schémas de développement typiques.

Dans une classe d'API non Web qui récupère un client, vous renverriez probablement la valeur null, votre code d'appel recherchant une réponse null:

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 la levée d'une exception HttpResponseException. Dans ce cas, pour faciliter les tests, pourquoi ne pas toujours simplement 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);
}
13
Brian Vallelunga

HttpResponseException dérive de Exception et incorpore HttpResponseMessage. Comme elle dérive de Exception, elle peut être utile dans les scénarios try-catch.

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

2
labilbe

Comme l'indiquent les questions initiales, il n'y a pas de réelle différence dans la réponse renvoyée.

Le but réel de HttpResponseException est de permettre aux sous-méthodes de créer et de "jeter" leurs propres HttpResponseMessages qui sont renvoyés dans la pile d'appels et 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 les erreurs, code écrit à la volée. HttpResponseException émise des bulles dans la pile d'appels d'actions, elle n'est pas interceptée par les gestionnaires d'exception normaux et renvoie son HttpResponseMessage comme le ferait la méthode d'action elle-même.

0
Mikee