Návratové typy akce kontroleru ve ASP.NET Core API

Scott Addie

Zobrazení nebo stažení ukázkového kódu (stažení)

ASP.NET Core nabízí pro návratové typy akcí kontroleru webového rozhraní API následující možnosti:

Tento dokument vysvětluje, kdy je nejvhodnější použít každý návratový typ.

Konkrétní typ

Nejjednodušší akce vrátí primitivní nebo složitý datový typ (například string nebo vlastní typ objektu). Zvažte následující akci, která vrátí kolekci vlastních Product objektů:

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

Bez známých podmínek pro ochranu před prováděním akce by vrácení konkrétního typu mohlo stačit. Předchozí akce nepřijímá žádné parametry, takže ověření omezení parametrů není potřeba.

Pokud je možné použít více návratových typů, je běžné kombinovat návratový typ s ActionResult primitivním nebo komplexním návratový typem. K tomuto typu akce je potřeba buď IActionResult, nebo ActionResult. <T> V tomto dokumentu je k dispozici několik ukázek více návratových typů.

Vrácení IEnumerable <T> nebo IAsyncEnumerable<T>

V ASP.NET Core verze 2.2 a starší výsledkem vrácení z akce je synchronní iterace kolekce IEnumerable<T> serializátorem. Výsledkem je blokování volání a potenciál pro vyhřešování fondu vláken. Pro ilustraci si představte, Entity Framework (EF) Core se používá pro potřeby přístupu k datům webového rozhraní API. Návratový typ následující akce je synchronně výčtu během serializace:

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

Pokud se chcete vyhnout synchronnímu výčtu a blokování čekání na databázi v ASP.NET Core verze 2.2 a starší, vyvolat ToListAsync :

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

V ASP.NET Core verze 3.0 a novější se vraťte IAsyncEnumerable<T> z akce:

  • Výsledkem už není synchronní iterace.
  • Je stejně efektivní jako vrácení IEnumerable<T> .

ASP.NET Core 3.0 a novějších verzích před poskytnutím serializátoru do vyrovnávací paměti výsledek následující akce:

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

Zvažte deklarování návratového typu signatury akce jako pro IAsyncEnumerable<T> zaručení asynchronní iterace. Režim iterace je nakonec založen na podkladovém konkrétním typu, který se vrací. MVC automaticky uloží do vyrovnávací paměti jakýkoli konkrétní typ, který implementuje IAsyncEnumerable<T> .

Vezměte v úvahu následující akci, která vrátí záznamy o produktech s prodejní cenou jako IEnumerable<Product> :

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

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

Ekvivalentem IAsyncEnumerable<Product> předchozí akce je:

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

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

Obě výše uvedené akce neblokují od ASP.NET Core 3.0.

Typ IActionResult

Návratový IActionResult typ je vhodný, pokud je ActionResult v akci možné použít více návratových typů. Typy ActionResult představují různé stavové kódy HTTP. Všechny ne abstrakční třídy odvozené z ActionResult kvalifikují jako platný návratový typ. Některé běžné návratové typy v této kategorii jsou BadRequestResult (400), NotFoundResult (404) a OkObjectResult (200). Alternativně lze ke vrácení typů z akce použít metody usnadnění ControllerBase ActionResult ve třídě . Například je return BadRequest(); zkrácená forma return new BadRequestResult(); .

Vzhledem k tomu, že v tomto typu akce existuje více návratových typů a cest, je nezbytné použít [ProducesResponseType] atribut . Tento atribut vygeneruje popisnější podrobnosti odpovědi na stránky nápovědy webového rozhraní API generované nástroji, jako je Swagger. [ProducesResponseType] označuje známé typy a stavové kódy HTTP, které má akce vrátit.

Synchronní akce

Zvažte následující synchronní akci, ve které existují dva možné návratové typy:

[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Product))]
[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);
}

V předchozí akci:

  • Stavový kód 404 se vrátí, když produkt reprezentovaný v podkladovém úložiště id dat neexistuje. Metoda NotFound convenience se volá jako zkrácená zkratka pro return new NotFoundResult(); .
  • Pokud produkt existuje, vrátí se s objektem stavový kód 200. Product Metoda Ok convenience se volá jako zkrácená zkratka pro return new OkObjectResult(product); .

Asynchronní akce

Zvažte následující asynchronní akci, ve které existují dva možné návratové typy:

[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);
}

V předchozí akci:

  • Pokud popis produktu obsahuje XYZ Widget, vrátí se stavový kód 400. Metoda BadRequest convenience se volá jako zkrácená zkratka pro return new BadRequestResult(); .
  • Při vytváření produktu se pomocí metody convenience vygeneruje stavový kód CreatedAtAction 201. Alternativou k volání CreatedAtAction je return new CreatedAtActionResult(nameof(GetById), "Products", new { id = product.Id }, product); . V této cestě kódu je Product objekt k dispozici v textu odpovědi. K dispozici je hlavička odpovědi obsahující adresu URL nově Location vytvořeného produktu.

Například následující model indikuje, že požadavky musí obsahovat Name vlastnosti Description a . Neúspěšné poskytnutí a Name v požadavku způsobí selhání ověření Description modelu.

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

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

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

Pokud se použije atribut ASP.NET Core 2.1 nebo novější, výsledkem chyb ověření modelu je [ApiController] stavový kód 400. Další informace najdete v tématu Automatické odpovědi HTTP 400.

ActionResult vs IActionResult

Následující část ActionResult porovnává IActionResult

Typ <T> ActionResult

ASP.NET Core zahrnuje návratový <T> typ ActionResult pro akce kontroleru webového rozhraní API. Umožňuje vrátit typ odvozený z nebo vrátit ActionResult konkrétní typ. ActionResult<T>nabízí nad typem IActionResult následující výhody:

  • Vlastnost [ProducesResponseType] atributu Type může být vyloučena. Například je [ProducesResponseType(200, Type = typeof(Product))] zjednodušená na [ProducesResponseType(200)] . Očekávaný návratový typ akce je místo toho odvozen z T v ActionResult<T> .
  • Implicitní operátory přetypování podporují převod T i na ActionResult ActionResult<T> . T převede na ObjectResult , což znamená, že je return new ObjectResult(T); zjednodušený na return T; .

Jazyk C# nepodporuje implicitní operátory přetypování na rozhraních. V důsledku toho je převod rozhraní na konkrétní typ nezbytný pro použití ActionResult<T> . Například použití v IEnumerable následujícím příkladu nefunguje:

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

Jednou z možností opravy předchozího kódu je vrácení _repository.GetProducts().ToList(); .

Většina akcí má konkrétní návratový typ. Během provádění akce může dojít k neočekávaným stavům. V takovém případě se konkrétní typ nevrátil. Například vstupní parametr akce může selhat při ověřování modelu. V takovém případě je běžné místo konkrétního typu vrátit ActionResult odpovídající typ.

Synchronní akce

Zvažte synchronní akci, ve které existují dva možné návratové typy:

[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;
}

V předchozí akci:

  • Pokud produkt v databázi neexistuje, vrátí se stavový kód 404.
  • Pokud produkt existuje, vrátí se stavový kód 200 s odpovídajícím Product objektem. Před ASP.NET Core 2.1 musel být return product; řádek return Ok(product); .

Asynchronní akce

Zvažte asynchronní akci, ve které existují dva možné návratové typy:

[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);
}

V předchozí akci:

  • Stavový kód 400 ( ) vrátí modul runtime ASP.NET Core BadRequest v případě, že:
    • Atribut [ApiController] byl použit a ověření modelu selže.
    • Popis produktu obsahuje "XYZ Widget".
  • Při vytvoření produktu se pomocí metody vygeneruje stavový kód CreatedAtAction 201. V této cestě kódu je Product objekt k dispozici v textu odpovědi. K dispozici je hlavička odpovědi obsahující adresu URL nově Location vytvořeného produktu.

Další materiály