Renvoyer le contenu avec IHttpActionResult pour une réponse non OK

185

Pour le retour d'un contrôleur Web API 2, je peux renvoyer du contenu avec la réponse si la réponse est OK (état 200) comme ceci:

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

Si possible, je souhaite utiliser les types de résultats intégrés ici lorsque cela est possible: https://msdn.microsoft.com/en-us/library/system.web.http.results(v=vs.118).aspx

Ma question est, pour un autre type de réponse (pas 200), comment puis-je renvoyer un message (chaîne) avec? Par exemple, je peux faire ceci:

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

mais pas ça:

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

Idéalement, je veux que cela soit généralisé afin de pouvoir renvoyer un message avec l'une des implémentations de IHttpActionResult.

Dois-je faire cela (et créer mon propre message de réponse):

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

ou y a-t-il un meilleur moyen?

mayabelle
la source
que diriez-vous de ceci: stackoverflow.com/questions/10732644/…
Milen
ne pourriez-vous pas utiliser ApiController.InternalServerError msdn.microsoft.com/en-us/library/dn292630(v=vs.118).aspx
Ric
@Milen, merci. Quelque chose comme ça pourrait fonctionner. La partie que je n'aime pas est qu'elle nécessite la création d'une implémentation IHttpActionResult différente pour chaque implémentation existante que je souhaite pouvoir utiliser.
mayabelle
@Ric, non, le paramètre est une exception. Je souhaite définir un message sous forme de chaîne. En outre, cela ne répond pas à un cas plus général où le code peut ne pas nécessairement être une erreur de serveur interne.
mayabelle
3
@mayabelle: Avez-vous vu la réponse de Shamil Yakupov? C'est beaucoup plus simple et concis que la réponse acceptée.
Isaac

Réponses:

420

Vous pouvez utiliser ceci:

return Content(HttpStatusCode.BadRequest, "Any object");
Shamil Yakupov
la source
1
Solution courte et simple. Avoir plus de codes signifie plus de bogues et une maintenance fastidieuse.
Thomas.Benz
6
Quand j'essaye ceci, la valeur retournée de code(où le code est une chaîne) dans return Content(HttpStatusCode.OK, code)est encapsulée dans "qui est inattendu, y a-t-il une raison pour ceci? Par exemple la valeur qui est retournée est "\"value\""j'utilise mvc5
Deza
2
Si vous devez le faire depuis l'extérieur de la classe ApiController, vous pouvez utiliser: return new NegotiatedContentResult <T> (code, new T (...), controller)
Etherman
puis-je le retourner à partir d'une bibliothèque de classe? À quoi dois-je faire référence?
Boîte à outils du
54

Vous pouvez utiliser HttpRequestMessagesExtensions.CreateErrorResponse ( System.Net.Httpnamespace), comme ceci:

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

Il est préférable de créer des réponses basées sur la demande pour profiter de la négociation de contenu de l'API Web.

user1620220
la source
6
Request.CreateErrorResponse renvoie un HttpResponseMessage, pas IHttpActionResult. Ce que vous décrivez est une bonne pratique pour créer un HttpResponseMessage mais ne répond pas à ma question. Merci quand même!
mayabelle
@mayabelle vous pouvez créer IHttpActionResult concret et encapsuler ce code comme ceci:
Quoc Nguyen
1
Cela a fonctionné pour moi, mais j'ai utilisé Request.CreateResponse afin que l'erreur s'affiche sous forme de chaîne au lieu de sous la clé Message.
Chimiste
Je reçois une erreur, l'extrait de code échoue. Il dit que «demande» est nul. J'essaie d'utiliser Request.CreateResponse @ user1620220
Sheena Agrawal
@SheenaAgrawal Ce code ne peut être exécuté que dans le cadre d'une requête HTTP. Si la valeur ApiController.Requestest nulle, cela signifie que vous n'êtes pas dans le bon contexte ou que quelque chose est cassé dans votre architecture WebAPI.
user1620220
35

J'ai fini par choisir la solution suivante:

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

... qui peut être utilisé comme ceci:

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

Je suis ouvert aux suggestions d'amélioration. :)

mayabelle
la source
1
La réponse de Shamil Yakupov est la meilleure réponse, mais uniquement de l'intérieur de la classe ApiController - elle doit être réécrite comme quelque chose comme "return new NegotiatedContentResult <T> (code, new T (...), controller)" à utiliser de l'extérieur du classe de contrôleur. Dans ce cas, une solution telle que celle ci-dessus peut être plus lisible.
Etherman
16

Vous pouvez également faire:

return InternalServerError(new Exception("SOME CUSTOM MESSAGE"));
ilans
la source
1
Oui, mais c'est une douleur de récupérer ce message texte
userSteve
7

Toute personne intéressée à retourner quelque chose avec n'importe quel code d'état avec le retour de ResponseMessage:

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

Dans l'API Web ASP.NET 2, vous pouvez encapsuler n'importe lequel ResponseMessagedans un ResponseMessageResult :

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

Dans certains cas, cela peut être le moyen le plus simple d'obtenir le résultat souhaité, bien qu'il soit généralement préférable d'utiliser les différents résultats dans System.Web.Http.Results .

sfuqua
la source
6

Facile:

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

N'oubliez pas de référencer System.Net.Http et System.Net .

Rodrigo Reis
la source
2

Je recommanderais de lire cet article. Il existe des tonnes de façons d'utiliser HttpResponse existant comme suggéré, mais si vous souhaitez profiter de Web Api 2, envisagez d'utiliser certaines des options IHttpActionResult intégrées telles que

return Ok() 

ou

return NotFound()

Choisissez le bon type de retour pour les contrôleurs Web Api

wegunterjr
la source
2

Un exemple plus détaillé avec prise en charge du code HTTP non défini en C # HttpStatusCode.

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

Contentest une méthode virtuelle définie dans la classe abstraite ApiController, la base du contrôleur. Voir la déclaration ci-dessous:

protected internal virtual NegotiatedContentResult<T> Content<T>(HttpStatusCode statusCode, T value);
champ
la source
1

@mayabelle vous pouvez créer IHttpActionResult concret et encapsuler ce code comme ceci:

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
la source
0

J'ai eu le même problème. Je veux créer un résultat personnalisé pour mes contrôleurs api, pour les appeler comme return Ok("some text");

Ensuite, j'ai fait ceci: 1) Créer un type de résultat personnalisé avec 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) Créez un contrôleur personnalisé avec une nouvelle méthode:

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

Et puis je peux les appeler dans mes contrôleurs, comme ceci:

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

cette réponse est basée sur la réponse de Shamil Yakupov, avec un objet réel au lieu d'une chaîne.

using System.Dynamic;

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

return Content<object>(HttpStatusCode.BadRequest, response);
Kugan Kumar
la source
1
Le contenu <T> est très utile
LastTribunal
0

Pour les exceptions, je fais habituellement

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

Les choses ci-dessus sont vraiment utiles.

Lors de la création de services Web, si vous prenez le cas des services consommateur sera grandement apprécié. J'ai essayé de maintenir l'uniformité de la sortie. Vous pouvez également donner une remarque ou un message d'erreur réel. Le consommateur du service Web ne peut que vérifier IsSuccess true ou non, il sera sûr qu'il y a un problème et agira selon la situation.

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

Vous êtes invités à donner des suggestions le cas échéant :)

Amol Khandagale
la source
-1

Désolé pour la réponse tardive, pourquoi ne pas utiliser simplement

return BadRequest("your message");

Je l'utilise pour tous mes IHttpActionResult erreurs, il fonctionne bien

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

Benraay
la source
7
Comme toutes les erreurs ne sont pas le résultat de mauvaises demandes, une 400réponse serait inappropriée. OP a spécifiquement donné une 500réponse à titre d'exemple.
user1620220
Oui, ce n'est possible qu'avec BadRequest, les autres types ne prennent pas d'argument de message
benraay