【问题标题】:Creating new IHttpActionResult action result methods创建新的 IHttpActionResult 操作结果方法
【发布时间】:2015-04-05 06:11:45
【问题描述】:

有没有办法可以使用新的IHttpActionResult 接口返回HttpStatusCode.NoContent 响应消息?

我目前正在使用return new HttpResponseMessage( HttpStatusCode.NoContent ); 并希望将其转换为return NoContent();。

IHttpActionResult 已经有 Ok()、Conflict() 和 NotFound(),但我找不到需要在我的项目中使用的 Forbidden() 和 NoContent()。

添加其他结果类型有多容易?

【问题讨论】:

    标签: c# asp.net-web-api2


    【解决方案1】:

    这对我很有效:

    public class CodeAndReason : IHttpActionResult
    {
        private readonly HttpStatusCode code;
        private readonly string reason;
    
        public CodeAndReason(HttpStatusCode code, string reason)
        {
            this.code = code;
            this.reason = reason;
        }
    
        public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
        {
            var response = new HttpResponseMessage(code)
            {
                ReasonPhrase = reason,
                Content = new StringContent(reason),
            };
    
            return Task.FromResult(response);
        }
    
        public static IHttpActionResult NotFound(string reason)
        {
            return new CodeAndReason(HttpStatusCode.NotFound, reason);
        }
    
        public static IHttpActionResult Conflict(string reason)
        {
            return new CodeAndReason(HttpStatusCode.Conflict, reason);
        }
    
        public static IHttpActionResult Unauthorized(string reason)
        {
            return new CodeAndReason(HttpStatusCode.Unauthorized, reason);
        }
    }
    

    用作:

    return CodeAndReason.NotFound("Record {blah} not found");
    

    【讨论】:

      【解决方案2】:

      您现在可以使用以下(.Net 标准):

      return StatusCode(HttpStatusCode.NoContent);
      

      或(.Net Core 2.1+)

      return NoContent();
      

      【讨论】:

        【解决方案3】:

        我尝试了@Intrepid 实现,但遇到了一些问题。我在这里看到两种解决方案:

        解决方案 1: 该部分:return Forbidden(); 不应该工作。

        编译器无法识别。

        应该是:return new ForbiddenResult(Request, "my reason");

        更新 1

        解决方案 2:

        我认为这是@Interpid 在他的实现中的意图,但他遗漏了一些东西。

        为了使用return Forbidden();,CommonApiController 应该使用为Forbidden 和NoContent 返回自定义IHttpActionResult 的函数进行更新

        该类应如下所示:

        public abstract class CommonApiController: ApiController {
        
            protected ForbiddenResult Forbidden() {
             return new ForbiddenResult(this.Request);
            }
        
            protected ForbiddenResult Forbidden(string reason) {
             return new ForbiddenResult(this.Request, reason);
            }
        
            protected NoContentResult NoContent() {
             return new NoContentResult(this.Request);
            }
        
            public class ForbiddenResult: IHttpActionResult {
             private readonly HttpRequestMessage _request;
             private readonly string _reason;
        
             public ForbiddenResult(HttpRequestMessage request, string reason) {
              _request = request;
              _reason = reason;
             }
        
             public ForbiddenResult(HttpRequestMessage request) {
              _request = request;
              _reason = "Forbidden";
             }
        
             public Task < HttpResponseMessage > ExecuteAsync(CancellationToken cancellationToken) {
              var response = _request.CreateResponse(HttpStatusCode.Forbidden, _reason);
              return Task.FromResult(response);
             }
            }
        
            public class NoContentResult: IHttpActionResult {
             private readonly HttpRequestMessage _request;
             private readonly string _reason;
        
             public NoContentResult(HttpRequestMessage request, string reason) {
              _request = request;
              _reason = reason;
             }
        
             public NoContentResult(HttpRequestMessage request) {
              _request = request;
              _reason = "No Content";
             }
        
             public Task < HttpResponseMessage > ExecuteAsync(CancellationToken cancellationToken) {
              var response = _request.CreateResponse(HttpStatusCode.NoContent, _reason);
              return Task.FromResult(response);
             }
            }
           }
        

        无论如何,如果我错了,@Interpid 的回答是正确的。为了使他的实施工作,我在这里缺少什么?

        【讨论】:

        • 更新了答案。添加了另一个替代解决方案。我认为第二个解决方案是@Interpid 最初的意思。
        • 我认为您的想法是正确的。这应该是公认的答案。
        • 注意:您不应返回带有 204 No Content 的内容正文。我会从代码中删除“受保护的 NoContentResult NoContent(字符串原因)”方法。请参阅stackoverflow.com/a/23374724/2463738 了解更多信息。
        • @valentin 注意。我更新了问题。感谢您的关注
        【解决方案4】:

        no-content 结果没有方便的方法,因为默认情况下,当操作返回 void 时,响应将具有 HTTP 状态 204。

        如果您希望在操作中明确指出这一点,您还可以从您的操作中返回 StatusCode(HttpStatusCode.NoContent) 或

        ResponseMessage(new HttpResponseMessage(HttpStatusCode.NoContent)).
        

        Unauthorized() 便捷方法为您提供 401 状态,因此,对于 Forbidden (403),您还必须使用 StatusCode(HttpStatusCode.Forbidden) 或

        ResponseMessage(new HttpResponseMessage(HttpStatusCode.Forbidden))
        

        【讨论】:

        • 未经授权=401。禁止=403。
        • 很好,这是最好的回应。
        • 在某些情况下返回 void 不是一个选项,因为您希望在验证中使用 BadRequest 或其他一些状态代码进行响应,仅在成功时发送 NoContent。返回StatusCode(HttpStatusCode.NoContent) 为我解决了这个问题,这是一个比公认答案更干净的解决方案。
        【解决方案5】:

        如果您想在响应中包含原因短语而不向 ApiController 添加子类,请构建一个 ResponseMessage 对象并通过 ResponseMessage() 方法从操作中返回它。试试这个:

        public class InvoiceController : ApiController
        {
            public async Task<IHttpActionResult> Post([FromBody]Invoice invoice)
            {
                if(User.IsInRole("Readonly"))
                {
                    var response = new HttpResponseMessage(HttpStatusCode.Forbidden);
        
                    response.ReasonPhrase = "User has the Readonly role";
                    return ResponseMessage(response);
                }
        
                // Rest of code
        
            }
        }
        

        【讨论】:

          【解决方案6】:

          我发现了这个example site,它展示了如何添加自定义的IHttpActionResult 方法,我已经使用它成功地创建了Forbidden() 和NoContent() 方法。

          public abstract class CommonApiController : ApiController
          {
              public class ForbiddenResult : IHttpActionResult
              {
                  private readonly HttpRequestMessage _request;
                  private readonly string _reason;
          
                  public ForbiddenResult(HttpRequestMessage request,string reason)
                  {
                      _request = request;
                      _reason = reason;
                  }
          
                  public ForbiddenResult(HttpRequestMessage request)
                  {
                      _request = request;
                      _reason = "Forbidden";
                  }
          
                  public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
                  {
                      var response = _request.CreateResponse(HttpStatusCode.Forbidden,_reason);
                      return Task.FromResult(response);
                  }
              }
          
              public class NoContentResult : IHttpActionResult
              {
                  private readonly HttpRequestMessage _request;
                  private readonly string _reason;
          
                  public NoContentResult(HttpRequestMessage request,string reason)
                  {
                      _request = request;
                      _reason = reason;
                  }
          
                  public NoContentResult(HttpRequestMessage request)
                  {
                      _request = request;
                      _reason = "No Content";
                  }
          
                  public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
                  {
                      var response = _request.CreateResponse(HttpStatusCode.NoContent,_reason);
                      return Task.FromResult(response);
                  }
              }
          }
          

          然后我可以这样使用它:

          public class InvoiceController : CommonApiController
          {
              public async Task<IHttpActionResult> Post([FromBody]Invoice invoice)
              {
                  if(User.IsInRole("Readonly"))
                  {
                      return Forbidden();
                  }
          
                  // Rest of code
          
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-12-17
            • 1970-01-01
            • 2023-02-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多