ASP.NET Core API控制器通常返回明确的类型(如果您创建新项目,则默认情况下会这样做),类似于:
ASP.NET Core API控制器一般会返回明确的类型(如果你创建一个新项目,默认情况下就是这种方式),例如:
[Route("api/[controller]")]
public class ThingsController : Controller
{
// GET api/things
[HttpGet]
public async Task<IEnumerable<Thing>> GetAsync()
{
//...
}
// GET api/things/5
[HttpGet("{id}")]
public async Task<Thing> GetAsync(int id)
{
Thing thingFromDB = await GetThingFromDBAsync();
if(thingFromDB == null)
return null; // This returns HTTP 204
// Process thingFromDB, blah blah blah
return thing;
}
// POST api/things
[HttpPost]
public void Post([FromBody]Thing thing)
{
//..
}
//... and so on...
}
问题在于return null;
- 它返回一个HTTP 204
:成功但没有内容。
这被许多客户端JavaScript组件视为成功,因此有以下代码:
const response = await fetch('.../api/things/5', {method: 'GET' ...});
if(response.ok)
return await response.json(); // Error, no content!
在线搜索(例如这个问题和这个答案)指向了控制器的有用的return NotFound();
扩展方法,但所有这些方法都返回不与我的Task<Thing>
返回类型兼容的IActionResult
。该设计模式如下:// GET api/things/5
[HttpGet("{id}")]
public async Task<IActionResult> GetAsync(int id)
{
var thingFromDB = await GetThingFromDBAsync();
if (thingFromDB == null)
return NotFound();
// Process thingFromDB, blah blah blah
return Ok(thing);
}
那行得通,但要使用它,GetAsync
的返回类型必须更改为 Task<IActionResult>
——明确的类型丢失了,要么控制器上的所有返回类型都必须更改(即根本不使用明确的类型),要么将会有一些操作处理明确的类型,而其他操作处理 IActionResult
类型。此外,单元测试现在需要假设序列化并明确反序列化 IActionResult
的内容,在这之前,它们具有具体的类型。有很多方法可以解决这个问题,但这似乎是一种混杂的困惑,很容易被设计出来,因此真正的问题是:ASP.NET Core 设计人员预期的正确方式是什么? 看起来可能的选项有:
1.根据预期的类型,具有明确的类型和
IActionResult
混合在一起(混乱且难以测试);
2.忘记明确的类型,它们并没有得到 Core MVC 的真正支持,总是使用 IActionResult
(那么它们究竟存在的意义是什么?);
3.编写 HttpResponseException
的实现,并像使用 ArgumentOutOfRangeException
那样使用它(参见此答案中的实现)。然而,这要求使用异常进行程序流程控制,这通常是一个坏主意,并且还被 MVC Core 团队弃用。
4.编写返回 404
的 HttpNoContentOutputFormatter
的实现,用于 GET 请求失败。
5.还有其他我在 Core MVC 中应该了解的东西吗?
6.或者,为什么对于未成功的 GET 请求,204
是正确的,而 404
是错误的?所有这些都涉及到牺牲和重构,它们失去了一些东西或增加了似乎与 MVC Core 设计不符的不必要的复杂性。哪种妥协才是正确的,为什么呢?
StatusCode(500)
只适用于返回IActionResult
的操作,然后我详细介绍了一些内容。 - KeithIActionResult
。我在询问具有 显式类型 的操作。我在第一个要点中询问了IActionResult
的使用,但我并不是在问如何调用StatusCode(404)
- 我已经知道并在问题中引用了它。 - Keithreturn new HttpResponseMessage(HttpStatusCode.NotFound);
的东西...此外,根据 https://learn.microsoft.com/en-us/aspnet/core/mvc/models/formatting,对于具有多个返回类型或选项的非平凡操作(例如,基于执行操作结果的不同HTTP状态代码),请优先选择IActionResult作为返回类型。 - Hackerman