連載
» 2013年12月16日 11時57分 UPDATE

連載:ASP.NET Web API 入門:第4回 ルーティングの設定/検証/例外処理 (2/3)

[矢後比呂加,著]

DataAnnotations属性を使用した検証

 ASP.NET Web APIでは、HTTPリクエストの内容を検証するために、DataAnnotations属性(System.ComponentModel.DataAnnotations名前空間にある属性)を使用した検証機能が提供されている。アクションメソッドの実行前、モデルバインド時に、属性を基に検証処理が走る。検証結果は、ApiControllerクラスのModelStateプロパティ(System.Web.Http.ModelBinding名前空間のModelStateDictionaryクラス)に格納される。

 注意したいのは、検証に失敗した場合に自動でクライアントにエラー情報を返す、といった機能は提供されていないことだ。検証結果は開発者の手でクライアントへ返すようにコーディングを行う必要がある。

 それでは、属性による検証機能を利用し、クライアントへエラー情報を返す実装を追ってみよう。API「GET ~/api/customers/」を定義し、HTTPリクエストのクエリ文字列「name」と「year」の値に対して、検証を行うように実装する。

検証機能の実装

 まず、HTTPリクエストのクエリ文字列の値をモデルバインドでクラスのプロパティに代入させるため、リスト11のようなクラスを用意する。各プロパティにはDataAnnotations属性を付与する。

using System.ComponentModel.DataAnnotations;

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

  [Range(2000, 2013, ErrorMessage = "{0} は {1} から {2} の範囲で指定してください。")]
  public int Year { get; set; }
}

リスト11 検証を行うため、DataAnnotations属性を付与したモデルクラスのコード

 ここで簡単にリスト11で使用した属性について説明する。Required属性は値が必須であること、Range属性は値が指定した範囲(リスト11の例では2000〜2013)であることを示している。引数のErrorMessageプロパティには検証失敗時のエラーメッセージを設定できる。エラーメッセージの「{0}」にはプロパティ名が入り、「{1}」にはRange属性のコンストラクターの第1パラメーター(minimum)の値が、「{2}」には第2パラメーター(maximum)の値が代入される*5

*5 本稿執筆時点でリリースされている ASP.NET Web APIバージョン2では、次の2点の問題があるので注意。今後修正される予定だ。
・ASP.NET MVCのように項目名をDisplay属性のNameプロパティで指定できない(Display属性を付与してもエラーメッセージに反映されない)。
・モデルバインドの対象が、今回のようにBodyの値ではなくURLの値の場合は、Required属性のErrorMessageプロパティを設定してもエラーメッセージに反映されない。


 モデルバインドの対象となるクラスの用意は以上だ。次は、APIコントローラーでの実装を確認しよう。ここでは、ASP.NET Web APIのバージョン1と2の両方で実装できるコードと、バージョン2でしか実装できないコードをそれぞれ掲載する。

public class CustomersController : ApiController
{
  public HttpResponseMessage Get([FromUri]MyParameter parameter)
  {
    if (!ModelState.IsValid)
    {
      var response = Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
      return response;
    }
    return Request.CreateResponse(HttpStatusCode.OK);
  }
}

リスト12 検証失敗時に、エラー情報を返すアクションメソッドのコード例。バージョン1と2の両方で使用できる

public class CustomersController : ApiController
{
  public IHttpActionResult Get([FromUri]MyParameter parameter)
  {
    if (!ModelState.IsValid)
    {
      return BadRequest(ModelState);
    }
    return Ok();
  }
}

リスト13 検証失敗時に、エラー情報を返すアクションメソッドのコード例。バージョン2でのみ使用できる

 ASP.NET Web API 2から、アクションメソッドの戻り値にIHttpActionResultオブジェクトが指定できるようになり、ApiControllerクラスにはIHttpActionResultオブジェクトを返すためのヘルパーメソッドが多数用意されている。リスト13はそのうちのOkメソッドとBadRequestメソッドを利用したものだ。また、検証結果は、ApiControllerクラスのModelStateプロパティに格納される。もし1つでも検証に失敗した場合は、ModelState.IsValidプロパティはfalseを返すので、検証結果の成否判断に使用できる。

 リスト12と13のコード例で、クライアントへ返されるHTTPレスポンスの中身は、両方とも次の表4のとおりとなる。なお、検証失敗の例は、クエリ文字列を一切付けていないURL「~/api/customers/」で送信した場合とした。

  検証結果
  成功 失敗
ステータスコード 200 OK 400 Bad Request
Body(JSON書式の場合) (無し) {"Message":"要求は無効です。",
"ModelState":{
   "Name":["Name プロパティが必要です。"],
   "Year":["Year は 2000 〜 2013 の範囲で指定してください。"]
   }
}
表4 検証結果に成功した場合と失敗した場合の、クライアントへ返されるHTTPレスポンスの内容

 検証に失敗した場合、BodyにはModelStateプロパティ値をシリアライズしたものが格納される。また、この例ではHTTPメソッドがGETの場合を例としたが、PUTやPOSTでもモデルバインドを使用すれば、ほぼ同じように*6検証結果を得ることができる。

 全てのアクションメソッドで毎回ModelStateをチェックするコードを書くことが面倒である場合、フィルター属性を作成することで処理を1つにまとめることもできる(参考:「ASP.NET Web API でモデルバインド時検証をカスタム ActionFilter を使って実装する」)。

*6 検証対象となるNameプロパティとYearプロパティの値を、GETのクエリ文字列で送信した場合と、POSTなどのBodyで送信した場合とでは、検証失敗時のHTTPレスポンスのBodyの内容がわずかに異なるので注意。GETで送信した場合は、検証結果のキーが「Year」「Name」となっているのに対し、POSTで送信した場合はキーが「parameter.Name」「parameter.Year」と、アクションメソッドの引数の名前がプリフィックスとして付く。


 DataAnnotations属性による検証機能の解説は以上だ。次は、例外処理について解説する。

Copyright© 1999-2017 Digital Advantage Corp. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。