Reputation: 2831
Is there a way I can use the new IHttpActionResult
interface to return a HttpStatusCode.NoContent
response message?
I am currently using return new HttpResponseMessage( HttpStatusCode.NoContent );
and would like to convert this into return NoContent();
.
IHttpActionResult
has already got Ok()
, Conflict()
and NotFound()
but I cannot find any for Forbidden()
and NoContent()
which I need to use in my project.
How easy is it to add other result types?
Upvotes: 43
Views: 32954
Reputation: 423
This worked well for me:
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);
}
}
Used as:
return CodeAndReason.NotFound("Record {blah} not found");
Upvotes: 3
Reputation: 81
You can now use the following (.Net Standard):
return StatusCode(HttpStatusCode.NoContent);
or (.Net Core 2.1+)
return NoContent();
Upvotes: 8
Reputation: 586
I tried the @Intrepid implementation and I ran into some problems. I see two solutions here:
Solution 1:
The part: return Forbidden();
should not work.
The compiler would not recognize this.
Instead it should be: return new ForbiddenResult(Request, "my reason");
UPDATE 1
Solution 2:
I think this is what @Interpid intended in his implementation, but he was missing a few things.
In order to use return Forbidden();
the CommonApiController
should be updated with the functions that return the custom IHttpActionResult
for Forbidden
and NoContent
The class should look like this:
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);
}
}
}
Anyway, if I am wrong and @Interpid's answer is correct. What am I missing here to make his implementation work?
Upvotes: 9
Reputation: 1790
There's no convenience method for no-content
result because, by default, when a action returns void
, the response will have the HTTP status 204.
If you wish to explicitly indicate that on the action, you could also return a StatusCode(HttpStatusCode.NoContent)
from your action or a
ResponseMessage(new HttpResponseMessage(HttpStatusCode.NoContent)).
The Unauthorized() convenience method gives you a 401 status so, for Forbidden (403), you would also have to use StatusCode(HttpStatusCode.Forbidden)
or
ResponseMessage(new HttpResponseMessage(HttpStatusCode.Forbidden))
Upvotes: 57
Reputation: 307
If you want to include a reason phrase with your response without adding a sub-class to ApiController, build a ResponseMessage object and return it from the action by the ResponseMessage() method. Try this:
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
}
}
Upvotes: 3
Reputation: 2831
I found this example site that shows how to add a custom IHttpActionResult
method and I've used this to create the Forbidden()
and NoContent()
methods with great success.
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);
}
}
}
And then I can use it like this:
public class InvoiceController : CommonApiController
{
public async Task<IHttpActionResult> Post([FromBody]Invoice invoice)
{
if(User.IsInRole("Readonly"))
{
return Forbidden();
}
// Rest of code
}
}
Upvotes: 25