8

新しいルーティング機能を使用して、asp.net 4.5 アプリケーションを作成しています。アイテムに関する情報を表示するページがあります。イベントではPage_Load、ルート データ (アイテム ID) とユーザーのアクセス許可を確認し、何かが正しくない場合 (たとえば、ID が削除されたアイテムの場合) を使用Response.RedirectToRouteして梱包を送り、すぐにホームページに戻ります。GO を通過しないでください。$200 を収集しないでください。

削除されたアイテムにアクセスしようとすると、ホームページの代わりにエラーページが表示されるまで、これは完全に理にかなっています. 私はいくつかの掘り下げを行い、RedirectToRoute(標準的な方法とは異なりRedirect)使用した後でもページコードの残りの部分が実行され続けることを発見しました.必要なデータが存在しない場合。

私はもう少しSOマイニングを行い、信じられないほどのを発見しましたResponse.End(). それは私が必要とすることをしますが、MSDNページResponse.Endでさえ、それは古代の呪われた言語のろくでなしの子供であり、日の目を見るのにふさわしくないことを教えてくれます。主な反論は、Response.End が例外をスローするという事実のようであり、それはパフォーマンスにとって悪いことです。私は最も経験豊富な開発者ではないので、この問題を完全には理解していませんが、例外をスローする方が Web ページ全体を読み込むよりもコストがかかるとは思えません。特にほとんどのページでは何らかの有効性チェックが必要なため、回避策は非常に単純なタスクに対してかなり複雑で過剰に思えます。

この状況で私は何をすべきですか?私の無礼を使っResponse.Endて許しを請う?いくつかの醜い回避策をまとめますか?それとも、そもそも問題に対する私の見方はすべて間違っていますか? 私は本当に知りたいです。

更新: もう少し考えてみたところ、この問題について間違った見方をしているのではないかと思います。おそらく、すぐにリダイレクトすることは、ユーザー エクスペリエンスにとって最善の対応ではありません。すべてのコントロールをパネルにラップして、このようなものを使用したほうがよいでしょうか?

Private Sub Page_Init(sender As Object, e As EventArgs) Handles Me.Init
    'Validation Code
    If notValid Then
        ControlsPanel.Visible = false
        ErrorPanel.Visible = true
    End If
End Sub
4

2 に答える 2

10

RedirectToRouteは実際には、リクエストを終了するためのResponse.Redirectパスをラップfalseします。したがって、リクエストは続行されます。HttpApplication.CompleteRequestを即時呼び出しとして使用して要求を終了し、次のアプリケーション イベントが呼び出されないようにすることができます。

Response.End(およびその他の Redirect バリエーション) はThreadAbortException、リクエスト処理スレッドを中止するためにスローします。これは、リクエスト処理を停止するには本当に悪い方法です。.NET の世界では、例外処理は常に高価であると見なされます。これは、CLR がスタック全体を検索して例外処理ブロックを探したり、スタック トレースを作成したりする必要があるためですCompleteRequest。 ASP.NET インフラストラクチャ コードでフラグを設定して、EndRequestイベント以外の以降の処理をスキップします。

さらに別の (そしてより良い) 方法は、Server.Transferを使用して、リダイレクトを設定するためのクライアント ラウンドトリップを回避することです。唯一の問題は、リダイレクトされた URL がクライアントのブラウザのアドレス バーに表示されないことです。私は通常、この方法を好みます。

ページはハンドラーであり、そのすべてのイベントは単一の (および現在の) アプリケーション イベント内で発生するため、後続のページ イベントがまだ呼び出されるページの場合、 EDIT
CompleteRequestは機能しませんProcessRequest。したがって、唯一の方法は、フラグを設定し、そのフラグを 、 などのオーバーライドで確認するRenderことですPreRenderRaisePostBackEvent

メンテナンスの観点から、ベース ページ クラスにそのような機能を持たせることは理にかなっています (つまり、フラグを維持し、CompleteRequestサブクラスにメソッドを提供し、ライフ サイクル イベント メソッドをオーバーライドします)。例えば、

internal class PageBase: System.Web.UI.Page
{
    bool _requestCompleted;

    protected void CompleteRequest()
    {
       Context.ApplicationInstance.CompleteRequest();
       _requestCompleted = true;
    }

    protected override void RaisePostBackEvent(IPostBackEventHandler sourceControl,
    string eventArgument)
    {
       if (_requestCompleted) return;
       base.RaisePostBackEvent(sourceControl, eventArgument);
    }

    protected internal override void Render(HtmlTextWriter writer)
    {
       if (_requestCompleted) return;
       base.Render(writer);   
    }

    protected internal override void OnPreRender(EventArgs e)
    {
       if (_requestCompleted) return;
       base.OnPreRender(e);   
    }

    ... and so on
}
于 2013-01-22T05:37:09.997 に答える