ASP.NET Core Web API のコントローラー アクションの戻り値の型Controller action return types in ASP.NET Core web API

作成者: Scott AddieBy Scott Addie

サンプル コードを表示またはダウンロードします (ダウンロード方法)。View or download sample code (how to download)

ASP.NET Core では、Web API コントローラー アクションの戻り値の型に次のオプションを提供しています。ASP.NET Core offers the following options for web API controller action return types:

このドキュメントでは、各戻り値の型を使用するのが最適な場合について説明します。This document explains when it's most appropriate to use each return type.

特定の型Specific type

最もシンプルなアクションでは、プリミティブ データ型または複合データ型が返されます (string やカスタム オブジェクトの型など)。The simplest action returns a primitive or complex data type (for example, string or a custom object type). カスタム Product オブジェクトのコレクションを返す次のアクションを考えてみましょう。Consider the following action, which returns a collection of custom Product objects:

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

アクションの実行中に保護できる既知の条件がない場合は、特定の型を返すだけで十分です。Without known conditions to safeguard against during action execution, returning a specific type could suffice. 前のアクションでパラメーターを受け取っていないので、パラメーターの制約の検証は必要ありません。The preceding action accepts no parameters, so parameter constraints validation isn't needed.

アクションで既知の条件を考慮する必要がある場合は、複数の戻り値のパスが導入されます。When known conditions need to be accounted for in an action, multiple return paths are introduced. このような場合、ActionResult の戻り値の型とプリミティブまたは複合の戻り値の型を混在させるのが一般的です。In such a case, it's common to mix an ActionResult return type with the primitive or complex return type. この種類のアクションに対応するには、IActionResult または ActionResult<T> のいずれかが必要です。Either IActionResult or ActionResult<T> are necessary to accommodate this type of action.

IEnumerable<T> または IAsyncEnumerable<T> を返すReturn IEnumerable<T> or IAsyncEnumerable<T>

ASP.NET Core 2.2 以前では、アクションから IAsyncEnumerable<T> が返されると、シリアライザーによって同期コレクションのイテレーションが行われます。In ASP.NET Core 2.2 and earlier, returning IAsyncEnumerable<T> from an action results in synchronous collection iteration by the serializer. その結果、呼び出しがブロックされ、スレッド プールが枯渇する可能性があります。The result is the blocking of calls and a potential for thread pool starvation. 例として、Web API のデータ アクセスのニーズに Entity Framework (EF) コアが使用されているとします。To illustrate, imagine that Entity Framework (EF) Core is being used for the web API's data access needs. 次のアクションの戻り値の型は、シリアル化中に同期的に列挙されます。The following action's return type is synchronously enumerated during serialization:

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

ASP.NET Core 2.2 以前のデータベースで同期的な列挙とブロックの待機を回避するには、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();

ASP.NET Core 3.0 以降では、アクションから IAsyncEnumerable<T> を返します。In ASP.NET Core 3.0 and later, returning IAsyncEnumerable<T> from an action:

  • 同期のイテレーションは行われなくなります。No longer results in synchronous iteration.
  • IEnumerable<T> を返す場合と同様に効率的になります。Becomes as efficient as returning IEnumerable<T>.

ASP.NET Core 3.0 以降では、次のアクションの結果がバッファーに出力されてから、シリアライザーに渡されます。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);

非同期のイテレーションを保証するために、アクション シグネチャの戻り値の型を IAsyncEnumerable<T> と宣言することを検討してください。Consider declaring the action signature's return type as IAsyncEnumerable<T> to guarantee the asynchronous iteration. 最終的に、イテレーション モードは、返される基となる具象型に基づいています。Ultimately, the iteration mode is based on the underlying concrete type being returned. MVC では、IAsyncEnumerable<T> を実装するすべての具象型が自動的にバッファーされます。MVC automatically buffers any concrete type that implements IAsyncEnumerable<T>.

販売価格が付けられた製品レコードが 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;
        }
    }
}

前の IAsyncEnumerable<Product> のアクションに相当するものは次のとおりです。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;
        }
    }
}

上記のアクションはいずれも ASP.NET Core 3.0 以降ではブロックされません。Both of the preceding actions are non-blocking as of ASP.NET Core 3.0.

IActionResult 型IActionResult type

戻り値の型 IActionResult は、アクションの戻り値の型 ActionResult が複数考えられる場合に適しています。The IActionResult return type is appropriate when multiple ActionResult return types are possible in an action. ActionResult 型は、さまざまな HTTP 状態コードを表します。The ActionResult types represent various HTTP status codes. ActionResult から派生したすべての非抽象クラスは、有効な戻り値の型として修飾されます。Any non-abstract class deriving from ActionResult qualifies as a valid return type. このカテゴリの一般的な戻り値の型として、BadRequestResult (400)、NotFoundResult (404)、OkObjectResult (200) などがあります。Some common return types in this category are BadRequestResult (400), NotFoundResult (404), and OkObjectResult (200). また、ControllerBase クラスの便利なメソッドを使用して、アクションから ActionResult 型を返すこともできます。Alternatively, convenience methods in the ControllerBase class can be used to return ActionResult types from an action. たとえば、return BadRequest(); は、return new BadRequestResult(); の短縮形です。For example, return BadRequest(); is a shorthand form of return new BadRequestResult();.

この種類のアクションには複数の戻り値の型とパスがあるため、[ProducesResponseType] 属性を十分に使える必要があります。Because there are multiple return types and paths in this type of action, liberal use of the [ProducesResponseType] attribute is necessary. この属性は、Swagger などのツールで生成される Web API ヘルプ ページのよりわかりやすい応答の詳細を生成します。This attribute produces more descriptive response details for web API help pages generated by tools like Swagger. [ProducesResponseType] は、アクションによって返される既知の型と HTTP 状態コードを示します。[ProducesResponseType] indicates the known types and HTTP status codes to be returned by the action.

同期アクションSynchronous action

2 つの戻り値の型が考えられる、次の同期アクションを考えてみましょう。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);
}

前のアクションの内容:In the preceding action:

  • id によって表される製品が、基になるデータ ストアに存在しないと、404 状態コードが返されます。A 404 status code is returned when the product represented by id doesn't exist in the underlying data store. NotFound の便利なメソッドは、return new NotFoundResult(); の短縮形として呼び出されます。The NotFound convenience method is invoked as shorthand for return new NotFoundResult();.
  • 製品が存在する場合は、Product オブジェクトと共に 200 状態コードが返されます。A 200 status code is returned with the Product object when the product does exist. Ok の便利なメソッドは、return new OkObjectResult(product); の短縮形として呼び出されます。The Ok convenience method is invoked as shorthand for return new OkObjectResult(product);.

非同期アクションAsynchronous action

2 つの戻り値の型が考えられる、次の非同期アクションを考えてみましょう。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);
}

前のアクションの内容:In the preceding action:

  • 製品の説明に "XYZ Widget" が含まれている場合は、400 状態コードが返されます。A 400 status code is returned when the product description contains "XYZ Widget". BadRequest の便利なメソッドは、return new BadRequestResult(); の短縮形として呼び出されます。The BadRequest convenience method is invoked as shorthand for return new BadRequestResult();.
  • 201 状態コードは、製品の作成時に CreatedAtAction の便利なメソッドによって生成されます。A 201 status code is generated by the CreatedAtAction convenience method when a product is created. 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);. このコード パスでは、Product オブジェクトは応答本文で指定されます。In this code path, the Product object is provided in the response body. 新しく作成された製品の URL を含む Location 応答ヘッダーが用意されています。A Location response header containing the newly created product's URL is provided.

たとえば、次のモデルでは、要求に Name プロパティと Description プロパティを含める必要があることを示しています。For example, the following model indicates that requests must include the Name and Description properties. 要求で NameDescription を提供するのに失敗すると、モデルの検証が失敗します。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; }
}

ASP.NET Core 2.1 以降の [ApiController] 属性が適用されている場合、モデルの検証エラーによって 400 状態コードが返されます。If the [ApiController] attribute in ASP.NET Core 2.1 or later is applied, model validation errors result in a 400 status code. 詳細については、「自動的な HTTP 400 応答」を参照してください。For more information, see Automatic HTTP 400 responses.

ActionResult<T> 型ActionResult<T> type

ASP.NET Core 2.1 では、Web API コントローラー アクションに対して、ActionResult<T> の戻り値の型が導入されました。ASP.NET Core 2.1 introduced the ActionResult<T> return type for web API controller actions. これで、ActionResult から派生した型を返したり、特定の型を返したりすることができるようになりました。It enables you to return a type deriving from ActionResult or return a specific type. ActionResult<T> により、IActionResult 型は次の利点を得られます。ActionResult<T> offers the following benefits over the IActionResult type:

  • [ProducesResponseType] 属性の Type プロパティを除外することができます。The [ProducesResponseType] attribute's Type property can be excluded. たとえば、[ProducesResponseType(200, Type = typeof(Product))][ProducesResponseType(200)] に簡略化されます。For example, [ProducesResponseType(200, Type = typeof(Product))] is simplified to [ProducesResponseType(200)]. アクションの予期される戻り値の型は、代わりに ActionResult<T>T から推論されます。The action's expected return type is instead inferred from the T in ActionResult<T>.
  • 暗黙的なキャスト演算子は、TActionResult の両方の ActionResult<T> への変換をサポートしています。Implicit cast operators support the conversion of both T and ActionResult to ActionResult<T>. TObjectResult に変換されます。つまり、return new ObjectResult(T);return T; に簡略化されます。T converts to ObjectResult, which means return new ObjectResult(T); is simplified to return T;.

C# はインターフェイス上での暗黙的なキャスト演算子をサポートしていません。C# doesn't support implicit cast operators on interfaces. そのため、ActionResult<T> を使用するには、インターフェイスを具象型に変換する必要があります。Consequently, conversion of the interface to a concrete type is necessary to use ActionResult<T>. たとえば、次の例における IEnumerable の使用は機能しません。For example, use of IEnumerable in the following example doesn't work:

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

上記のコードを修正するための選択肢の 1 つは、_repository.GetProducts().ToList(); を返すことです。One option to fix the preceding code is to return _repository.GetProducts().ToList();.

ほとんどのアクションには、特定の戻り値の型があります。Most actions have a specific return type. アクションの実行中に予期しない状態が発生する場合、特定の型は返されません。Unexpected conditions can occur during action execution, in which case the specific type isn't returned. たとえば、アクションの入力パラメーターがモデルの検証に失敗する場合があります。For example, an action's input parameter may fail model validation. このような場合、通常は特定の型ではなく、適切な ActionResult 型が返されます。In such a case, it's common to return the appropriate ActionResult type instead of the specific type.

同期アクションSynchronous action

2 つの戻り値の型が考えられる、同期アクションを考えてみましょう。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;
}

前のアクションの内容:In the preceding action:

  • 製品がデータベース内に存在しない場合、404 状態コードが返されます。A 404 status code is returned when the product doesn't exist in the database.
  • 製品が存在する場合、対応する Product オブジェクトと共に 200 状態コードが返されます。A 200 status code is returned with the corresponding Product object when the product does exist. ASP.NET Core 2.1 より前のバージョンは、return product; 行を return Ok(product); にする必要がありました。Before ASP.NET Core 2.1, the return product; line had to be return Ok(product);.

非同期アクションAsynchronous action

2 つの戻り値の型が考えられる、非同期アクションを考えてみましょう。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);
}

前のアクションの内容:In the preceding action:

  • 次の場合、ASP.NET Core ランタイムによって 400 状態コード (BadRequest) が返されます。A 400 status code (BadRequest) is returned by the ASP.NET Core runtime when:
    • [ApiController] 属性が適用されていて、モデルの検証が失敗する。The [ApiController] attribute has been applied and model validation fails.
    • 製品の説明に "XYZ Widget" が含まれている。The product description contains "XYZ Widget".
  • 201 状態コードは、製品の作成時に CreatedAtAction メソッドによって生成されます。A 201 status code is generated by the CreatedAtAction method when a product is created. このコード パスでは、Product オブジェクトは応答本文で指定されます。In this code path, the Product object is provided in the response body. 新しく作成された製品の URL を含む Location 応答ヘッダーが用意されています。A Location response header containing the newly created product's URL is provided.

その他の技術情報Additional resources