フィルターを使用して別のアクションを実行しますか?
-
19-09-2019 - |
質問
たくさん持つのは避けたい if Request.IsAjaxRequest()
私のコントローラーでは。このロジックを ActionFilter に凝縮できれば、アプリケーションで規則を採用して、次のようなリクエストに対して 2 番目のアクションを提供するのが簡単になるだろうと考えていました。 5月 Ajax を使用しますが、JavaScript が無効になっている場合はフォールバックを提供します。
public ActionResult Details(int id)
{
// called normally, show full page
}
public ActionResult Details_Ajax(int id)
{
// called through ajax, return a partial view
}
最初は次のようなことができるのではないかと考えました。
public class AjaxRenameAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.RouteData.Values["action"] = filterContext.RouteData.Values["action"] + "_Ajax";
}
しかし、呼び出すアクションが決定され、そのアクションに対するフィルターが処理されるため、これは機能しません。
誰かがアクションを呼び出すたびに RedirectResult を返すことは実際にはしたくありません。HTTP リクエストの量を 2 倍にするのは少し無意味に思えます。
リクエストを別のアクションにルーティングする別の方法はありますか?それとも、私がやっていることはお勧めできず、もっと良い方法を探す必要があるのでしょうか?
乾杯
解決
AcceptAjaxAttribute
おそらくここで必要なものはこれです。しかし、私はこの問題について別の考え方を提案したいと思います。
すべての Ajax リクエストが等しいわけではありません。Ajax リクエストは、次のいずれかを実行しようとしている可能性があります。
- JSON データをリッチ グリッド (jqGrid など) にバインドします。
- RSS フィードなどの XML データの解析/変換。
- 部分的な HTML をページの領域にロードします。
- スクリプトを非同期でロードする (
google.load
これはできます); - クライアントからの一方向メッセージを処理します。
- そして、おそらく私が忘れているものがさらにいくつかあります。
のみに基づいて特定の「代替アクション」を「選択」すると、 IsAjaxRequest
このメソッドでは、非常に一般的なもの (非同期リクエスト) をサーバー上の特定の機能に結び付けています。最終的には設計がより脆弱になり、コントローラーの単体テストも難しくなります (コンテキストをモックするなど、方法はありますが)。
うまく設計された アクション あるべきです 一貫性のある, 、それは気にするだけです 何 リクエストはそうではありませんでした どうやって リクエストが行われました。次のような他の属性を指すこともできます。 AuthorizeAttribute
例外として、フィルタについては区別します。フィルタは、ほとんどの場合、アクションが発生する「代わりに」ではなく、アクションが発生する「前」または「後」のいずれかに発生する必要がある動作を記述します。
ここで本題に入りますが、質問に記載されている目標は良いものです。あなたがすべき 絶対に 異なるアクションとして正しく説明されるものには、異なるメソッドがあります。
public ActionResult Details(int id)
{
return View("Details", GetDetails(id));
}
public ActionResult JsonDetails(int id)
{
return Json(GetDetails(id));
}
public ActionResult PartialDetails(int id)
{
return PartialView("DetailTable", GetDetails(id));
}
等々。ただし、Ajax アクション セレクターを使用してこれらのメソッドを選択することは、次の慣例に従います。 「優雅な劣化」, 、これは本質的に(少なくともIMO)によって置き換えられました。 プログレッシブエンハンスメント.
このため、私は ASP.NET MVC が大好きですが、ほとんどの場合は避けています。 AjaxHelper
, というのは、この概念をうまく表現しているとは思えないからです。それはあなたからあまりにも多くのことを隠そうとします。「Ajax フォーム」または「Ajax アクション」の概念を持たずに、区別をなくして、ストレートな HTML にこだわりましょう。 クライアントが Ajax 機能を処理できることが確認できたら、Ajax 機能を個別に挿入します。
これは jQuery での例です。ただし、これは MS AJAX でも実行できます。
$(function() {
$("#showdetails").click(function() {
$("#details").load("PartialDetails", { id: <%= Record.ID %> });
return false;
}
});
Ajax を MVC ページに挿入するために必要なのはこれだけです。プレーンな古い HTML リンクから開始し、Ajax 呼び出しでオーバーライドします。 それは別のコントローラーアクションに移ります.
ここで、サイトの別の場所で、代わりにグリッドを使用したいが、部分レンダリングを使用してページを分割したくない場合は、次のように記述できます (次のような単一のマスター詳細ページがあるとします)左側に「注文」のリスト、右側に詳細表):
$(".detaillink").click(function() {
$('#detailGrid').setGridParam({
url: $(this).attr("href").replace(/\/order\/details/i,
"/order/jsondetails")
});
$("#detailGrid").trigger("reloadGrid");
});
このアプローチは、クライアントの動作をサーバーの動作から完全に切り離します。サーバーは事実上、クライアントに次のように伝えています。 JSONバージョンが必要な場合は、 聞く JSON バージョンの場合、ちなみに、実行方法がわかっている場合は、リンクを変換するためのスクリプトを次に示します。 アクション セレクターやメソッド オーバーロードの処理は必要ありません。単純なテストを実行するために特別なモックを作成する必要はありません。どのアクションがいつ何を行うかについて混乱することもありません。ほんの数行の JavaScript です。コントローラーのアクションは短くて魅力的で、まさにその通りです。
これが唯一のアプローチではありません。明らかに、次のようなクラス AcceptAjaxAttribute
一部の開発者がリクエスト検出メソッドを使用することを期待していたために、このメソッドが存在しました。しかし、両方をかなり試した後、私はこの方法を見つけました 多くの 推論が容易になるため、正しく設計/コード化することが容易になります。
他のヒント
どのようにAcceptAjaxAttributeについてMvcFuturesで?