Restituisci contenuti con IHttpActionResult per una risposta non OK


185

Per tornare da un controller Web API 2, posso restituire il contenuto con la risposta se la risposta è OK (stato 200) in questo modo:

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

Se possibile, desidero utilizzare i tipi di risultati incorporati qui quando possibile: https://msdn.microsoft.com/en-us/library/system.web.http.results(v=vs.118).aspx

La mia domanda è, per un altro tipo di risposta (non 200), come posso restituire un messaggio (stringa) con esso? Ad esempio, posso fare questo:

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

ma non questo:

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

Idealmente, voglio che questo sia generalizzato in modo da poter inviare un messaggio indietro con una qualsiasi delle implementazioni di IHttpActionResult.

Devo fare questo (e creare il mio messaggio di risposta):

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

o c'è un modo migliore?



potresti non usare ApiController.InternalServerError msdn.microsoft.com/en-us/library/dn292630(v=vs.118).aspx
Ric

@Milen, grazie. Qualcosa del genere potrebbe funzionare. La parte che non mi piace è che richiede la creazione di un'implementazione IHttpActionResult diversa per ogni implementazione esistente che voglio poter usare.
Mayabelle,

@Ric, no, il parametro è un'eccezione. Voglio impostare un messaggio come stringa. Inoltre, questo non risolve un caso più generale in cui il codice potrebbe non essere necessariamente un errore interno del server.
Mayabelle,

3
@mayabelle: hai visto la risposta di Shamil Yakupov? È molto più semplice e conciso che la risposta accettata.
Isaac,

Risposte:


420

Puoi usare questo:

return Content(HttpStatusCode.BadRequest, "Any object");

1
Soluzione breve e semplice. Avere più codici significa più bug e una manutenzione che richiede tempo.
Thomas.Benz,

6
Quando sto provando questo, il valore restituito di code(dove il codice è una stringa) return Content(HttpStatusCode.OK, code)è incapsulato in "il che è inaspettato, c'è qualche motivo per questo? Ad esempio, il valore che viene restituito "\"value\""sto usando mvc5
Deza

2
Se è necessario eseguire questa operazione dall'esterno della classe ApiController, è possibile utilizzare: return new NegotiatedContentResult <T> (codice, nuova T (...), controller)
Etherman,

posso restituirlo da una biblioteca di classe? Cosa devo fare riferimento?
Toolkit

54

Puoi usare HttpRequestMessagesExtensions.CreateErrorResponse ( System.Net.Httpnamespace), in questo modo:

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

È preferibile creare risposte basate sulla richiesta per sfruttare la negoziazione del contenuto dell'API Web.


6
Request.CreateErrorResponse restituisce un HttpResponseMessage, non IHttpActionResult. Quello che descrivi è una buona pratica per creare un HttpResponseMessage ma non risponde alla mia domanda. Grazie comunque!
Mayabelle,

@mayabelle puoi creare IHttpActionResult concrete e avvolgere quel codice in questo modo:
Quoc Nguyen

1
Questo ha funzionato per me, ma ho usato Request.CreateResponse in modo che l'errore venga visualizzato come una stringa anziché nella chiave del messaggio.
Chimico

Ricevo un errore, lo snippet non riesce. Dice che "richiesta" è nulla. Sto cercando di utilizzare Request.CreateResponse @ user1620220
Sheena Agrawal

@SheenaAgrawal Questo codice può essere eseguito solo nel contesto di una richiesta HTTP. Se ApiController.Requestè null significa che non sei nel giusto contesto o che qualcosa non funziona nell'architettura WebAPI.
user1620220

35

Ho finito per andare con la seguente soluzione:

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

... che può essere utilizzato in questo modo:

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

Sono aperto a suggerimenti per il miglioramento. :)


1
La risposta di Shamil Yakupov è la risposta migliore ma solo dall'interno della classe ApiController - deve essere riscritta come qualcosa come "return new NegotiatedContentResult <T> (code, new T (...), controller)" da usare dall'esterno del classe controller. In tal caso, una soluzione come questa può essere più leggibile.
Etherman,

16

Puoi anche fare:

return InternalServerError(new Exception("SOME CUSTOM MESSAGE"));

1
Sì, ma è una seccatura recuperare quel messaggio
userSteve

7

Chiunque sia interessato a restituire qualcosa con qualsiasi codice statico con ReturnMessage di ritorno:

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

7

Nell'API Web ASP.NET 2, puoi racchiudere qualsiasi oggetto ResponseMessagein ResponseMessageResult :

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

In alcuni casi questo può essere il modo più semplice per ottenere il risultato desiderato, sebbene in generale sia preferibile utilizzare i vari risultati in System.Web.Http.Results .


6

Semplice:

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

Ricordarsi di fare riferimento a System.Net.Http e System.Net .



2

Un esempio più dettagliato con supporto del codice HTTP non definito in C # HttpStatusCode.

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

Contentè un metodo virtuale definito in classe astratta ApiController, la base del controller. Vedi la dichiarazione come di seguito:

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

1

@mayabelle puoi creare IHttpActionResult concrete e avvolgere quel codice in questo modo:

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

Ho avuto lo stesso problema. Voglio creare risultati personalizzati per i miei controller API, per chiamarli come return Ok("some text");

Quindi ho fatto questo: 1) Crea un tipo di risultato personalizzato con 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) Crea controller personalizzato con il nuovo metodo:

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

E poi posso chiamarli nei miei controller, in questo modo:

public IHttpActionResult SomeMethod()
    {
       return EmptyResult();
    }

0

questa risposta si basa sulla risposta di Shamil Yakupov, con oggetto reale anziché stringa.

using System.Dynamic;

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

return Content<object>(HttpStatusCode.BadRequest, response);

1
Il contenuto <T> è molto utile
LastTribunal

0

Per eccezioni, di solito lo faccio

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

0

Le cose sopra sono davvero utili.

Durante la creazione di servizi Web, se prenderai il caso di servizi il consumatore sarà molto apprezzato. Ho cercato di mantenere l'uniformità dell'output. Inoltre è possibile fornire commenti o messaggi di errore reali. L'utente del servizio web può solo verificare IsSuccess su true oppure no, è sicuro che ci sia un problema e agire secondo la situazione.

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

Ti invitiamo a dare qualche suggerimento :)


-1

Ci scusiamo per la risposta tardiva perché non usi semplicemente

return BadRequest("your message");

Lo uso per tutti i miei IHttpActionResult errori, funziona bene

ecco la documentazione: https://msdn.microsoft.com/en-us/library/system.web.http.apicontroller.badrequest(v=vs.118).aspx


7
Perché non tutti gli errori sono il risultato di cattive richieste, quindi una 400risposta sarebbe inappropriata. OP ha dato una 500risposta specifica come esempio.
user1620220

Sì, è possibile solo con BadRequest gli altri tipi non accettano un argomento di messaggio
benraay
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.