创建新的 IHttpActionResult 操作结果方法

Posted

技术标签:

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

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

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

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

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

【问题讨论】:

【参考方案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 应该使用为ForbiddenNoContent 返回自定义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(字符串原因)”方法。请参阅***.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

    

【讨论】:

以上是关于创建新的 IHttpActionResult 操作结果方法的主要内容,如果未能解决你的问题,请参考以下文章

返回 IHttpActionResult 时如何对 Web api 操作方法进行单元测试?

将HttpResponseBase转换为IHttpActionResult

使用 c# 使用 IHttpActionResult 将请求类型作为 XML 发送

[使用C#使用IHttpActionResult将请求类型发送为XML

如何使用IHttpActionResult对Created-201响应进行编码

ASP.NET Core 中的 IHttpActionResult 和辅助方法