ASP.NET Web API で GET クエリ文字列パラメーターをモデル バインドする

ASP.NET MVC 4 と共に提供される ASP.NET Web API は、バックエンドで Entity Framework などと組み合わせつつ、軽量な HTTP サービスを構築するのに向いたフレームワークです。

※ Web API については下記などをご参照ください。

本日(7/10)時点では、ASP.NET MVC 4 の RC 版をお使いいただくことができますが、Beta 版から RC 版にかけて Web API の実装は比較的大きく修正がおこなわれています。今回は、その中のひとつ、モデルバインディングに関する変更点をご紹介します。

● モデル バインディング

ASP.NET MVC の特徴的な機能であるモデルバインダーを Web API でも利用できます。HTTP GET のリクエストとして URI よりパラメーターを受け取る場合、ルーティングで定義した URI のルート パラメーター、またはクエリ文字列パラメーターから取得でき、それらをコントローラーのアクション メソッドのパラメーターにバインドできます(モデル バインディング)。既定のモデル バインダーでも、プリミティブ型、複合型、コレクション、ディクショナリなどへ容易にバインド可能です。

例えば、下記のようなアクションメソッドで、パラメーター: int id を使用する場合を見てみましょう。

    1: public class HomeController : Controller
    2: {
    3:     public ActionResult ShowId(int id)
    4:     {
    5:         return Content(id.ToString());
    6:     }
    7: }

ルーティングは規定で下記のとおり id がルート パラメータに含まれています。

    1: routes.MapRoute(
    2:     name: "Default",
    3:     url: "{controller}/{action}/{id}",
    4:     defaults: new { controller = "Home",
    5:                     action = "Index",
    6:                     id = UrlParameter.Optional }
    7: );

これにより、下記のように URI に含めた “7” が ShowId の INT 型パラメーター id にバインドされます。

image

また、GET のクエリー文字列としてもパラメーターを付加することができます。

image

さらに、下記のようにモデル クラスを使って複合型をバインドすることもできます。

    1: public class ValueModel
    2: {
    3:     public string Value1 { get; set; }
    4:     public string Value2 { get; set; }
    5: }
    6:  
    7: public class HomeController : Controller
    8: {
    9:     public ActionResult ShowId(int id, ValueModel val)
   10:     {
   11:         return Content(val.Value1 + "-" + val.Value2);
   12:     }
   13: }

image

 

ここまでは、ASP.NET MVC フレームワークで提供される Controller クラスによる基本的なモデルバインドの動作です。

では、Web API ではどうでしょうか?

● Web API におけるモデル バインディング

上記と同じ処理を Web API でも試してみます。

    1: public class ValuesController : ApiController
    2: {
    3:     // GET api/values
    4:     public ValueModel Get(ValueModel val)
    5:     {
    6:         return val;
    7:     }
    8: }

Fidder を使って API を呼び出すと下記のようにエラー 500 となってしまいます。

image

image

これは、Web API のコントローラーのベースクラスが ApiController で、ASP.NET MVC の Controller とは実装が異なっていることによります。

この ApiController クラスでは HTTP リクエストをラップする Request オブジェクトが System.Net.Http.HttpRequestMessage クラスになり、これを通して受け取るパラメーターについては URI から取得するか、メッセージ Body から取得するかの指定が必要となっているためです。これを指定する属性としては、下記の2つが用意されています。

この属性を使って、先の Web API の実装コードを書き換えたのが下記となります。

    1: public class ValuesController : ApiController
    2: {
    3:     // GET api/values
    4:     public ValueModel Get([FromUri]ValueModel val)
    5:     {
    6:         return val;
    7:     }
    8:  
    9:     // GET api/values/5
   10:     public ValueModel Get(int id, [FromUri]ValueModel val)
   11:     {
   12:         return val;
   13:     }
   14:  
   15:     // POST api/values
   16:     public void Post([FromBody]ValueModel val)
   17:     {
   18:     }
   19:  
   20:     // PUT api/values/5
   21:     public void Put(int id, [FromBody]ValueModel val)
   22:     {
   23:     }
   24: }

この実行結果は下記のとおりです。GET のクエリー文字列として渡したパラメーターが ValueModel にバインドされ、正しく処理されていることがわかります。

image 

◆◆◆

以上のように、ASP.NET MVC の様々な機能を継承しつつ、より洗練されたフレームワークに仕上がってきている ASP.NET Web API は、MVC 4 とともにもう間もなく RTW となります。お楽しみに!