Types de retour de l’action du contrôleur dans ASP.NET Core API WebController action return types in ASP.NET Core web API

Par Scott AddieBy Scott Addie

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)View or download sample code (how to download)

ASP.NET Core offre les options suivantes pour les types de retours d’action du contrôleur d’API Web :ASP.NET Core offers the following options for web API controller action return types:

Ce document décrit quel type de retour est le plus adapté en fonction de chaque cas.This document explains when it's most appropriate to use each return type.

Type spécifiqueSpecific type

L’action la plus simple retourne un type de données primitif ou complexe (par exemple, string ou un type d’objet personnalisé).The simplest action returns a primitive or complex data type (for example, string or a custom object type). Considérez l’action suivante, qui retourne une collection d’objets Product personnalisés :Consider the following action, which returns a collection of custom Product objects:

[HttpGet]
public List<Product> Get() =>
    _repository.GetProducts();

Sans conditions connues contre lesquelles une protection est nécessaire pendant l’exécution de l’action, le retour d’un type spécifique peut suffire.Without known conditions to safeguard against during action execution, returning a specific type could suffice. L’action précédente n’acceptant aucun paramètre, la validation des contraintes de paramètre n’est pas nécessaire.The preceding action accepts no parameters, so parameter constraints validation isn't needed.

Quand des conditions connues doivent être prises en compte dans une action, plusieurs chemins de retour sont introduits.When known conditions need to be accounted for in an action, multiple return paths are introduced. Dans ce cas, il est courant de mélanger un type de retour ActionResult avec le type de retour primitif ou complexe.In such a case, it's common to mix an ActionResult return type with the primitive or complex return type. IActionResult ou ActionResult<T> sont nécessaires pour prendre en charge ce type d’action.Either IActionResult or ActionResult<T> are necessary to accommodate this type of action.

Retourne IEnumerable<T > ou IAsyncEnumerable<T >Return IEnumerable<T> or IAsyncEnumerable<T>

Dans ASP.NET Core 2,2 et versions antérieures, le retour de IEnumerable<T> à partir d’une action entraîne une itération de collection synchrone par le sérialiseur.In ASP.NET Core 2.2 and earlier, returning IEnumerable<T> from an action results in synchronous collection iteration by the serializer. Le résultat est le blocage des appels et un potentiel pour la privation du pool de threads.The result is the blocking of calls and a potential for thread pool starvation. À titre d’illustration, imaginez que Entity Framework (EF) Core est utilisé pour les besoins d’accès aux données de l’API Web.To illustrate, imagine that Entity Framework (EF) Core is being used for the web API's data access needs. Le type de retour de l’action suivante est énuméré de manière synchrone lors de la sérialisation :The following action's return type is synchronously enumerated during serialization:

public IEnumerable<Product> GetOnSaleProducts() =>
    _context.Products.Where(p => p.IsOnSale);

Pour éviter l’énumération synchrone et bloquer les attentes sur la base de données dans ASP.NET Core 2,2 et versions antérieures, appelez ToListAsync:To avoid synchronous enumeration and blocking waits on the database in ASP.NET Core 2.2 and earlier, invoke ToListAsync:

public async Task<IEnumerable<Product>> GetOnSaleProducts() =>
    await _context.Products.Where(p => p.IsOnSale).ToListAsync();

Dans ASP.NET Core 3,0 et versions ultérieures, le retour de IAsyncEnumerable<T> à partir d’une action :In ASP.NET Core 3.0 and later, returning IAsyncEnumerable<T> from an action:

  • N’entraîne plus d’itération synchrone.No longer results in synchronous iteration.
  • Devient aussi efficace que le retour de IEnumerable<T>.Becomes as efficient as returning IEnumerable<T>.

ASP.NET Core 3,0 et ultérieur met en mémoire tampon le résultat de l’action suivante avant de la fournir au sérialiseur :ASP.NET Core 3.0 and later buffers the result of the following action before providing it to the serializer:

public IEnumerable<Product> GetOnSaleProducts() =>
    _context.Products.Where(p => p.IsOnSale);

Envisagez de déclarer le type de retour de la signature d’action comme IAsyncEnumerable<T> pour garantir l’itération asynchrone.Consider declaring the action signature's return type as IAsyncEnumerable<T> to guarantee the asynchronous iteration. En fin de compte, le mode d’itération est basé sur le type concret sous-jacent qui est retourné.Ultimately, the iteration mode is based on the underlying concrete type being returned. MVC met automatiquement en mémoire tampon tout type concret qui implémente IAsyncEnumerable<T>.MVC automatically buffers any concrete type that implements IAsyncEnumerable<T>.

Examinez l’action suivante, qui retourne les enregistrements de produit facturés à la vente en tant que IEnumerable<Product>:Consider the following action, which returns sale-priced product records as IEnumerable<Product>:

[HttpGet("syncsale")]
public IEnumerable<Product> GetOnSaleProducts()
{
    var products = _repository.GetProducts();

    foreach (var product in products)
    {
        if (product.IsOnSale)
        {
            yield return product;
        }
    }
}

L’équivalent IAsyncEnumerable<Product> de l’action précédente est le suivant :The IAsyncEnumerable<Product> equivalent of the preceding action is:

[HttpGet("asyncsale")]
public async IAsyncEnumerable<Product> GetOnSaleProductsAsync()
{
    var products = _repository.GetProductsAsync();

    await foreach (var product in products)
    {
        if (product.IsOnSale)
        {
            yield return product;
        }
    }
}

Les deux actions précédentes sont non bloquantes à partir de ASP.NET Core 3,0.Both of the preceding actions are non-blocking as of ASP.NET Core 3.0.

Type IActionResultIActionResult type

Le type de retour IActionResult est approprié lorsque plusieurs types de retour ActionResult sont possibles dans une action.The IActionResult return type is appropriate when multiple ActionResult return types are possible in an action. Les types ActionResult représentent différents codes d’état HTTP.The ActionResult types represent various HTTP status codes. Toute classe non abstraite dérivant de ActionResult est qualifiée de type de retour valide.Any non-abstract class deriving from ActionResult qualifies as a valid return type. Voici quelques types de retour courants dans cette catégorie : BadRequestResult (400), NotFoundResult (404) et OkObjectResult (200).Some common return types in this category are BadRequestResult (400), NotFoundResult (404), and OkObjectResult (200). Les méthodes pratiques de la classe ControllerBase peuvent également être utilisées pour retourner des ActionResult types à partir d’une action.Alternatively, convenience methods in the ControllerBase class can be used to return ActionResult types from an action. Par exemple, return BadRequest(); est une forme abrégée de return new BadRequestResult();.For example, return BadRequest(); is a shorthand form of return new BadRequestResult();.

Comme il existe plusieurs types de retour et chemins d’accès dans ce type d’action, l’utilisation libérale de l’attribut [ProducesResponseType] est nécessaire.Because there are multiple return types and paths in this type of action, liberal use of the [ProducesResponseType] attribute is necessary. Cet attribut produit des détails de réponse plus descriptifs pour les pages d’aide de l’API Web générées par des outils tels que Swagger.This attribute produces more descriptive response details for web API help pages generated by tools like Swagger. [ProducesResponseType] indique les types connus et les codes d’état HTTP que l’action doit retourner.[ProducesResponseType] indicates the known types and HTTP status codes to be returned by the action.

Action synchroneSynchronous action

Considérez l’action synchrone suivante pour laquelle il existe deux types de retour possibles :Consider the following synchronous action in which there are two possible return types:

[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public IActionResult GetById(int id)
{
    if (!_repository.TryGetProduct(id, out var product))
    {
        return NotFound();
    }

    return Ok(product);
}
[HttpGet("{id}")]
[ProducesResponseType(typeof(Product), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public IActionResult GetById(int id)
{
    if (!_repository.TryGetProduct(id, out var product))
    {
        return NotFound();
    }

    return Ok(product);
}

Dans l’action précédente :In the preceding action:

  • Un code d’État 404 est retourné lorsque le produit représenté par id n’existe pas dans le magasin de données sous-jacent.A 404 status code is returned when the product represented by id doesn't exist in the underlying data store. La méthode de commodité NotFound est appelée comme raccourci pour return new NotFoundResult();.The NotFound convenience method is invoked as shorthand for return new NotFoundResult();.
  • Un code d’état 200 est retourné avec l’objet Product lorsque le produit existe.A 200 status code is returned with the Product object when the product does exist. La méthode de commodité Ok est appelée comme raccourci pour return new OkObjectResult(product);.The Ok convenience method is invoked as shorthand for return new OkObjectResult(product);.

Action asynchroneAsynchronous action

Considérez l’action asynchrone suivante pour laquelle il existe deux types de retour possibles :Consider the following asynchronous action in which there are two possible return types:

[HttpPost]
[Consumes(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> CreateAsync(Product product)
{
    if (product.Description.Contains("XYZ Widget"))
    {
        return BadRequest();
    }

    await _repository.AddProductAsync(product);

    return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}
[HttpPost]
[Consumes("application/json")]
[ProducesResponseType(typeof(Product), StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> CreateAsync([FromBody] Product product)
{
    if (product.Description.Contains("XYZ Widget"))
    {
        return BadRequest();
    }

    await _repository.AddProductAsync(product);

    return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}

Dans l’action précédente :In the preceding action:

  • Un code d’état 400 est retourné lorsque la description du produit contient « widget XYZ ».A 400 status code is returned when the product description contains "XYZ Widget". La méthode de commodité BadRequest est appelée comme raccourci pour return new BadRequestResult();.The BadRequest convenience method is invoked as shorthand for return new BadRequestResult();.
  • Un code d’État 201 est généré par la méthode de commodité CreatedAtAction lors de la création d’un produit.A 201 status code is generated by the CreatedAtAction convenience method when a product is created. Une alternative à l’appel de CreatedAtAction est return new CreatedAtActionResult(nameof(GetById), "Products", new { id = product.Id }, product);.An alternative to calling CreatedAtAction is return new CreatedAtActionResult(nameof(GetById), "Products", new { id = product.Id }, product);. Dans ce chemin d’accès de code, l’objet Product est fourni dans le corps de la réponse.In this code path, the Product object is provided in the response body. Un en-tête de réponse Location contenant l’URL du produit nouvellement créé est fourni.A Location response header containing the newly created product's URL is provided.

Par exemple, le modèle suivant indique que les requêtes doivent inclure les propriétés Name et Description.For example, the following model indicates that requests must include the Name and Description properties. L’impossibilité de fournir des Name et des Description dans la demande entraîne l’échec de la validation du modèle.Failure to provide Name and Description in the request causes model validation to fail.

public class Product
{
    public int Id { get; set; }

    [Required]
    public string Name { get; set; }

    [Required]
    public string Description { get; set; }
}

Si l’attribut [ApiController] dans ASP.net Core 2,1 ou une version ultérieure est appliqué, les erreurs de validation de modèle génèrent un code d’état 400.If the [ApiController] attribute in ASP.NET Core 2.1 or later is applied, model validation errors result in a 400 status code. Pour plus d’informations, consultez Réponses HTTP 400 automatiques.For more information, see Automatic HTTP 400 responses.

Type ActionResult<T>ActionResult<T> type

ASP.NET Core 2,1 a introduit le type de retour ActionResult<t > pour les actions du contrôleur d’API Web.ASP.NET Core 2.1 introduced the ActionResult<T> return type for web API controller actions. Elle vous permet de retourner un type dérivant de ActionResult ou de retourner un type spécifique.It enables you to return a type deriving from ActionResult or return a specific type. ActionResult<T> offre les avantages suivants par rapport au type IActionResult :ActionResult<T> offers the following benefits over the IActionResult type:

  • La propriété Type de l’attribut [ProducesResponseType] peut être exclue.The [ProducesResponseType] attribute's Type property can be excluded. Par exemple, [ProducesResponseType(200, Type = typeof(Product))] est simplifié en [ProducesResponseType(200)].For example, [ProducesResponseType(200, Type = typeof(Product))] is simplified to [ProducesResponseType(200)]. Le type de retour attendu pour l’action est déduit de T dans ActionResult<T>.The action's expected return type is instead inferred from the T in ActionResult<T>.
  • Des opérateurs de cast implicite prennent en charge la conversion de T et ActionResult en ActionResult<T>.Implicit cast operators support the conversion of both T and ActionResult to ActionResult<T>. T convertit en ObjectResult, ce qui signifie que return new ObjectResult(T); est simplifié pour return T;.T converts to ObjectResult, which means return new ObjectResult(T); is simplified to return T;.

C# ne prend pas en charge les opérateurs de cast implicite sur les interfaces.C# doesn't support implicit cast operators on interfaces. Par conséquent, ActionResult<T> nécessite une conversion de l’interface en un type concret.Consequently, conversion of the interface to a concrete type is necessary to use ActionResult<T>. Par exemple, l’utilisation de IEnumerable dans l’exemple suivant ne fonctionne pas :For example, use of IEnumerable in the following example doesn't work:

[HttpGet]
public ActionResult<IEnumerable<Product>> Get() =>
    _repository.GetProducts();

Pour corriger le code précédent, vous pouvez retourner _repository.GetProducts().ToList();.One option to fix the preceding code is to return _repository.GetProducts().ToList();.

La plupart des actions ont un type de retour spécifique.Most actions have a specific return type. Des conditions inattendues peuvent se produire pendant l’exécution d’une action, auquel cas le type spécifique n’est pas retourné.Unexpected conditions can occur during action execution, in which case the specific type isn't returned. Par exemple, le paramètre d’entrée d’une action peut entraîner l’échec de la validation du modèle.For example, an action's input parameter may fail model validation. Dans ce cas, il est courant de retourner le type ActionResult approprié à la place du type spécifique.In such a case, it's common to return the appropriate ActionResult type instead of the specific type.

Action synchroneSynchronous action

Considérez une action synchrone pour laquelle il existe deux types de retour possibles :Consider a synchronous action in which there are two possible return types:

[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<Product> GetById(int id)
{
    if (!_repository.TryGetProduct(id, out var product))
    {
        return NotFound();
    }

    return product;
}

Dans l’action précédente :In the preceding action:

  • Un code d’État 404 est retourné lorsque le produit n’existe pas dans la base de données.A 404 status code is returned when the product doesn't exist in the database.
  • Un code d’état 200 est retourné avec l’objet Product correspondant lorsque le produit existe.A 200 status code is returned with the corresponding Product object when the product does exist. Avant le ASP.NET Core 2,1, la ligne de return product; devait être return Ok(product);.Before ASP.NET Core 2.1, the return product; line had to be return Ok(product);.

Action asynchroneAsynchronous action

Considérez une action asynchrone pour laquelle il existe deux types de retour possibles :Consider an asynchronous action in which there are two possible return types:

[HttpPost]
[Consumes(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<Product>> CreateAsync(Product product)
{
    if (product.Description.Contains("XYZ Widget"))
    {
        return BadRequest();
    }

    await _repository.AddProductAsync(product);

    return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}

Dans l’action précédente :In the preceding action:

  • Un code d’état 400 (BadRequest) est retourné par le runtime ASP.NET Core dans les cas suivants :A 400 status code (BadRequest) is returned by the ASP.NET Core runtime when:
    • L’attribut [ApiController] a été appliqué et la validation du modèle échoue.The [ApiController] attribute has been applied and model validation fails.
    • La description de produit contient « XYZ Widget ».The product description contains "XYZ Widget".
  • Un code d’État 201 est généré par la méthode CreatedAtAction lors de la création d’un produit.A 201 status code is generated by the CreatedAtAction method when a product is created. Dans ce chemin d’accès de code, l’objet Product est fourni dans le corps de la réponse.In this code path, the Product object is provided in the response body. Un en-tête de réponse Location contenant l’URL du produit nouvellement créé est fourni.A Location response header containing the newly created product's URL is provided.

Ressources supplémentairesAdditional resources