Retornar conteúdo com IHttpActionResult para resposta não OK

185

Para retornar de um controlador da API da Web 2, posso retornar o conteúdo com a resposta se a resposta estiver OK (status 200) assim:

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

Se possível, desejo usar os tipos de resultados internos aqui, quando possível: https://msdn.microsoft.com/en-us/library/system.web.http.results(v=vs.118).aspx

Minha pergunta é, para outro tipo de resposta (não 200), como posso retornar uma mensagem (string) com ela? Por exemplo, eu posso fazer isso:

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

mas não isso:

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

Idealmente, quero que isso seja generalizado para que eu possa enviar uma mensagem de volta com qualquer uma das implementações de IHttpActionResult.

Preciso fazer isso (e criar minha própria mensagem de resposta):

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

Ou há um modo melhor?

mayabelle
fonte
você não poderia usar o ApiController.InternalServerError msdn.microsoft.com/en-us/library/dn292630(v=vs.118).aspx
Ric
@Milen, obrigado. Algo assim pode funcionar. A parte que eu não gosto é que exige a criação de uma implementação IHttpActionResult diferente para cada implementação existente que eu quero poder usar.
Mayabelle
@ Ric, não, o parâmetro é uma exceção. Quero definir uma mensagem como uma sequência. Além disso, isso não trata de um caso mais geral em que o código pode não necessariamente ser um erro interno do servidor.
mayabelle
3
@ mayabelle: Você viu a resposta de Shamil Yakupov? É muito mais simples e conciso que a resposta aceita.
Isaac

Respostas:

420

Você pode usar isto:

return Content(HttpStatusCode.BadRequest, "Any object");
Shamil Yakupov
fonte
1
Solução curta e simples. Ter mais códigos significa mais erros e manutenção demorada.
Thomas.Benz
6
Quando estou tentando isso, o valor retornado de code(onde o código é uma string) em return Content(HttpStatusCode.OK, code)é encapsulado em "o que é inesperado, há alguma razão para este exemplo, o valor que é retornado é? "\"value\""Eu estou usando mvc5
Deza
2
Se você precisar fazer isso de fora da classe ApiController, poderá usar: return new NegotiatedContentResult <T> (código, novo T (...), controlador) #
9337
posso devolvê-lo de uma biblioteca de classes? O que eu preciso fazer referência?
Toolkit
54

Você pode usar HttpRequestMessagesExtensions.CreateErrorResponse ( System.Net.Httpnamespace), assim:

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

É preferível criar respostas com base na solicitação para aproveitar a negociação de conteúdo da API da Web.

user1620220
fonte
6
Request.CreateErrorResponse retorna um HttpResponseMessage, não IHttpActionResult. O que você descreve é ​​uma boa prática para criar um HttpResponseMessage, mas não aborda minha pergunta. Obrigado mesmo assim!
mayabelle
@mayabelle você pode criar IHttpActionResult concreto e envolveu os código como este:
Quoc Nguyen
1
Isso funcionou para mim, mas eu usei Request.CreateResponse para que o erro seja exibido como uma sequência em vez de em Chave da mensagem.
Chemist
Estou recebendo um erro, o snippet está falhando. Ele diz que 'request' é nulo. Estou tentando usar Request.CreateResponse @ user1620220
Sheena Agrawal
@SheenaAgrawal Esse código pode ser executado apenas no contexto de uma solicitação HTTP. Se ApiController.Requestfor nulo, significa que você não está no contexto certo ou algo está quebrado na arquitetura da WebAPI.
precisa saber é o seguinte
35

Acabei indo com a seguinte solução:

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

... que pode ser usado assim:

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

Estou aberto a sugestões de melhorias. :)

mayabelle
fonte
1
A resposta de Shamil Yakupov é a melhor resposta, mas apenas dentro da classe ApiController - ela precisa ser reescrita como algo como "retornar novo NegotiatedContentResult <T> (código, novo T (...), controlador)" a ser usado de fora da classe classe de controlador. Nesse caso, uma solução como esta acima pode ser mais legível.
27617
16

Você também pode fazer:

return InternalServerError(new Exception("SOME CUSTOM MESSAGE"));
ilans
fonte
1
Sim, mas a sua dor a obter esse texto mensagem de volta
userSteve
7

Qualquer pessoa interessada em retornar qualquer coisa com qualquer código de status retornando o ResponseMessage:

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

Na API da Web do ASP.NET 2, você pode agrupar qualquer ResponseMessageem um ResponseMessageResult :

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

Em alguns casos, essa pode ser a maneira mais simples de obter o resultado desejado, embora geralmente seja preferível usar os vários resultados em System.Web.Http.Results .

sfuqua
fonte
6

Simples:

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

Lembre-se de referenciar System.Net.Http e System.Net .

Rodrigo Reis
fonte
2

Eu recomendaria ler este post. Existem várias maneiras de usar o HttpResponse existente, conforme sugerido, mas se você quiser tirar proveito do Web Api 2, consulte o uso de algumas das opções IHttpActionResult internas, como

return Ok() 

ou

return NotFound()

Escolha o tipo de retorno correto para os controladores de API da Web

wegunterjr
fonte
2

Um exemplo mais detalhado com suporte ao código HTTP não definido em C # HttpStatusCode.

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

Contenté um método virtual definido na classe abstrata ApiController, a base do controlador. Veja a declaração abaixo:

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

@ mayabelle, você pode criar o IHttpActionResult concreto e agrupar esses códigos assim:

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
fonte
0

Eu tive o mesmo problema. Eu quero criar um resultado personalizado para meus controladores de API, para chamá-los como return Ok("some text");

Então eu fiz isso: 1) Crie um tipo de resultado personalizado com 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) Crie um controlador personalizado com o novo método:

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

E então eu posso chamá-los nos meus controladores, assim:

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

esta resposta é baseada na resposta de Shamil Yakupov, com objeto real em vez de string.

using System.Dynamic;

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

return Content<object>(HttpStatusCode.BadRequest, response);
Kugan Kumar
fonte
1
O conteúdo <T> é muito útil
LastTribunal
0

Para exceções, eu costumo fazer

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

As coisas acima são realmente úteis.

Ao criar serviços da web, se você considerar os serviços, o consumidor será muito apreciado. Eu tentei manter a uniformidade da saída. Além disso, você pode enviar comentários ou mensagens de erro reais. O consumidor de serviço da web pode apenas verificar se o IsSuccess é verdadeiro ou não, se não há certeza de que há algum problema e agir de acordo com a situação.

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

Você pode sugerir, se houver :)

Amol Khandagale
fonte
-1

Desculpe pela resposta tardia, por que você não usa simplesmente

return BadRequest("your message");

Eu o uso para todos os meus IHttpActionResulterros, está funcionando bem

aqui está a documentação: https://msdn.microsoft.com/en-us/library/system.web.http.apicontroller.badrequest(v=vs.118).aspx

Benraay
fonte
7
Como nem todos os erros são resultado de solicitações incorretas, uma 400resposta seria inadequada. O OP deu uma 500resposta específica como exemplo.
user1620220
Sim, é possível somente com BadRequest os outros tipos não tomar um argumento mensagem
benraay