連載
» 2013年11月06日 13時06分 UPDATE

連載:ASP.NET Web API 入門:第3回 APIコントローラの実装方法 (2/3)

[矢後比呂加,著]

2-3 HTTPリクエストを取得する

画像:図5 HTTPリクエストの取得方法を表した概要図 図5 HTTPリクエストの取得方法を表した概要図

 アクション・メソッドにて、HTTPリクエストを取得するには、先述のとおり、アクション・メソッドに引数を定義する。大半はこの方法でよいが、実はもう1つの方法がある。それはAPIコントローラ・クラスの基底クラスであるApiControllerのRequestプロパティ(HttpRequestMessageクラス)を参照することだ。まずは、アクション・メソッドの引数よりHTTPリクエストの取得を試み、それでも不十分の場合に、ApiControllerのRequestプロパティを参照することを推奨する。

 それでは、よくある以下の項目を、アクション・メソッドの引数から取得してみよう*10

  • URLのクエリ文字列
  • URLの一部の値
  • Body値

*10アクション・メソッドの引数からHTTPリクエストを取得できる仕組みについて簡単に説明する。アクション・メソッドに引数を定義すると、ASP.NET Web APIフレームワークにより、HTTPリクエストから適切な値を引数に代入した状態で、メソッドの呼び出しが行われる。このHTTPリクエストの値を引数に代入する仕組みのことを、モデル・バインド、代入することをバインドと呼称する。


○ URLのクエリ文字列を取得する

 クエリ文字列を取得するには、クエリ文字列の名前と同じ名前である引数を、アクション・メソッドに定義する。例として、URL「~/api/cusomers/?category=name&number=1」のクエリ文字列の値を取得するには、下のリスト2のように引数を定義する。

public string Get(string category, int number) { }

リスト2 URL「~/api/cusomers/?category=name&number=1」のクエリ文字列の値を取得するためのアクション・メソッドの定義例

 引数の型は、プリミティブ型(参照:Type.IsPrimitive プロパティ)である必要がある。復合データ型(独自クラス)を定義したい場合は、属性クラスFromUriAttribute(System.Web.Http名前空間)を付与する。

 下のリスト3は、MyParameterクラス(開発者が定義する独自クラス)の各プロパティに、先ほどのURL「~/api/cusomers/?category=name&number=1」のクエリ文字列をバインドさせたいときのコードである。

public class MyParemeter
{
  public string Category { get; set; }
  public string Number { get; set; }
}

public class CustomersController : ApiController
{
  public string Get([FromUri]MyParemeter parameter) { }
}

リスト3 URL「~/api/cusomers/?category=name&number=1」のクエリ文字列を独自クラスのプロパティにバインドさせたいときのコード例

 このときの注意点として、MyParameterクラスの各プロパティの名前は、クエリ文字列の名前と同じにする必要がある(アクション・メソッドの引数の名前は何でもよい)。

○ URLの一部の値を取得する

 場合によっては、「~/api/customers/japan/tokyo」といったURLを定義して、「japan」や「tokyo」に当てはまるURLの一部をパラメータとして受け取りたいこともあるだろう。これは、ルーティングの設定にてマッピング・ルールを追加することで実現可能だ。

 例として、先ほどのURL「~/api/customers/japan/tokyo」の「japan」や「tokyo」を取得したい場合は、リスト4のようにあらかじめ記述されているルーティングの設定のコードの前に、マッピング・ルールを追加し、リスト5のようにメソッドの引数を定義する。

public static class WebApiConfig
{
  public static void Register(HttpConfiguration config)
  {
    config.Routes.MapHttpRoute(
      name: "AddressApi",
      routeTemplate: "api/address/{country}/{prefecture}", // ……?
      defaults: new { controller = "address" }
    );
    // ……省略(あらかじめ記述されているルーティングの設定)……

リスト4 URLの一部をパラメータとして受け取るためのマッピング・ルールの追加登録のコード例
あらかじめ記述されているルーティングの設定の前に、上のようにMapHttpRouteメソッドを記述する。

public class AddressController : ApiController
{
  public string Get(string country, string prefecture)
  {
    return country + prefecture;
  }
}

リスト5 追加したマッピング・ルールのパラメータを受け取るメソッド引数のコード例

 注意点は、ルーティングの設定で指定しているパラメータの名前(リスト4の「{country}」や「{prefecture}」の部分)と、アクション・メソッドの引数の名前を同じにすることである。また、クエリ文字列と同様に属性クラスFromUriAttribute(System.Web.Http名前空間)を付与することで、アクション・メソッドの引数の型に複合データ型を指定することもできる。

○ Bodyの値を取得する

 Bodyには、メッセージの本質を表す情報をある書式に変換して格納する。例えば、下の表6のように、顧客を追加するためのHTTPリクエストの場合は、追加したい顧客の情報をJSON形式などの書式で格納する。

HTTPリクエストの項目
HTTPメソッド POST
HTTPヘッダ Content-Type : application/json
Body { Name : “Taro”, Addres : “Tokyo” }(JSON形式)
表6 Bodyの値を送信するHTTPリクエストの例

 このBodyの値を取得するには、複合データ型(独自のクラス)をアクション・メソッドの引数に定義することで可能になる。

 ただし、Bodyの書式(=Content-Typeヘッダで指定される値)が、ASP.NET Web APIフレームワークによってあらかじめサポートされていない場合は、別途、メディア・フォーマッタを実装するか、もしくは、アクション・メソッドの引数からではなくApiControllerクラスのRequestプロパティから参照する必要がある(メディア・フォーマッタの実装については、次回で解説予定)。

 ASP.NET Web API フレームワークによってあらかじめサポートされている書式は、以下の3つである。

  • application/x-www-form-urlencoded(フォームの送信時に使用される形式)
  • application/json(JSON形式)
  • application/xml(XML形式)

 いわゆるJSONやXMLといった一般的な書式がサポートされている。ここでは、下のHTTPリクエストのように、JSON形式で表された(=ヘッダ「Content-Type」で指定される値が「application/json」である)Bodyの値を取得する例を取り上げる。

HTTPリクエストの項目
HTTPメソッド POST
HTTPヘッダ Content-Type : application/json
Body { Name : “Taro”, Addres : “Tokyo” }(JSON形式)
表7 JSON形式のHTTPリクエストの例

 まず、Bodyの値をバインドさせるためのクラス「Person」を用意し、アクション・メソッドでPerson型の引数を定義する(リスト6)。

public class Person
{
  public string Name { get; set; }
  public int Number { get; set; }
  public DateTime Birthday { get; set; }
}
public class PersonController : ApiController
{
  public void Post(Person person)
  {
  }
}

リスト6 JSON形式のHTTPリクエストを受け取るアクション・メソッドのコード例

 注意点としては、先ほどのURL取得時のように属性クラスFromUriAttributeを付与しないことと、Personクラスのプロパティ名を、Bodyの値のJSONプロパティの名前と同じにすることである。

○ ApiControllerクラスのRequestプロパティを参照する

 上記で取り上げたHTTPリクエストの値以外を取得するには、ApiControllerクラスのRequestプロパティを参照する。この方法では、先ほどアクション・メソッドの引数で取得したURLやBodyの値も取得できる。リスト7にサンプル・コードを掲載するので、必要なときに参考にしてほしい。

public class PersonController : ApiController
{
  public void Post()
  {
    // URLの絶対パスを取得
    string absolutePath = this.Request.RequestUri.AbsolutePath;
    // URLパラメータ「category」の値を取得
    string routeCategory = this.Request.GetRouteData().Values["category"].ToString();
    // クエリ文字列「number」の値の取得
    string queryNumber = this.Request.GetQueryNameValuePairs().First(q => q.Key == "number").Value;
    // ヘッダ「Accept」の値の取得
    string acceptEncoding = this.Request.Headers.Accept.First().MediaType;
    // Bodyに格納されたバイナリ値を(同期で)取得
    Stream stream = ((StreamContent)this.Request.Content).ReadAsStreamAsync().Result;
  }
}

リスト7 ApiControllerクラスのRequestプロパティを参照するコード例
各HTTPリクエストの値が設定されていると想定してコーディングしているため、実際に試す場合は、送信するHTTPリクエストに不備があると例外が発生するので注意。

 HTTPリクエストの値の取得については以上だ。次は反対に、サーバからクライアントへ返すHTTPレスポンスの内容を指定する方法を解説する。

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

@IT Special

- PR -

TechTargetジャパン

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

RSSについて

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

メールマガジン登録

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