AJAX を使用し、動的更新を配信する

提供元: Microsoft

PDF のダウンロード

これは、ASP.NET MVC 1 を使用して小規模で完全な Web アプリケーションを構築する方法を説明する無料の "NerdDinner" アプリケーション チュートリアルの手順 10 です。

手順 10 では、ディナーの詳細ページ内に組み込まれている Ajax ベースのアプローチを使って、ログインしているユーザーがディナーへの参加に関心があると返事するためのサポートを実装します。

ASP.NET MVC 3 を使用している場合は、MVC 3 の概要または MVC Music Store に関するチュートリアルに従うことをお勧めします。

NerdDinner 手順 10: RSVP の受け取りを実現する AJAX

ここでは、ログインしているユーザーがディナーへの参加に関心があると返事するためのサポートを実装しましょう。 ディナーの詳細ページ内に組み込まれている AJAX ベースのアプローチを使って、これを実現します。

ユーザーが返事済みであるかどうかを示す

ユーザーは、/Dinners/Details/[id] という URL にアクセスして、特定のディナーに関する詳細を表示できます。

Screenshot of the Nerd Dinner web page with details about the Dinner.

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 のサポートを実装するための最初の手順は、(前に作成した Dinner.cs 部分クラス内の) Dinner オブジェクトに "IsUserRegistered(username)" というヘルパー メソッドを追加することです。 このヘルパー メソッドは、ユーザーがその Dinner に対して現在返事済みであるかどうかに応じて、true または false を返します。

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.

<% } %>

これで、ユーザーが登録済みの Dinner にアクセスすると、次のメッセージが表示されます。

Screenshot of the Nerd Dinners details page, the message You Are Registered For This Event is shown at the bottom.

また、登録していない Dinner にアクセスすると、次のメッセージが表示されます。

Screenshot of the Nerd Dinners details page. The message You Are Not Registered For this Event is shown.

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

次に、ユーザーがディナーの詳細ページから出席できるようにするために必要な機能を追加しましょう。

これを実装するには、\Controllers ディレクトリを右クリックし、[追加] > [コントローラー] メニュー コマンドの順に選択して、新しい "RSVPController" クラスを作成します。

新しい RSVPController クラス内に "Register" アクション メソッドを実装します。このメソッドは、Dinner の 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 アクション メソッドの呼び出し

AJAX を使って、Details ビューから Register アクション メソッドを呼び出します。 その実装は非常に簡単です。 まず、次の 2 つのスクリプト ライブラリ参照を追加します。

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

最初のライブラリは、ASP.NET AJAX クライアント側スクリプト ライブラリのコアを参照しています。 このファイルはサイズが約 24k (圧縮済み) で、クライアント側のコア AJAX 機能が含まれています。 2 つ目のライブラリには、ASP.NET MVC の組み込み AJAX ヘルパー メソッド (まもなく使用します) と統合されるユーティリティ関数が含まれています。

次に、先ほど追加したビュー テンプレートのコードを更新して、"You are not registered for this event" (このイベントに登録されていません) というメッセージを出力する代わりにリンクをレンダリングします。このリンクを選択すると AJAX 呼び出しが実行され、RSVP コントローラーに対して RSVPForEvent アクション メソッドが呼び出されて、ユーザーの RSVP が処理されます。

<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" アクション メソッドを呼び出し、DinnerID を "id" パラメーターとして渡しています。 最後に渡している AjaxOptions パラメーターは、アクション メソッドから返されたコンテンツを取得し、ID が "rsvpmsg" であるページ上の HTML <div> 要素を更新することを示しています。

これで、ユーザーがまだ登録していないディナーを参照すると、それに出席するためのリンクが表示されます。

Screenshot of the Nerd Dinners page with the R S V P button at the bottom.

"RSVP for this event" (このイベントに出席する) リンクをクリックすると、RSVP コントローラーの Register アクション メソッドに対して AJAX 呼び出しが行われ、それが完了すると次のように更新されたメッセージが表示されます。

Screenshot of the Nerd Dinner details page with the message Thanks We Will See You There at the bottom.

この AJAX 呼び出しを行う際に要求されるネットワーク帯域幅とトラフィックはごくわずかです。 ユーザーが "RSVP for this event" (このイベントに出席する) リンクをクリックすると、URL /Dinners/Register/1 に対して小さな HTTP POST ネットワーク要求が行われます (ネットワーク上では次のようになります)。

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

Register アクション メソッドからの応答はシンプルです。

HTTP/1.1 200 OK
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>

jQuery を使って記述するコードでは、CSS セレクターを使って 1 つ以上の HTML 要素を取得する、グローバルな "$()" JavaScript メソッドを使うことがよくあります。 たとえば、$("#rsvpmsg") では ID が rsvpmsg である HTML 要素を、$(".something") では CSS クラス名が "something" であるすべての要素を選択できます。 "オンであるすべてのラジオ ボタンを返す" といったより高度なクエリを作成することもできます。その場合は $("input[@type=radio][@checked]") のようなセレクター クエリを使います。

要素を選択したら、それらに対してメソッドを呼び出してアクションを実行できます。たとえば、非表示にする場合: $("#rsvpmsg").hide();

RSVP のシナリオでは、"rsvpmsg" <div> を選択し、そのテキスト コンテンツのサイズをアニメーション化する、"AnimateRSVPMessage" という名前の単純な JavaScript 関数を定義します。 次のコードでは、テキストを最初は小さく表示し、400 ミリ秒の時間枠で徐々に拡大させます。

<script type="text/javascript">

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

</script>

次に、この JavaScript 関数を組み込んで AJAX 呼び出しが正常に完了した後に呼び出されるようにします。そのために、関数の名前を Ajax.ActionLink() ヘルパー メソッドに (AjaxOptions の "OnSuccess" イベント プロパティを使って) 渡します。

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

これで、"RSVP for this event" (このイベントに出席する) リンクをクリックして AJAX 呼び出しが正常に完了すると、返されるコンテンツ メッセージはアニメーション化されて大きくなります。

Screenshot of the Nerd Dinners page with the message Thanks We Will See You There in large print at the bottom.

AjaxOptions オブジェクトは、"OnSuccess" イベントだけでなく OnBegin、OnFailure、OnComplete の各イベントも提供しており、これらを処理することもできます (他にもさまざまなプロパティや便利なオプションがあります)。

クリーンアップ - RSVP 部分ビューのリファクタリング

詳細ビュー テンプレートは少し長くなってきているので、時間が経つと理解しにくくなるおそれがあります。 コードを読みやすくするために、Details ページのすべての RSVP ビュー コードをカプセル化する部分ビュー (RSVPStatus.ascx) を作成して仕上げましょう。

これを行うには、\Views\Dinners フォルダーを右クリックし、[追加] > [ビュー] メニュー コマンドを選択します。 ここでは、厳密に型指定された ViewModel として Dinner オブジェクトを受け取るようにします。 その後、Details.aspx ビューから RSVP コンテンツをコピーして貼り付けることができます。

完了したら、Edit と Delete のリンク ビュー コードをカプセル化する別の部分ビュー (EditAndDeleteLinks.ascx) も作成しましょう。 これも、厳密に型指定された ViewModel として Dinner オブジェクトを受け取るように設定し、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 をさらに使用して、アプリケーションに対話型マッピングのサポートを追加する方法を見てみましょう。