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



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

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.


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. :) :)


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

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

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 .


6

Einfach:

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

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



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

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

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

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

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

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 :)


-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


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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.