Geben Sie den Inhalt mit IHttpActionResult für eine nicht OK-Antwort zurück

184

Für die Rückkehr von einem Web API 2-Controller kann ich Inhalt mit der Antwort zurückgeben, wenn die Antwort wie folgt in Ordnung ist (Status 200):

    public IHttpActionResult Get()
    {
        string myResult = ...
        return Ok(myResult);
    }

Wenn möglich, möchte ich die integrierten Ergebnistypen hier verwenden, wenn dies möglich ist: https://msdn.microsoft.com/en-us/library/system.web.http.results(v=vs.118).aspx

Meine Frage ist, wie kann ich für eine andere Art von Antwort (nicht 200) eine Nachricht (Zeichenfolge) damit zurückgeben? Zum Beispiel kann ich das tun:

    public IHttpActionResult Get()
    {
       return InternalServerError();
    }

aber nicht das:

    public IHttpActionResult Get()
    {
       return InternalServerError("Message describing the error here");
    }

Idealerweise möchte ich, dass dies verallgemeinert wird, damit ich eine Nachricht mit einer der Implementierungen von IHttpActionResult zurücksenden kann.

Muss ich das tun (und meine eigene Antwortnachricht erstellen):

    public IHttpActionResult Get()
    {
       HttpResponseMessage responseMessage = ...
       return ResponseMessage(responseMessage);
    }

oder gibt es einen besseren weg

Mayabelle
quelle
Wie wäre es damit: stackoverflow.com/questions/10732644/…
Milen
könnten Sie nicht ApiController.InternalServerError msdn.microsoft.com/en-us/library/dn292630(v=vs.118).aspx
Ric
@Milen, danke. So etwas könnte funktionieren. Der Teil, den ich nicht mag, erfordert das Erstellen einer anderen IHttpActionResult-Implementierung für jede vorhandene Implementierung, die ich verwenden möchte.
Mayabelle
@ Ric, nein, der Parameter ist eine Ausnahme. Ich möchte eine Nachricht als Zeichenfolge festlegen. Dies betrifft auch keinen allgemeineren Fall, in dem der Code möglicherweise nicht unbedingt ein interner Serverfehler ist.
Mayabelle
3
@ Mayabelle: Hast du Shamil Yakupovs Antwort gesehen? Es ist viel einfacher und prägnanter als die akzeptierte Antwort.
Isaac

Antworten:

419

Sie können dies verwenden:

return Content(HttpStatusCode.BadRequest, "Any object");
Shamil Yakupov
quelle
1
Kurze und einfache Lösung. Mehr Codes bedeuten mehr Fehler und zeitaufwändige Wartung.
Thomas.Benz
6
Wenn ich dies versuche, wird der zurückgegebene Wert von code(wobei Code eine Zeichenfolge ist) in return Content(HttpStatusCode.OK, code)eingekapselt in "was unerwartet ist, gibt es einen Grund dafür? "\"value\""ZB der zurückgegebene Wert ist mvc5
Deza
2
Wenn Sie dies von außerhalb der ApiController-Klasse tun müssen, können Sie Folgendes verwenden: return new NegotiatedContentResult <T> (Code, neues T (...), Controller)
Etherman
Kann ich es aus einer Klassenbibliothek zurückgeben? Worauf muss ich verweisen?
Toolkit
54

Sie können HttpRequestMessagesExtensions.CreateErrorResponse ( System.Net.HttpNamespace) wie folgt verwenden :

public IHttpActionResult Get()
{
   return ResponseMessage(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Message describing the error here"));
}

Es ist vorzuziehen, Antworten basierend auf der Anforderung zu erstellen, um die Inhaltsverhandlung der Web-API zu nutzen.

user1620220
quelle
6
Request.CreateErrorResponse gibt eine HttpResponseMessage zurück, nicht IHttpActionResult. Was Sie beschreiben, ist eine gute Vorgehensweise zum Erstellen einer HttpResponseMessage, geht aber nicht auf meine Frage ein. Danke trotzdem!
Mayabelle
@ Mayabelle Sie können IHttpActionResult Beton erstellen und diesen Code wie folgt verpackt:
Quoc Nguyen
1
Dies hat bei mir funktioniert, aber ich habe Request.CreateResponse verwendet, sodass der Fehler als Zeichenfolge anstelle des Nachrichtenschlüssels angezeigt wird.
Chemiker
Ich erhalte eine Fehlermeldung, das Snippet schlägt fehl. Es heißt, "Anfrage" ist null. Ich versuche, Request.CreateResponse @ user1620220
Sheena Agrawal
@SheenaAgrawal Dieser Code kann nur im Rahmen einer HTTP-Anfrage ausgeführt werden. Wenn ApiController.Requestnull ist, bedeutet dies, dass Sie sich nicht im richtigen Kontext befinden oder dass Ihre WebAPI-Architektur fehlerhaft ist.
user1620220
35

Am Ende habe ich folgende Lösung gewählt:

public class HttpActionResult : IHttpActionResult
{
    private readonly string _message;
    private readonly HttpStatusCode _statusCode;

    public HttpActionResult(HttpStatusCode statusCode, string message)
    {
        _statusCode = statusCode;
        _message = message;
    }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        HttpResponseMessage response = new HttpResponseMessage(_statusCode)
        {
            Content = new StringContent(_message)
        };
        return Task.FromResult(response);
    }
}

... was so verwendet werden kann:

public IHttpActionResult Get()
{
   return new HttpActionResult(HttpStatusCode.InternalServerError, "error message"); // can use any HTTP status code
}

Ich bin offen für Verbesserungsvorschläge. :) :)

Mayabelle
quelle
1
Shamil Yakupovs Antwort ist die beste Antwort, aber nur innerhalb der ApiController-Klasse - sie muss als "return new NegotiatedContentResult <T> (Code, neues T (...), Controller)" umgeschrieben werden, um von außerhalb verwendet zu werden Controller-Klasse. In diesem Fall ist eine Lösung wie diese möglicherweise besser lesbar.
Etherman
16

Sie können auch tun:

return InternalServerError(new Exception("SOME CUSTOM MESSAGE"));
ilans
quelle
1
Ja, aber es ist ein Schmerz, diesen Nachrichtentext zurückzubekommen
userSteve
7

Jeder, der daran interessiert ist, etwas mit einem beliebigen Statuscode mit der Rückgabe von ResponseMessage zurückzugeben:

//CreateResponse(HttpStatusCode, T value)
return ResponseMessage(Request.CreateResponse(HttpStatusCode.XX, object));
CularBytes
quelle
7

In ASP.NET Web API 2 können Sie alle ResponseMessagein ein ResponseMessageResult einschließen :

public IHttpActionResult Get()
{
   HttpResponseMessage responseMessage = ...
   return new ResponseMessageResult(responseMessage);
}

In einigen Fällen ist dies möglicherweise der einfachste Weg, um das gewünschte Ergebnis zu erzielen , obwohl es im Allgemeinen vorzuziehen ist, die verschiedenen Ergebnisse in System.Web.Http.Results zu verwenden .

sfuqua
quelle
6

Einfach:

return ResponseMessage(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Your message"));

Denken Sie daran, auf System.Net.Http und System.Net zu verweisen .

Rodrigo Reis
quelle
2

Ich würde empfehlen, diesen Beitrag zu lesen. Es gibt unzählige Möglichkeiten, vorhandene HttpResponse wie vorgeschlagen zu verwenden. Wenn Sie jedoch Web Api 2 nutzen möchten, sollten Sie einige der integrierten IHttpActionResult-Optionen verwenden, z

return Ok() 

oder

return NotFound()

Wählen Sie den richtigen Rückgabetyp für Web-API-Controller

wegunterjr
quelle
2

Ein detaillierteres Beispiel mit Unterstützung von HTTP-Code, der nicht in C # definiert ist HttpStatusCode.

public class MyController : ApiController
{
    public IHttpActionResult Get()
    {
        HttpStatusCode codeNotDefined = (HttpStatusCode)429;
        return Content(codeNotDefined, "message to be sent in response body");
    }
}

Contentist eine virtuelle Methode, die in der abstrakten Klasse ApiController, der Basis des Controllers, definiert ist. Siehe die Erklärung wie folgt:

protected internal virtual NegotiatedContentResult<T> Content<T>(HttpStatusCode statusCode, T value);
Themenfeld
quelle
1

@mayabelle Sie können IHttpActionResult-Beton erstellen und diesen Code wie folgt umschließen:

public class NotFoundPlainTextActionResult : IHttpActionResult
{
    public NotFoundPlainTextActionResult(HttpRequestMessage request, string message)
    {
        Request = request;
        Message = message;
    }

    public string Message { get; private set; }
    public HttpRequestMessage Request { get; private set; }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        return Task.FromResult(ExecuteResult());
    }

    public HttpResponseMessage ExecuteResult()
    {
        var response = new HttpResponseMessage();

        if (!string.IsNullOrWhiteSpace(Message))
            //response.Content = new StringContent(Message);
            response = Request.CreateErrorResponse(HttpStatusCode.NotFound, new Exception(Message));

        response.RequestMessage = Request;
        return response;
    }
}
Quoc Nguyen
quelle
0

Ich hatte das gleiche Problem. Ich möchte ein benutzerdefiniertes Ergebnis für meine API-Controller erstellen, um sie wie folgt aufzurufen return Ok("some text");

Dann habe ich Folgendes getan: 1) Erstellen Sie einen benutzerdefinierten Ergebnistyp mit Singletone

public sealed class EmptyResult : IHttpActionResult
{
    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        return Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.NoContent) { Content = new StringContent("Empty result") });
    }
}

2) Erstellen Sie einen benutzerdefinierten Controller mit einer neuen Methode:

public class CustomApiController : ApiController
{
    public IHttpActionResult EmptyResult()
    {
        return new EmptyResult();
    }
}

Und dann kann ich sie in meinen Controllern so aufrufen:

public IHttpActionResult SomeMethod()
    {
       return EmptyResult();
    }
Merchezatter
quelle
0

Diese Antwort basiert auf der Antwort von Shamil Yakupov mit einem realen Objekt anstelle einer Zeichenfolge.

using System.Dynamic;

dynamic response = new ExpandoObject();
response.message = "Email address already exist";

return Content<object>(HttpStatusCode.BadRequest, response);
Kugan Kumar
quelle
1
Inhalt <T> ist sehr nützlich
LastTribunal
0

Für Ausnahmen mache ich normalerweise

 catch (Exception ex)
        {
            return InternalServerError(new ApplicationException("Something went wrong in this request. internal exception: " + ex.Message));
        }
ahsant
quelle
0

Die oben genannten Dinge sind wirklich hilfreich.

Beim Erstellen von Webdiensten wird der Verbraucher sehr geschätzt, wenn Sie sich mit Diensten befassen. Ich habe versucht, die Einheitlichkeit der Ausgabe aufrechtzuerhalten. Sie können auch eine Bemerkung oder eine tatsächliche Fehlermeldung geben. Der Webdienst-Konsument kann nur überprüfen, ob IsSuccess wahr ist oder nicht, sonst wird er sicher sein, dass ein Problem vorliegt, und je nach Situation handeln.

  public class Response
    {
        /// <summary>
        /// Gets or sets a value indicating whether this instance is success.
        /// </summary>
        /// <value>
        /// <c>true</c> if this instance is success; otherwise, <c>false</c>.
        /// </value>
        public bool IsSuccess { get; set; } = false;

        /// <summary>
        /// Actual response if succeed 
        /// </summary>
        /// <value>
        /// Actual response if succeed 
        /// </value>
        public object Data { get; set; } = null;

        /// <summary>
        /// Remark if anythig to convey
        /// </summary>
        /// <value>
        /// Remark if anythig to convey
        /// </value>
        public string Remark { get; set; } = string.Empty;
        /// <summary>
        /// Gets or sets the error message.
        /// </summary>
        /// <value>
        /// The error message.
        /// </value>
        public object ErrorMessage { get; set; } = null;


    }  




[HttpGet]
        public IHttpActionResult Employees()
        {
            Response _res = new Response();
            try
            { 
                DalTest objDal = new DalTest(); 
                _res.Data = objDal.GetTestData();
                _res.IsSuccess = true;
                return Ok<Response>(_res);
            }
            catch (Exception ex)
            {
                _res.IsSuccess = false;
                _res.ErrorMessage = ex;
                return ResponseMessage(Request.CreateResponse(HttpStatusCode.InternalServerError, _res )); 
            } 
        }

Sie können gerne Vorschläge machen, falls vorhanden :)

Amol Khandagale
quelle
-1

Entschuldigen Sie die späte Antwort, warum verwenden Sie sie nicht einfach?

return BadRequest("your message");

Ich benutze es für alle meine IHttpActionResultFehler, es funktioniert gut

Hier ist die Dokumentation: https://msdn.microsoft.com/en-us/library/system.web.http.apicontroller.badrequest(v=vs.118).aspx

Benraay
quelle
7
Da nicht alle Fehler auf fehlerhafte Anfragen zurückzuführen sind, 400wäre eine Antwort unangemessen. OP gab speziell eine 500Antwort als Beispiel.
user1620220
Ja, es ist nur mit BadRequest möglich, dass die anderen Typen kein Nachrichtenargument
annehmen