簡體   English   中英

如何使 ASP.NET Core 無效/任務操作方法返回 204 No Content

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

如何將void / Task操作方法的響應類型配置為204 No Content而不是200 OK

例如,考慮一個簡單的控制器:

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();
    }
}

我希望這兩種方法都返回204 No Content ,但默認值(以及/foo返回的內容)似乎是200 OK 我嘗試了各種方法,例如將[ProducesResponseType(204)]屬性添加到/foo ,但我沒有發現任何似乎有任何影響的東西。

這是一個解決方案,它為所有返回voidTask控制器方法返回 204 而不是 200 。 首先,創建一個結果過濾器:

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)
        {
        }
    }
}

然后全局注冊過濾器:

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

這將影響您的所有控制器方法。

Nish26 提供了一個可行的解決方案。 但是,如果您不想被多余的代碼阻塞控制器,那么另一種選擇是創建一個ResultFilter

public class ResponseCodeAttribute : Attribute, IResultFilter
{
    private readonly int _statusCode;
    public ResponseCode(int statusCode)
    {
        this._statusCode = statusCode;
    }

    public void OnResultExecuting(ResultExecutingContext context)
    {
    }
    public void OnResultExecuted(ResultExecutedContext context)
    {
        context.HttpContext.Response.StatusCode = _statusCode;
    }
}

然后將其與 action 方法一起使用:

[ResponseCode(204)]
[HttpPost("foo")]
public async Task Foo() {
    await Task.CompletedTask;
}

順便說一句, ProducesResponseType只是一個有助於創建 API 元數據的屬性。

首先,我認為這不是一個好主意。 控制器操作應該是可測試的,而無需創建整個管道。 您可以通過檢查返回結果來測試Bar()以確保它返回204 您不能使用通過過濾器修改返回結果的操作來做到這一點。

也就是說,可以通過使用Result Filters來修改結果,這些屬性實現了IResultFilterIAsyncResultFilter接口。 還有一個抽象ResultFilterAttribute類,它實現了兩個接口,為調用IResultFilter方法的 IAsyncResultFilter 提供了一個實現。

您可以創建一個修改狀態代碼的屬性,如下所示:

public class ResponseCodeAttribute : ResultFilterAttribute
{
    //Public property to enable reflection, inspection
    public int StatusCode {get;}

    public ResponseCodeAttribute(int statusCode)=>StatusCode=statusCode;

    public override void OnResultExecuted(ResultExecutedContext context)
    {
        context.HttpContext.Response.StatusCode = StatusCode;
    }
}

並將其用於:

[HttpPost,ResponseCode(204)]
public async Task Foo() {
    await Task.CompletedTask;
}

但這還不夠

此方法的調用者無法知道它將返回204而不是預期的200 這就是僅元數據屬性ProducesResponseTypeAttribute 的用武之地。該屬性實現了IApiResponseMetadataProvider ,該屬性用於向 API ExplorerSwagger 等代理/文檔工具提供元數據。 至少你應該使用這兩個屬性,例如:

[HttpPost,ResponseCode(204),ProducesResponseType(204)]
public async Task Foo() {
    await Task.CompletedTask;
}

更好的是,將ResponseCodeAttributeIApiResponseMetadataProvider結合起來:

public class ResponseCodeAttribute : ResultFilterAttribute,IApiResponseMetadataProvider
{
    public int StatusCode {get;}

    public Type Type { get; }=typeof(void);

    public ResponseCodeAttribute(int statusCode)=>StatusCode=statusCode;

    public override void OnResultExecuted(ResultExecutedContext context)
    {
        context.HttpContext.Response.StatusCode = StatusCode;
    }

    void IApiResponseMetadataProvider.SetContentTypes(MediaTypeCollection contentTypes)
    {            
    }
}

並用初始應用它:

[HttpPost,ResponseCode(204)]
public async Task Foo() {
    await Task.CompletedTask;
}

控制器基類具有HttpResponse類型的 Response 屬性。 您可以直接設置:

 Response.StatusCode = 204 ;

您可以從 outputformatters 中刪除 HttpNoContent 格式化程序。 博士小姐

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options =>
    {
        // requires using Microsoft.AspNetCore.Mvc.Formatters;
        options.OutputFormatters.RemoveType<StringOutputFormatter>();
        options.OutputFormatters.RemoveType<HttpNoContentOutputFormatter>();
    });
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM