ASP.NET API de Base des contrôleurs renvoient généralement des types explicites (et de le faire par défaut si vous créez un nouveau projet), quelque chose comme:
[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...
}
Le problème est qu' return null;
- , elle retourne un HTTP 204
: le succès, l'absence de contenu.
C'est alors considérée par un grand nombre de composants Javascript côté client que du succès, il y a un code comme:
const response = await fetch('.../api/things/5', {method: 'GET' ...});
if(response.ok)
return await response.json(); // Error, no content!
Une recherche en ligne (comme cette question et cette réponse) points utiles return NotFound();
des méthodes d'extension pour le contrôleur, mais tous ces retour IActionResult
, ce qui n'est pas compatible avec mon Task<Thing>
type de retour. Que modèle de conception ressemble à ceci:
// 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);
}
Cela fonctionne, mais pour utiliser le type de retour d' GetAsync
doit être changée en Task<IActionResult>
- le typage explicite est perdu, et tous les types de retour sur le contrôleur avoir à changer (c'est à dire de ne pas utiliser explicitement saisie) ou il y aura un mélange où certaines actions de traiter avec des types explicites tandis que d'autres. En plus des tests unitaires maintenant besoin de faire des hypothèses sur la sérialisation et explicitement deserialise le contenu de l' IActionResult
où avant ils avaient un type concret.
Il y a des tas de façons de contourner cela, mais il semble être une source de confusion méli-mélo qui pourrait facilement être conçus, donc la vraie question est: quelle est la bonne manière prévue par la ASP.NET de Base des designers?
Il semble que les options possibles sont:
- Ont une drôle de (salissant pour tester) le mélange de types explicites et
IActionResult
selon le type attendu. - Oubliez les types explicites, ils ne sont pas vraiment pris en charge par Core, MVC, toujours utiliser
IActionResult
(dans ce cas, pourquoi sont-ils présents à tous?) - Écrire une implémentation de l'
HttpResponseException
et l'utiliser commeArgumentOutOfRangeException
(voir cette réponse pour une mise en œuvre). Toutefois, cela ne requièrent l'utilisation d'exceptions pour les flux de programme, qui est généralement une mauvaise idée et également désapprouvées par la MVC du Noyau de l'équipe. - Écrire une implémentation de l'
HttpNoContentOutputFormatter
qui renvoie404
pour les requêtes GET. - Autre chose qui me manque dans la façon dont Core, MVC est censé fonctionner?
- Ou pourquoi est -
204
est correcte et404
mauvais pour l'échec d'une requête GET?
Toutes ces activités impliquent des compromis et refactoring de perdre quelque chose ou ajouter ce qui semble être la complexité inutile, en contradiction avec la conception de la MVC de Base. Les compromis qui est le bon et pourquoi?