ASP.NET Coreのバリデーションエラー自動応答
ASP.NET Core にはモデルをバリデーションする機能があります。 ASP.NET Core 2.1 では毎回記述していて面倒だったバリデーションエラーのレスポンスを返す処理を自動で返せるようになりました。 ASP.NET Core 2.2 ではこのレスポンス形式に変更が入ったようですので、バリデーションエラーの自動応答とレスポンスの変更点の2つを確認します。
バリデーションエラーの自動応答
まずは ASP.NET Core 2.1 で追加されたバリデーションエラーの自動応答を試してみます。バリデーションの自動応答とは、リクエストされた内容がバリデーション違反していたときに、今までだったらこのようなコードを記述していたところを ASP.NET Core フレームワークが自動でステータスコード 400 のレスポンスを返してくれる機能です。
[HttpPost] public ActionResult Post([FromBody] string value) { // ModelStateの状態をチェックして if (!this.ModelState.IsValid) { // バリデーション違反状態だったら400レスポンスを返す return this.BadRequest(this.ModelState); } return Ok(); }
バリデーションエラーの自動応答を利用するには、
- Startup の ConfigureServices で MVC 追加時に
SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
を設定する ApiControllerAttribute
をコントローラークラスに付与する
この2つの設定が必要です。 VisualStudio や Rider を使用して ASP.NET Core 2.1 のプロジェクトを新規で作成すると1つめの MVC 互換バージョン設定は既定で入っています。ですので、必要なのはコントローラーに ApiController
属性を付与することだけです。
※ MVC 互換バージョン設定
public void ConfigureServices(IServiceCollection services) { services .AddMvc() .SetCompatibilityVersion(CompatibilityVersion.Version_2_1); }
API 用のコントローラーを作成するには ControllerBase
または Controller
を継承したクラスを作成し、 API メソッドを定義します。 ControllerBase
と Controller
の違いは MVC の View 機能が実装されているかで、 ControllerBase
には View の機能がありません。
GET の API でクエリストリングに対してバリデーションを設定するには次の様になります。
[Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase { [HttpGet("sample")] public ActionResult GetSample([Required] string keyword, [Range(1, 10000)] int count = 1000) { return Ok(); } }
この API に対して api/values/sample?count=100000
でアクセスすると、必須バリデーションも数値のレンジバリデーションにも違反するため2つのバリデーションエラーが自動で応答されます。
{ "count": [ "The field count must be between 1 and 10000." ], "keyword": [ "The keyword field is required." ] }
なおこのレスポンスをコントローラーから直接返すには BadRequest
を使用します。
[HttpGet("sample")] public ActionResult GetSample([Required] string keyword, [Range(1, 10000)] int count = 1000) { if (!this.ModelState.IsValid) { return this.BadRequest(this.ModelState); } ... }
ASP.NET Core 2.2 でのレスポンス形式変更
先のコントローラーからのバリデーション自動応答を ASP.NET Core 2.2 環境で試すと次のような違う結果が返ってきます。
{ "errors": { "count": [ "The field count must be between 1 and 10000." ], "keyword": [ "The keyword field is required." ] }, "title": "One or more validation errors occurred.", "status": 400, "traceId": "0HLJ9DK5VK4UQ:00000003" }
直接エラーのオブジェクトが返ってくる形式から、エラータイトルやステータスコードまで含まれるようになり分かりやすくなりました。コントローラーから直接このモデルを返すには ValidationProblem
を使用します。
[HttpGet("sample")] public ActionResult GetSample([Required] string keyword, [Range(1, 10000)] int count = 1000) { if (!this.ModelState.IsValid) { return this.ValidationProblem(this.ModelState); } ... }
2.2 環境で自動応答のモデルを変更したくない場合は Startup.ConfigureServices
で API の動作設定を変更し、 SuppressModelStateInvalidFilter
に true
を設定します。
public void ConfigureServices(IServiceCollection services) { services .AddMvc() .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) .ConfigureApiBehaviorOptions(options => { options.SuppressModelStateInvalidFilter = true; }); }