第2回 スキャフォールディング機能で軽々DB連携アプリケーション連載:ASP.NET MVC入門(4/5 ページ)

» 2009年05月22日 00時00分 公開

5. Createアクション・メソッド&ビューを定義する

 次に、書籍情報を登録するための新規作成画面(アクション・メソッドとビュー)を作成する。ビューの作成に必要な情報は、次のとおり。

項目 設定値
View name Create
Create a partial view(.ascx) チェックしない
Create a strongly-typed view チェックする
View data class MvcApp.Book(VBの場合)
MvcAppCs.Models.Book(C#の場合)
View content Create
Select master page チェックしない
表6 [Add View]ダイアログの設定値

 自動生成されたコードを基に、必要な個所を追記/修正したのが以下のコードだ(追記/修正した部分は太字で示している)。なお、入力値の検証処理については次回以降にあらためて解説するものとし、ここでは割愛している。

//
// GET: /Book/Create
// 初回アクセス時に呼び出される
public ActionResult Create() {
  // そのままCreate.aspxを呼び出し
  return View();
}

//
// POST: /Book/Create
// [作成]ボタンクリックのタイミングで呼び出される
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Book b, FormCollection collection) { [A]
  try {
    // Bookオブジェクトを追加&保存
    _db.AddToBook(b);
    _db.SaveChanges();

    // 処理後はIndexアクションにリダイレクト
    return RedirectToAction("Index"); [B]

  } catch {
    // 処理に失敗した場合にはCreate.aspxを再描画
    return View();
  }
}

'
' GET: /Book/Create
' 初回アクセス時に呼び出される
Function Create() As ActionResult
  ' そのままCreate.aspxを呼び出し
  Return View()
End Function

'
' POST: /Book/Create
' [作成]ボタンクリックのタイミングで呼び出される
<AcceptVerbs(HttpVerbs.Post)> _
Function Create(ByVal b As Book , ByVal collection As FormCollection) As ActionResult [A]
  Try
    ' Bookオブジェクトを追加&保存
    _db.AddToBook(b)
    _db.SaveChanges()

    ' 処理後はIndexアクションにリダイレクト
    Return RedirectToAction("Index") [B]

  Catch
    ' 処理に失敗した場合にはCreate.aspxを再描画
    Return View()
  End Try
End Function

リスト8 Createアクション・メソッドを定義するコード(上:BookController.cs、下:BookController.vb)

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<MvcAppCs.Models.Book>" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
  <title>新規作成</title>
  <link rel="Stylesheet" type="text/css"
         href="../../Content/MyApp.css"/>
</head>
<body>
  <%= Html.ValidationSummary("以下のエラーが発生しました。")%>
  <% using (Html.BeginForm()) {%>
    <fieldset>
      <legend>書籍情報</legend>
      <p>
        <label for="isbn">ISBNコード:</label>
        <%= Html.TextBox("isbn") %>
        <%= Html.ValidationMessage("isbn", "*") %>
      </p>
      <p>
        <label for="title">書名:</label>
        <%= Html.TextBox("title") %>
        <%= Html.ValidationMessage("title", "*") %>
      </p>
      <p>
        <label for="price">価格:</label>
        <%= Html.TextBox("price") %>
        <%= Html.ValidationMessage("price", "*") %>
      </p>
      <p>
        <label for="publish">出版社:</label>
        <%= Html.TextBox("publish") %>
        <%= Html.ValidationMessage("publish", "*") %>
      </p>
      <p>
        <label for="published">刊行日:</label>
        <%= Html.TextBox("published") %>
        <%= Html.ValidationMessage("published", "*") %>
      </p>
      <p>
          <input type="submit" value="作成" />
      </p>
    </fieldset>
  <% } %>
  <div>
    <%=Html.ActionLink("一覧へ戻る", "Index") %>
  </div>
</body>
</html>

<%@ Page Language="VB" Inherits="System.Web.Mvc.ViewPage(Of MvcApp.Book)" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
  <title>新規作成</title>
  <link rel="Stylesheet" type="text/css"
         href="../../Content/MyApp.css"/>
</head>
<body>
  <%=Html.ValidationSummary("以下のエラーが発生しました。")%>
  <% Using Html.BeginForm()%>
    <fieldset>
        <legend>書籍情報</legend>
        <p>
          <label for="isbn">ISBNコード:</label>
          <%= Html.TextBox("isbn") %>
          <%= Html.ValidationMessage("isbn", "*") %>
        </p>
        <p>
          <label for="title">書名:</label>
          <%= Html.TextBox("title") %>
          <%= Html.ValidationMessage("title", "*") %>
        </p>
        <p>
          <label for="price">価格:</label>
          <%= Html.TextBox("price") %>
          <%= Html.ValidationMessage("price", "*") %>
        </p>
        <p>
          <label for="publish">出版社:</label>
          <%= Html.TextBox("publish") %>
          <%= Html.ValidationMessage("publish", "*") %>
        </p>
        <p>
          <label for="published">刊行日:</label>
          <%= Html.TextBox("published") %>
          <%= Html.ValidationMessage("published", "*") %>
        </p>
        <p>
          <input type="submit" value="作成" />
        </p>
      </fieldset>
  <% End Using %>
  <div>
    <%=Html.ActionLink("一覧へ戻る", "Index")%>
  </div>
</body>
</html>

リスト9 書籍情報の新規登録画面を表示するためのビュー(Book/Create.aspx。上がC#、下がVB)

 ビューについては既出の内容であり、あえて解説すべき点はない。ここで注目していただきたいのは、Createアクション・メソッドだ。

 前回も触れたように、コントローラ・クラスではAcceptVerbs属性を利用することで、HTTPメソッドによって呼び出すべきアクション・メソッドを切り替えることができる。ここでも引数なしのCreateメソッドと引数付きのCreateメソッドが定義されているが、前者は初回アクセス時(GET呼び出し時)に呼び出され、後者は新規作成画面で[作成]ボタンがクリックされたとき(POST呼び出し時)に呼び出されることを想定している。

 このうち、引数なしのCreateメソッドについては、Viewメソッドでただビューを呼び出しているだけなので、問題はないだろう。以下、引数付きのCreateメソッドについて、いくつかのポイントに絞って解説する。

(1)入力値をオブジェクトにバインドする(リスト8の[A]

 アクション・メソッドでは、モデルを表すオブジェクトを引数として受け取るようにしておくだけで、入力値をオブジェクトに自動的にバインドすることができる。この場合、引数としてBookオブジェクトが指定されているので、Bookオブジェクトのisbnプロパティには入力要素isbnの値が、titleプロパティには入力要素titleの値が、それぞれ順に割り当てられるわけだ*3

*3 前回のPostアクション・メソッドの例のように、個々のパラメータ(isbn、title、price)を引数として受け取って、その値を手動でBookオブジェクトのプロパティに割り当てても構わない。しかし、特別な理由がない限り、あえてそのような手間をかける意味はないだろう。


 ここでは、自動バインドされたBookオブジェクトをAddToBookメソッドでコンテキスト・オブジェクトに追加したうえで、SaveChangesメソッドによりデータベースに反映している。この辺の手続きはEntity Frameworkに属する話であるので、詳細は別稿「.NETの新データアクセス・テクノロジADO.NET Entity Framework」の4ページ目を参照いただきたい。ここでは、データ保存に成功した場合にはIndexアクションへリダイレクトし、失敗した場合には(Catchブロックで)元のCreate.aspxを再描画していることを押さえておこう。

[参考]FormCollectionオブジェクト

 Createメソッドの第2引数で指定されたFormCollectionオブジェクト(リスト8)は、名前のとおり、フォームから入力された値のコレクションを表す。個別のフォーム値にアクセスするには、「collection("title")」(C#では「collection["title"]」)のように記述すればよい。

 しかし、前回、今回と紹介したようなパラメータのバインド機能を利用することで、厳密に型付けされた状態で値を取得できる。コーディングの効率を考えても、まずはバインド機能の利用を検討すべきだろう。



(2)別のアクションにリダイレクトする(リスト8の[B]

 アクションの実行後、ビューを呼び出すのではなく、別のアクションを実行したい場合には、Viewメソッドの代わりにRedirectToActionメソッドを呼び出せばよい。RedirectToActionメソッドの構文は以下。

RedirectToAction (action As String [,controller As String] [,routeValues As Object])
' action:アクション名
' controller:コントローラ名
' routeValues:ルーティング・ルールに引き渡すパラメータ

RedirectToActionメソッドの構文(VBの場合)

 引数controllerが省略された場合には、同一クラスの中から指定されたアクションが検索され、処理をリダイレクトする。引数routeValuesの例については、前述したActionLinkメソッドも参考にするとよいだろう。

 ここまでを理解したら「http://localhost:3568/Book/Create」にアクセスし*4、実際に新規のデータを入力してみよう。

*4 一覧画面にアクセスしたうえで、[新規作成]リンクをクリックしても構わない。なお、ポート番号部分(ここでは「3568」)は環境によって異なる。


図9 新規作成画面で新しい書籍情報を登録

 データ入力後、一覧画面で新規登録したデータが確認できれば、サンプルは正しく動作している。

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

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

メールマガジン登録

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