ASP.NET Webサイトでは、静的なクラスは各Webリクエストに固有ですか、それとも必要なときにインスタンス化され、GCがそれらを破棄することを決定するたびにGCされますか?
私が尋ねる理由は、以前にC#でいくつかの静的クラスを記述したことがあり、その動作が予想とは異なるためです。静的クラスは各リクエストに固有であると予想していましたが、そうではないようです。
それらが各リクエストに固有ではない場合、それらを許可する方法はありますか?
更新:
driisがくれた答えは、まさに私が必要としていたものでした。私はすでにシングルトンクラスを使用していましたが、静的インスタンスを使用していたため、ユーザーが異なっていてもリクエスト間で共有されていました。この場合は悪いことです。 HttpContext.Current.Items
を使用すると、問題が完全に解決します。将来この質問に出くわした人のために、パターンを理解しやすいように、簡略化および短縮された私の実装を以下に示します。
using System.Collections;
using System.Web;
public class GloballyAccessibleClass
{
private GloballyAccessibleClass() { }
public static GloballyAccessibleClass Instance
{
get
{
IDictionary items = HttpContext.Current.Items;
if(!items.Contains("TheInstance"))
{
items["TheInstance"] = new GloballyAccessibleClass();
}
return items["TheInstance"] as GloballyAccessibleClass;
}
}
}
静的クラスと静的インスタンスフィールドは、アプリケーションへのすべてのリクエスト間で共有され、アプリケーションドメインと同じ有効期間を持ちます。したがって、同期の問題などがある可能性があるため、静的インスタンスを使用する場合は注意が必要です。また、アプリケーションプールがリサイクルされる前に静的インスタンスはGCされないため、静的インスタンスによって参照されるすべてのものはGCされないことに注意してください。これにより、メモリ使用量の問題が発生する可能性があります。
リクエストと同じ有効期間のインスタンスが必要な場合は、HttpContext.Current.Items
コレクションを使用することをお勧めします。これは、設計上、要求全体に必要なものを保管する場所を意味します。デザインと読みやすさを向上させるために、Singletonパターンを使用してこれらのアイテムを管理できます。インスタンスをHttpContext.Current.Items
に保存するシングルトンクラスを作成するだけです。 (ASP.NETの共通ライブラリには、この目的のための一般的なSingletonRequestクラスがあります)。
静的メンバーのスコープは現在のワーカープロセスのみであるため、同じワーカープロセスによって異なるリクエストが処理される場合と処理されない場合があるため、リクエストとは関係ありません。
ところで、ワーカープロセスの既定の数は1です。そのため、静的メンバーにはアプリケーション全体のスコープがあると考える人でWebがいっぱいです。
型はアプリドメインに含まれているため、アプリドメインがリサイクルされない限り、またはリクエストが別のアプリドメインによって処理される場合は、静的クラスが存在することを期待します。
特定のリクエストに固有のオブジェクトを作成するいくつかの方法は、あなたが何をしたいかによって異なります。 Application.BeginRequestでオブジェクトをインスタンス化し、それをHttpRequestオブジェクトに格納して、リクエスト処理パイプライン内のすべてのオブジェクトからアクセスできるようにすることができます。
それらが各リクエストに固有ではない場合、それらを許可する方法はありますか?
いや。静的メンバーはASP.NETプロセスによって所有され、Webアプリのallユーザーによって共有されます。セッション変数など、他のセッション管理手法に目を向ける必要があります。
通常、静的メソッド、プロパティ、およびクラスはApplication
レベルで一般的です。アプリケーションが存続している限り、それらは共有されます。
ThreadStatic
属性を使用して、異なる動作を指定できます。その場合、それらは現在のスレッドに固有であり、それは各リクエストに固有であると思います。
これは複雑すぎると思われるので、これはお勧めしません。
HttpContext.Current.Items
を使用して、1つのリクエストに対してスタッフを設定するか、HttpContext.Current.Session
を使用して(リクエスト全体で)1人のユーザーに対してスタッフを設定できます。
ただし、一般的に、Server.Transfer
のようなものを使用する必要がない限り、基本的な方法は基本的に一度作成し、メソッド呼び出しによって明示的に渡すことです。