FC2ブログ
日々の開発でぶち当たった疑問解消のプロセスを残していきます。

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
-------- : スポンサー広告 :
Pagetop

[ASP.NET MVC3] AJAXを使用した部分更新

まずはサンプルの通りに実装してみる

ASP.NET MVC3とAJAXを組み合わせて部分更新をしようと思った際にはまったのでメモです。 環境は以下の通り。

  • Visual Studio 2010 SP1
  • ASP.NET MVC3
  • ビューエンジンはRazor

とっかかりに「ASP.NET MVCで認証、テスト、フィルタ機能、AJAXを活用しよう」をみながらサンプルを実装してみました。 まずはVisual StudioでASP.NET MVC3のテンプレートを使ってプロジェクトを作成します。 (MVC3のテンプレートならどれでも同じ結果になりますが、いろいろ作るのが面倒なのでインターネット用のを今回は使いました。)

続いてビューにAjaxHelperを使ってフォームとリンクを作ります。 これもサンプルと同じ感じで実装します。

@using (Ajax.BeginForm("GetDateTime", new AjaxOptions()
{
    UpdateTargetId = "DateTimeSpan"
}))
{
    <input type="submit" value="更新" />
}
@Ajax.ActionLink("更新", "GetDateTime", new AjaxOptions()
{
    UpdateTargetId = "DateTimeSpan"
})
<div>
    <p>
        現在時刻:<span id="DateTimeSpan"></span>
    </p>
</div>

次にコントローラの実装です。 これもサンプルと同じように、stringを返すアクションメソッドを作成します。

public string GetDateTime()
{
    // 確認のために1秒スリープします。
    System.Threading.Thread.Sleep(1000);
    return DateTime.Now.ToString();
}

サンプルではここまで実装して実行すると部分更新が実現できる、となっています。 しかし、MVC3のテンプレートではこのまま実行しても部分更新は実行されません。 実際に実行してみると、GetDateTimeメソッドの戻り値の表示されるページに遷移してしまいます。 これはBeginFormでレンダリングしたボタンであっても、ActionLinkでレンダリングしたアンカータグでも同様です。

サーバサイドから目的の値を取得することができているので、問題は部分更新を実現する部分にあることは明白です。 ASP.NET Web Formを使用した場合、部分更新を実現する最も簡単な方法はUpdatePanelを使用した方法です。 このとき、おまじないのように配置していたScriptManagerコントロールが、部分更新まわりのJavaScriptをまとめて公開してくれていましたが、AP.NET MVC3ではそのような便利コントロールはありません。 ASP.NET MVC3で部分更新を行うためには、テンプレートを適用した際に一緒に入ってくるjQueryのスクリプトを使用します。

プロジェクトを作成した際に自動的に出力される[Scripts]フォルダに対象のJavaScriptが入っています。 jquery.unobtrusive-ajax.js(またはjquery.unobtrusive-ajax.min.js)がそれです。 名前の通り、中身の実装はjQueryのライブラリに依存していますので、併せてjQuery本体のJavaScriptファイルも参照します。

既定では、HTMLのヘッダ部分はレイアウトファイルに記載されます。 プロジェクトルートから[Views]-[Shared]フォルダの中に_Layout.cshtmlファイルがあります。 これが既定のレイアウトファイルです。 このファイルのヘッダを以下のように設定します。

<head>
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
</head>

jQuery本体は私の環境では1.5.1が入っているのでそうなっていますが、環境に合わせて書き換えてください。

ここまで実装できたら再度実行してみてください。 今度は正しく部分更新が実行されるように見えるはずです。

ハイパーリンクが正しく動かない

さて、一見正しく動作しているように見えますが、ハイパーリンクのタグを数回クリックしてみてください。 最初の1回は正しく部分更新されている様子が見えますが、2回目以降は日時が更新されません。 ハイパーリンク→ボタン→ハイパーリンクの順でクリックすると、1回目のハイパーリンククリックで取得した値に2回目のハイパーリンククリックで戻ってしまう様が確認できるかと思います。

これはハイパーリンクの方のHTTPメソッドに原因があります。 レンダリングされたHTMLを確認してみるとわかりますが、カスタムのタグはあるものの基本的にはただのアンカータグが出力されていると思います。

<a data-ajax="true"
    data-ajax-mode="replace"
    data-ajax-update="#DateTimeSpan"
    href="/Home/GetDateTime">
    更新
</a>

通常ブラウザはただのアンカータグからはHTTP GETのメソッドを使用してアクセスを行います。 また取得した値はブラウザ内でキャッシュを獲得するように動作します。 そのため、2回目のクリックではブラウザ内のキャッシュがそのまま使用され、最初にクリックした値が再表示されてしまうわけです。 すなわちサーバサイドにリクエストを投げることもしません。 なお、この動作はブラウザの設定によって異なる可能性がありますので、正しく動作してしまう場合はブラウザのキャッシュの設定を確認ください。

この動作を変更するには、HTTP GETメソッドによるデータの取得から、POSTメソッドによる取得に変更する必要があります。 Ajax.ActionLinkメソッドの呼び出し部分に、さらに1行追加してPOSTメソッドによるデータ取得を行うよう変更します。

@Ajax.ActionLink("更新", "GetDateTime", new AjaxOptions()
{
    HttpMethod = "POST",
    UpdateTargetId = "DateTimeSpan"
})

この状態で再度実行してみると、ボタンを押下しても、ハイパーリンクを押下しても同じ結果が得られるようになると思います。

スポンサーサイト
2012-01-17 : ASP.NET MVC3 : コメント : 1 : トラックバック : 0
Pagetop
ホーム

プロフィール

masatsuna

筆者:某システム会社のダメSE
競技スキーをこよなく愛するダメSEです。

月別アーカイブ

検索フォーム

ブロとも申請フォーム

この人とブロともになる

QRコード

QR
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。