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

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

ルーティングの設定を行い、URLを柔軟に定義しよう。ASP.NET Web APIでは検証/例外処理はどのように行うべきだろうか?

[矢後比呂加,著]
連載:ASP.NET Web API 入門
Insider.NET

 

「連載:ASP.NET Web API 入門」のインデックス

連載目次

 本連載は、ASP.NET Web APIを基礎から解説している。第4回目となる本稿で、基礎情報の紹介は終了とする。前回は、ASP.NET Web APIにおいて最低限必要となる実装である「APIコントローラーの実装」を解説した。今回は、まず初めに「ルーティングの設定」をマスターし、URLの定義を行おう。

 言語はC#、本稿で対象とするASP.NET Web APIのバージョンは、1と2の両方とし、違いがある場合は随時補足する。

ASP.NET Web APIのルーティングの設定

図1 ASP.NET Web APIルーティングの設定の概要図 図1 ASP.NET Web APIルーティングの設定の概要図

 ルーティングとは、HTTPリクエストのURLに応じて、呼び出す処理を決定する仕組みのことだ。ASP.NET MVCから登場し、今やASP.NET Webフォームにも組み込まれている。開発者は、ルーティングの設定を行うことで、URLを柔軟に決定できる。Web APIを提供するASP.NET Web APIとしてはとても重要な仕組みだ。

 ASP.NET Web APIのルーティングの設定について学ぶ前に、把握しておきたいことがある。それは、ルーティングのメカニズム――HTTPリクエストはどのようにしてアクションメソッドにマッピングされるか――である。ASP.NET MVCでは特に意識することはないのだが、ASP.NET Web APIのそれは若干のクセがある。ルーティングのメカニズムを把握した上でルーティングの設定を行おう。

ASP.NET Web APIのルーティングメカニズム

 ASP.NET Web APIではアクションメソッドの選択時、ルーティングの設定の他に次の2つの条件を確認する。

  1. HTTPメソッドによる条件
  2. URLのパラメーターによる条件

 HTTPリクエストとアクションメソッドがこれらの条件に合わないと、いくらルーティングの設定を行っても思うようにマッピングされないので注意が必要だ。それぞれの条件について詳しく見てみよう。

1. HTTPメソッドによる条件

 1つ目の条件は、アクションメソッドのメソッド名が、HTTPメソッド(Get/Post/Put/Delete/Head/Options/Patch)で始まるか、もしくはHttpPost属性などの属性が付与されていることだ(ただし、例外が存在するので後述する)。

  HTTPリクエスト側 アクションメソッド側
確認項目 HTTPメソッド メソッド名、または属性の付与
表1 1つ目の条件で確認される項目

 例えば、次のリスト1のようなAPIコントローラーとアクションメソッドが定義されている場合、「GET ~/api/customers/」でアクセスするとGetAllメソッドが、「PUT ~/api/customers/」でアクセスするとUpdateCustomerメソッドが呼び出される(デフォルトのルーティング設定が適用されているものとする)。

public class CustomersController : ApiController
{
  // GET ~/api/cutstomers
  public string GetAll();

  // PUT ~/api/cutsomers
  [HttpPut]
  public void UpdateCustomer();

  // POST ~/api/cutsomers
  public string Hoge();
}

リスト1 HTTPメソッドによってマッピングされるアクションメソッドの例

 リスト1に記述されている「[HttpPut]」といった属性は、HTTPメソッドを表す。このような属性クラスとしては、HttpGet/HttpPost/HttpPut/HttpDelete属性などが使用できる*1(全てSystem.Web.Http名前空間に配置されている*2)。アクションメソッド名がHTTPメソッドで始まらない場合は、これらHTTPメソッドを表す属性を付与しなければならない。

 ただし例外として、HTTPメソッドがPOSTの場合は、これらの条件は無視される(アクションメソッド名がPostで始まる必要もなく、HttpPost属性を付与する必要もない)。つまり、「POST ~/api/customers/」でアクセスすると、リスト1のHogeメソッドが呼び出される。

*1 AcceptVerbs属性で「[AcceptVerds("Get")]」といったようにHTTPメソッドを文字列で指定することも可能だ。

*2 ASP.NET MVCのSystem.Web.Mvc名前空間に同じ名前の属性があるので間違えないように注意。


2. URLのパラメーターによる条件

 2つ目の条件は、アクションメソッドの引数の型がプリミティブ型*3である場合、HTTPリクエストのURLに、引数と同じ名前のパラメーター(クエリ文字列、またはURLの一部)が定義されていなければならないことだ。

*3 プリミティブ型(参照:Type.IsPrimitive プロパティ)の引数


  HTTPリクエスト側 アクションメソッド側
確認項目 クエリ文字列、またはURLの一部 メソッドの引数(プリミティブ型)
表2 2つ目の条件で確認される項目

 文章だと理解しにくいのでコードを見てほしい。例えば下のリスト2のようにアクションメソッドが定義されている場合、「GET ~/api/customers?name=Taro」のようにクエリ文字列が指定されていないとマッピングされない。または、ルーティングの設定のURLテンプレートで「api/customers/{name}」のように「name」のパラメーターが定義されている必要がある。

public class CustomersController : ApiController
{
  //GET ~/api/customers/?name=Taro
  //または
  //GET ~/api/customers/{name} など
  public string Get(string name);
}

リスト2 URLのパラメーターによってマッピングされるアクションメソッドの例

 また、できるだけ多くのパラメーターと一致する引数が定義されるアクションメソッドが優先して呼び出される。例えば、下のリスト3のようにアクションメソッドが定義されている場合、「GET ~/api/customers/?name=taro」はGet(string name)メソッドにマッピングされ、「GET ~/api/cutomers/?name=taro&number=2」は、Get(string name, string number)メソッドにマッピングされる(パラメーターの順序や大文字小文字は無視される)。

public class CustomersController : ApiController
{
  //GET ~/api/customers?name=taro&number=1
  public string Get(string name, string number);
  //GET ~/api/customers?name=taro
  public string Get(string name);
}

リスト3 URLのパラメーターの一致数によってマッピングされるアクションメソッドの例

 リスト3の例は、新たにルーティングの設定を追加する必要がなく、それぞれのアクションメソッドにマッピングできることが利点だ。

 反対に、リスト2と3で「GET ~/api/customers/」の場合はどうなるかというと、アクションメソッドに定義されている引数に該当するパラメーターがないため、マッピングされない。もしマッピングさせる場合は、下のリスト4のGet(string name)メソッドのように初期値を設定する必要がある(初期値は、ルーティングの設定でも行うことができる)。

public class CustomersController : ApiController
{
  public string Get(string name, string number);
  //GET ~/api/customers
  public string Get(string name = "anonymous");
}

リスト4 初期値を設定すると、URLにパラメーターがない場合でもマッピングされるコードの例
「GET ~/api/customers」の場合は、後者のGetメソッドがマッピングされる。

 以上2つの条件が、ASP.NET Web API特有のマッピングの条件である。ルーティングの設定とは違い、変更するには拡張が必要なので注意が必要だ。

ルーティングの設定

 それでは上記の条件を踏まえて、ルーティングの設定を行っていこう。概要は第1回の節「ルーティングの設定」ですでに説明しているので、ここでは特筆すべき事項を記載する。

 下のリスト5は、デフォルトのルーティングの設定に1つルーティングを追加した例だ。

public static class WebApiConfig
{
  public static void Register(HttpConfiguration config)
  {
    config.Routes.MapHttpRoute(
      name: "UserProfileApi",
      routeTemplate: "api/profile/{name}",
      defaults: new { controller = "UserProfile", name = RouteParameter.Optional }
    );

    config.Routes.MapHttpRoute(
      name: "DefaultApi",
      routeTemplate: "api/{controller}/{id}",
      defaults: new { id = RouteParameter.Optional }
    );
    //...(省略)

リスト5 デフォルトのルーティングの設定の前に、1つルーティングを追加している例
URL「~/api/profile/{name}」でUserProfileコントローラーのアクションメソッドにマッピングされるよう設定を追加している。
この場合アクションメソッドの選択は、前の章で解説したマッピングの条件に従って特定される。

 ルーティングの設定は、MapHttpRoute拡張メソッド(System.Web.Http名前空間)により、任意の数だけルーティングを追加できる。追加されたルーティングは登録した順に、HTTPリクエストのURLと一致するURLテンプレートがないか照会される。一致した場合、該当のル―ティング設定の情報を基に、APIコントローラーとアクションメソッドが特定される。

 リスト5の例を基に、MapHttpRoute拡張メソッドの引数について説明したものが次の表3となる。

引数名 引数の説明
name ルートの名前を定義する。任意の値でよいが、他のルートと重複しないよう一意の名前を定義する必要がある
routeTemplate マッピングしたいURLのパターンを記述する。プレイスホルダーで指定した部分はパラメーターとして扱われる
defaults パラメーターの初期値を設定する。RouteParameter.Optionalはパラメーターの存在が必須ではないことを表している
表3 ルーティングの設定を行うMapHttpRoute拡張メソッドの引数とその説明

 パラメーター「controller」は、APIコントローラーの特定に必要なため、引数routeTemplateまたはdefaultsのどちらかで必ず指定する必要がある。また、リスト5には記述されていないが、パラメーターは他にアクションを指定する「action」がある。このアクションについては次の節で解説する*4

 また、ルーティングの設定で定義したパラメーターは、アクションメソッドの引数に同じ名前で定義することで、パラメーターに該当するURLの一部の値を、アクションメソッドで取得できる(参考「第3回 APIコントローラーの実装方法 HTTPリクエストを取得する」)

*4 ルーティングの設定方法は、ASP.NET MVCとほぼ同じであるため、詳しい設定方法については「[ASP.NET MVC]ルート定義を追加するには?[3.5、4、C#、VB]」を参考にしてほしい(ただし、ASP.NET MVCとASP.NET Web APIのルーティングの設定は、登録先のオブジェクトが異なるので注意。ASP.NET Web APIでは、HttpConfigurationクラスにルーティングの設定情報を登録している)。


アクションを指定する

 ASP.NET Web APIでは、デフォルトのルーティングの設定だけでは不十分で、アクションの指定が必要な場合がある。

 例えば次のリスト6のように、同じAPIコントローラー内に複数のHTTPメソッドに対応したアクションメソッドを定義した場合、とあるHTTPリクエストを送信するとルーティング設定のエラーが発生してしまう。理由は、「GET ~/api/cutomers」にマッピングされるアクションメソッドが複数あるためだ。

public class CustomerController : ApiController
{
  public string GetName();
  public string GetNumber();
}

リスト6 「GET ~/api/customers」でどちらのアクションメソッドもマッピングの対象となってしまう例

 この場合は、アクション(パラメーター名「action」)に、アクションメソッド名を指定したルーティングの設定を追加することで、正しくマッピングできる。次のリスト7は、リスト6に定義されたアクションメソッドを異なるURLでマッピングさせるための設定例だ。

public static class WebApiConfig
{
  public static void Register(HttpConfiguration config)
  {
    config.Routes.MapHttpRoute(
        name: "CustomerNameApi",
        routeTemplate: "api/customers/name",
        defaults: new { controller = "Customers", action = "GetName" }
      );

    config.Routes.MapHttpRoute(
        name: "CustomerNumberApi",
        routeTemplate: "api/customers/number",
        defaults: new { controller = "Customers", action = "GetNumber" }
      );

    config.Routes.MapHttpRoute(
      name: "DefaultApi",
      routeTemplate: "api/{controller}/{id}",
      defaults: new { id = RouteParameter.Optional }
    );
  }
}

リスト7 パラメーター「action」を指定することで、アクションメソッド名を指定しているルーティング設定の例

 アクションに設定する値は、必ずしもアクションメソッド名である必要はない。リスト8のように ActionName属性(=System.Web.Http名前空間のActionNameAttributeクラス)を付与すれば、ルーティング設定でアクションメソッド名ではなくActionName属性の引数に設定した値を使用できる。

public class CustomerController : ApiController
{
  [ActionName("name")]
  public string GetName();
}

リスト8 アクションメソッドにActionName属性を付与する

 以上紹介したアクションの設定はほんの一例だ。APIコントローラーに大量のAPIを用意する場合やRESTfulなURL設計を行わない場合、恐らくアクション名の指定が必要になるであろう。だが、先ほどの例のように1つ1つルーティングを設定するのは面倒である。この場合は、デフォルトのルーティングの設定をアクションベースにする方法(リスト9を参照)や、ASP.NET Web API 2から提供されている属性ルーティング(リスト10を参照)を使用する方法を採ることで解決できる。

config.Routes.MapHttpRoute(
  name: "DefaultApi",
  routeTemplate: "api/{controller}/{action}/{id}",
  defaults: new { id = RouteParameter.Optional }
);

リスト9 デフォルトのルーティングの設定をアクションベースにした場合のコード例
URLでアクションの指定が必須となる。

[RoutePrefix("api/customers/{customerId}")]
public class OrdersController : ApiController
{
  //  ~/api/customers/{customerId}/orders
  [Route("orders")]
  public IEnumerable<Order> GetOrdersByCustomer(int customerId);

  //  ~/api/customers/{customerId}/orders/{orderId}
  [Route("orders/{orderId}")]
  public Order GetOrderByCustomer(int customerId, int orderId);
}

リスト10 ASP.NET Web API 2で提供さえている属性ルーティングを使用した場合の、APIコントローラー例
属性を付与することで、1行でルーティングの設定を行える。属性ルーティングを使用するには、WebApiConfig.csファイルでHttpConfigurationの拡張メソッドであるMapHttpAttributeRoutesメソッド(System.Web.Http名前空間)を記述する必要がある。

 ルーティングの設定の解説は以上だ。次は、HTTPリクエストの内容を検証する方法について解説する。

       1|2|3 次のページへ

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

@IT Special

- PR -

TechTargetジャパン

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

RSSについて

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

メールマガジン登録

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