読者です 読者をやめる 読者になる 読者になる

しばやん雑記

ASP.NET とメイドさんが大好きなフリーランスのプログラマーのブログ

ASP.NET MVC 4 Beta で追加された Web API プロジェクトを試す

ASP.NET MVC 4 は本当にランタイムの更新が皆無ですね。恐らく Web Pages 2 のが更新多いと思います。

まあ、それはそれとしてベータで追加された ASP.NET Web API を使うプロジェクトを試してみたいと思います。WCF Web API では NuGet からインストールする必要がありましたが、MVC 4 ではテンプレートを選ぶだけです。

Web API テンプレートを選んで「OK」をクリックするとプロジェクトが生成されます。参照するアセンブリが増えているので、作成にちょっと時間がかかるかもしれません。

プロジェクトが生成されたら、とりあえず実行してみましょうか。

DP でデフォルトのデザインが変わりましたが、よく見ると ASP.NET Web API 向けに文章が変わっています。そして、この後に何をすべきかも書いてあるのでわかりやすいですね。

プロジェクトを作ったらまずは実行!と考えておいてもいいかも知れません。

ASP.NET Web API に関しては http://www.asp.net/web-api を参照してくれと書いてありますが、まだリリースノートも公開されていない状態で当然ながらこのページも存在してません。恐らく近日中には公開されるんじゃないかと思います。

とりあえず、これからどうすればいいかトップページから引っ張ってきました。

  1. Name your Web API
    • Requests are routed to Web APIs based on their name. The Web API in this template will respond to requests sent to /api/values, but you can change this by renaming the ValuesController type. Your Web API name should end with Controller.
  2. Implement your Web API actions
    • By convention, Web API actions map directly to HTTP methods, like GET, POST, PUT, and DELETE. To handle a given HTTP method just prefix your action name with the HTTP method you want to handle. Action parameters are bound to data from the request through model binding. Data returned from an action is formatted in the response as JSON or XML as requested by the client.
  3. Add Web APIs and routes
    • Add additional Web APIs using the Add New Item dialog. You can also fully control the URI space for your Web APIs in Global.asax by adding routes to the HttpConfiguration object passed to the RegisterApis method.

要約すると API の名前を決めて、実装して、ルーティングに加えろということです。既にサンプルとして ValuesController が追加されているので、これを修正すればいいぜ!ということみたいですね。

それでは ValuesController についてみていきたいと思います。

public class ValuesController : ApiController
{
    // GET /api/values
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

    // GET /api/values/5
    public string Get(int id)
    {
        return "value";
    }

    // POST /api/values
    public void Post(string value)
    {
    }

    // PUT /api/values/5
    public void Put(int id, string value)
    {
    }

    // DELETE /api/values/5
    public void Delete(int id)
    {
    }
}

非常にシンプルですね。ASP.NET MVC のコントローラと異なる点は Controller クラスではなく ApiController クラスを継承していること、そしてアクションに該当するメソッドが HTTP の動詞名になっていることです。

あまりにも直観的すぎて、正直これ以上は説明が要らないんじゃないかと思うほどです。メソッドの実装は HTTP 動詞が表す通りなので、特に API であることを意識せずにモデル周りを作って、処理を実装するだけですね。

コントローラが完成したら、最後にルーティングに登録しろと書いてありました。ルーティングの登録と言えばもちろん Global.asax.cs で行いますので開きましょう。

すると Application_Start には以下のようなデフォルトのルーティングが追加されています。

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

ASP.NET Web API のルーティング定義は MapHttpRoute を使って行います。引数は MapRoute とほぼ変わらないですが、routeTemplate にアクションがないので注意してください。コントローラのどのアクションが呼ばれるかは、全て HTTP 動詞によって決定されるので定義がありません。

既に全てのコントローラに対応できるルーティングが定義されていたのでそのまま使いましょう。

それでは実際に API にアクセスしてみたいと思いますが、今回はめんどくさいので F12 開発者ツールを使って実行します。API のエンドポイントは /api/values となるので、jQuery を使って取得してみます。

$.ajax({
    type: "GET",
    url: "/api/values",
    success: function (obj) {
        alert(obj);
    }
});

とりあえず返ってきたオブジェクトを表示するだけです。実行結果は以下の通りです。

ちゃんと値が返ってきてますね。F12 開発者ツールのネットワークキャプチャ機能でみると、JSON で帰ってきていることが確認できます。

JavaScript から使う分には JSON であれば問題ないと思いますが、やはりデスクトップアプリからでも利用される API であれば XML で欲しい!という要望もあると思います。

でも大丈夫、ASP.NET Web API は Accept ヘッダの値で JSON と XML の切り替えが出来るようになっています。jQuery では dataType を指定すれば xml で取得することが出来ます。

$.ajax({
    type: "GET",
    url: "/api/values",
    dataType: "xml",
    success: function (obj) {
        //alert(obj);
    }
});

実行結果は以下の通り、ちゃんと XML として値が返ってきていますね。

基本的な使い方は以上ですが、ASP.NET Web API にも MVC と同様にいくつか属性が用意されています。今回、それも少しだけ試してみたいと思います。

まずは Authorize 属性を付けて試してみます。使い方は MVC と全く同じです。

[Authorize]
public class ValuesController : ApiController
{
}

これで試してみると以下のようになりました。

うーむ、何でログインページへリダイレクトしてしまうんでしょうね…。API なので余計なことせずに 403 だけ返してくれていたらいいんですが。

他にも FromBody, FromUri といった独自の属性が用意されています。名前からすぐにわかると思いますが、アクション引数のバインドされる値を URI かリクエストボディからに限定する為の属性です。

public void Put([FromUri] int id, [FromBody] string value)
{
}

この場合では id は URI から、value はリクエストボディからバインドされるようになります。ちなみに Nullable じゃないパラメータのバインドに失敗した場合には 400 が返ります。

これで最後です。やっぱり ASP.NET MVC と言えばモデルバインダが最強ですよね!なので Web API でも試してみました。

public string Put(int id, Product value)
{
    return value.Name + " " + value.Stock;
}

何故か Visual Studio でデバッグ実行が出来なかったので、実行結果として受け取ったパラメータを連結して返すという残念な仕様にしました。Product クラスは Name と Stock プロパティを持つだけの簡単なものです。

そして適当に jQuery で API を叩いてみます。

$.ajax({
    type: "PUT",
    url: "/api/values/1",
    data: "Name=hoge&Stock=10",
    success: function (obj) {
        alert(obj);
    }
});

そしてこれの実行結果が以下のようになりました。

ちゃんと Product クラスにバインドされていることが確認できました。しかし、残念ながら今のところは JSON をバインドすることはできないようです。今後の対応に期待したいと思います。