Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make an ASP.NET Core void/Task action method return 204 No Content

How do I configure the response type of a void/Task action method to be 204 No Content rather than 200 OK?

For example, consider a simple controller:

public class MyController : Controller
{
    [HttpPost("foo")]
    public async Task Foo() {
        await Task.CompletedTask;
    }

    [HttpPost("bar")]
    public async Task<IActionResult> Bar() {
        await Task.CompletedTask;
        return NoContent();
    }
}

I'd like both methods to return 204 No Content, but the default (and thus what /foo returns) seems to be 200 OK. I tried various things, such as adding a [ProducesResponseType(204)] attribute to /foo, but I haven't found anything that seems to have any effect.

like image 905
Tomas Aschan Avatar asked May 14 '18 08:05

Tomas Aschan


People also ask

What does IActionResult return?

The IActionResult return type is appropriate when multiple ActionResult return types are possible in an action. The ActionResult types represent various HTTP status codes. Any non-abstract class deriving from ActionResult qualifies as a valid return type.

What is the Web API action method can have the following return types?

A Web API controller action can return any of the following: void. HttpResponseMessage. IHttpActionResult.


1 Answers

Here is a solution that returns 204 instead of 200 for all controller methods that return void or Task. First, create a result filter:

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using static Microsoft.AspNetCore.Http.StatusCodes;

namespace StackOverflow.SampleCode
{
    /// <summary>
    /// A filter that transforms http status code 200 OK to 204 No Content for controller actions that return nothing,
    /// i.e. <see cref="System.Void"/> or <see cref="Task"/>.
    /// </summary>
    internal class VoidAndTaskTo204NoContentFilter : IResultFilter
    {
        /// <inheritdoc/>
        public void OnResultExecuting(ResultExecutingContext context)
        {
            if (context.ActionDescriptor is ControllerActionDescriptor actionDescriptor)
            {
                var returnType = actionDescriptor.MethodInfo.ReturnType;
                if (returnType == typeof(void) || returnType == typeof(Task))
                {
                    context.HttpContext.Response.StatusCode = Status204NoContent;
                }
            }
        }

        /// <inheritdoc/>
        public void OnResultExecuted(ResultExecutedContext context)
        {
        }
    }
}

Then register the filter globally:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options => options.Filters.Add<VoidAndTaskTo204NoContentFilter>());
}

This will affect all your controller methods.

like image 91
0xced Avatar answered Oct 19 '22 08:10

0xced