Tipos de retorno de ação do controlador em ASP.NET Core API WebController action return types in ASP.NET Core web API

Por Scott AddieBy Scott Addie

Exibir ou baixar código de exemplo (como baixar)View or download sample code (how to download)

O ASP.NET Core oferece as seguintes opções para tipos de retorno de ação do controlador da API Web:ASP.NET Core offers the following options for web API controller action return types:

Este documento explica quando é mais adequado usar cada tipo de retorno.This document explains when it's most appropriate to use each return type.

Tipo específicoSpecific type

A ação mais simples retorna um tipo de dados complexo ou primitivo (por exemplo, string ou um tipo de objeto personalizado).The simplest action returns a primitive or complex data type (for example, string or a custom object type). Considere a seguinte ação, que retorna uma coleção de objetos Product personalizados:Consider the following action, which returns a collection of custom Product objects:

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

Sem condições conhecidas contra as quais se proteger durante a execução da ação, retornar um tipo específico pode ser suficiente.Without known conditions to safeguard against during action execution, returning a specific type could suffice. A ação anterior não aceita parâmetros, assim, validação de restrições de parâmetro não é necessária.The preceding action accepts no parameters, so parameter constraints validation isn't needed.

Quando condições conhecidas precisarem ser incluídas em uma ação, vários caminhos de retorno serão introduzidos.When known conditions need to be accounted for in an action, multiple return paths are introduced. Nesse caso, é comum misturar um ActionResult tipo de retorno com o tipo de retorno primitivo ou complexo.In such a case, it's common to mix an ActionResult return type with the primitive or complex return type. IActionResult ou ActionResult<T > é necessário para acomodar esse tipo de ação.Either IActionResult or ActionResult<T> are necessary to accommodate this type of action.

Retornar IEnumerable<T > ou IAsyncEnumerable<t >Return IEnumerable<T> or IAsyncEnumerable<T>

No ASP.NET Core 2,2 e anteriores, retornar IAsyncEnumerable<T> de uma ação resulta em uma iteração de coleção síncrona pelo serializador.In ASP.NET Core 2.2 and earlier, returning IAsyncEnumerable<T> from an action results in synchronous collection iteration by the serializer. O resultado é o bloqueio de chamadas e um potencial para a privação do pool de threads.The result is the blocking of calls and a potential for thread pool starvation. Para ilustrar, imagine que o núcleo do Entity Framework (EF) está sendo usado para as necessidades de acesso a dados da API Web.To illustrate, imagine that Entity Framework (EF) Core is being used for the web API's data access needs. O tipo de retorno da ação a seguir é enumerado de forma síncrona durante a serialização:The following action's return type is synchronously enumerated during serialization:

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

Para evitar a enumeração síncrona e as esperas de bloqueio no banco de dados no ASP.NET Core 2,2 ToListAsynce anteriores, invoque: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();

No ASP.NET Core 3,0 e posterior, retornando IAsyncEnumerable<T> de uma ação:In ASP.NET Core 3.0 and later, returning IAsyncEnumerable<T> from an action:

  • Não resulta mais em iteração síncrona.No longer results in synchronous iteration.
  • Torna-se tão eficiente IEnumerable<T>quanto retornar.Becomes as efficient as returning IEnumerable<T>.

ASP.NET Core 3,0 e posterior armazena em buffer o resultado da seguinte ação antes de fornecer ao serializador: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);

Considere declarar o tipo de retorno da assinatura de IAsyncEnumerable<T> ação como para garantir a iteração assíncrona.Consider declaring the action signature's return type as IAsyncEnumerable<T> to guarantee the asynchronous iteration. Por fim, o modo de iteração é baseado no tipo concreto subjacente que está sendo retornado.Ultimately, the iteration mode is based on the underlying concrete type being returned. O MVC armazena em buffer automaticamente qualquer tipo concreto IAsyncEnumerable<T>que implemente.MVC automatically buffers any concrete type that implements IAsyncEnumerable<T>.

Considere a seguinte ação, que retorna registros de produtos com preço de venda IEnumerable<Product>como: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;
        }
    }
}

O IAsyncEnumerable<Product> equivalente da ação anterior é: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;
        }
    }
}

As duas ações anteriores não são bloqueadas a partir do ASP.NET Core 3,0.Both of the preceding actions are non-blocking as of ASP.NET Core 3.0.

Tipo IActionResultIActionResult type

O IActionResult tipo de retorno é apropriado quando ActionResult vários tipos de retorno são possíveis em uma ação.The IActionResult return type is appropriate when multiple ActionResult return types are possible in an action. Os tipos ActionResult representam vários códigos de status HTTP.The ActionResult types represent various HTTP status codes. Qualquer classe não abstrata derivada de ActionResult é qualificada como um tipo de retorno válido.Any non-abstract class deriving from ActionResult qualifies as a valid return type. Alguns tipos de retorno comuns nessa categoria são BadRequestResult (400), NotFoundResult (404) e OkObjectResult (200).Some common return types in this category are BadRequestResult (400), NotFoundResult (404), and OkObjectResult (200). Como alternativa, os ControllerBase métodos de conveniência na classe podem ser usados para retornar ActionResult tipos de uma ação.Alternatively, convenience methods in the ControllerBase class can be used to return ActionResult types from an action. Por exemplo, return BadRequest(); é uma forma abreviada return new BadRequestResult();de.For example, return BadRequest(); is a shorthand form of return new BadRequestResult();.

Como há vários tipos de retorno e caminhos nesse tipo de ação, liberal uso do atributo [ProducesResponseType] é necessário.Because there are multiple return types and paths in this type of action, liberal use of the [ProducesResponseType] attribute is necessary. Esse atributo produz detalhes de resposta mais descritivos para páginas de ajuda da API Web geradas por ferramentas como o Swagger.This attribute produces more descriptive response details for web API help pages generated by tools like Swagger. [ProducesResponseType] indica os tipos conhecidos e os códigos de status HTTP a serem retornados pela ação.[ProducesResponseType] indicates the known types and HTTP status codes to be returned by the action.

Ação síncronaSynchronous action

Considere a seguinte ação síncrona em que há dois tipos de retorno possíveis: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);
}

Na ação anterior:In the preceding action:

  • Um código de status 404 é retornado quando o produto representado id pelo não existe no armazenamento de dados subjacente.A 404 status code is returned when the product represented by id doesn't exist in the underlying data store. O NotFound método de conveniência é invocado como return new NotFoundResult();abreviação para.The NotFound convenience method is invoked as shorthand for return new NotFoundResult();.
  • Um código de status 200 é retornado com Product o objeto quando o produto existe.A 200 status code is returned with the Product object when the product does exist. O Ok método de conveniência é invocado como return new OkObjectResult(product);abreviação para.The Ok convenience method is invoked as shorthand for return new OkObjectResult(product);.

Ação assíncronaAsynchronous action

Considere a seguinte ação assíncrona em que há dois tipos de retorno possíveis: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);
}

Na ação anterior:In the preceding action:

  • Um código de status 400 é retornado quando a descrição do produto contém "widget XYZ".A 400 status code is returned when the product description contains "XYZ Widget". O BadRequest método de conveniência é invocado como return new BadRequestResult();abreviação para.The BadRequest convenience method is invoked as shorthand for return new BadRequestResult();.
  • Um código de status 201 é gerado pelo CreatedAtAction método de conveniência quando um produto é criado.A 201 status code is generated by the CreatedAtAction convenience method when a product is created. Uma alternativa para chamar 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);. Nesse caminho de código, o Product objeto é fornecido no corpo da resposta.In this code path, the Product object is provided in the response body. É Location fornecido um cabeçalho de resposta contendo a URL do produto recém-criado.A Location response header containing the newly created product's URL is provided.

Por exemplo, o modelo a seguir indica que as solicitações devem incluir as propriedades Name e Description.For example, the following model indicates that requests must include the Name and Description properties. A falha em Name fornecer Description e na solicitação faz com que a validação do modelo falhe.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 o atributo [ApiController] no ASP.NET Core 2,1 ou posterior for aplicado, os erros de validação de modelo resultarão em um código de status 400.If the [ApiController] attribute in ASP.NET Core 2.1 or later is applied, model validation errors result in a 400 status code. Para obter mais informações, veja Respostas automáticas HTTP 400.For more information, see Automatic HTTP 400 responses.

Tipo ActionResult<T>ActionResult<T> type

ASP.NET Core 2,1 introduziu o tipo de retorno <ActionResult T > para ações do controlador da API Web.ASP.NET Core 2.1 introduced the ActionResult<T> return type for web API controller actions. Ele permite que você retorne um tipo derivado de ActionResult ou retorne um tipo específico.It enables you to return a type deriving from ActionResult or return a specific type. ActionResult<T> oferece os seguintes benefícios em relação ao tipo IActionResult:ActionResult<T> offers the following benefits over the IActionResult type:

  • O atributo [ProducesResponseType] pode ter sua propriedade Type excluída.The [ProducesResponseType] attribute's Type property can be excluded. Por exemplo, [ProducesResponseType(200, Type = typeof(Product))] é simplificado para [ProducesResponseType(200)].For example, [ProducesResponseType(200, Type = typeof(Product))] is simplified to [ProducesResponseType(200)]. O tipo de retorno esperado da ação é inferido do T em ActionResult<T>.The action's expected return type is instead inferred from the T in ActionResult<T>.
  • Operadores de conversão implícita são compatíveis com a conversão de T e ActionResult em ActionResult<T>.Implicit cast operators support the conversion of both T and ActionResult to ActionResult<T>. TConverte para ObjectResult, que significa return new ObjectResult(T); é simplificado return T;para.T converts to ObjectResult, which means return new ObjectResult(T); is simplified to return T;.

C# não dá suporte a operadores de conversão implícita em interfaces.C# doesn't support implicit cast operators on interfaces. Consequentemente, a conversão da interface para um tipo concreto é necessário para usar ActionResult<T>.Consequently, conversion of the interface to a concrete type is necessary to use ActionResult<T>. Por exemplo, o uso de IEnumerable no exemplo a seguir não funciona:For example, use of IEnumerable in the following example doesn't work:

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

Uma opção para corrigir o código anterior é retornar a _repository.GetProducts().ToList();.One option to fix the preceding code is to return _repository.GetProducts().ToList();.

A maioria das ações tem um tipo de retorno específico.Most actions have a specific return type. Condições inesperadas podem ocorrer durante a execução da ação, caso em que o tipo específico não é retornado.Unexpected conditions can occur during action execution, in which case the specific type isn't returned. Por exemplo, o parâmetro de entrada de uma ação pode falhar na validação do modelo.For example, an action's input parameter may fail model validation. Nesse caso, é comum retornar o tipo ActionResult adequado, em vez do tipo específico.In such a case, it's common to return the appropriate ActionResult type instead of the specific type.

Ação síncronaSynchronous action

Considere uma ação síncrona em que há dois tipos de retorno possíveis: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;
}

Na ação anterior:In the preceding action:

  • Um código de status 404 é retornado quando o produto não existe no banco de dados.A 404 status code is returned when the product doesn't exist in the database.
  • Um código de status 200 é retornado com o Product objeto correspondente quando o produto existe.A 200 status code is returned with the corresponding Product object when the product does exist. Antes ASP.NET Core 2,1, a return product; linha tinha que ser return Ok(product);.Before ASP.NET Core 2.1, the return product; line had to be return Ok(product);.

Ação assíncronaAsynchronous action

Considere uma ação assíncrona em que há dois tipos de retorno possíveis: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);
}

Na ação anterior:In the preceding action:

  • Um código de status 400BadRequest() é retornado pelo tempo de execução de ASP.NET Core quando:A 400 status code (BadRequest) is returned by the ASP.NET Core runtime when:
    • O atributo [ApiController] tiver sido aplicado e o modelo de validação falhar.The [ApiController] attribute has been applied and model validation fails.
    • A descrição do produto contém "Widget XYZ".The product description contains "XYZ Widget".
  • Um código de status 201 é gerado pelo CreatedAtAction método quando um produto é criado.A 201 status code is generated by the CreatedAtAction method when a product is created. Nesse caminho de código, o Product objeto é fornecido no corpo da resposta.In this code path, the Product object is provided in the response body. É Location fornecido um cabeçalho de resposta contendo a URL do produto recém-criado.A Location response header containing the newly created product's URL is provided.

Recursos adicionaisAdditional resources