【问题标题】:Return content with IHttpActionResult for non-OK response使用 IHttpActionResult 为非 OK 响应返回内容
【发布时间】:2015-04-19 18:02:13
【问题描述】:

为了从 Web API 2 控制器返回,如果响应正常(状态 200),我可以返回包含响应的内容,如下所示:

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

如果可能,我想尽可能在​​这里使用内置结果类型:https://msdn.microsoft.com/en-us/library/system.web.http.results(v=vs.118).aspx

我的问题是,对于另一种类型的响应(不是 200),我怎样才能用它返回消息(字符串)?例如,我可以这样做:

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

但不是这个:

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

理想情况下,我希望将其通用化,以便我可以使用 IHttpActionResult 的任何实现发回消息。

我是否需要这样做(并构建我自己的响应消息):

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

或者有更好的方法吗?

【问题讨论】:

  • 你不能用ApiController.InternalServerErrormsdn.microsoft.com/en-us/library/dn292630(v=vs.118).aspx
  • @Milen,谢谢。类似的东西可能会奏效。我不喜欢的部分是它需要为我希望能够使用的每个现有实现创建不同的 IHttpActionResult 实现。
  • @Ric,不,参数是异常。我想将消息设置为字符串。此外,这并没有解决更一般的情况,即代码不一定是内部服务器错误。
  • @mayabelle:你看到 Shamil Yakupov 的回答了吗?接受的答案要简单得多。

标签: c# asp.net-web-api httpresponse


【解决方案1】:

下面的代码/类对处理所有类型的响应非常有帮助。可能成功也可能失败等等。

我为什么要使用这个? :

假设我正在使用 Web API 服务。输出的几种可能性如下:

  1. 由于验证错误,您可能不会得到任何结果
  2. 你会得到预期的结果
  3. 你会得到错误。

所以在这里我有处理所有场景的解决方案。我也试图保持输出的一致性。您可以给出备注或实际的错误信息。 Web服务消费者只能检查IsSuccess是否为真,否则确定有问题,并根据情况采取行动。 Web API 开发者和 Web API 消费者之间应该有完美的沟通。如果结果没有产生那么为什么。评论或例外将承认,他们将采取相应的行动。 因此,这是 Web API 消费者/用户的最佳解决方案。

所有类型结果的单一响应。

  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 Request.CreateResponse(HttpStatusCode.OK, _res);
            }
            catch (Exception ex)
            {
                _res.IsSuccess = false;
                _res.ErrorMessage = ex;
                return ResponseMessage(Request.CreateResponse(HttpStatusCode.InternalServerError, _res )); 
            } 
        }

如果有任何建议,欢迎您提出建议:)

如果有人使用并从中受益,我很高兴。如果有任何添加或修改使这更加改进,请在 akhandagale65@gmail.com 上写信给我。

【讨论】:

    【解决方案2】:

    简单:

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

    记得参考 System.Net.HttpSystem.Net

    【讨论】:

      【解决方案3】:

      你可以用这个:

      return BadRequest("No data is present in table!!");
      

      【讨论】:

        【解决方案4】:

        支持未在 C# HttpStatusCode 中定义的 HTTP 代码的更详细示例。

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

        Content 是定义在抽象类ApiController 中的虚方法,它是控制器的基础。声明如下:

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

        【讨论】:

          【解决方案5】:

          我会推荐阅读这篇文章。有很多方法可以按照建议使用现有的 HttpResponse,但是如果您想利用 Web Api 2,那么请考虑使用一些内置的 IHttpActionResult 选项,例如

          return Ok() 
          

          return NotFound()
          

          Choose the right return type for Web Api Controllers

          【讨论】:

            【解决方案6】:

            对于例外情况,我通常会这样做

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

            【讨论】:

              【解决方案7】:

              此答案基于 Shamil Yakupov 答案,使用真实对象而不是字符串。

              using System.Dynamic;
              
              dynamic response = new ExpandoObject();
              response.message = "Email address already exist";
              
              return Content<object>(HttpStatusCode.BadRequest, response);
              

              【讨论】:

              • 内容很有用
              【解决方案8】:

              我遇到了同样的问题。我想为我的 api 控制器创建自定义结果,像这样调用它们 return Ok("some text");

              然后我这样做了: 1) 使用单音创建自定义结果类型

              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) 使用新方法创建自定义控制器:

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

              然后我可以在我的控制器中调用它们,如下所示:

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

              【讨论】:

                【解决方案9】:

                在 ASP.NET Web API 2 中,您可以将任何 ResponseMessage 包装在 ResponseMessageResult 中:

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

                在某些情况下,这可能是获得所需结果的最简单方法,尽管通常最好使用System.Web.Http.Results 中的各种结果。

                【讨论】:

                  【解决方案10】:

                  抱歉回答晚了,你为什么不简单使用

                  return BadRequest("your message");

                  我将它用于我所有的 IHttpActionResult 错误,它运行良好

                  这里是文档:https://msdn.microsoft.com/en-us/library/system.web.http.apicontroller.badrequest(v=vs.118).aspx

                  【讨论】:

                  • 因为不是所有错误都是错误请求的结果,所以400 响应是不合适的。 OP 专门给出了一个500 响应作为示例。
                  • 是的,只有 BadRequest 才有可能,其他类型不接受消息参数
                  【解决方案11】:

                  任何有兴趣返回任何状态码并返回 ResponseMessage 的人:

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

                  【讨论】:

                    【解决方案12】:

                    你可以用这个:

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

                    【讨论】:

                    • 简短而简单的解决方案。拥有更多代码意味着更多的错误和耗时的维护。
                    • 当我尝试这个时,return Content(HttpStatusCode.OK, code)code (其中代码是一个字符串)的返回值被封装在“这是意外的,有什么原因吗?例如这个值返回的是"\"value\""我正在使用mvc5
                    • 如果您需要从 ApiController 类外部执行此操作,则可以使用:return new NegotiatedContentResult(code, new T(...), controller)
                    • 我可以从类库中返回它吗?我需要参考什么?
                    【解决方案13】:

                    你可以使用HttpRequestMessagesExtensions.CreateErrorResponseSystem.Net.Http命名空间),像这样:

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

                    最好根据请求创建响应,以利用 Web API 的内容协商。

                    【讨论】:

                    • Request.CreateErrorResponse 返回一个 HttpResponseMessage,而不是 IHttpActionResult。您所描述的是创建 HttpResponseMessage 的良好做法,但没有解决我的问题。还是谢谢!
                    • @mayabelle 你可以创建具体的 IHttpActionResult 并像这样包装这些代码:
                    • 这对我有用,但我使用了 Request.CreateResponse 以便错误显示为字符串而不是 Message 键。
                    • 我收到一个错误,sn-p 失败。它说“请求”为空。我正在尝试使用 Request.CreateResponse @user1620220
                    • @SheenaAgrawal 此代码只能在 HTTP 请求的上下文中执行。如果 ApiController.Request 为 null,则表示您不在正确的上下文中,或者您的 WebAPI 架构中有问题。
                    【解决方案14】:

                    你也可以这样做:

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

                    【讨论】:

                    • 是的,但是要找回该消息文本很痛苦
                    【解决方案15】:

                    @mayabelle 你可以创建具体的 IHttpActionResult 并像这样包装这些代码:

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

                    【讨论】:

                      【解决方案16】:

                      我最终选择了以下解决方案:

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

                      ... 可以这样使用:

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

                      我愿意接受改进建议。 :)

                      【讨论】:

                      • Shamil Yakupov 的答案是最好的答案,但只能从 ApiController 类内部 - 它需要重写为类似“return new NegotiatedContentResult(code, new T(...), controller )" 从控制器类外部使用。在这种情况下,上述解决方案可能更具可读性。
                      猜你喜欢
                      • 2017-11-02
                      • 2017-11-01
                      • 1970-01-01
                      • 2011-10-27
                      • 2021-04-23
                      • 1970-01-01
                      • 2018-03-17
                      • 1970-01-01
                      • 2014-06-04
                      相关资源
                      最近更新 更多