ASP.NET Core 中的 Ok(null) 与 NoContent() - 哪个更有效?

Sup*_*Bob 4 c# optimization asp.net-core

两者最终都会产生一个空的 204 状态响应,但哪个更快?

显然,如果您遵循 DRY 准则,则编写起来会更简洁

return Ok(something);
Run Code Online (Sandbox Code Playgroud)

而不是

if (something == null)
{
    return NoContent()
}
else
{
    return Ok(something);
}
Run Code Online (Sandbox Code Playgroud)

检查源代码后,NoContent()转换为调用StatusCode(204),因为Ok(null)我没有深入了解他们在何处检查(如果有的话)为空值,如果它为空,决定返回一个 StatusCode 204(或处理它以其他方式)。

我个人认为这NoContent()会产生更快的性能,即使我们将讨论的差异在几分之一秒内。

Cod*_*ter 5

当您调用 时return NoContent(),它会返回StatusCodeResult NoContentResult.

当StatusCodeResult要执行 a 时,它所做的就是在响应上设置状态代码:

public override void ExecuteResult(ActionContext context)
{
    // snip boilerplate code

    context.HttpContext.Response.StatusCode = StatusCode;
}
Run Code Online (Sandbox Code Playgroud)

现在,当您调用时return Ok(something),实际返回的是OkObjectResult(something). 顾名思义,anOkObjectResult是一个ObjectResult。

并且有很多很多方法可以将对象结果写入输出,这就是 MVC 的内部机制发挥作用的地方。

当要执行响应时,在 的情况下ObjectResult,注册的IActionResultExecutor<ObjectResult>被解析并被ExecuteAsync()调用。

使用默认 MVC 注册时,这是ObjectResultExecutor. 它ExecuteAsync()卸载它的格式化程序选择(即使用哪个已注册的格式化程序将提供的 ObjectResult 实际写入到线路上)到OutputFormatterSelector它被注入到其构造函数中的恰当命名的名称。

当然,默认情况下,这是DefaultOutputFormatterSelector. 现在这个类从 中提取它的输出格式化程序MvcOptions.OutputFormatters,它在默认配置中包含:

  • HttpNoContentOutputFormatter
  • 字符串输出格式器
  • 流输出格式器
  • SystemTextJsonOutputFormatter

以该顺序。现在的实际选择(忽略内容协商代码,因为这里没有内容),在注册格式化选择迭代,并选择第一个回报true的CanWriteResult()。而如果HttpNoContentOutputFormatter设置为TreatNullValueAsNoContent,这是默认设置,并在Object以回报null,那么它只是返回。

然后运行更多代码,最后WriteAsync()在该格式化程序上调用,执行以下操作:

public Task WriteAsync(OutputFormatterWriteContext context)
{
    var response = context.HttpContext.Response;
    response.ContentLength = 0;

    if (response.StatusCode == StatusCodes.Status200OK)
    {
        response.StatusCode = StatusCodes.Status204NoContent;
    }

    return Task.CompletedTask;
}
Run Code Online (Sandbox Code Playgroud)

所以是的,运行了更多的代码。但是,这是否真的很明显,应该由您进行基准测试。

现在你是否真的想要 Ok(null)返回 204 而不是 200有待讨论;您可以在启动时使用此代码选择退出:

services.AddMvc(options => 
{
    var noContentFormatter = options.OutputFormatters.OfType<HttpNoContentOutputFormatter>().FirstOrDefault();
    if (noContentFormatter != null)
    {
        noContentFormatter.TreatNullValueAsNoContent = false;
    }
});
Run Code Online (Sandbox Code Playgroud)