Tipi restituiti dall'azione del controller nell'API Web ASP.NET CoreController action return types in ASP.NET Core web API

Di Scott AddieBy Scott Addie

Visualizzare o scaricare il codice di esempio (procedura per il download)View or download sample code (how to download)

ASP.NET Core offre le opzioni seguenti per i tipi restituiti dell'azione del controller API Web:ASP.NET Core offers the following options for web API controller action return types:

Questo documento spiega quando è più appropriato utilizzare ogni tipo restituito.This document explains when it's most appropriate to use each return type.

Tipo specificoSpecific type

L'azione più semplice restituisce un tipo di dati primitivo o complesso, ad esempio, string o un tipo di oggetto personalizzato.The simplest action returns a primitive or complex data type (for example, string or a custom object type). Si consideri l'azione seguente, che restituisce una raccolta di oggetti Product personalizzati:Consider the following action, which returns a collection of custom Product objects:

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

In assenza di condizioni note da cui proteggersi durante l'esecuzione dell'azione, la restituzione di un tipo specifico potrebbe essere sufficiente.Without known conditions to safeguard against during action execution, returning a specific type could suffice. L'azione precedente non accetta parametri, quindi non è necessario eseguire la convalida dei vincoli dei parametri.The preceding action accepts no parameters, so parameter constraints validation isn't needed.

Quando per un'azione devono essere prese in considerazione condizioni note, vengono introdotti più percorsi di ritorno.When known conditions need to be accounted for in an action, multiple return paths are introduced. In tal caso, è comune combinare un tipo di ActionResult restituito con il tipo restituito primitivo o complesso.In such a case, it's common to mix an ActionResult return type with the primitive or complex return type. Ai fini di questo tipo di azione, è necessario usare IActionResult oppure ActionResult<T >.Either IActionResult or ActionResult<T> are necessary to accommodate this type of action.

Return IEnumerable<T > o IAsyncEnumerable<T >Return IEnumerable<T> or IAsyncEnumerable<T>

In ASP.NET Core 2,2 e versioni precedenti, restituendo IEnumerable<T> da un'azione viene generata un'iterazione di raccolta sincrona da parte del serializzatore.In ASP.NET Core 2.2 and earlier, returning IEnumerable<T> from an action results in synchronous collection iteration by the serializer. Il risultato è il blocco delle chiamate e un potenziale per l'inedia del pool di thread.The result is the blocking of calls and a potential for thread pool starvation. Per illustrare, si supponga che Entity Framework (EF) Core venga usato per le esigenze di accesso ai dati dell'API Web.To illustrate, imagine that Entity Framework (EF) Core is being used for the web API's data access needs. Il tipo restituito dell'azione seguente viene enumerato in modo sincrono durante la serializzazione:The following action's return type is synchronously enumerated during serialization:

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

Per evitare l'enumerazione sincrona e le attese di blocco sul database in ASP.NET Core 2,2 e versioni precedenti, richiamare ToListAsync:To avoid synchronous enumeration and blocking waits on the database in ASP.NET Core 2.2 and earlier, invoke ToListAsync:

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

In ASP.NET Core 3,0 e versioni successive, restituendo IAsyncEnumerable<T> da un'azione:In ASP.NET Core 3.0 and later, returning IAsyncEnumerable<T> from an action:

  • Non produce più un'iterazione sincrona.No longer results in synchronous iteration.
  • Diventa efficiente come la restituzione di IEnumerable<T>.Becomes as efficient as returning IEnumerable<T>.

ASP.NET Core 3,0 e versioni successive memorizza nel buffer il risultato dell'azione seguente prima di fornirlo al serializzatore: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);

Provare a dichiarare il tipo restituito della firma dell'azione come IAsyncEnumerable<T> per garantire l'iterazione asincrona.Consider declaring the action signature's return type as IAsyncEnumerable<T> to guarantee the asynchronous iteration. In definitiva, la modalità di iterazione è basata sul tipo concreto sottostante restituito.Ultimately, the iteration mode is based on the underlying concrete type being returned. MVC esegue automaticamente il buffering di qualsiasi tipo concreto che implementi IAsyncEnumerable<T>.MVC automatically buffers any concrete type that implements IAsyncEnumerable<T>.

Si consideri l'azione seguente, che restituisce i record di prodotto con prezzo di vendita come 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;
        }
    }
}

Il IAsyncEnumerable<Product> equivalente dell'azione precedente è: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;
        }
    }
}

Entrambe le azioni precedenti sono non bloccanti a partire da ASP.NET Core 3,0.Both of the preceding actions are non-blocking as of ASP.NET Core 3.0.

Tipo IActionResultIActionResult type

Il tipo restituito IActionResult è appropriato quando più tipi restituiti ActionResult sono possibili in un'azione.The IActionResult return type is appropriate when multiple ActionResult return types are possible in an action. I tipi ActionResult rappresentano vari codici di stato HTTP.The ActionResult types represent various HTTP status codes. Qualsiasi classe non astratta che deriva da ActionResult è qualificata come tipo restituito valido.Any non-abstract class deriving from ActionResult qualifies as a valid return type. Alcuni tipi restituiti comuni in questa categoria sono BadRequestResult (400), NotFoundResult (404) e OkObjectResult (200).Some common return types in this category are BadRequestResult (400), NotFoundResult (404), and OkObjectResult (200). In alternativa, è possibile usare metodi pratici nella classe ControllerBase per restituire ActionResult tipi da un'azione.Alternatively, convenience methods in the ControllerBase class can be used to return ActionResult types from an action. Ad esempio, return BadRequest(); è una forma abbreviata di return new BadRequestResult();.For example, return BadRequest(); is a shorthand form of return new BadRequestResult();.

Poiché in questo tipo di azione sono presenti più tipi e percorsi restituiti, è necessario usare il liberal [ProducesResponseType] attributo.Because there are multiple return types and paths in this type of action, liberal use of the [ProducesResponseType] attribute is necessary. Questo attributo produce dettagli di risposta più descrittivi per le pagine della Guida dell'API Web generate da strumenti come spavalderia.This attribute produces more descriptive response details for web API help pages generated by tools like Swagger. [ProducesResponseType] indica i tipi noti e i codici di stato HTTP che l'azione deve restituire.[ProducesResponseType] indicates the known types and HTTP status codes to be returned by the action.

Azione sincronaSynchronous action

Si consideri la seguente azione sincrona che prevede due possibili tipi restituiti: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);
}

Nell'azione precedente:In the preceding action:

  • Viene restituito un codice di stato 404 quando il prodotto rappresentato da id non esiste nell'archivio dati sottostante.A 404 status code is returned when the product represented by id doesn't exist in the underlying data store. Il metodo NotFound praticità viene richiamato come abbreviazione per return new NotFoundResult();.The NotFound convenience method is invoked as shorthand for return new NotFoundResult();.
  • Quando il prodotto esiste, viene restituito un codice di stato 200 con l'oggetto Product.A 200 status code is returned with the Product object when the product does exist. Il metodo Ok praticità viene richiamato come abbreviazione per return new OkObjectResult(product);.The Ok convenience method is invoked as shorthand for return new OkObjectResult(product);.

Azione asincronaAsynchronous action

Si consideri la seguente azione asincrona che prevede due possibili tipi restituiti: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);
}

Nell'azione precedente:In the preceding action:

  • Quando la descrizione del prodotto contiene "XYZ widget", viene restituito un codice di stato 400.A 400 status code is returned when the product description contains "XYZ Widget". Il metodo BadRequest praticità viene richiamato come abbreviazione per return new BadRequestResult();.The BadRequest convenience method is invoked as shorthand for return new BadRequestResult();.
  • Un codice di stato 201 viene generato dal metodo CreatedAtAction praticità quando viene creato un prodotto.A 201 status code is generated by the CreatedAtAction convenience method when a product is created. Un'alternativa alla chiamata di CreatedAtAction è 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);. In questo percorso di codice, l'oggetto Product viene fornito nel corpo della risposta.In this code path, the Product object is provided in the response body. Viene fornita una Location intestazione della risposta contenente l'URL del prodotto appena creato.A Location response header containing the newly created product's URL is provided.

Ad esempio, il modello seguente indica che le richieste devono includere le proprietà Name e Description.For example, the following model indicates that requests must include the Name and Description properties. L'impossibilità di fornire Name e Description nella richiesta causa l'esito negativo della convalida del modello.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; }
}

Se viene applicato l'attributo [ApiController] in ASP.NET Core 2,1 o versioni successive, gli errori di convalida del modello generano un codice di stato 400.If the [ApiController] attribute in ASP.NET Core 2.1 or later is applied, model validation errors result in a 400 status code. Per altre informazioni, vedere Risposte HTTP 400 automatiche.For more information, see Automatic HTTP 400 responses.

Tipo ActionResult<T>ActionResult<T> type

ASP.NET Core 2,1 ha introdotto il tipo restituito > ActionResult<t per le azioni del controller API Web.ASP.NET Core 2.1 introduced the ActionResult<T> return type for web API controller actions. Consente di restituire un tipo derivante da ActionResult o restituire un tipo specifico.It enables you to return a type deriving from ActionResult or return a specific type. ActionResult<T> offre i vantaggi seguenti rispetto al tipo IActionResult:ActionResult<T> offers the following benefits over the IActionResult type:

  • È possibile escludere la proprietà Type dell'attributo [ProducesResponseType] .The [ProducesResponseType] attribute's Type property can be excluded. Ad esempio, [ProducesResponseType(200, Type = typeof(Product))] viene semplificato in [ProducesResponseType(200)].For example, [ProducesResponseType(200, Type = typeof(Product))] is simplified to [ProducesResponseType(200)]. Il tipo restituito previsto dell'azione viene invece dedotto da T in ActionResult<T>.The action's expected return type is instead inferred from the T in ActionResult<T>.
  • Operatori di cast impliciti supportano la conversione di T e ActionResult in ActionResult<T>.Implicit cast operators support the conversion of both T and ActionResult to ActionResult<T>. T converte in ObjectResult, il che significa che return new ObjectResult(T); è stato semplificato per return T;.T converts to ObjectResult, which means return new ObjectResult(T); is simplified to return T;.

C# non supporta operatori di cast impliciti sulle interfacce.C# doesn't support implicit cast operators on interfaces. Di conseguenza, per la conversione dell'interfaccia in un tipo concreto è necessario usare ActionResult<T>.Consequently, conversion of the interface to a concrete type is necessary to use ActionResult<T>. Ad esempio, usare IEnumerable nell'esempio seguente non funziona:For example, use of IEnumerable in the following example doesn't work:

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

Una delle opzioni disponibili per correggere il codice precedente consiste nel restituire _repository.GetProducts().ToList();.One option to fix the preceding code is to return _repository.GetProducts().ToList();.

La maggior parte delle azioni presenta un tipo restituito specifico.Most actions have a specific return type. Durante l'esecuzione di un'azione possono verificarsi condizioni impreviste, nel qual caso il tipo specifico non viene restituito.Unexpected conditions can occur during action execution, in which case the specific type isn't returned. Ad esempio, il parametro di input di un'azione potrebbe non superare la convalida del modello.For example, an action's input parameter may fail model validation. In tal caso, è consueto che venga restituito il tipo ActionResult appropriato anziché il tipo specifico.In such a case, it's common to return the appropriate ActionResult type instead of the specific type.

Azione sincronaSynchronous action

Si consideri un'azione sincrona che prevede due possibili tipi restituiti: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;
}

Nell'azione precedente:In the preceding action:

  • Quando il prodotto non esiste nel database, viene restituito un codice di stato 404.A 404 status code is returned when the product doesn't exist in the database.
  • Quando il prodotto esiste, viene restituito un codice di stato 200 con l'oggetto Product corrispondente.A 200 status code is returned with the corresponding Product object when the product does exist. Prima di ASP.NET Core 2,1, era necessario return Ok(product);la riga di return product;.Before ASP.NET Core 2.1, the return product; line had to be return Ok(product);.

Azione asincronaAsynchronous action

Si consideri un'azione asincrona che prevede due possibili tipi restituiti: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);
}

Nell'azione precedente:In the preceding action:

  • Un codice di stato 400 (BadRequest) viene restituito dal runtime di ASP.NET Core quando:A 400 status code (BadRequest) is returned by the ASP.NET Core runtime when:
    • L'attributo [ApiController] è stato applicato e la convalida del modello ha esito negativo.The [ApiController] attribute has been applied and model validation fails.
    • La descrizione del prodotto contiene "XYZ Widget".The product description contains "XYZ Widget".
  • Un codice di stato 201 viene generato dal metodo CreatedAtAction quando viene creato un prodotto.A 201 status code is generated by the CreatedAtAction method when a product is created. In questo percorso di codice, l'oggetto Product viene fornito nel corpo della risposta.In this code path, the Product object is provided in the response body. Viene fornita una Location intestazione della risposta contenente l'URL del prodotto appena creato.A Location response header containing the newly created product's URL is provided.

Risorse aggiuntiveAdditional resources