質問

ユーザーが一連の異なる ASP.Net Web フォームで実行しているいくつかのアクションの「状態」を保存したいと考えています。状態を永続化するにはどのような選択肢がありますか?また、各ソリューションの長所/短所は何ですか?

私は Session オブジェクトを使用し、いくつかのヘルパー メソッドを使用してオブジェクトを厳密に型指定してきました。

    public static Account GetCurrentAccount(HttpSessionState session)
    {
        return (Account)session[ACCOUNT];
    }

    public static void SetCurrentAccount(Account obj, HttpSessionState session)
    {
        session[ACCOUNT] = obj;
    }

私は多くの情報源から「セッションは悪である」と言われてきたので、それがこの質問の根本的な原因です。あなたが考える「ベストプラクティス」とその理由を知りたいです。

役に立ちましたか?

解決

セッション状態には本質的に悪いことは何もありません。

ただし、注意すべき点がいくつかあります。

  1. ユーザーがブラウザの戻るボタンを押すと、前のページに戻りますが、セッション状態は元に戻りません。そのため、CurrentAccount はページに元々表示されていたものと異なる可能性があります。
  2. ASP.NET プロセスは IIS によってリサイクルできます。それが発生すると、次のリクエストにより新しいプロセスが開始されます。デフォルトのプロセスセッション状態を使用している場合、それはなくなります:-(
  3. ユーザーがしばらくアクティブでなかった場合にも、同じ結果でセッションがタイムアウトする可能性があります。デフォルトは 20 分なので、おいしいランチで十分です。
  4. アウトプロセスセッション状態を使用するには、セッション状態に格納されているすべてのオブジェクトがシリアル化可能である必要があります。
  5. ユーザーが 2 番目のブラウザ ウィンドウを開いた場合、2 番目の別個のアプリケーションがあることを期待しますが、セッション状態は 2 つの間で共有される可能性が高くなります。したがって、一方のブラウザ ウィンドウで CurrentAccount を変更すると、もう一方のブラウザ ウィンドウでも同じことが行われます。

他のヒント

フォーム データを一時的に保存するための 2 つの選択肢は、1 つ目は各フォームの情報をセッション状態変数に保存すること、2 つ目は URL パラメーターを使用してフォーム情報を渡すことです。潜在的な 3 番目のオプションとして Cookie を使用することは、訪問者の多くが Cookie をオフにしている可能性が高いという単純な理由から、単純に実行できません (ただし、これはセッション Cookie には影響しません)。また、質問の性質上、完全にコミットされるまでこの情報をデータベース テーブルに保存したくないのではないかと思います。

セッション変数の使用はこの問題に対する古典的な解決策ですが、いくつかの欠点があります。その中には、(1) インプロセス セッション管理を使用している場合、大量のデータがサーバーの RAM を使い果たす可能性があること、(2) サーバー ファーム内の複数のサーバー間でセッション変数を共有するには追加の考慮事項が必要であること、(3) 専門的に設計されたアプリを使用する必要があることなどが挙げられます。セッションの有効期限が切れないよう保護します (セッション変数をキャストして使用するだけではなく、セッションの有効期限が切れている場合はキャストによってエラーがスローされます)。ただし、ほとんどのアプリケーションでは、セッション変数が最適な方法であることは間違いありません。

別の方法は、各フォームの情報を URL に含めて渡すことです。このアプローチの主な問題は、情報を「伝える」際に細心の注意を払う必要があることです。たとえば、4 つのページで情報を収集している場合、最初のページで情報を収集し、その情報を URL で 2 番目のページに渡し、そのページのビューステートに保存する必要があります。次に、3 番目のページを呼び出すときに、2 番目のページとビューステート変数からフォーム データを収集し、両方を URL などにエンコードします。ページが 5 ページ以上ある場合、または訪問者がサイト内を飛び回っている場合は、非常に面倒なことになります。また、すべての情報は、A) URL セーフな文字列にシリアル化され、B) 単純な URL ベースのハッキングを防ぐ方法でエンコードされる必要があることにも留意してください。価格をクリアテキストで送信すると、誰かが価格を変更する可能性があります)。一種の「セッション マネージャー」を作成し、それに URL 文字列を管理させることで、これらの問題の一部を軽減できますが、それでも、特定のリンクが誰かのセッション全体を吹き飛ばす可能性があることに非常に敏感である必要があることに注意してください。適切に管理されていません。

結局のところ、私は非常に限られたデータをあるページから次のページに渡すためにのみ URL 変数を使用します (例:そのアイテムへのリンク内でエンコードされたアイテムの ID)。

次に、実際に組み込みのセッション機能を使用してユーザーのデータを管理すると仮定してみましょう。なぜ「セッションは悪だ」と言われるのでしょうか?さて、上で示したメモリ負荷、サーバー ファーム、および有効期限に関する考慮事項に加えて、セッション変数に対する主な批判は、それらが事実上型なし変数であるということです。

幸いなことに、セッション変数を慎重に使用するとメモリの問題を回避できます (大きな項目はとにかくデータベースに保存する必要があります)。また、サーバー ファームが必要なほど大きなサイトを実行している場合は、ASP に組み込まれた状態共有に利用できるメカニズムがたくさんあります。 .NET (ヒント:インプロセスストレージは使用しません)。

Session のその他の欠点を本質的にすべて回避するには、セッション データを保持するオブジェクトと、いくつかの単純な Session オブジェクト管理機能を実装することをお勧めします。次に、これらを Page クラスの子孫に構築し、この子孫の Page クラスをすべてのページに使用します。これにより、ページ クラスを介して、厳密に型指定された値のセットとしてセッション データにアクセスすることが簡単になります。オブジェクトのフィールドは、厳密に型指定された方法で各「セッション変数」にアクセスする方法を提供することに注意してください (例:変数ごとに 1 つのフィールド)。

これがあなたにとって簡単なタスクなのか、それともサンプル コードが必要なのかをお知らせください。

私の知る限りでは、 Session は、この情報を保存するための意図された方法です。セッション状態は通常、デフォルトでプロセスに保存されることに注意してください。複数の Web サーバーがある場合、または IIS が再起動されると、セッション状態が失われます。この問題は、ASP.NET State Service、または SQL データベースを使用してセッションを保存することで修正できます。これにより、別の Web サーバーに再ルーティングされた場合や、ワーカー プロセスがリサイクルされた場合でも、ユーザーは確実にセッションを取り戻すことができます。

この不吉な評判の理由の 1 つは、急いでいる開発者が (あなたのようなヘルパー クラスではなく) UI コード内の文字列リテラルをアイテム キーとして使用してこれを過剰に使用し、最終的にはテスト不可能な無差別状態の大きな袋ができてしまうことです。何らかのラッパーは、悪意のないセッションを使用するための入門レベルの要件です。

「セッションの悪さ」とは……従来の ASP で開発しているのであれば、私も同意せざるを得ませんが、ASP.NET/IIS ははるかに優れた仕事をします。

本当の問題は、状態を維持する最善の方法は何かということです。私たちの場合、現在ログインしているユーザーに関しては、そのオブジェクトをセッションに保存します。 常に 名前、電子メール アドレス、権限などについてそれを参照します。

その他ちょっとした 豆知識 長期的な永続化を必要としない情報には、Cookie とビューステートの組み合わせを使用します。

Web アプリケーションにグローバルにアクセスできる情報を保存したい場合、これを行う方法は次のとおりです。 ThreadStatic 属性。これにより、 static のメンバー Class 現在のスレッドによって共有されるメンバーに追加されますが、他のスレッドには共有されません。の利点 ThreadStatic Web コンテキストを使用できる必要がないということです。たとえば、参照しないバックエンドがある場合、 System.Web, 、しかしそこでも情報を共有したい場合は、ユーザーの id すべてのリクエストの最初に、 ThreadStatic プロパティにアクセスする必要なく、依存関係でそれを参照できます。 Session 物体。

その理由は static ただし、単一のスレッドに対してのみ、他の同時訪問者がセッションを取得できないようにします。これは、リクエストごとにプロパティがリセットされるようにする限り機能します。そのため、クッキーとの相性が抜群です。

この場合、Session オブジェクトを使用しても問題ないと思いますが、ブラウザーのアクティビティが長時間ない場合、Session が期限切れになる可能性があることを覚えておく必要があります (HttpSessionState.Timeout プロパティは、セッション状態プロバイダーがセッションを終了するまでの分数を決定します)。そのため、戻る前に値の存在を確認することをお勧めします。

public static Account GetCurrentAccount(HttpSessionState session)
{
    if (Session[ACCOUNT]!=null)
        return (Account)Session[ACCOUNT];
    else
        throw new Exception("Can't get current account. Session expired.");
}

次のリクエストまで存続する必要がある短期間の情報も、 ViewState. 。これは、オブジェクトがシリアル化されてブラウザに送信されたページに保存され、クリック イベントなどでサーバーにポストバックされることを意味します。そうして ViewState はデコードされて再びオブジェクトに変換され、取得できるようになります。

セッションは悪ではなく、ASP.NET アプリケーションで重要な機能を果たし、ユーザーの「セッション」中に複数のページ間で共有する必要があるデータを提供します。いくつか提案がありますが、可能な限り SQL セッション管理を使用し、セッション コレクションで使用しているオブジェクトが「シリアル化可能」であることを確認することをお勧めします。ベスト プラクティスは、ページ間で状態情報を共有する必要がある場合にセッション オブジェクトを使用し、必要のない場合は使用しないことです。情報はクライアント側では利用できません。セッション キーは Cookie 内、クエリ文字列を通じて、または構成に応じて他の方法を使用して保持されます。その後、セッション オブジェクトはデータベース テーブルで利用可能になります ( InProc を使用しない限り、その場合、セッションはサイトのリロード中に吹き飛ばされる可能性があり、ほとんどのクラスター環境ではほとんど役に立たなくなります)。

「悪」はセッションの使いすぎから来ると思います。何でもかんでもそこに貼り付けると (すべてにグローバル変数を使用するなど)、パフォーマンスが低下し、ただ混乱するだけになります。

セッション オブジェクトに置いたものは、クリーンアップされない限り、セッションの間ずっとそこに残ります。inproc および stateserver を使用して保存されたメモリの管理が不十分だと、必要よりも早くスケールアウトする必要が生じます。セッション/ユーザーの ID のみをセッションに保存し、ヘルパー クラスを使用してオンデマンドで必要なものをキャッシュ オブジェクトに読み込みます。そうすることで、データを使用した頻度に応じて寿命を微調整できます。asp.net の次のバージョンには分散キャッシュが搭載される可能性があります (噂)。

悪としてのセッション:ASP.NET に存在せず、正しく構成されています。確かに、できるだけ無国籍であることが理想的ですが、現実にはここからそこに到達することはできません。ただし、Session の影響を軽減する方法で Session を動作させることはできます (特に、StateServer またはデータベース セッション)。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top