Shoeisha Technology Media

CodeZine(コードジン)

記事種別から探す

ASP.NET 4.5の「モデルバインド」を活用する

実例で学ぶASP.NET 4.5 Webフォーム 新機能活用法 第3回

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2013/08/21 14:00

 ASP.NET 4.5のWebフォームにはさまざまな新機能が追加されましたが、一番の目玉が今回紹介する「モデルバインド」です。どんなものなのか、サンプルと共に見ていきましょう。

目次

非モデルバインドの問題点

 従来のデータソースコントロールとデータバインドコントロールの組み合わせには、単純な処理ならコードビハインドが一切不要になるという利点がありました。その反面、少し凝ったことをやろうとすると、ItemInserting、ItemInsertedなどの処理前後の各種イベントを駆使して処理を記述する必要があります(リスト1、2)。

リスト1 非モデルバインドのaspxファイル(ReservationsAdd.aspxより)
<asp:FormView ID="ReservationsFormView" runat="server"
  DataSourceID="ReservationsObjectDataSource"
  DefaultMode="Insert" ItemType="MRRS.Entity.Reservation"
  OnItemInserting="ReservationsFormView_ItemInserting"
  OnItemInserted="ReservationsFormView_ItemInserted">
リスト2 非モデルバインドのコードビハインド(ReservationsAdd.aspx.csより)
protected void ReservationsFormView_ItemInserting(object sender, FormViewInsertEventArgs e)
{
  // データバインドできないため、自前で値を設定する
  e.Values.Add("MeetingRoomId", MeetingRoomDropDownList.SelectedValue);

  e.Values["ReserveDateFrom"] = DateTimeUtilities.ConvertDateTime(ReserveDateFromTextBox.Text, ReserveDateFromTimeTextBox.Text);
  e.Values["ReserveDateTo"] = DateTimeUtilities.ConvertDateTime(ReserveDateToTextBox.Text, ReserveDateToTimeTextBox.Text);
}

protected void ReservationsFormView_ItemInserted(object sender, FormViewInsertedEventArgs e)
{
  var ex = e.Exception;
  if (ex != null)
  {
    if (ex.InnerException is ReservationLogic.OverlapReservationException)
    {
      this.ShowErrorMessage("予約期間が重なる予約がすでに登録されています。");

      // 入力値を維持
      e.KeepInInsertMode = true;

      // 例外を処理済みとマーク
      e.ExceptionHandled = true;

      return;
    }
  }

  // 予約参照画面に戻る
  Response.Redirect("~/Reservations.aspx");
}

 この方法の大きな問題点は、本来は「追加」といったような1つのアクションに関連する処理が、各イベントに分散してしまうことです(図1)。サンプルの例でいえば、①追加前イベントハンドラーで入力値を取得、設定し、②ビジネスロジックの追加処理を呼び出した後、③追加後イベントハンドラーでエラーの有無を確認、というようになっています。このようにイベントの発生順を覚えていないと処理される順番も分かりませんし、それぞれのイベントを組み合わせてどんなことをしようとしているかの概観を理解するだけでも一苦労です。

 もう一つ、ビジネスロジック上のエラーを例外を使って表す以外に方法がないことも問題です。本来業務エラーは戻り値などを使って扱いたいところですが、非モデルバインドではそれができません。また処理フロー制御に例外を用いるのは、原則的には避けるべきです。

図1:非モデルバインドでのコード分散
図1:非モデルバインドでのコード分散

モデルバインドでの問題解決

 そこで、ASP.NET 4.5のWebフォームで新たに導入されたモデルバインドを用いることで、この問題を解決できます。モデルバインドでは、検索、追加、更新、削除といった、いわゆるCRUD処理それぞれに対応するメソッドを、コードビハインドに記述します。そのため、1つのアクションに対応する処理が分散することがありません(図2)。また、もちろん業務エラーも戻り値で表すことができるようになります。サンプルの例でいえば、①aspxファイルに指定した更新処理メソッドを直接呼出し、入力値の取得、設定を行った後、②ビジネスロジックの更新処理メソッドを呼び出します。そして③戻り値を判断して、以後の処理の分岐を行います。

 ただ、当然データソースコントロールを使えば不要だったコードビハインドのコードが必要となるため、その使用には注意が必要です。何でもかんでもモデルバインドを使ってしまうと、その分コード量が増えてしまいバグを埋め込む可能性が高まります。

図2:モデルバインドのイメージ
図2:モデルバインドのイメージ

モデルバインドの使用方法

 それでは、モデルバインドの具体的な使用方法を学んでいきましょう。前述のとおり、モデルバインドではCRUDそれぞれに対応するメソッドをコードビハインドに定義します。そして、それらのメソッドをaspxファイルでデータバインドコントロールに関連付けるというのが基本的な考え方です。サンプルの予約情報詳細画面(ReservationsDetail.aspx、aspx.cs)を例に、順に説明していきます。

検索処理メソッド定義

 まず、予約情報詳細画面では予約情報検索画面で選択された予約情報のIDを元に、編集対象データをデータベースから取得する必要があります。この検索処理メソッドは次のようになります(リスト3)。

リスト3 予約情報詳細画面の検索処理メソッド(ReservationsDetail.aspx.csより)
// (1) 検索処理メソッド定義
public Reservation SelectReservation([QueryString]int reservationId)
{
  // (2) 削除後に検索処理が呼ばれるため、同じデータを返すようSessionに入れておく
  if (Session["reservation"] != null)
  {
    return Session["reservation"] as Reservation;
  }

  // (3) ビジネスロジックの検索処理を呼び出す
  var logic = new ReservationLogic();
  var reservation = logic.Find(reservationId);
  Session.Add("reservation", reservation);
  return reservation;
}

  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • WINGSプロジェクト 高野 将(タカノ ショウ)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2017年5月時点での登録メンバは52名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂き...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XMLD...

バックナンバー

連載:実例で学ぶASP.NET 4.5 Webフォーム 新機能活用法
All contents copyright © 2005-2017 Shoeisha Co., Ltd. All rights reserved. ver.1.5