-
Notifications
You must be signed in to change notification settings - Fork 0
MS_PartialRenderingAndJavaScript
移行メモ(戻るリンクの補完): 原文には「戻る」の行が無かったため、
本文の参照関係から ASP.NET 配下として補った。
クライアント・サイドの JavaScript フレームワークとシームレスに連動して
部分更新を実現する仕組み。
補足(本ページの主題): 「Ajax で画面の一部だけを更新する」ことを、
サーバ側のフレームワークが肩代わりするという発想の仕組みを扱う。【本ページが扱う方式】サーバ主導の部分更新 UpdatePanel(Web Forms)、Ajax.BeginForm(MVC) → 開発者は Ajax を書かない。フレームワークが隠蔽する 【現在の方式】クライアント主導 fetch / axios で API を呼び、 React / Vue / Blazor が DOM を更新する → 何が起きているかがコードに現れる結論を先に言うと、本ページの 2 方式はいずれも現在は使われない
(Ajax.BeginForm は ASP.NET Core MVC で廃止、
UpdatePanel は Web Forms とともに .NET Framework 止まり)。
原文が末尾で挙げる問題点の分析が、そのまま廃止の理由になっている。
ASP.NET Web Formsの UpdatePanel
-
UpdatePanel を敷いた部分が部分更新となる。
-
ソレ以外の部分は、全体更新と成る。
-
仕組みとしては、
- 部分更新イベントで全情報がポストバックされ、
- 対象となるイベント・ハンドラが実行され、
- 部分更新される部分の HTML が返され、
- 返された HTML がレンダリングされる。
補足(「全情報がポストバックされる」が要点): 原文の
この記述が、UpdatePanel の性質を最もよく表している。【見た目】 画面の一部だけが書き換わる(Ajax っぽい) 【実際の通信】 フォーム全体 + ViewState を丸ごと POST している サーバ側ではページ ライフサイクルが「全部」走る ([ASP.NET Web Formsのイベント発生順](MS_ASPNETWebFormsEventOrder))つまり 「通信量も処理量も、全体更新とほぼ変わらない」。
減るのは描画のちらつきだけである。
通常のポストバック UpdatePanel 本来の Ajax 送信データ フォーム全体 + ViewState 同じ 必要な項目のみ サーバ処理 全ライフサイクル 全ライフサイクル 必要な処理のみ 応答 ページ全体の HTML 更新部分の HTML JSON(数十バイト) 画面のちらつき あり 無い 無い ViewState が肥大化していると、UpdatePanel は非常に重くなる。
「Ajax にしたのに速くならない」という体感は、これが原因である。
-
@IT
-
[ASP.NET AJAX]UpdatePanelコントロール利用時の注意点とは?[2.0のみ、C#、VB]
https://www.atmarkit.co.jp/fdotnet/dotnettips/672aspajaxasyncpost/aspajaxasyncpost.html -
第2回 PageRequestManagerクラスでUpdatePanelコントロールを極める!(1/5)
https://www.atmarkit.co.jp/fdotnet/ajaxlib/ajaxlib02/ajaxlib02_01.html
-
ASP.NET MVCの Ajax.BeginForm
-
-
モジュール構造は大きく変わらない。
(部分ビューは、共通化目的で Html.BeginForm にも存在する。) -
ただし、以下のように動作は大きく異なる。
- jQuery を使用してリクエストし、
- 更新部位のレスポンスを受けて JavaScript で描画。
-
-
部分更新のターゲットを意識する必要がある。
- 送信時に設定したターゲット以外を更新しようとして、結果的に画面遷移する場合、
- RedirectToAction・RedirectToRoute 等で ActionResult を返すことが出来ないので、
JavaScriptResult 等で JavaScript を返し、画面遷移をする必要がある。
補足(この「ターゲット問題」が本質的な弱点): 原文が指摘する
**「リダイレクトを返せない」**という制約は、
サーバ主導の部分更新に共通する構造的な問題である。Ajax.BeginForm は「更新先の DOM 要素(UpdateTargetId)」を あらかじめ 1 つ決めておく方式 → 正常時: 部分ビューの HTML を返し、その要素を差し替える → 異常時/画面遷移したい: 返す先が決まっているので、 RedirectToAction を返しても「その要素の中に遷移先の HTML が 埋め込まれる」という珍妙な結果になる → JavaScriptResult で location.href を書いて返す、という回避策// 回避策:JavaScript を返して遷移させる return JavaScript($"window.location='{Url.Action("Index")}';");サーバが「HTML の断片」を返す方式は、
「どこに差し込むか」をサーバとクライアントの両方が知っている必要があり、
結合度が高くなる。
これが、JSON を返して描画はクライアントに任せる方式へ
移行した理由の一つである。
以下の問題が大きかったのか、
ASP.NET Core MVC で、discon となっている。
補足(正確な経緯):
Ajax.BeginForm(Microsoft.jQuery.Unobtrusive.Ajax)は
ASP.NET Core MVC には移植されなかった。後継として用意されたもの:
機能 ASP.NET Core での代替 Ajax.BeginForm無し(自分で fetchを書く)部分ビューの返却 PartialView()は健在部分更新 fetch+innerHTML、または htmxサーバ主導の DOM 更新 Blazor Server(SignalR で差分を送る) // 現在の素朴な部分更新 const res = await fetch('/Items/List', { headers: { 'X-Requested-With': 'fetch' } }); document.getElementById('list').innerHTML = await res.text();
htmxは、まさにAjax.BeginFormと同じ発想
(HTML 断片を返して差し替える)をライブラリとして実装したもので、
ASP.NET Core と組み合わせる例が近年増えている。<form hx-post="/Items/Create" hx-target="#list" hx-swap="innerHTML">Blazor Server は、
UpdatePanel の思想を現代的に再構築したものとも言える
(サーバ側に状態を持ち、差分だけを送って DOM を更新する)。
ただし ViewState ではなく SignalR の常時接続で実現している点、
差分が DOM レベルで最小化されている点が決定的に異なる。
- 連載:ASP.NET MVC入門:第3回
ActionResultオブジェクトでアクション操作も自由自在 (4-5) - @IT
http://www.atmarkit.co.jp/ait/articles/0907/10/news109_4.html
その性質上、Ajax 通信の結果をページの一部に
反映させるようなケースで利用することになるだろう。
- ASP.NET MVC で Ajax を使った時の書き方に悩んだ - dunno logs
http://dany1468.hatenablog.com/entry/2013/01/08/144546
もともと、ASP.NET Web Formsの UpdatePanel では、
- ScriptManager がブラックボックスで
- 他の JavaScript に干渉する可能性があり。
- 危なっかしくて触りたくない感があった。
実際のトコロ、
-
JavaScript の挙動の分析が困難になり、
特に、サーバー側で JavaScript を生成して UI を制御しているとき
問題発生時のトラブルシュートが難しくなることがある。 -
部分描画では、ブラウザがレスポンス待ちかどうかユーザが識別できず、
レスポンスに時間が抱えるケースで、UX が低下するという問題を生んだ。
移行メモ(誤記): 原文の「レスポンスに時間が抱える」は
**「時間がかかる」**の誤記と判断されるが、
原文の表現を保ちつつここに注記する。
補足(この分析は的確で、そのまま廃止理由になっている): 原文が挙げる
2 点は、いずれもサーバ主導の部分更新に固有の弱点である。① JavaScript の干渉
UpdatePanel が DOM を差し替えると、 ・その領域に付けたイベント ハンドラが消える ・jQuery プラグインの初期化が失われる ・$(document).ready は再実行されない → Sys.WebForms.PageRequestManager の add_endRequest で再初期化する、という定型的な回避策が要るSys.WebForms.PageRequestManager.getInstance() .add_endRequest(function () { initPlugins(); });「差し替えたら初期化し直す」という責務が暗黙になっていることが、
原文の言う「ブラックボックス」「危なっかしい」の実体である。**現在のフレームワーク(React / Vue / Blazor)**は、
DOM の差し替えを仮想 DOM / 差分レンダリングで管理し、
ライフサイクル フック(useEffect、OnAfterRender等)を
明示的に提供することでこの問題を解消している。② 待ち状態が分からない(UX の低下)
通常のポストバック → ブラウザがローディング表示を出す 部分描画 → ブラウザは何も表示しない → ユーザーは「押せていない」と思い、二重送信する**対処は「自分でローディング表示を出す」**ことであり、
UpdatePanel にはUpdateProgressコントロールが用意されていた。現在もこの責務はクライアント側に残るが、
設計として明示されている点が異なる。
対処 現在の実装 ローディング表示 状態変数 + スピナー( isLoading)二重送信の防止 送信中はボタンを disabledに楽観的 UI 先に画面を更新し、失敗したら戻す 進捗の可視化 スケルトン表示 結論: 原文の懸念は正当で、
「部分更新をフレームワークが隠す」という設計自体が問題だった。
現在は隠さずに、明示的に扱う方向に収束している。
- UpdatePanel コントロールの概要
https://learn.microsoft.com/ja-jp/previous-versions/aspnet/bb399001(v=vs.100) - ASP.NET Core Blazor
https://learn.microsoft.com/ja-jp/aspnet/core/blazor/ - ASP.NET Core での部分ビュー
https://learn.microsoft.com/ja-jp/aspnet/core/mvc/views/partial
Tags: 移行, .NET開発, ASP.NET, ASP.NET Web Forms, ASP.NET MVC
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。