NerdDinnerチュートリアル

NerdDinnerステップ10:RSVPの承諾を可能にするAJAX

Scott Guthrie 著/Chica
2010/03/08

 本記事は、Microsoftの本社副社長であり、ASP.NETやSilverlightなどの開発チームを率いるScott Guthrie氏が公開している「NerdDinner Tutorial」を翻訳したものです。氏の許可を得て転載しています。

[これは無償の"NerdDinner"アプリケーション・チュートリアルのステップ10で、ASP.NET MVCを使用して、小さいながらも完全なWebアプリケーションを構築する手順を紹介しています。]

 それでは、興味のある夕食会参加にログイン・ユーザーがRSVP*できるようにするためのサポートを実装しましょう。これには、その夕食会の詳細ページ内に統合されるAJAXベースのアプローチを使います。

* 【編集部注】招待状などで「お返事をください」という意味で使われるが、NerdDinnerでは夕食会への参加登録といった意味で使われている。

ユーザーがRSVPされたかどうかを表示

 ユーザーは/Dinners/Details/[id] URLを訪れて、特定の夕食会の詳細を見られます。


図1

 Detailsアクション・メソッドは以下のように実装されています。

//
// GET: /Dinners/Details/2

public ActionResult Details(int id) {

  Dinner dinner = dinnerRepository.GetDinner(id);

  if (dinner == null)
    return View("NotFound");
  else
    return View(dinner);
}

 RSVPサポートを実装する最初の手順は、“IsUserRegistered(username)”ヘルパー・メソッドを(先に構築したDinner.csにある部分クラス内の)Dinnerオブジェクトへ追加します。このヘルパー・メソッドは、そのユーザーが現在、夕食会にRSVPされているかどうかを返します。

public partial class Dinner {

  public bool IsUserRegistered(string userName) {
    return RSVPs.Any(r => r.AttendeeName.Equals(userName, StringComparison.InvariantCultureIgnoreCase));
  }
}

 そして、以下のコードをDetails.aspxビュー・テンプレートに追加して、そのユーザーがそのイベントに登録されているかどうかを示した適切なメッセージを表示させます。

<% if (Request.IsAuthenticated) { %>
  <% if (Model.IsUserRegistered(Context.User.Identity.Name)) { %>

    <p>You are registred for this event!</p>

  <% } else {  %>

    <p>You are not registered for this event</p>

  <% }  %>

<% } else { %>
  <a href="/Account/Logon">Logon</a> to RSVP for this event.

<% } %>

 今後、登録された夕食会をユーザーが訪れたときは、このメッセージが表示されます。


図2

 また、ユーザーが登録されていない夕食会を訪れたときは、以下のメッセージが表示されます。


図3

Registerアクション・メソッドの実装

 では詳細ページでユーザーが夕食会にRSVPできるようにするための機能を追加しましょう。

 これを実装するために、\Controllersディレクトリ上を右クリックし、[Add]−[Controller]のメニュー・コマンドを選択して、新しい“RSVPController”クラスを作成します。

 “Register”アクション・メソッドを新しいRSVPControllerクラス内に実装します。これは引数として夕食会のIDを取り、それに対応したDinnerオブジェクトを取得し、そのログイン・ユーザーが現在これに対して登録されているユーザー一覧にあるかどうかを確認し、登録されていない場合はRSVPオブジェクトをそこへ追加します。

public class RSVPController : Controller {

  DinnerRepository dinnerRepository = new DinnerRepository();

  //
  // AJAX: /Dinners/RSVPForEvent/1

  [Authorize, AcceptVerbs(HttpVerbs.Post)]
  public ActionResult Register(int id) {

    Dinner dinner = dinnerRepository.GetDinner(id);

    if (!dinner.IsUserRegistered(User.Identity.Name)) {

      RSVP rsvp = new RSVP();
      rsvp.AttendeeName = User.Identity.Name;

      dinner.RSVPs.Add(rsvp);
      dinnerRepository.Save();
    }

    return Content("Thanks - we'll see you there!");
  }
}

 そのアクション・メソッドの出力として、簡単な文字列が返されている様子を上記でご確認ください。ビュー・テンプレート内にこのメッセージを埋め込むこともできますが、非常に短いため、単純にContentヘルパー・メソッドをコントローラの基本クラスで使用して、上記のように文字列メッセージを返しています。

AJAXを使用したRSVPForEventアクション・メソッドの呼び出し

 DetailsビューからRegisterアクション・メソッドを起動させるためにAJAXを使用します。この実装は非常に簡単です。最初に、2つのスクリプト・ライブラリの参照を追加します。

<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>

 最初のライブラリは、コアとなるASP.NET AJAXのクライアント側のスクリプト・ライブラリを参照します。このファイルのサイズはおよそ24Kbytes(圧縮)で、コアのクライアント側のAJAX機能が含まれています。2つ目のライブラリは、ASP.NET MVCのビルトインAJAXヘルパー・メソッドと統合されているユーティリティ機能が含まれています(これはすぐ後で使用します)。

 その後、先に追加したそのビュー・テンプレートのコードを更新して、“You are not registered for this event”メッセージを出力する代わりに、リンクを描画し、それが押されたときに、RSVPコントローラ上のRSVPForEventアクション・メソッドを起動して、そのユーザーをRSVPするAJAXの呼び出しが実行されるようにします。

<div id="rsvpmsg">

<% if(Request.IsAuthenticated) { %>
  <% if(Model.IsUserRegistered(Context.User.Identity.Name)) { %>

    <p>You are registred for this event!</p>

  <% } else { %>

    <%= Ajax.ActionLink( "RSVP for this event",
               "Register", "RSVP",
               new { id=Model.DinnerID },
               new AjaxOptions { UpdateTargetId="rsvpmsg"}) %>
  <% } %>

<% } else { %>
  <a href="/Account/Logon">Logon</a> to RSVP for this event.

<% } %>

</div>

 上記で使用しているAjax.ActionLinkヘルパー・メソッドはASP.NET MVCにビルトインされており、Html.ActionLinkヘルパー・メソッドに似ていますが、通常の操作を実行する代わりに、リンクがクリックされるとアクション・メソッドへAJAX呼び出しを行います。上記では、“RSVP”コントローラ上で“Register”アクション・メソッドを呼び出し、それに対して“id”パラメータとしてDinnerIDを引き渡しています。最後に引き渡しているAjaxOptionsパラメータはアクション・メソッドから返されたコンテンツを取って、IDが“rsvpmsg”のページ上のHTML <div>要素を更新したいことを示しています。

 ユーザーがまだ登録していない夕食会を表示しているときに、RSVPするためのリンクを表示します。


図4

 “RSVP for this event”リンクをクリックした場合、RSVPコントローラ上のRegisterアクション・メソッドへAJAX呼び出しを行い、それが完了したら、以下のような更新されたメッセージが表示されます。


図5

 このAJAX呼び出しを行うときのネットワークの帯域やトラフィックは非常に軽量です。ユーザーが“RSVP for this event”リンク上をクリックしたとき、以下のような小さなHTTP-POSTネットワーク・リクエストが/Dinners/Register/1 URLに送信されます。

X-Requested-With: XMLHttpRequest
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Referer: http://localhost:8080/Dinners/Details/49

 そして、Registerアクション・メソッドからのレスポンスは単純です。

Content-Type: text/html; charset=utf-8
Content-Length: 29
Thanks - we'll see you there!

 この軽量な呼び出しは速いので、遅いネットワークでも動作します。

jQueryアニメーションの追加

 実装したAJAX機能はうまく、そして速く動作します。ときどき非常に速いことがあり、ユーザーはRSVPリンクが新しい文字と置換されたことに気付かないかもしれません。この結果をもう少し分かりやすくするために、単純なアニメーションを追加して、更新されたメッセージに注意が向くようにしましょう。

 デフォルトのASP.NET MVCプロジェクト・テンプレートにはjQueryが含まれていますが、これは優れた(そしてとても人気のある)オープンソースのJavaScriptライブラリで、Microsoftもサポートしています。jQueryは数多くの機能を提供しており、HTML DOMの選択や効果のための優れたライブラリが含まれています。

 jQueryを使うには、最初にスクリプト参照を追加します。サイト内のさまざまな場所でjQueryを使用するつもりなので、そのスクリプトの参照をSite.masterマスター・ページ・ファイルに追加し、すべてのページで使用できるようにします。

<script src="/Scripts/jQuery-1.3.2.js" type="text/javascript"></script>

TIPS:JavaScript IntelliSense hotfix for VS 2008 SP1がインストールされているかどうかご確認ください。これにより、JavaScriptファイル(jQueryを含む)へのよりリッチなIntelliSenseサポートが有効になります。http://tinyurl.com/vs2008javascripthotfixからダウンロードできます。

 jQueryを使用して書かれたコードは、しばしばグローバルな“$()”JavaScriptメソッドを使用しており、これはCSSセレクタを使用して1つ以上のHTML要素を取得できます。例えば、$("#rsvpmsg")は、idがrsvpmsgのすべてのHTML要素を選択しますが、$(".something")は、“something”というCSSクラス名の要素を選択します。「$("input[@type=radio][@checked]")」のようにセレクタ・クエリを使用して、“チェックされたラジオボタンをすべて返す”といったような、より高度なクエリを書くこともできます。

 要素を選択すれば、アクションを行うために、その上でメソッドを呼び出せます。例えば、それらを非表示にするには、「$("#rsvpmsg").hide();」のようにします。

 RSVPのシナリオでは、“AnimateRSVPMessage”という名前の単純なJavaScript関数を定義し、それにより“rsvpmsg”<div>要素を選択し、その文字コンテンツのサイズをアニメーション化します。以下のコードでは、最初文字を小さくしておき、400ミリ秒のタイムフレームで大きくしていきます。

<script type="text/javascript">

  function AnimateRSVPMessage() {
    $("#rsvpmsg").animate({fontSize: "1.5em"},400);
  }

</script>

 (AjaxOptionsの“OnSuccess”イベント・プロパティを通じて)Ajax.ActionLinkヘルパー・メソッドへ名前を引き渡しておけば、AJAX呼び出しがうまく完了した後、このJavaScript関数が呼び出されるように接続できます。

<%= Ajax.ActionLink( "RSVP for this event",
           "Register", "RSVP",
           new { id=Model.DinnerID },
           new AjaxOptions { UpdateTargetId="rsvpmsg",
                     OnSuccess="AnimateRSVPMessage"}) %>

 今後、“RSVP for this event”リンクがクリックされて、AJAX呼び出しがうまく完了したとき、送信されるコンテンツのメッセージは、アニメーションしながら大きくなります。


図6

 “OnSuccess”イベントに加え、AjaxOptionsオブジェクトは、(さまざまなプロパティや便利なオプションとともに)操作可能なOnBegin、OnFailure、OnCompleteイベントを公開しています。

後片付け ― RSVPパーシャル・ビューのリファクタリング

 詳細のビュー・テンプレートが少し長くなってきたため、時間がたてば理解するのが少し難しくなる可能性があります。コードの可読性を改善させるのに、RSVPStatus.ascxというパーシャル・ビューを作成して完了としましょう。これはDetailsページのすべてのRSVPビューのコードをカプセル化します。

 \Views\Dinnersフォルダ上で右クリックし、[Add]−[View]メニュー・コマンドを選択すると、これを行えます。これにより、Dinnerオブジェクトを強く型付けされたViewModelとして受け取るようにします。その後、そこへDetails.aspxビューからRSVPコンテンツをコピー/ペーストできます。

 それが終われば、ほかのパーシャル・ビューも作成しましょう。EditAndDeleteLinks.ascxは、EditとDeleteリンクのビュー・コードをカプセル化します。これもDinnerオブジェクトを強く型付けされたViewModelとして受け取るようにし、そこへDetails.aspxビューからEditとDeleteのロジックをコピー/ペーストします。

 そうすると、詳細のビュー・テンプレートには、最後の部分に2つのHtml.RenderPartialメソッドを含むだけとなります。

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent"runat="server">
  <%= Html.Encode(Model.Title) %>
</asp:Content>

<asp:Content ID="details" ContentPlaceHolderID="MainContent" runat="server">

  <div id="dinnerDiv">

    <h2><%=Html.Encode(Model.Title) %></h2>
    <p>
      <strong>When:</strong>
      <%=Model.EventDate.ToShortDateString() %>

      <strong>@</strong>
      <%=Model.EventDate.ToShortTimeString() %>
    </p>
    <p>
      <strong>Where:</strong>
      <%=Html.Encode(Model.Address) %>,
      <%=Html.Encode(Model.Country) %>
    </p>
     <p>
      <strong>Description:</strong>
      <%=Html.Encode(Model.Description) %>
    </p>
    <p>
      <strong>Organizer:</strong>
      <%=Html.Encode(Model.HostedBy) %>
      (<%=Html.Encode(Model.ContactPhone) %>)
    </p>

    <% Html.RenderPartial("RSVPStatus"); %>
    <% Html.RenderPartial("EditAndDeleteLinks"); %>
  </div>

</asp:Content>

これによりコードがよりクリーンになり、読みやすく保守しやすくなります。

次のステップ

 ではさらにAJAXイベントの使用方法を調べて、アプリケーションにインタラクティブなマッピング・サポートを追加しましょう。

[注:NerdDinnerアプリケーションの完成版はhttp://nerddinner.codeplex.com/からダウンロードできます。] End of Article

 
インデックス・ページヘ  「NerdDinnerチュートリアル」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間