Pourquoi devrais-je utiliser IHttpActionResult au lieu de HttpResponseMessage?

326

J'ai développé avec WebApi et je suis passé à WebApi2 où Microsoft a introduit une nouvelle IHttpActionResultinterface qui semble être recommandée plutôt que de renvoyer un HttpResponseMessage. Je suis confus sur les avantages de cette nouvelle interface. Il semble principalement fournir simplement un moyen légèrement plus facile de créer un fichierHttpResponseMessage .

Je dirais que c'est "l'abstraction pour l'abstraction". Suis-je en train de manquer quelque chose? Quels sont les avantages réels que j'obtiens de l'utilisation de cette nouvelle interface, à part peut-être la sauvegarde d'une ligne de code?

Ancienne méthode (WebApi):

public HttpResponseMessage Delete(int id)
{
    var status = _Repository.DeleteCustomer(id);
    if (status)
    {
        return new HttpResponseMessage(HttpStatusCode.OK);
    }
    else
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }
}

Nouvelle façon (WebApi2):

public IHttpActionResult Delete(int id)
{
    var status = _Repository.DeleteCustomer(id);
    if (status)
    {
        //return new HttpResponseMessage(HttpStatusCode.OK);
        return Ok();
    }
    else
    {
        //throw new HttpResponseException(HttpStatusCode.NotFound);
        return NotFound();
    }
}
Jason Roell
la source
Je viens de trouver quelque chose d'intéressant. Je ne sais pas si ces résultats peuvent être vérifiés par quelqu'un d'autre. Mais les performances se sont beaucoup améliorées avec certains appels que j'ai faits: * Avec un exemple d'utilisation, HttpResponseMessagej'ai obtenu la réponse en 9545 ms . * En utilisant le, IHttpActionResultj'ai obtenu la même réponse en 294 ms .
chris lesage
@chrislesage 9545 ms est presque 10 secondes. Même 294 ms est un peu lent. Si vous avez quelque chose qui prend plus de 100 ms, alors quelque chose d'autre est à l'œuvre. Il y a plus dans cette histoire que rencontre l'ee.
AaronLS

Réponses:

305

Vous pouvez décider de ne pas l'utiliser, IHttpActionResultcar votre code existant génère un HttpResponseMessagequi ne correspond pas à l'une des réponses prédéfinies. Vous pouvez cependant vous adapter HttpResponseMessageà l' IHttpActionResultutilisation de la réponse standardisée de ResponseMessage. Il m'a fallu un certain temps pour comprendre cela, j'ai donc voulu le poster montrant que vous n'avez pas nécessairement à choisir l'un ou l'autre:

public IHttpActionResult SomeAction()
{
   IHttpActionResult response;
   //we want a 303 with the ability to set location
   HttpResponseMessage responseMsg = new HttpResponseMessage(HttpStatusCode.RedirectMethod);
   responseMsg.Headers.Location = new Uri("http://customLocation.blah");
   response = ResponseMessage(responseMsg);
   return response;
}

Remarque, ResponseMessageest une méthode de la classe de base ApiControllerdont votre contrôleur doit hériter.

AaronLS
la source
1
Il m'a fallu un certain temps pour découvrir que ResponseMessage est désormais ResponseMessageResult. Peut-être qu'il a été renommé récemment? PS Vous avez également manqué un nouveau mot-clé dans la réponse et merci beaucoup pour la suggestion :)
Ilya Chernomordik
10
@IlyaChernomordik ResponseMessageet ce ResponseMessageResultsont deux choses différentes. ResponseMessage()est une méthode de ApiControllerlaquelle votre contrôleur doit hériter de, et est donc un simple appel de méthode. Donc, aucun newmot-clé n'est nécessaire là-bas. Vous n'héritez probablement pas ApiControllerou vous êtes dans une méthode statique. ResponseMessageResultest le type de retour de ResponseMessage().
AaronLS
3
@IlyaChernomordik J'aurais pu écrire response = base.ResponseMessage(responseMsg)pour préciser que c'est une méthode de la classe de base ApiController
AaronLS
Merci, j'avais en effet un service qui n'héritait pas d'ApiController, c'est pourquoi il a fallu du temps pour le trouver.
Ilya Chernomordik
3
@pootzko Vous avez raison, j'ai abordé le fait que le PO semblait impliquer qu'ils pensaient que les deux approches s'excluaient mutuellement en les qualifiant d '"ancienne manière" vs de "nouvelle façon" alors qu'en fait elles ne le sont pas. Je pense que la réponse de Darrel explique bien certains des avantages du retour de IHttpActionResult, et ma réponse montre comment vous pouvez convertir l'ancien HttpResponseMessage en IHttpActionResult afin que vous puissiez avoir le meilleur des deux mondes.
AaronLS
84

Vous pouvez toujours utiliser HttpResponseMessage. Cette capacité ne disparaîtra pas. J'ai ressenti la même chose que vous et j'ai longuement argumenté avec l'équipe qu'il n'y avait pas besoin d'une abstraction supplémentaire. Il y a eu quelques arguments pour essayer de justifier son existence, mais rien ne m'a convaincu que cela en valait la peine.

Autrement dit, jusqu'à ce que je vois cet échantillon de Brad Wilson . Si vous construisez des IHttpActionResultclasses d'une manière qui peut être enchaînée, vous gagnez la possibilité de créer un pipeline de réponse de "niveau action" pour générer le HttpResponseMessage. Sous les couvertures, voici comment ActionFilterssont implémentées cependant, l'ordre de celles-ci ActionFiltersn'est pas évident lors de la lecture de la méthode d'action, ce qui est une des raisons pour lesquelles je ne suis pas un fan des filtres d'action.

Cependant, en créant un IHttpActionResultqui peut être explicitement enchaîné dans votre méthode d'action, vous pouvez composer toutes sortes de comportements différents pour générer votre réponse.

Darrel Miller
la source
62

Voici plusieurs avantages de IHttpActionResultplus HttpResponseMessagementionnés dans la documentation Microsoft ASP.Net :

  • Simplifie les tests unitaires de vos contrôleurs.
  • Déplace la logique commune pour créer des réponses HTTP dans des classes distinctes.
  • Rend l'intention de l'action du contrôleur plus claire, en masquant les détails de bas niveau de la construction de la réponse.

Mais voici quelques autres avantages de l'utilisation qui IHttpActionResultméritent d'être mentionnés:

  • Respect du principe de responsabilité unique : faire en sorte que les méthodes d'action aient la responsabilité de servir les requêtes HTTP et ne les impliquent pas dans la création des messages de réponse HTTP.
  • Implémentations utiles déjà définies dans System.Web.Http.Results à savoir: Ok NotFound Exception Unauthorized BadRequest Conflict Redirect InvalidModelState( lien vers la liste complète )
  • Utilise Async et Await par défaut.
  • Facile à créer son propre ActionResult simplement en implémentant la ExecuteAsyncméthode.
  • vous pouvez utiliser ResponseMessageResult ResponseMessage(HttpResponseMessage response)pour convertir HttpResponseMessage en IHttpActionResult .
Behzad Bahmanyar
la source
32
// this will return HttpResponseMessage as IHttpActionResult
return ResponseMessage(httpResponseMessage); 
Adam Tal
la source
18

Ceci est juste mon opinion personnelle et les gens de l'équipe d'API Web peuvent probablement mieux l'articuler, mais voici mon 2c.

Tout d'abord, je pense que ce n'est pas une question de l'un sur l'autre. Vous pouvez les utiliser à la fois en fonction de ce que vous voulez faire dans votre méthode d'action , mais pour comprendre la puissance réelle de IHttpActionResult, vous devrez probablement pas en dehors de ces méthodes d'assistance pratique de ApiControllertels que Ok, NotFound, etc.

Fondamentalement, je pense qu'une classe implémentant IHttpActionResultcomme une usine de HttpResponseMessage. Avec cet état d'esprit, il devient maintenant un objet qui doit être retourné et une usine qui le produit. Dans le sens général de la programmation, vous pouvez créer l'objet vous-même dans certains cas et dans certains cas, vous avez besoin d'une usine pour le faire. Pareil ici.

Si vous souhaitez renvoyer une réponse qui doit être construite à travers une logique complexe, par exemple de nombreux en-têtes de réponse, etc., vous pouvez résumer toute cette logique dans une classe de résultats d'action implémentant IHttpActionResultet l'utiliser dans plusieurs méthodes d'action pour renvoyer la réponse.

Un autre avantage de l'utilisation IHttpActionResultcomme type de retour est qu'il rend la méthode d'action de l'API Web ASP.NET similaire à MVC. Vous pouvez renvoyer n'importe quel résultat d'action sans vous faire prendre dans les formateurs de médias.

Bien sûr, comme l'a noté Darrel, vous pouvez enchaîner les résultats d'actions et créer un micro-pipeline puissant similaire aux gestionnaires de messages eux-mêmes dans le pipeline d'API. Vous en aurez besoin en fonction de la complexité de votre méthode d'action.

Bref, ce n'est pas IHttpActionResultcontre HttpResponseMessage. Fondamentalement, c'est la façon dont vous souhaitez créer la réponse. Faites-le vous-même ou dans une usine.

Badri
la source
Le problème que j'ai eu avec la justfication d'usine est que je peux facilement créer des méthodes statiques comme ResponseFactory.CreateOkResponse()celle qui retournent HttpResponseMessage, et je n'ai pas eu à faire face au truc asynchrone lors de la création de la réponse. Un membre de l'équipe a mentionné le fait que l'async peut être utile si vous devez effectuer des E / S afin de générer des valeurs d'en-tête. Je ne sais pas combien de fois cela se produit.
Darrel Miller
Je pense que cela revient à dire pourquoi avons-nous besoin d'un modèle de méthode d'usine. Pourquoi ne pas simplement utiliser des méthodes statiques pour créer des objets. Bien sûr, c'est faisable - chaque création d'objet ne mérite pas un modèle d'usine approprié. Mais à mon humble avis, cela dépend de la façon dont vous souhaitez modéliser vos classes. Voulez-vous avoir une logique pour créer différents types de réponses toutes entassées dans une classe sous la forme de plusieurs méthodes statiques ou avoir différentes classes basées sur une interface. Encore une fois, il n'y a ni bon ni mauvais. Tout dépend. Quoi qu'il en soit, mon point est que ce n'est pas l'un sur l'autre et personnellement, j'aime mieux les choses d'usine :)
Badri
6

L'API Web renvoie essentiellement 4 type d'objet: void, HttpResponseMessage, IHttpActionResultet d' autres types forts. La première version de l'API Web renvoie HttpResponseMessagece qui est un message de réponse HTTP assez simple.

Le a IHttpActionResultété introduit par WebAPI 2 qui est une sorte d'enveloppe HttpResponseMessage. Il contient la ExecuteAsync()méthode pour créer un fichier HttpResponseMessage. Il simplifie les tests unitaires de votre contrôleur.

Les autres types de retour sont des types de classes typées fortes sérialisées par l'API Web à l'aide d'un formateur de média dans le corps de la réponse. L'inconvénient était que vous ne pouvez pas retourner directement un code d'erreur tel qu'un 404. Tout ce que vous pouvez faire est de lancer une HttpResponseExceptionerreur.

Peter.Wang
la source
3

Je préfère implémenter la fonction d'interface TaskExecuteAsync pour IHttpActionResult. Quelque chose comme:

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = _request.CreateResponse(HttpStatusCode.InternalServerError, _respContent);

        switch ((Int32)_respContent.Code)
        { 
            case 1:
            case 6:
            case 7:
                response = _request.CreateResponse(HttpStatusCode.InternalServerError, _respContent);
                break;
            case 2:
            case 3:
            case 4:
                response = _request.CreateResponse(HttpStatusCode.BadRequest, _respContent);
                break;
        } 

        return Task.FromResult(response);
    }

, où _request est le HttpRequest et _respContent est la charge utile.

appletwo
la source
2

Nous avons les avantages suivants d'utiliser IHttpActionResultplus de HttpResponseMessage:

  1. En utilisant le, IHttpActionResultnous nous concentrons uniquement sur les données à envoyer et non sur le code d'état. Donc, ici, le code sera plus propre et très facile à entretenir.
  2. Les tests unitaires de la méthode de contrôleur implémentée seront plus faciles.
  3. Utilise asyncet awaitpar défaut.
Debendra Dash
la source