创建新的IHttpActionResult操作结果方法

43

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

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

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

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

6个回答

57

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

如果您希望在操作中明确指示该状态,还可以从操作中返回 StatusCode(HttpStatusCode.NoContent)

ResponseMessage(new HttpResponseMessage(HttpStatusCode.NoContent)).

Unauthorized() 是方便的方法,可以给你返回 401 状态码。如果要返回 Forbidden (403) 状态码,你还需要使用 StatusCode(HttpStatusCode.Forbidden)

ResponseMessage(new HttpResponseMessage(HttpStatusCode.Forbidden))

3
未经授权=401。禁止访问=403。 - Damien_The_Unbeliever
很好,这是最棒的回应。 - Mark Rogers
3
在某些情况下,返回void并不是一个选项,因为你可能希望在验证失败时返回BadRequest或其他状态码,在成功时只发送NoContent。对我来说,返回StatusCode(HttpStatusCode.NoContent)解决了这个问题,它比已接受的答案更清晰。 - Stanislav

25

我找到了这个显示如何添加自定义 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

    }
}

9
我尝试了@Intrepid的实现,遇到了一些问题。在这里我看到两个解决方案:
解决方案1: 部分:return Forbidden();应该无法工作。 编译器无法识别此内容。 而应该是:return new ForbiddenResult(Request, "my reason"); 更新1
解决方案2: 我认为@Interpid在他的实现中打算这样做,但他漏掉了一些东西。 为了使用return Forbidden();CommonApiController 应该更新包含返回自定义IHttpActionResult的函数,用于ForbiddenNoContent 该类应如下所示:
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的答案是正确的。那么我在这里缺少什么,以使他的实现起作用?

1
已更新答案。添加了另一个替代方案。我认为第二个方案才是@Interpid一开始想要的。 - Asaf Epelbaum
1
我认为你的想法是正确的。这应该是被接受的答案。 - valentin
1
请注意:您不应返回带有204无内容状态码的内容主体。我将从代码中删除“protected NoContentResult NoContent(string reason)”方法。有关更多信息,请参见https://dev59.com/mHE95IYBdhLWcg3wDpcG#23374724。 - valentin
@valentin 已经注意到了。我更新了问题。谢谢你的提醒。 - Asaf Epelbaum

8
您现在可以使用以下内容(.Net Standard):
return StatusCode(HttpStatusCode.NoContent);

或者(.Net Core 2.1+)
return NoContent();

3
如果你想在响应中包含一个原因短语,而不是添加一个子类到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

    }
}

2
这对我很有帮助:

最初的回答:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接