technoshop

杉並区和泉のソフトウェアハウス、株式会社テラソフトの技術ブログです。主に.NET MVCとKnockoutJSの情報をまとめます。

.Net MVC4 でも Web API で REST してみる!

ザクです。そろそろMVC4飽きてきたと思います。「はよKnockoutやらんかい」と思われた方も多いと思いますが、物事には順序があります。そういうものです。

これまでは、KnockoutJSのチュートリアルをやるために必要なMVC4側の知識をおおまかに解説してきました。(たいていのアプリのたたき台は、これまで説明してきたスキルを使って作れると思います)今回のWeb APIはKnockoutJSをMVC4アプリケーション上でやる上で最も重要な知識と思われます。しっかり習得しましょう。

Web API のコントローラを作成する

Web APIは、MVC4になって追加された新機能です。これでようやく.NetでもRESTが簡単に実装できるようになりました。Web APIについての説明は詳しくしませんが、知りたい人はこの辺を読むと良いと思われます。

MSDN Blogs

ザクの講座では必要な知識だけ手短にまとめたいので、不要な知識ははしょります。

Web APIで必要なものは「専用コントローラとルーティング」のファイルです。(APIで取り出すモデルが必要なのは言うまでもないでしょう)Web APIだけをやるプロジェクトを作ってもいいのですが、既存のMVC4アプリのプロジェクトに追加する形で加えても構いません。SPAで作るところ以外(例えばユーザー管理とか)はAPI使いませんからね。試しに、これまで作ってきたチュートリアルのプロジェクトで作ってみましょう。

既存のモデルからデータを取り出すAPIを作るならスキャフォールドすると楽ちんです。プロジェクトのControllersフォルダを右クリックして追加を選び、コントローラを新規作成します。ダイアログボックスが開くので以下のように設定します。

f:id:technoshop:20140930102520j:plain

StudentAPIController.csファイルがControllersフォルダ内に作られました。4種類のHTTPメソッドに対応したアクションが作られ、モデル名やコンテクスト名も正しく設定されています。見た感じ良さそうなので、とりあえずビルドしておきます。

Chromeアプリ「Advanced REST Client」でGETを呼んでみる

Web APIからデータを取り出すには、コントローラのアクションの上にコメントされたURLを使ってGETを呼び出せばいいだけですが、View側でこれを呼び出すものが今何もありません。。。どうしたらいいのか?ブラウザでAPIを呼び出して、結果が見れたらAPIがちゃんと応答しているか簡単に確認できますよね。それには、Chromeアプリ「Advanced REST Client」を使うとラクです。こいつをChromeに追加します。

f:id:technoshop:20140930150119j:plain

起動するとこんな画面が出たと思います。一番上がURLを書くところになっているので、自分のアプリのアドレスを入れます。GETにチェックが入っているので、Sendボタンを押します。

あれあれ、エラーが出ました。

f:id:technoshop:20140930150453j:plain

「シリアル化に失敗しました」とあります。Web APIからJsonでデータを取ってくるとき、モデルにつけてるナビゲーションプロパティが悪さをすることがあります。これを無視する設定をGlobal.asaxに追加します。

protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterAuth();
            WebSecurity.InitializeDatabaseConnection(
                "DefaultConnection",
                "UserProfile",
                "UserId",
                "UserName", autoCreateTables: true);

            GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        }

ビルドして、もう一度APIに繋ぎます。まだエラーが出ますね。エラーの下の方を見てみます。「"この Command に関連付けられている DataReader が既に開かれています。このコマンドを最初に閉じる必要があります。"」とありますね。調べたら、これで直るみたいです。Web.configのDefaultConnectionに下を加えてください。

MultipleActiveResultSets=true;

ビルドして、APIに繋ぎます。今度はちゃんとレスポンスが帰ってきました!でも、ナビゲーションプロパティの入れ子がややこしくなっていますね。モデルの定義がちょっと入り組んでるので仕方がないかもしれませんが。Studentからみて、子供のEnrollmentまでが取れれば良いとして、余計なデータを取ってこないように、API取得用にEnrollmentモデルを調整します。ナビゲーションプロパティの上に[JsonIgnore]を加えてみてください。

public class Enrollment
    {
        public int EnrollmentId { get; set; }
        public int CourseId { get; set; }
        public int StudentId { get; set; }
        public Grade? Grade { get; set; }

        [JsonIgnore]
        public virtual Course Course { get; set; }
        [JsonIgnore]
        public virtual Student Student { get; set; }
    }

だいぶスッキリしました!

f:id:technoshop:20140930163552j:plain