[英]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
,但我沒有發現任何似乎有任何影響的東西。
這是一個解決方案,它為所有返回void
或Task
控制器方法返回 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來修改結果,這些屬性實現了IResultFilter
和IAsyncResultFilter
接口。 還有一個抽象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 Explorer和Swagger 等代理/文檔工具提供元數據。 至少你應該使用這兩個屬性,例如:
[HttpPost,ResponseCode(204),ProducesResponseType(204)]
public async Task Foo() {
await Task.CompletedTask;
}
更好的是,將ResponseCodeAttribute
與IApiResponseMetadataProvider
結合起來:
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.