ASP.NET Core を使って Web API を作成する

ASP.NET Core では、コントローラーまたは Minimal API を使用した Web API の作成がサポートされています。 Web API の "コントローラー" は ControllerBase から派生するクラスです。 コントローラーはアクティブ化され、要求ごとに破棄されます。

この記事では、コントローラーを使って Web API 要求を処理する方法について説明します。 コントローラーを使用せずに Web API を作成する方法については、「チュートリアル: ASP.NET Core で Minimal API を作成する」を参照してください。

ControllerBase クラス

コントローラーベースの Web API は、ControllerBase から派生した 1 つまたは複数のコントローラー クラスで構成されます。 Web API のプロジェクト テンプレートでは、スターター コントローラーが提供されます。

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

Web API コントローラーは、Controller からではなく、ControllerBase から派生する必要があります。 ControllerBase から派生した Controller にはビューのサポートが追加されるため、これは Web API 要求ではなく Web ページを処理するためのものです。 同じコントローラーでビューと Web API をサポートする必要がある場合は、Controller から派生させます。

ControllerBase クラスには、HTTP 要求の処理に役立つプロパティとメソッドが多数用意されています。 たとえば、CreatedAtAction では状態コード 201 が返されます。

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

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

次の表に、ControllerBase に含まれるメソッドの例を示します。

メソッド メモ
BadRequest 400 状態コードを返します。
NotFound 404 状態コードを返します。
PhysicalFile ファイルを返します。
TryUpdateModelAsync モデル バインドを呼び出します。
TryValidateModel モデル検証を呼び出します。

使用可能なすべてのメソッドとプロパティの一覧については、「ControllerBase」を参照してください。

属性

Microsoft.AspNetCore.Mvc 名前空間には、Web API のコントローラーとアクション メソッドの動作の構成に使用できる属性が用意されています。 次の例では、属性を使って、サポート対象の HTTP アクション動詞と、返却される可能性がある既知の HTTP ステータス コードを指定します。

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

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

次に、使用できる属性の例をさらにいくつか示します。

属性 メモ
[Route] コントローラーまたはアクションの URL パターンを指定します。
[Bind] モデル バインドのために含めるプレフィックスとプロパティを指定します。
[HttpGet] HTTP GET アクション動詞をサポートするアクションを特定します。
[Consumes] アクションが受け取るデータ型を指定します。
[Produces] アクションによって返すデータ型を指定します。

使用可能な属性を含む一覧については、Microsoft.AspNetCore.Mvc 名前空間をご覧ください。

ApiController 属性

[ApiController] 属性をコントローラー クラスに適用して、次の厳格な、API に固有の動作を有効にできます。

特定のコントローラーにおける属性

プロジェクト テンプレートからの次の例のように、[ApiController] 属性は特定のコントローラーに適用できます。

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

複数のコントローラーにおける属性

複数のコントローラーでこの属性を使う方法の 1 つは、[ApiController] 属性で注釈を付けたカスタム基本コントローラー クラスを作成することです。 次は、カスタム基底クラスとそこから派生したコントローラーを示す例です。

[ApiController]
public class MyControllerBase : ControllerBase
{
}
[Produces(MediaTypeNames.Application.Json)]
[Route("[controller]")]
public class PetsController : MyControllerBase

アセンブリにおける属性

アセンブリには、[ApiController] 属性を適用できます。 [ApiController] 属性がアセンブリに適用されると、そのアセンブリ内のすべてのコントローラーに [ApiController] 属性が適用されます。 個別のコントローラーを除外する方法はありません。 アセンブリ レベルの属性を Program.cs ファイルに適用します。

using Microsoft.AspNetCore.Mvc;
[assembly: ApiController]

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

属性ルーティング要件

[ApiController] 属性では、属性ルーティング要件が作成されます。 次に例を示します。

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

UseEndpointsUseMvc、または UseMvcWithDefaultRoute で定義された規則ルート経由でアクションにアクセスすることはできません。

自動的な HTTP 400 応答

[ApiController] 属性により、モデル検証エラーが発生すると HTTP 400 応答が自動的にトリガーされます。 その結果、アクション メソッド内の次のコードは不要になります。

if (!ModelState.IsValid)
{
    return BadRequest(ModelState);
}

ASP.NET Core MVC では、ModelStateInvalidFilter アクション フィルターの使用により前のチェックが行われます。

既定の BadRequest 応答

HTTP 400 応答に対する既定の応答の種類は ValidationProblemDetails です。 次の応答本文は、シリアル化された型の例です。

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "|7fb5e16a-4c8f23bbfc974667.",
  "errors": {
    "": [
      "A non-empty request body is required."
    ]
  }
}

ValidationProblemDetails 型:

  • Web API 応答でエラーを指定するための、コンピューターが判読できる形式を提供します。
  • RFC 7807 仕様に準拠しています。

自動とカスタムの応答を一貫させるには、BadRequest ではなく ValidationProblem メソッドを呼び出します。 ValidationProblemValidationProblemDetails オブジェクトと、自動的な応答を返します。

自動的な 400 応答を記録する

自動的な 400 応答をログに記録するには、InvalidModelStateResponseFactory デリゲート プロパティを設定してカスタム処理を実行します。 既定では、InvalidModelStateResponseFactory では、ProblemDetailsFactory を使用して ValidationProblemDetails のインスタンスを作成します。

次の例では、ILogger<TCategoryName> のインスタンスを取得して、自動的な 400 応答に関する情報をログに記録する方法を示しています。

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
      // To preserve the default behavior, capture the original delegate to call later.
        var builtInFactory = options.InvalidModelStateResponseFactory;

        options.InvalidModelStateResponseFactory = context =>
        {
            var logger = context.HttpContext.RequestServices
                                .GetRequiredService<ILogger<Program>>();

            // Perform logging here.
            // ...

            // Invoke the default behavior, which produces a ValidationProblemDetails
            // response.
            // To produce a custom response, return a different implementation of 
            // IActionResult instead.
            return builtInFactory(context);
        };
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

自動的な 400 応答を無効にする

自動的な 400 の動作を無効にするには、SuppressModelStateInvalidFilter プロパティを true に設定します。 次の強調表示されたコードを追加します。

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

バインディング ソース パラメーター推論

バインディング ソース属性では、アクション パラメーターの値が存在する場所が定義されます。 次のバインディング ソース属性が存在します。

属性 バインド ソース
[FromBody] 要求本文
[FromForm] 要求本文内のフォーム データ
[FromHeader] 要求ヘッダー
[FromQuery] 要求のクエリ文字列パラメーター
[FromRoute] 現在の要求からのルート データ
[FromServices] アクション パラメーターとして挿入される要求サービス
[AsParameters] メソッドのパラメーター

警告

値に %2f (つまり、/) が含まれる可能性がある場合は、[FromRoute] を使用しないでください。 %2f/ にエスケープ解除されません。 値に %2f が含まれる可能性がある場合は、[FromQuery] を使用してください。

[ApiController] 属性や [FromQuery] などのバインディング ソース属性がない場合は、ASP.NET Core ランタイムにより複合オブジェクト モデル バインダーの使用が試行されます。 複合オブジェクト モデル バインダーでは、値プロバイダーから定義された順序でデータを取得します。

次の例では、discontinuedOnly パラメーター値が要求 URL のクエリ文字列に指定されていることが [FromQuery] によって示されています。

[HttpGet]
public ActionResult<List<Product>> Get(
    [FromQuery] bool discontinuedOnly = false)
{
    List<Product> products = null;

    if (discontinuedOnly)
    {
        products = _productsInMemoryStore.Where(p => p.IsDiscontinued).ToList();
    }
    else
    {
        products = _productsInMemoryStore;
    }

    return products;
}

[ApiController] 属性により、アクション パラメーターの既定のデータ ソースに対する推論規則が適用されます。 これらの規則により、アクション パラメーターに属性を適用することで手動でバインディング ソースを特定する必要がなくなります。 バインディング ソースの推論規則は、次のように動作します。

  • [FromServices] は、DI コンテナーに登録されている複合型パラメーターに対して推論されます。
  • [FromBody] は、DI コンテナーに登録されていない複合型パラメーターに対して推論されます。 [FromBody] 推論規則に対する例外は、IFormCollectionCancellationToken など、特殊な意味を持つ組み込みの複合型です。 バインディング ソース推論コードでは、そのような特殊な型は無視されます。
  • [FromForm]IFormFile および IFormFileCollection 型のアクション パラメーターに対して推論されます。 簡易型またはユーザー定義型に対しては推論されません。
  • [FromRoute] は、ルート テンプレート内のパラメーターと一致する任意のアクション パラメーター名に対して推論されます。 複数のルートがアクション パラメーターと一致する場合、ルート値はいずれも [FromRoute] と見なされます。
  • [FromQuery] は他の任意のアクション パラメーターに対して推論されます。

FromBody 推論に関するメモ

[FromBody] は、stringint などの単純型に対しては推論されません。 そのため、その機能が必要な場合、単純型に対しては [FromBody] 属性を使用する必要があります。

要求本文からバインドされるパラメーターがアクションに複数ある場合は、例外がスローされます。 たとえば、次のアクション メソッドのシグネチャはすべて例外の原因となります。

  • 複合型であるため、両方に対して [FromBody] が推論されます。

    [HttpPost]
    public IActionResult Action1(Product product, Order order)
    
  • 1 つには [FromBody] 属性が使われ、もう 1 つは複合型なので推論されます。

    [HttpPost]
    public IActionResult Action2(Product product, [FromBody] Order order)
    
  • 両方で [FromBody] 属性が使われます。

    [HttpPost]
    public IActionResult Action3([FromBody] Product product, [FromBody] Order order)
    

FromServices 推論に関するメモ

パラメーター バインドでは、型がサービスとして構成されているときに、依存関係の挿入によってパラメーターをバインドします。 つまり、パラメーターに [FromServices] 属性を明示的に適用する必要はありません。 次のコードでは、どちらのアクションでも時刻が返されます。

[Route("[controller]")]
[ApiController]
public class MyController : ControllerBase
{
    public ActionResult GetWithAttribute([FromServices] IDateTime dateTime) 
                                                        => Ok(dateTime.Now);

    [Route("noAttribute")]
    public ActionResult Get(IDateTime dateTime) => Ok(dateTime.Now);
}

自動 DI により、まれに API コントローラーのアクション メソッドでも受け入れられる型が DI 内にあるアプリが動作しなくなる可能性があります。 型が DI 内にある、かつ API コントローラー アクションの引数として存在することは一般的ではありません。

1 つのアクション パラメーターの [FromServices] 推論を無効にするには、目的のバインディング ソース属性をパラメーターに適用します。 たとえば、要求の本文からバインドする必要があるアクション パラメーターに [FromBody] 属性を適用します。

[FromServices] 推論をグローバルに無効にするには、DisableImplicitFromServicesParameterstrue に設定します。

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddSingleton<IDateTime, SystemDateTime>();

builder.Services.Configure<ApiBehaviorOptions>(options =>
{
    options.DisableImplicitFromServicesParameters = true;
});

var app = builder.Build();

app.MapControllers();

app.Run();

型は、IServiceProviderIsService を使用してアプリの起動時に確認され、API コントローラー アクションの引数が DI または他のソースから取得されたかどうかが判断されます。

API コントローラー アクション パラメーターのバインディング ソースを推論するメカニズムでは、次の規則を使用します。

  • 以前に指定された BindingInfo.BindingSource が上書きされることはありません。
  • DI コンテナーに登録されている複合型パラメーターには、BindingSource.Services が割り当てられます。
  • DI コンテナーに登録されていない複合型パラメーターには、BindingSource.Body が割り当てられます。
  • ''任意'' のルート テンプレートでルート値として表示される名前を持つパラメーターには、BindingSource.Path が割り当てられます。
  • その他のパラメーターはすべて BindingSource.Query です。

推論規則を無効にする

バインディング ソースの推論を無効にするには、SuppressInferBindingSourcesForParameterstrue に設定します。

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
        options.DisableImplicitFromServicesParameters = true;
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

マルチパート/フォーム データ要求の推論

[ApiController] 属性を設定すると、IFormFile および IFormFileCollection 型のアクション パラメーターに対して推論規則が適用されます。 multipart/form-data 要求コンテンツ タイプは、これらの種類に対して推論されます。

既定の動作を無効にするには、SuppressConsumesConstraintForFormFileParameters プロパティを true に設定します。

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

エラー状態コードに関する問題の詳細

MVC によってエラー結果 (状態コードが 400 以降の結果) が ProblemDetails による結果に変換されます。 ProblemDetails 型は、HTTP 応答でコンピューターが判読できるエラーの詳細を提供するための RFC 7807 仕様に基づきます。

コントローラー アクションで次のコードがあるとします。

if (pet == null)
{
    return NotFound();
}

NotFound メソッドにより、ProblemDetails 本文を使用して HTTP 404 ステータス コードが生成されます。 次に例を示します。

{
  type: "https://tools.ietf.org/html/rfc7231#section-6.5.4",
  title: "Not Found",
  status: 404,
  traceId: "0HLHLV31KRN83:00000001"
}

ProblemDetails 応答を無効にする

SuppressMapClientErrors プロパティが true に設定されている場合、エラー状態コード用の ProblemDetails の自動作成は無効になります。 次のコードを追加します。

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

[Consumes] 属性を使ってサポートされる要求のコンテンツの種類を定義する

既定では、アクションでは使用可能な要求のコンテンツの種類がすべてサポートされます。 たとえば、アプリが JSON と XML の入力フォーマッタを両方サポートするように構成されている場合、アクションでは、application/jsonapplication/xml を含む複数のコンテンツの種類がサポートされます。

[Consumes] 属性を使用すると、アクションでサポートされる要求のコンテンツの種類を制限できます。 1 つ以上のコンテンツの種類を指定して、アクションまたはコントローラーに [Consumes] 属性を適用します。

[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)

上記のコードでは、CreateProduct アクションでコンテンツの種類 application/xml が指定されています。 このアクションにルーティングされる要求では、Content-Type ヘッダーに application/xml を指定する必要があります。 Content-Type ヘッダーに application/xml を指定していない要求では、415 Unsupported Media Type 応答が発生します。

また、[Consumes] 属性を使用すると、種類の制約を適用することによって、受信要求のコンテンツの種類に基づいてアクションの選択に影響を与えることができます。 次に例を示します。

[ApiController]
[Route("api/[controller]")]
public class ConsumesController : ControllerBase
{
    [HttpPost]
    [Consumes("application/json")]
    public IActionResult PostJson(IEnumerable<int> values) =>
        Ok(new { Consumes = "application/json", Values = values });

    [HttpPost]
    [Consumes("application/x-www-form-urlencoded")]
    public IActionResult PostForm([FromForm] IEnumerable<int> values) =>
        Ok(new { Consumes = "application/x-www-form-urlencoded", Values = values });
}

上記のコードでは、ConsumesControllerhttps://localhost:5001/api/Consumes の URL に送信された要求を処理するように構成されています。 コントローラーの両方のアクション PostJsonPostForm では、同じ URL の POST 要求が処理されます。 種類の制約を適用する [Consumes] 属性がなかった場合は、あいまい一致の例外がスローされます。

[Consumes] 属性は両方のアクションに適用されます。 PostJson アクションでは、Content-Type ヘッダーに application/json を指定して送信された要求が処理されます。 PostForm アクションでは、Content-Type ヘッダーに application/x-www-form-urlencoded を指定して送信された要求が処理されます。

その他の技術情報

ASP.NET Core では、コントローラーまたは Minimal API を使用した Web API の作成がサポートされています。 Web API の "コントローラー" は ControllerBase から派生するクラスです。 この記事では、コントローラーを使って Web API 要求を処理する方法について説明します。 コントローラーを使用せずに Web API を作成する方法については、「チュートリアル: ASP.NET Core で Minimal API を作成する」を参照してください。

ControllerBase クラス

コントローラーベースの Web API は、ControllerBase から派生した 1 つまたは複数のコントローラー クラスで構成されます。 Web API のプロジェクト テンプレートでは、スターター コントローラーが提供されます。

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

Web API コントローラーは、Controller からではなく、ControllerBase から派生する必要があります。 ControllerBase から派生した Controller にはビューのサポートが追加されるため、これは Web API 要求ではなく Web ページを処理するためのものです。 同じコントローラーでビューと Web API をサポートする必要がある場合は、Controller から派生させます。

ControllerBase クラスには、HTTP 要求の処理に役立つプロパティとメソッドが多数用意されています。 たとえば、CreatedAtAction では状態コード 201 が返されます。

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

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

次の表に、ControllerBase に含まれるメソッドの例を示します。

メソッド メモ
BadRequest 400 状態コードを返します。
NotFound 404 状態コードを返します。
PhysicalFile ファイルを返します。
TryUpdateModelAsync モデル バインドを呼び出します。
TryValidateModel モデル検証を呼び出します。

使用可能なすべてのメソッドとプロパティの一覧については、「ControllerBase」を参照してください。

属性

Microsoft.AspNetCore.Mvc 名前空間には、Web API のコントローラーとアクション メソッドの動作の構成に使用できる属性が用意されています。 次の例では、属性を使って、サポート対象の HTTP アクション動詞と、返却される可能性がある既知の HTTP ステータス コードを指定します。

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

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

次に、使用できる属性の例をさらにいくつか示します。

属性 メモ
[Route] コントローラーまたはアクションの URL パターンを指定します。
[Bind] モデル バインドのために含めるプレフィックスとプロパティを指定します。
[HttpGet] HTTP GET アクション動詞をサポートするアクションを特定します。
[Consumes] アクションが受け取るデータ型を指定します。
[Produces] アクションによって返すデータ型を指定します。

使用可能な属性を含む一覧については、Microsoft.AspNetCore.Mvc 名前空間をご覧ください。

ApiController 属性

[ApiController] 属性をコントローラー クラスに適用して、次の厳格な、API に固有の動作を有効にできます。

特定のコントローラーにおける属性

プロジェクト テンプレートからの次の例のように、[ApiController] 属性は特定のコントローラーに適用できます。

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

複数のコントローラーにおける属性

複数のコントローラーでこの属性を使う方法の 1 つは、[ApiController] 属性で注釈を付けたカスタム基本コントローラー クラスを作成することです。 次は、カスタム基底クラスとそこから派生したコントローラーを示す例です。

[ApiController]
public class MyControllerBase : ControllerBase
{
}
[Produces(MediaTypeNames.Application.Json)]
[Route("[controller]")]
public class PetsController : MyControllerBase

アセンブリにおける属性

アセンブリには、[ApiController] 属性を適用できます。 [ApiController] 属性がアセンブリに適用されると、そのアセンブリ内のすべてのコントローラーに [ApiController] 属性が適用されます。 個別のコントローラーを除外する方法はありません。 アセンブリ レベルの属性を Program.cs ファイルに適用します。

using Microsoft.AspNetCore.Mvc;
[assembly: ApiController]

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

属性ルーティング要件

[ApiController] 属性では、属性ルーティング要件が作成されます。 次に例を示します。

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

UseEndpointsUseMvc、または UseMvcWithDefaultRoute で定義された規則ルート経由でアクションにアクセスすることはできません。

自動的な HTTP 400 応答

[ApiController] 属性により、モデル検証エラーが発生すると HTTP 400 応答が自動的にトリガーされます。 その結果、アクション メソッド内の次のコードは不要になります。

if (!ModelState.IsValid)
{
    return BadRequest(ModelState);
}

ASP.NET Core MVC では、ModelStateInvalidFilter アクション フィルターの使用により前のチェックが行われます。

既定の BadRequest 応答

次の応答本文は、シリアル化された型の例です。

{
  "": [
    "A non-empty request body is required."
  ]
}

HTTP 400 応答に対する既定の応答の種類は ValidationProblemDetails です。 次の応答本文は、シリアル化された型の例です。

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "|7fb5e16a-4c8f23bbfc974667.",
  "errors": {
    "": [
      "A non-empty request body is required."
    ]
  }
}

ValidationProblemDetails 型:

  • Web API 応答でエラーを指定するための、コンピューターが判読できる形式を提供します。
  • RFC 7807 仕様に準拠しています。

自動とカスタムの応答を一貫させるには、BadRequest ではなく ValidationProblem メソッドを呼び出します。 ValidationProblemValidationProblemDetails オブジェクトと、自動的な応答を返します。

自動的な 400 応答を記録する

自動的な 400 応答をログに記録するには、InvalidModelStateResponseFactory デリゲート プロパティを設定してカスタム処理を実行します。 既定では、InvalidModelStateResponseFactory では、ProblemDetailsFactory を使用して ValidationProblemDetails のインスタンスを作成します。

次の例では、ILogger<TCategoryName> のインスタンスを取得して、自動的な 400 応答に関する情報をログに記録する方法を示しています。

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
      // To preserve the default behavior, capture the original delegate to call later.
        var builtInFactory = options.InvalidModelStateResponseFactory;

        options.InvalidModelStateResponseFactory = context =>
        {
            var logger = context.HttpContext.RequestServices
                                .GetRequiredService<ILogger<Program>>();

            // Perform logging here.
            // ...

            // Invoke the default behavior, which produces a ValidationProblemDetails
            // response.
            // To produce a custom response, return a different implementation of 
            // IActionResult instead.
            return builtInFactory(context);
        };
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

自動的な 400 応答を無効にする

自動的な 400 の動作を無効にするには、SuppressModelStateInvalidFilter プロパティを true に設定します。 次の強調表示されたコードを追加します。

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

バインディング ソース パラメーター推論

バインディング ソース属性では、アクション パラメーターの値が存在する場所が定義されます。 次のバインディング ソース属性が存在します。

属性 バインド ソース
[FromBody] 要求本文
[FromForm] 要求本文内のフォーム データ
[FromHeader] 要求ヘッダー
[FromQuery] 要求のクエリ文字列パラメーター
[FromRoute] 現在の要求からのルート データ
[FromServices] アクション パラメーターとして挿入される要求サービス

警告

値に %2f (つまり、/) が含まれる可能性がある場合は、[FromRoute] を使用しないでください。 %2f/ にエスケープ解除されません。 値に %2f が含まれる可能性がある場合は、[FromQuery] を使用してください。

[ApiController] 属性や [FromQuery] などのバインディング ソース属性がない場合は、ASP.NET Core ランタイムにより複合オブジェクト モデル バインダーの使用が試行されます。 複合オブジェクト モデル バインダーでは、値プロバイダーから定義された順序でデータを取得します。

次の例では、discontinuedOnly パラメーター値が要求 URL のクエリ文字列に指定されていることが [FromQuery] によって示されています。

[HttpGet]
public ActionResult<List<Product>> Get(
    [FromQuery] bool discontinuedOnly = false)
{
    List<Product> products = null;

    if (discontinuedOnly)
    {
        products = _productsInMemoryStore.Where(p => p.IsDiscontinued).ToList();
    }
    else
    {
        products = _productsInMemoryStore;
    }

    return products;
}

[ApiController] 属性により、アクション パラメーターの既定のデータ ソースに対する推論規則が適用されます。 これらの規則により、アクション パラメーターに属性を適用することで手動でバインディング ソースを特定する必要がなくなります。 バインディング ソースの推論規則は、次のように動作します。

  • [FromBody] は、DI コンテナーに登録されていない複合型パラメーターに対して推論されます。 [FromBody] 推論規則に対する例外は、IFormCollectionCancellationToken など、特殊な意味を持つ組み込みの複合型です。 バインディング ソース推論コードでは、そのような特殊な型は無視されます。
  • [FromForm]IFormFile および IFormFileCollection 型のアクション パラメーターに対して推論されます。 簡易型またはユーザー定義型に対しては推論されません。
  • [FromRoute] は、ルート テンプレート内のパラメーターと一致する任意のアクション パラメーター名に対して推論されます。 複数のルートがアクション パラメーターと一致する場合、ルート値はいずれも [FromRoute] と見なされます。
  • [FromQuery] は他の任意のアクション パラメーターに対して推論されます。

FromBody 推論に関するメモ

[FromBody] は、stringint などの単純型に対しては推論されません。 そのため、その機能が必要な場合、単純型に対しては [FromBody] 属性を使用する必要があります。

要求本文からバインドされるパラメーターがアクションに複数ある場合は、例外がスローされます。 たとえば、次のアクション メソッドのシグネチャはすべて例外の原因となります。

  • 複合型であるため、両方に対して [FromBody] が推論されます。

    [HttpPost]
    public IActionResult Action1(Product product, Order order)
    
  • 1 つには [FromBody] 属性が使われ、もう 1 つは複合型なので推論されます。

    [HttpPost]
    public IActionResult Action2(Product product, [FromBody] Order order)
    
  • 両方で [FromBody] 属性が使われます。

    [HttpPost]
    public IActionResult Action3([FromBody] Product product, [FromBody] Order order)
    

推論規則を無効にする

バインディング ソースの推論を無効にするには、SuppressInferBindingSourcesForParameterstrue に設定します。

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

マルチパート/フォーム データ要求の推論

[ApiController] 属性を設定すると、IFormFile および IFormFileCollection 型のアクション パラメーターに対して推論規則が適用されます。 multipart/form-data 要求コンテンツ タイプは、これらの種類に対して推論されます。

既定の動作を無効にするには、SuppressConsumesConstraintForFormFileParameters プロパティを true に設定します。

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

エラー状態コードに関する問題の詳細

MVC によってエラー結果 (状態コードが 400 以降の結果) が ProblemDetails による結果に変換されます。 ProblemDetails 型は、HTTP 応答でコンピューターが判読できるエラーの詳細を提供するための RFC 7807 仕様に基づきます。

コントローラー アクションで次のコードがあるとします。

if (pet == null)
{
    return NotFound();
}

NotFound メソッドにより、ProblemDetails 本文を使用して HTTP 404 ステータス コードが生成されます。 次に例を示します。

{
  type: "https://tools.ietf.org/html/rfc7231#section-6.5.4",
  title: "Not Found",
  status: 404,
  traceId: "0HLHLV31KRN83:00000001"
}

ProblemDetails 応答を無効にする

SuppressMapClientErrors プロパティが true に設定されている場合、エラー状態コード用の ProblemDetails の自動作成は無効になります。

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

[Consumes] 属性を使ってサポートされる要求のコンテンツの種類を定義する

既定では、アクションでは使用可能な要求のコンテンツの種類がすべてサポートされます。 たとえば、アプリが JSON と XML の入力フォーマッタを両方サポートするように構成されている場合、アクションでは、application/jsonapplication/xml を含む複数のコンテンツの種類がサポートされます。

[Consumes] 属性を使用すると、アクションでサポートされる要求のコンテンツの種類を制限できます。 1 つ以上のコンテンツの種類を指定して、アクションまたはコントローラーに [Consumes] 属性を適用します。

[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)

上記のコードでは、CreateProduct アクションでコンテンツの種類 application/xml が指定されています。 このアクションにルーティングされる要求では、Content-Type ヘッダーに application/xml を指定する必要があります。 Content-Type ヘッダーに application/xml を指定していない要求では、415 Unsupported Media Type 応答が発生します。

また、[Consumes] 属性を使用すると、種類の制約を適用することによって、受信要求のコンテンツの種類に基づいてアクションの選択に影響を与えることができます。 次に例を示します。

[ApiController]
[Route("api/[controller]")]
public class ConsumesController : ControllerBase
{
    [HttpPost]
    [Consumes("application/json")]
    public IActionResult PostJson(IEnumerable<int> values) =>
        Ok(new { Consumes = "application/json", Values = values });

    [HttpPost]
    [Consumes("application/x-www-form-urlencoded")]
    public IActionResult PostForm([FromForm] IEnumerable<int> values) =>
        Ok(new { Consumes = "application/x-www-form-urlencoded", Values = values });
}

上記のコードでは、ConsumesControllerhttps://localhost:5001/api/Consumes の URL に送信された要求を処理するように構成されています。 コントローラーの両方のアクション PostJsonPostForm では、同じ URL の POST 要求が処理されます。 種類の制約を適用する [Consumes] 属性がなかった場合は、あいまい一致の例外がスローされます。

[Consumes] 属性は両方のアクションに適用されます。 PostJson アクションでは、Content-Type ヘッダーに application/json を指定して送信された要求が処理されます。 PostForm アクションでは、Content-Type ヘッダーに application/x-www-form-urlencoded を指定して送信された要求が処理されます。

その他の技術情報

ASP.NET Core では、C# を使った RESTful サービス (別名: Web API) の作成がサポートされています。 要求を処理するために、Web API ではコントローラーを使用します。 Web API の "コントローラー" は ControllerBase から派生するクラスです。 この記事では、コントローラーを使って Web API 要求を処理する方法について説明します。

サンプル コードを表示またはダウンロードします。 (ダウンロード方法)。

ControllerBase クラス

Web API は、ControllerBase から派生した 1 つ以上のコントローラー クラスで構成されます。 Web API のプロジェクト テンプレートでは、スターター コントローラーが提供されます。

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

Controller クラスから派生させて Web API のコントローラーを作成しないでください。 ControllerBase から派生した Controller にはビューのサポートが追加されるため、これは Web API 要求ではなく Web ページを処理するためのものです。 このルールには例外があります。ビューと Web API の両方で同じコントローラーを使うことを計画している場合は、Controller から派生させます。

ControllerBase クラスには、HTTP 要求の処理に役立つプロパティとメソッドが多数用意されています。 たとえば、ControllerBase.CreatedAtAction では状態コード 201 が返されます。

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

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

次に、ControllerBase に用意されているメソッドの例をさらにいくつか示します。

メソッド メモ
BadRequest 400 状態コードを返します。
NotFound 404 状態コードを返します。
PhysicalFile ファイルを返します。
TryUpdateModelAsync モデル バインドを呼び出します。
TryValidateModel モデル検証を呼び出します。

使用可能なすべてのメソッドとプロパティの一覧については、「ControllerBase」を参照してください。

属性

Microsoft.AspNetCore.Mvc 名前空間には、Web API のコントローラーとアクション メソッドの動作の構成に使用できる属性が用意されています。 次の例では、属性を使って、サポート対象の HTTP アクション動詞と、返却される可能性がある既知の HTTP ステータス コードを指定します。

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

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

次に、使用できる属性の例をさらにいくつか示します。

属性 メモ
[Route] コントローラーまたはアクションの URL パターンを指定します。
[Bind] モデル バインドのために含めるプレフィックスとプロパティを指定します。
[HttpGet] HTTP GET アクション動詞をサポートするアクションを特定します。
[Consumes] アクションが受け取るデータ型を指定します。
[Produces] アクションによって返すデータ型を指定します。

使用可能な属性を含む一覧については、Microsoft.AspNetCore.Mvc 名前空間をご覧ください。

ApiController 属性

[ApiController] 属性をコントローラー クラスに適用して、次の厳格な、API に固有の動作を有効にできます。

特定のコントローラーにおける属性

プロジェクト テンプレートからの次の例のように、[ApiController] 属性は特定のコントローラーに適用できます。

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

複数のコントローラーにおける属性

複数のコントローラーでこの属性を使う方法の 1 つは、[ApiController] 属性で注釈を付けたカスタム基本コントローラー クラスを作成することです。 次は、カスタム基底クラスとそこから派生したコントローラーを示す例です。

[ApiController]
public class MyControllerBase : ControllerBase
{
}
[Produces(MediaTypeNames.Application.Json)]
[Route("[controller]")]
public class PetsController : MyControllerBase

アセンブリにおける属性

アセンブリには、[ApiController] 属性を適用できます。 この方法での注釈では、アセンブリ内のすべてのコントローラーに Web API の動作が適用されます。 個別のコントローラーを除外する方法はありません。 アセンブリ レベルの属性を Startup クラスを囲む名前空間宣言に適用します。

[assembly: ApiController]
namespace WebApiSample
{
    public class Startup
    {
        ...
    }
}

属性ルーティング要件

[ApiController] 属性では、属性ルーティング要件が作成されます。 次に例を示します。

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

Startup.ConfigureUseEndpointsUseMvc、または UseMvcWithDefaultRoute で定義された規則ルート経由でアクションにアクセスすることはできません。

自動的な HTTP 400 応答

[ApiController] 属性により、モデル検証エラーが発生すると HTTP 400 応答が自動的にトリガーされます。 その結果、アクション メソッド内の次のコードは不要になります。

if (!ModelState.IsValid)
{
    return BadRequest(ModelState);
}

ASP.NET Core MVC では、ModelStateInvalidFilter アクション フィルターの使用により前のチェックが行われます。

既定の BadRequest 応答

次の要求本文は、シリアル化された型の例です。

{
  "": [
    "A non-empty request body is required."
  ]
}

HTTP 400 応答に対する既定の応答の種類は ValidationProblemDetails です。 次の要求本文は、シリアル化された型の例です。

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "|7fb5e16a-4c8f23bbfc974667.",
  "errors": {
    "": [
      "A non-empty request body is required."
    ]
  }
}

ValidationProblemDetails 型:

  • Web API 応答でエラーを指定するための、コンピューターが判読できる形式を提供します。
  • RFC 7807 仕様に準拠しています。

自動とカスタムの応答を一貫させるには、BadRequest ではなく ValidationProblem メソッドを呼び出します。 ValidationProblemValidationProblemDetails オブジェクトと、自動的な応答を返します。

自動的な 400 応答を記録する

自動的な 400 応答をログに記録するには、InvalidModelStateResponseFactory デリゲート プロパティを設定して、Startup.ConfigureServices でカスタム処理を実行します。 既定では、InvalidModelStateResponseFactory では、ProblemDetailsFactory を使用して ValidationProblemDetails のインスタンスを作成します。

次の例では、ILogger<TCategoryName> のインスタンスを取得して、自動的な 400 応答に関する情報をログに記録する方法を示しています。

services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        // To preserve the default behavior, capture the original delegate to call later.
        var builtInFactory = options.InvalidModelStateResponseFactory;

        options.InvalidModelStateResponseFactory = context =>
        {
            var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<Startup>>();

            // Perform logging here.
            // ...

            // Invoke the default behavior, which produces a ValidationProblemDetails response.
            // To produce a custom response, return a different implementation of IActionResult instead.
            return builtInFactory(context);
        };
    });

自動的な 400 応答を無効にする

自動的な 400 の動作を無効にするには、SuppressModelStateInvalidFilter プロパティを true に設定します。 Startup.ConfigureServices で次の強調表示されたコードを追加します。

services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
        options.DisableImplicitFromServicesParameters = true;
    });

バインディング ソース パラメーター推論

バインディング ソース属性では、アクション パラメーターの値が存在する場所が定義されます。 次のバインディング ソース属性が存在します。

属性 バインド ソース
[FromBody] 要求本文
[FromForm] 要求本文内のフォーム データ
[FromHeader] 要求ヘッダー
[FromQuery] 要求のクエリ文字列パラメーター
[FromRoute] 現在の要求からのルート データ
[FromServices] アクション パラメーターとして挿入される要求サービス

警告

値に %2f (つまり、/) が含まれる可能性がある場合は、[FromRoute] を使用しないでください。 %2f/ にエスケープ解除されません。 値に %2f が含まれる可能性がある場合は、[FromQuery] を使用してください。

[ApiController] 属性や [FromQuery] などのバインディング ソース属性がない場合は、ASP.NET Core ランタイムにより複合オブジェクト モデル バインダーの使用が試行されます。 複合オブジェクト モデル バインダーでは、値プロバイダーから定義された順序でデータを取得します。

次の例では、discontinuedOnly パラメーター値が要求 URL のクエリ文字列に指定されていることが [FromQuery] によって示されています。

[HttpGet]
public ActionResult<List<Product>> Get(
    [FromQuery] bool discontinuedOnly = false)
{
    List<Product> products = null;

    if (discontinuedOnly)
    {
        products = _productsInMemoryStore.Where(p => p.IsDiscontinued).ToList();
    }
    else
    {
        products = _productsInMemoryStore;
    }

    return products;
}

[ApiController] 属性により、アクション パラメーターの既定のデータ ソースに対する推論規則が適用されます。 これらの規則により、アクション パラメーターに属性を適用することで手動でバインディング ソースを特定する必要がなくなります。 バインディング ソースの推論規則は、次のように動作します。

  • [FromBody] は複合型パラメーターに対して推論されます。 [FromBody] 推論規則に対する例外は、IFormCollectionCancellationToken など、特殊な意味を持つ組み込みの複合型です。 バインディング ソース推論コードでは、そのような特殊な型は無視されます。
  • [FromForm]IFormFile および IFormFileCollection 型のアクション パラメーターに対して推論されます。 簡易型またはユーザー定義型に対しては推論されません。
  • [FromRoute] は、ルート テンプレート内のパラメーターと一致する任意のアクション パラメーター名に対して推論されます。 複数のルートがアクション パラメーターと一致する場合、ルート値はいずれも [FromRoute] と見なされます。
  • [FromQuery] は他の任意のアクション パラメーターに対して推論されます。

FromBody 推論に関するメモ

[FromBody] は、stringint などの単純型に対しては推論されません。 そのため、その機能が必要な場合、単純型に対しては [FromBody] 属性を使用する必要があります。

要求本文からバインドされるパラメーターがアクションに複数ある場合は、例外がスローされます。 たとえば、次のアクション メソッドのシグネチャはすべて例外の原因となります。

  • 複合型であるため、両方に対して [FromBody] が推論されます。

    [HttpPost]
    public IActionResult Action1(Product product, Order order)
    
  • 1 つには [FromBody] 属性が使われ、もう 1 つは複合型なので推論されます。

    [HttpPost]
    public IActionResult Action2(Product product, [FromBody] Order order)
    
  • 両方で [FromBody] 属性が使われます。

    [HttpPost]
    public IActionResult Action3([FromBody] Product product, [FromBody] Order order)
    

推論規則を無効にする

バインディング ソースの推論を無効にするには、SuppressInferBindingSourcesForParameterstrue に設定します。 Startup.ConfigureServices に次のコードを追加します。

services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
        options.DisableImplicitFromServicesParameters = true;
    });

マルチパート/フォーム データ要求の推論

[ApiController] 属性を設定すると、IFormFile および IFormFileCollection 型のアクション パラメーターに対して推論規則が適用されます。 multipart/form-data 要求コンテンツ タイプは、これらの種類に対して推論されます。

既定の動作を無効にするには、Startup.ConfigureServicesSuppressConsumesConstraintForFormFileParameters プロパティを true に設定します。

services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
        options.DisableImplicitFromServicesParameters = true;
    });

エラー状態コードに関する問題の詳細

MVC によってエラー結果 (状態コードが 400 以降の結果) が ProblemDetails による結果に変換されます。 ProblemDetails 型は、HTTP 応答でコンピューターが判読できるエラーの詳細を提供するための RFC 7807 仕様に基づきます。

コントローラー アクションで次のコードがあるとします。

if (pet == null)
{
    return NotFound();
}

NotFound メソッドにより、ProblemDetails 本文を使用して HTTP 404 ステータス コードが生成されます。 次に例を示します。

{
  type: "https://tools.ietf.org/html/rfc7231#section-6.5.4",
  title: "Not Found",
  status: 404,
  traceId: "0HLHLV31KRN83:00000001"
}

ProblemDetails 応答を無効にする

SuppressMapClientErrors プロパティが true に設定されている場合、エラー状態コード用の ProblemDetails の自動作成は無効になります。 Startup.ConfigureServices に次のコードを追加します。

services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
        options.DisableImplicitFromServicesParameters = true;
    });

[Consumes] 属性を使ってサポートされる要求のコンテンツの種類を定義する

既定では、アクションでは使用可能な要求のコンテンツの種類がすべてサポートされます。 たとえば、アプリが JSON と XML の入力フォーマッタを両方サポートするように構成されている場合、アクションでは、application/jsonapplication/xml を含む複数のコンテンツの種類がサポートされます。

[Consumes] 属性を使用すると、アクションでサポートされる要求のコンテンツの種類を制限できます。 1 つ以上のコンテンツの種類を指定して、アクションまたはコントローラーに [Consumes] 属性を適用します。

[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)

上記のコードでは、CreateProduct アクションでコンテンツの種類 application/xml が指定されています。 このアクションにルーティングされる要求では、Content-Type ヘッダーに application/xml を指定する必要があります。 Content-Type ヘッダーに application/xml を指定していない要求では、415 Unsupported Media Type 応答が発生します。

また、[Consumes] 属性を使用すると、種類の制約を適用することによって、受信要求のコンテンツの種類に基づいてアクションの選択に影響を与えることができます。 次に例を示します。

[ApiController]
[Route("api/[controller]")]
public class ConsumesController : ControllerBase
{
    [HttpPost]
    [Consumes("application/json")]
    public IActionResult PostJson(IEnumerable<int> values) =>
        Ok(new { Consumes = "application/json", Values = values });

    [HttpPost]
    [Consumes("application/x-www-form-urlencoded")]
    public IActionResult PostForm([FromForm] IEnumerable<int> values) =>
        Ok(new { Consumes = "application/x-www-form-urlencoded", Values = values });
}

上記のコードでは、ConsumesControllerhttps://localhost:5001/api/Consumes の URL に送信された要求を処理するように構成されています。 コントローラーの両方のアクション PostJsonPostForm では、同じ URL の POST 要求が処理されます。 種類の制約を適用する [Consumes] 属性がなかった場合は、あいまい一致の例外がスローされます。

[Consumes] 属性は両方のアクションに適用されます。 PostJson アクションでは、Content-Type ヘッダーに application/json を指定して送信された要求が処理されます。 PostForm アクションでは、Content-Type ヘッダーに application/x-www-form-urlencoded を指定して送信された要求が処理されます。

その他の技術情報

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase

Controller クラスから派生させて Web API のコントローラーを作成しないでください。 ControllerBase から派生した Controller にはビューのサポートが追加されるため、これは Web API 要求ではなく Web ページを処理するためのものです。 このルールには例外があります。ビューと Web API の両方で同じコントローラーを使うことを計画している場合は、Controller から派生させます。 ControllerBase クラスには、HTTP 要求の処理に役立つプロパティとメソッドが多数用意されています。 たとえば、ControllerBase.CreatedAtAction では状態コード 201 が返されます。

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

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

次に、ControllerBase に用意されているメソッドの例をさらにいくつか示します。

メソッド メモ
BadRequest 400 状態コードを返します。
NotFound 404 状態コードを返します。
PhysicalFile ファイルを返します。
TryUpdateModelAsync モデル バインドを呼び出します。
TryValidateModel モデル検証を呼び出します。

使用可能なすべてのメソッドとプロパティの一覧については、「ControllerBase」を参照してください。

属性

Microsoft.AspNetCore.Mvc 名前空間には、Web API のコントローラーとアクション メソッドの動作の構成に使用できる属性が用意されています。 次の例では、属性を使って、サポート対象の HTTP アクション動詞と、返却される可能性がある既知の HTTP ステータス コードを指定します。

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

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

次に、使用できる属性の例をさらにいくつか示します。

属性 メモ
[Route] コントローラーまたはアクションの URL パターンを指定します。
[Bind] モデル バインドのために含めるプレフィックスとプロパティを指定します。
[HttpGet] HTTP GET アクション動詞をサポートするアクションを特定します。
[Consumes] アクションが受け取るデータ型を指定します。
[Produces] アクションによって返すデータ型を指定します。

使用可能な属性を含む一覧については、Microsoft.AspNetCore.Mvc 名前空間をご覧ください。

ApiController 属性

[ApiController] 属性をコントローラー クラスに適用して、次の厳格な、API に固有の動作を有効にできます。

特定のコントローラーにおける属性

プロジェクト テンプレートからの次の例のように、[ApiController] 属性は特定のコントローラーに適用できます。

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase

複数のコントローラーにおける属性

複数のコントローラーでこの属性を使う方法の 1 つは、[ApiController] 属性で注釈を付けたカスタム基本コントローラー クラスを作成することです。 次は、カスタム基底クラスとそこから派生したコントローラーを示す例です。

[ApiController]
public class MyControllerBase : ControllerBase
{
}
[Produces(MediaTypeNames.Application.Json)]
[Route("api/[controller]")]
public class PetsController : MyControllerBase

アセンブリにおける属性

互換性バージョンが 2.2 以降に設定されている場合は、[ApiController] 属性をアセンブリに適用できます。 この方法での注釈では、アセンブリ内のすべてのコントローラーに Web API の動作が適用されます。 個別のコントローラーを除外する方法はありません。 アセンブリ レベルの属性を Startup クラスを囲む名前空間宣言に適用します。

[assembly: ApiController]
namespace WebApiSample
{
    public class Startup
    {
        ...
    }
}

属性ルーティング要件

[ApiController] 属性では、属性ルーティング要件が作成されます。 次に例を示します。

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase

Startup.ConfigureUseMvc または UseMvcWithDefaultRoute で定義された規則ルート経由でアクションにアクセスすることはできません。

自動的な HTTP 400 応答

[ApiController] 属性により、モデル検証エラーが発生すると HTTP 400 応答が自動的にトリガーされます。 その結果、アクション メソッド内の次のコードは不要になります。

if (!ModelState.IsValid)
{
    return BadRequest(ModelState);
}

ASP.NET Core MVC では、ModelStateInvalidFilter アクション フィルターの使用により前のチェックが行われます。

既定の BadRequest 応答

2\.1 の互換性バージョンを使う場合、HTTP 400 応答に対する既定の応答の種類は SerializableError です。 次の要求本文は、シリアル化された型の例です。

{
  "": [
    "A non-empty request body is required."
  ]
}

2\.2 以降の互換性バージョンを使う場合、HTTP 400 応答に対する既定の応答の種類は ValidationProblemDetails です。 次の要求本文は、シリアル化された型の例です。

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "|7fb5e16a-4c8f23bbfc974667.",
  "errors": {
    "": [
      "A non-empty request body is required."
    ]
  }
}

ValidationProblemDetails 型:

  • Web API 応答でエラーを指定するための、コンピューターが判読できる形式を提供します。
  • RFC 7807 仕様に準拠しています。

自動とカスタムの応答を一貫させるには、BadRequest ではなく ValidationProblem メソッドを呼び出します。 ValidationProblemValidationProblemDetails オブジェクトと、自動的な応答を返します。

自動的な 400 応答を記録する

How to log automatic 400 responses on model validation error (dotnet/AspNetCore.Docs #12157)」(モデル検証エラー時に自動的な 400 応答を記録する方法) を参照してください。

自動的な 400 応答を無効にする

自動的な 400 の動作を無効にするには、SuppressModelStateInvalidFilter プロパティを true に設定します。 Startup.ConfigureServices で次の強調表示されたコードを追加します。

services.Configure<ApiBehaviorOptions>(options =>
{
    options.SuppressConsumesConstraintForFormFileParameters = true;
    options.SuppressInferBindingSourcesForParameters = true;
    options.SuppressModelStateInvalidFilter = true;
});

バインディング ソース パラメーター推論

バインディング ソース属性では、アクション パラメーターの値が存在する場所が定義されます。 次のバインディング ソース属性が存在します。

属性 バインド ソース
[FromBody] 要求本文
[FromForm] 要求本文内のフォーム データ
[FromHeader] 要求ヘッダー
[FromQuery] 要求のクエリ文字列パラメーター
[FromRoute] 現在の要求からのルート データ
[FromServices] アクション パラメーターとして挿入される要求サービス

警告

値に %2f (つまり、/) が含まれる可能性がある場合は、[FromRoute] を使用しないでください。 %2f/ にエスケープ解除されません。 値に %2f が含まれる可能性がある場合は、[FromQuery] を使用してください。 [ApiController] 属性や [FromQuery] などのバインディング ソース属性がない場合は、ASP.NET Core ランタイムにより複合オブジェクト モデル バインダーの使用が試行されます。 複合オブジェクト モデル バインダーでは、値プロバイダーから定義された順序でデータを取得します。

次の例では、discontinuedOnly パラメーター値が要求 URL のクエリ文字列に指定されていることが [FromQuery] によって示されています。

[HttpGet]
public ActionResult<List<Product>> Get(
    [FromQuery] bool discontinuedOnly = false)
{
    List<Product> products = null;

    if (discontinuedOnly)
    {
        products = _productsInMemoryStore.Where(p => p.IsDiscontinued).ToList();
    }
    else
    {
        products = _productsInMemoryStore;
    }

    return products;
}

[ApiController] 属性により、アクション パラメーターの既定のデータ ソースに対する推論規則が適用されます。 これらの規則により、アクション パラメーターに属性を適用することで手動でバインディング ソースを特定する必要がなくなります。 バインディング ソースの推論規則は、次のように動作します。

  • [FromBody] は複合型パラメーターに対して推論されます。 [FromBody] 推論規則に対する例外は、IFormCollectionCancellationToken など、特殊な意味を持つ組み込みの複合型です。 バインディング ソース推論コードでは、そのような特殊な型は無視されます。
  • [FromForm]IFormFile および IFormFileCollection 型のアクション パラメーターに対して推論されます。 簡易型またはユーザー定義型に対しては推論されません。
  • [FromRoute] は、ルート テンプレート内のパラメーターと一致する任意のアクション パラメーター名に対して推論されます。 複数のルートがアクション パラメーターと一致する場合、ルート値はいずれも [FromRoute] と見なされます。
  • [FromQuery] は他の任意のアクション パラメーターに対して推論されます。

FromBody 推論に関するメモ

[FromBody] は、stringint などの単純型に対しては推論されません。 そのため、その機能が必要な場合、単純型に対しては [FromBody] 属性を使用する必要があります。

要求本文からバインドされるパラメーターがアクションに複数ある場合は、例外がスローされます。 たとえば、次のアクション メソッドのシグネチャはすべて例外の原因となります。

  • 複合型であるため、両方に対して [FromBody] が推論されます。

    [HttpPost]
    public IActionResult Action1(Product product, Order order)
    
  • 1 つには [FromBody] 属性が使われ、もう 1 つは複合型なので推論されます。

    [HttpPost]
    public IActionResult Action2(Product product, [FromBody] Order order)
    
  • 両方で [FromBody] 属性が使われます。

    [HttpPost]
    public IActionResult Action3([FromBody] Product product, [FromBody] Order order)
    

注意

ASP.NET Core 2.1 では、リストや配列などのコレクション型パラメーターが誤って [FromQuery] と推論されます。 これらのパラメーターを要求本文からバインドする場合は、[FromBody] 属性を使用する必要があります。 この動作は ASP.NET Core 2.2 以降で修正されており、既定でコレクション型パラメーターが本文からバインドされることが推論されます。

推論規則を無効にする

バインディング ソースの推論を無効にするには、SuppressInferBindingSourcesForParameterstrue に設定します。 Startup.ConfigureServices に次のコードを追加します。

services.Configure<ApiBehaviorOptions>(options =>
{
    options.SuppressConsumesConstraintForFormFileParameters = true;
    options.SuppressInferBindingSourcesForParameters = true;
    options.SuppressModelStateInvalidFilter = true;
});

マルチパート/フォーム データ要求の推論

[ApiController] 属性を設定すると、IFormFile および IFormFileCollection 型のアクション パラメーターに対して推論規則が適用されます。 multipart/form-data 要求コンテンツ タイプは、これらの種類に対して推論されます。 既定の動作を無効にするには、Startup.ConfigureServicesSuppressConsumesConstraintForFormFileParameters プロパティを true に設定します。

services.Configure<ApiBehaviorOptions>(options =>
{
    options.SuppressConsumesConstraintForFormFileParameters = true;
    options.SuppressInferBindingSourcesForParameters = true;
    options.SuppressModelStateInvalidFilter = true;
});

エラー状態コードに関する問題の詳細

互換性バージョンが 2.2 以上である場合、MVC によってエラー結果 (状態コードが 400 以上の結果) が ProblemDetails を含む結果に変換されます。 ProblemDetails 型は、HTTP 応答でコンピューターが判読できるエラーの詳細を提供するための RFC 7807 仕様に基づきます。 コントローラー アクションで次のコードがあるとします。

if (pet == null)
{
    return NotFound();
}

NotFound メソッドにより、ProblemDetails 本文を使用して HTTP 404 ステータス コードが生成されます。 次に例を示します。

{
  type: "https://tools.ietf.org/html/rfc7231#section-6.5.4",
  title: "Not Found",
  status: 404,
  traceId: "0HLHLV31KRN83:00000001"
}

ProblemDetails 応答を無効にする

SuppressMapClientErrors プロパティが true に設定されている場合、エラー状態コード用の ProblemDetails の自動作成は無効になります。 Startup.ConfigureServices に次のコードを追加します。

[Consumes] 属性を使ってサポートされる要求のコンテンツの種類を定義する

既定では、アクションでは使用可能な要求のコンテンツの種類がすべてサポートされます。 たとえば、アプリが JSON と XML の入力フォーマッタを両方サポートするように構成されている場合、アクションでは、application/jsonapplication/xml を含む複数のコンテンツの種類がサポートされます。

[Consumes] 属性を使用すると、アクションでサポートされる要求のコンテンツの種類を制限できます。 1 つ以上のコンテンツの種類を指定して、アクションまたはコントローラーに [Consumes] 属性を適用します。

[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)

上記のコードでは、CreateProduct アクションでコンテンツの種類 application/xml が指定されています。 このアクションにルーティングされる要求では、Content-Type ヘッダーに application/xml を指定する必要があります。 Content-Type ヘッダーに application/xml を指定していない要求では、415 Unsupported Media Type 応答が発生します。 また、[Consumes] 属性を使用すると、種類の制約を適用することによって、受信要求のコンテンツの種類に基づいてアクションの選択に影響を与えることができます。 次に例を示します。

[ApiController]
[Route("api/[controller]")]
public class ConsumesController : ControllerBase
{
    [HttpPost]
    [Consumes("application/json")]
    public IActionResult PostJson(IEnumerable<int> values) =>
        Ok(new { Consumes = "application/json", Values = values });

    [HttpPost]
    [Consumes("application/x-www-form-urlencoded")]
    public IActionResult PostForm([FromForm] IEnumerable<int> values) =>
        Ok(new { Consumes = "application/x-www-form-urlencoded", Values = values });
}

上記のコードでは、ConsumesControllerhttps://localhost:5001/api/Consumes の URL に送信された要求を処理するように構成されています。 コントローラーの両方のアクション PostJsonPostForm では、同じ URL の POST 要求が処理されます。 種類の制約を適用する [Consumes] 属性がなかった場合は、あいまい一致の例外がスローされます。 [Consumes] 属性は両方のアクションに適用されます。 PostJson アクションでは、Content-Type ヘッダーに application/json を指定して送信された要求が処理されます。 PostForm アクションでは、Content-Type ヘッダーに application/x-www-form-urlencoded を指定して送信された要求が処理されます。

その他の技術情報