Warum sollte ich IHttpActionResult anstelle von HttpResponseMessage verwenden?

326

Ich habe mit WebApi entwickelt und bin zu WebApi2 übergegangen, wo Microsoft eine neue Benutzeroberfläche eingeführt hat IHttpActionResult, die anscheinend empfohlen wird, über die Rückgabe von a HttpResponseMessage. Ich bin verwirrt über die Vorteile dieser neuen Schnittstelle. Es scheint hauptsächlich nur eine etwas einfachere Möglichkeit zu bieten, eine zu erstellen HttpResponseMessage.

Ich würde argumentieren, dass dies "Abstraktion um der Abstraktion willen" ist. Vermisse ich etwas Was sind die realen Vorteile, die ich durch die Verwendung dieser neuen Schnittstelle bekomme, außer vielleicht das Speichern einer Codezeile?

Alter Weg (WebApi):

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

Neuer Weg (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
quelle
Ich habe gerade etwas Interessantes gefunden. Ich bin nicht sicher, ob diese Ergebnisse von jemand anderem überprüft werden können. Bei einigen Anrufen hat sich die Leistung jedoch erheblich verbessert: * Bei einem Beispiel mit habe HttpResponseMessageich die Antwort in 9545 ms zurückerhalten . * Mit dem habe IHttpActionResultich die gleiche Antwort in 294 ms zurückbekommen .
Chris Lesage
@chrislesage 9545 ms ist fast 10 Sekunden. Sogar 294 ms sind ziemlich langsam. Wenn etwas länger als 100 ms dauert, ist dort etwas anderes am Werk. In dieser Geschichte steckt mehr, als man erwartet.
AaronLS

Antworten:

305

Sie können sich entscheiden, diese nicht zu verwenden, IHttpActionResultda Ihr vorhandener Code eine erstellt HttpResponseMessage, die nicht zu einer der vordefinierten Antworten passt. Sie können sich jedoch HttpResponseMessagean IHttpActionResultdie vordefinierte Antwort von anpassen ResponseMessage. Es hat eine Weile gedauert, bis ich das herausgefunden habe, also wollte ich es veröffentlichen und zeigen, dass Sie sich nicht unbedingt für das eine oder andere entscheiden müssen:

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

Hinweis: Dies ResponseMessageist eine Methode der Basisklasse ApiController, von der Ihr Controller erben soll.

AaronLS
quelle
1
Ich habe eine Weile gebraucht, um herauszufinden, dass ResponseMessage jetzt ResponseMessageResult ist. Vielleicht wurde es kürzlich umbenannt? PS Sie haben auch ein neues Schlüsselwort in der Antwort verpasst und vielen Dank für den Vorschlag :)
Ilya Chernomordik
10
@IlyaChernomordik ResponseMessageund ResponseMessageResultsind zwei verschiedene Dinge. ResponseMessage()ist eine Methode, von ApiControllerder Ihr Controller erben sollte, und ist daher nur ein Methodenaufruf. Dort wird also kein newSchlüsselwort benötigt. Sie erben wahrscheinlich nicht von ApiControlleroder befinden sich in einer statischen Methode. ResponseMessageResultist der Rückgabetyp von ResponseMessage().
AaronLS
3
@IlyaChernomordik Ich hätte schreiben können response = base.ResponseMessage(responseMsg), um klarer zu machen, dass es eine Methode der Basisklasse ApiController ist
AaronLS
Vielen Dank, ich hatte tatsächlich einen Dienst, der nicht von ApiController geerbt wurde. Deshalb hat es einige Zeit gedauert, ihn zu finden.
Ilya Chernomordik
3
@pootzko Sie haben Recht, ich habe die Tatsache angesprochen, dass das OP zu implizieren schien, dass sie glaubten, dass sich die beiden Ansätze gegenseitig ausschließen, indem sie es als "alten Weg" gegen "neuen Weg" formulierten, obwohl dies nicht der Fall ist. Ich denke, Darrels Antwort erklärt einige der Vorteile der Rückgabe von IHttpActionResult gut, und meine Antwort zeigt, wie Sie die alte HttpResponseMessage in ein IHttpActionResult konvertieren können, damit Sie das Beste aus beiden Welten haben.
AaronLS
84

Sie können immer noch verwenden HttpResponseMessage. Diese Fähigkeit wird nicht verschwinden. Ich fühlte mich genauso wie Sie und argumentierte ausführlich mit dem Team, dass keine zusätzliche Abstraktion erforderlich sei. Es gab ein paar Argumente, um seine Existenz zu rechtfertigen, aber nichts, was mich davon überzeugt hätte, dass es sich gelohnt hat.

Das heißt, bis ich dieses Beispiel von Brad Wilson gesehen habe . Wenn Sie IHttpActionResultKlassen auf eine Weise erstellen, die verkettet werden kann, können Sie eine Antwortpipeline auf Aktionsebene zum Generieren der erstellen HttpResponseMessage. Unter dem Deckmantel wird dies so ActionFiltersimplementiert, aber die Reihenfolge dieser ActionFiltersist beim Lesen der Aktionsmethode nicht offensichtlich, was ein Grund ist, warum ich kein Fan von Aktionsfiltern bin.

Indem Sie jedoch eine erstellen IHttpActionResult, die in Ihrer Aktionsmethode explizit verkettet werden kann, können Sie alle Arten von unterschiedlichen Verhaltensweisen erstellen , um Ihre Antwort zu generieren.

Darrel Miller
quelle
62

Hier sind einige Vorteile von IHttpActionResultüber HttpResponseMessagein den genannten Microsoft ASP.Net Dokumentation :

  • Vereinfacht das Testen Ihrer Controller.
  • Verschiebt die allgemeine Logik zum Erstellen von HTTP-Antworten in separate Klassen.
  • Verdeutlicht die Absicht der Controller-Aktion, indem die Details der Erstellung der Antwort auf niedriger Ebene ausgeblendet werden.

Aber hier sind einige andere Vorteile der Verwendung, die es IHttpActionResultwert sind, erwähnt zu werden:

  • Respektieren des Prinzips der Einzelverantwortung : Bewirken Sie, dass Aktionsmethoden für die Zustellung der HTTP-Anforderungen verantwortlich sind, und beziehen Sie sie nicht in die Erstellung der HTTP-Antwortnachrichten ein.
  • Nützliche Implementierungen, die bereits in System.Web.Http.Results definiert sind, nämlich: Ok NotFound Exception Unauthorized BadRequest Conflict Redirect InvalidModelState( Link zur vollständigen Liste )
  • Verwendet standardmäßig Async und Await .
  • Einfaches Erstellen eines eigenen ActionResult durch einfache Implementierung der ExecuteAsyncMethode.
  • Sie verwenden können , ResponseMessageResult ResponseMessage(HttpResponseMessage response)um HttpResponseMessage zu IHttpActionResult zu konvertieren .
Behzad Bahmanyar
quelle
32
// this will return HttpResponseMessage as IHttpActionResult
return ResponseMessage(httpResponseMessage); 
Adam Tal
quelle
18

Dies ist nur meine persönliche Meinung und Leute vom Web-API-Team können es wahrscheinlich besser artikulieren, aber hier ist meine 2c.

Zunächst denke ich, dass es nicht um einander geht. Sie können sie beide je verwenden, was Sie in Ihrer Aktionsmethode tun wollen , sondern um die wirkliche Macht zu verstehen IHttpActionResult, dass Sie wahrscheinlich müssen Schritt außerhalb dieser bequemen Helfermethoden ApiControllerwie Ok, NotFoundusw.

Grundsätzlich denke ich, dass eine Klasse IHttpActionResultals Fabrik von implementiert HttpResponseMessage. Mit dieser Einstellung wird es nun zu einem Objekt, das zurückgegeben werden muss, und zu einer Fabrik, die es produziert. Im allgemeinen Programmiersinn können Sie das Objekt in bestimmten Fällen selbst erstellen, und in bestimmten Fällen benötigen Sie eine Factory, um dies zu tun. Hier gilt das gleiche.

Wenn Sie eine Antwort zurückgeben möchten, die durch eine komplexe Logik erstellt werden muss, z. B. viele Antwortheader usw., können Sie all diese Logik in eine Aktionsergebnisklasse abstrahieren, die implementiert wird, IHttpActionResultund sie in mehreren Aktionsmethoden verwenden, um eine Antwort zurückzugeben.

Ein weiterer Vorteil der Verwendung IHttpActionResultals Rückgabetyp besteht darin, dass die ASP.NET-Web-API-Aktionsmethode MVC ähnelt. Sie können jedes Aktionsergebnis zurückgeben, ohne sich in Medienformatierern zu verfangen.

Wie von Darrel bemerkt, können Sie natürlich Aktionsergebnisse verketten und eine leistungsstarke Mikro-Pipeline erstellen, die den Nachrichtenhandlern selbst in der API-Pipeline ähnelt. Dies benötigen Sie abhängig von der Komplexität Ihrer Aktionsmethode.

Lange Rede kurzer Sinn - es ist nicht IHttpActionResultversus HttpResponseMessage. Grundsätzlich möchten Sie die Antwort so erstellen. Mach es selbst oder durch eine Fabrik.

Badri
quelle
Das Problem, das ich mit der Factory-Rechtfertigung hatte, ist, dass ich leicht statische Methoden wie ResponseFactory.CreateOkResponse()diese erstellen kann , die HttpResponseMessage zurückgeben, und dass ich mich beim Erstellen der Antwort nicht mit dem asynchronen Zeug befassen musste. Ein Teammitglied erwähnte die Tatsache, dass die Asynchronisierung nützlich sein kann, wenn Sie E / A ausführen müssen, um Headerwerte zu generieren. Ich bin mir nicht sicher, wie oft das passiert.
Darrel Miller
Ich denke, es ist dasselbe wie zu sagen, warum wir ein Factory-Methodenmuster brauchen. Warum nicht einfach statische Methoden verwenden, um Objekte zu erstellen? Sicher, es ist machbar - jede Objekterstellung verdient kein richtiges Fabrikmuster. Aber meiner Meinung nach hängt es davon ab, wie Sie Ihre Klassen modellieren möchten. Möchten Sie eine Logik haben, um verschiedene Arten von Antworten zu erstellen, die alle in Form mehrerer statischer Methoden in einer Klasse zusammengefasst sind, oder um verschiedene Klassen basierend auf einer Schnittstelle zu haben? Auch hier gibt es kein Gut oder Böse. Es hängt alles ab. Wie auch immer, mein Punkt ist, dass es nicht übereinander ist und ich persönlich mag Fabriksache besser :)
Badri
6

Der Web - API zurückgeben grundsätzlich 4 Objekttyp: void, HttpResponseMessage, IHttpActionResult, und andere starke Typen. Die erste Version der Web-API gibt HttpResponseMessageeine ziemlich einfache HTTP-Antwortnachricht zurück.

Das IHttpActionResultwurde von WebAPI 2 eingeführt, das eine Art Wrap von ist HttpResponseMessage. Es enthält die ExecuteAsync()Methode zum Erstellen eines HttpResponseMessage. Dies vereinfacht das Testen von Einheiten Ihres Controllers.

Andere Rückgabetypen sind stark typisierte Klassen, die von der Web-API mithilfe eines Medienformatierers in den Antworttext serialisiert werden. Der Nachteil war, dass Sie einen Fehlercode wie einen 404 nicht direkt zurückgeben können. Sie können lediglich einen HttpResponseExceptionFehler auslösen.

Peter.Wang
quelle
3

Ich möchte lieber die TaskExecuteAsync-Schnittstellenfunktion für IHttpActionResult implementieren. Etwas wie:

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

, wobei _request die HttpRequest und _respContent die Nutzlast ist.

Appletwo
quelle
2

Wir haben die folgenden Vorteile der Verwendung von IHttpActionResultover HttpResponseMessage:

  1. Bei Verwendung von IHttpActionResultkonzentrieren wir uns nur auf die zu sendenden Daten, nicht auf den Statuscode. Hier wird der Code also sauberer und sehr einfach zu pflegen sein.
  2. Unit-Tests der implementierten Controller-Methode werden einfacher.
  3. Verwendet asyncund awaitstandardmäßig.
Debendra Dash
quelle