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.