HttpModule Init メソッドが数回呼び出されます。なぜですか?
-
16-09-2019 - |
質問
http モジュールを作成していて、デバッグ中に、最初は (少なくとも) 奇妙な動作のように見えることに気づきました。
httpmodule の init メソッドにブレークポイントを設定すると、デバッグのために Web サイトを起動して 1 回のリクエストを行っただけであるにもかかわらず、http モジュールの init メソッドが数回呼び出されていることがわかります (1 回しかヒットしない場合もあります) 、他の場合は10回まで)。
HttpApplication の複数のインスタンスが実行され、それぞれに対して http モジュールが作成されることを期待する必要があることはわかっていますが、単一のページをリクエストする場合、それは単一の http アプリケーション オブジェクトによって処理される必要があるため、関連付けられたイベントは 1 回だけ起動されます。しかし、それでもリクエストごとにイベントを数回起動しますが、これは意味がありません - その httpApplication 内で何度か追加されている必要があることを除けば - つまり、毎回呼び出されるのは同じ httpmodule init メソッドであり、新しい http アプリケーションではありませんブレークポイントに到達するたびに作成されます(下部のコード例を参照)。
ここで何が問題になっているのでしょうか?デバッグ中で http モジュールにブレークポイントを設定しているからでしょうか?
デバッグのために Web サイトを起動し、httpmodule のブレークポイントをすぐに越えると、init メソッドにヒットするのは 1 回だけであり、イベントハンドラーにも同じことが当てはまります。代わりにブレークポイントで数秒間ハングさせた場合、init メソッドが数回呼び出されます (ブレークポイントを超えるまでの待機時間に依存するようです)。おそらくこれは、httpmodule が初期化され、http アプリケーションがリクエストを処理できることを確認するための組み込み機能である可能性がありますが、壊滅的な結果をもたらす可能性があるもののようにも思えます。
これは、リクエストを終了しようとしており、ブレークポイントを設定しているため、何か問題が発生したと考えられ、init メソッドを再度呼び出そうとしているため、論理的に見えるかもしれません。それでリクエストを処理できるでしょうか?
しかし、これは何が起こっているのでしょうか、そしてすべてがうまくいっているのでしょうか(私はただ推測しています)、それともそれは本当に問題なのでしょうか?
私が特に懸念しているのは、何かが原因で「実稼働/ライブ」サーバーで数秒間ハングすると、多くのイベント ハンドラーが init 経由で追加されるため、ページへの各リクエストで突然イベント ハンドラーが数回起動されることです。
この動作により、どのサイトもすぐにダウンしてしまう可能性があります。
Formsauthentication や rolemanagermodule などの http モジュールに使用されている「元の」 .net コードを調べましたが、私のコードはそれらのモジュールが使用しているものと何ら変わりません。
私のコードは次のようになります。
public void Init(HttpApplication app)
{
if (CommunityAuthenticationIntegration.IsEnabled)
{
FormsAuthenticationModule formsAuthModule = (FormsAuthenticationModule) app.Modules["FormsAuthentication"];
formsAuthModule.Authenticate += new FormsAuthenticationEventHandler(this.OnAuthenticate);
}
}
これは、.NET Framework の RoleManagerModule でどのように実行されるかという例です。
public void Init(HttpApplication app)
{
if (Roles.Enabled)
{
app.PostAuthenticateRequest += new EventHandler(this.OnEnter);
app.EndRequest += new EventHandler(this.OnLeave);
}
}
何が起こっているのか知っている人はいますか?
(誰かがなぜこれが起こっているのかを教えてくれて、すべてが完全に問題ないことを保証してくれることを願っています):)
アップデート:
私は問題を絞り込もうとしましたが、これまでのところ、呼び出される Init メソッドは常に http モジュールの新しいオブジェクト上にあることがわかりました (以前に考えたこととは異なります)。
最初のリクエスト(サイトの起動時)では、作成されているすべての HttpApplication オブジェクトとそのモジュールが最初のリクエストを処理しようとしているため、追加されているイベントハンドラーにすべてヒットしているようです。なぜこれが起こっているのか本当にわかりません。
別のページをリクエストすると、作成されたすべての HttpApplication (およびそのモジュール) が再度リクエストを処理しようとし、イベントハンドラーが複数回ヒットします。
しかし、その後最初のページ(または別のページ)にジャンプすると、1 つの HttpApplication だけがリクエストの処理を開始し、ブレークポイントでハングさせない限り、すべてが期待どおりになるようです。
ブレークポイントでハングさせると、新しい HttpApplication のオブジェクトの作成が開始され、リクエストを処理/処理するために HttpApplications (1 つ以上) の追加が開始されます (リクエストは現在ブレークポイントで停止している HttpApplication によってすでに処理されています)。 。
私は、これが負荷やエラーの分散と処理を支援するインテリジェントな「舞台裏」の方法ではないかと期待しています。しかし、私には手がかりがありません。中には完全に大丈夫だと保証してくれる人がいるといいのですが、どうあるべきなのでしょうか?
解決
HttpContext.Current.Request を調べて、どのようなリクエストに対してモジュールの init が起動されたかを確認します。ブラウザが複数のリクエストを送信している可能性があります。
IIS に接続している場合は、IIS ログを確認して、ブレーク ポイントに滞在している間にリクエストを受信したかどうかを確認してください。
他のヒント
それは普通のことです。アプリケーションが起動すると、ASP.NETワーカープロセスは、多くのHttpApplicationオブジェクトをインスタンス化します、それはそれが必要と考えているように、それは(例えば、データベース接続プーリングに似た新しい要求、のためにそれらは再使用)、それらをプールします。
これで、各のHttpApplicationオブジェクトのために、それはまた、登録されている各のIHttpModuleの一つのコピーをインスタンス化し、その何倍Initメソッドを呼び出します。 5つのHttpApplicationオブジェクトが作成されている場合は、あなたのIHttpModuleの5つのコピーが作成され、あなたのinitメソッドが5回と呼ばれます。意味をなさない?
さて、なぜそれが言う5つのHttpApplicationsオブジェクトをインスタンス化されますか?まあ多分あなたのASPXページがブラウザにダウンロードしようとする他のリソースへのリンク、CSS、JavaScriptの、WebResource.aspx、どこか多分IFRAMEを持っています。それとも、ASP.NETワーカープロセスは、1つの以上のHttpApplicationオブジェクトを起動するための「気分にされ」、それは本当に(ウェブサーバに内蔵されたりVS)IISの下で実行されているASP.NETプロセスの内部の詳細/最適化です。
あなたは一度だけ実行する(とGlobal.asaxの中Application_StartUpイベントを使用する必要はありません)保証のコードをしたい場合は、、あなたのIHttpModuleに次のように試みることができる:
private static bool HasAppStarted = false;
private readonly static object _syncObject = new object();
public void Init(HttpApplication context)
{
if (!HasAppStarted)
{
lock (_syncObject)
{
if (!HasAppStarted)
{
// Run application StartUp code here
HasAppStarted = true;
}
}
}
}
私は似たようなやったと私は私が何かを見逃している場合には、私の作品の批評を歓迎するだろうけれども、動作しているようです。
ここでは説明のビットは、使用すべきか、いつ、どのように動作することとなります。 はいつGlobal.asaxの中で初期化対のApplication_Startを使用するには?
編集:より多くの読み取り
Examleは、上記のすべての要求のためのIHttpModuleをロックし、その後、それはアプリケーション全体をfrezes。
:あなたのIHttpModuleコールが数回要求した場合のHttpApplication方法CompleteRequestを呼び出し、このようなのHttpApplicationのインスタンスを除去するために、EndRequestのイベントでのIHttpModuleののHttpApplicationインスタンスを配置するために必要とされますpublic class TestModule :IHttpModule
{
#region IHttpModule Members
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
context.EndRequest += new EventHandler(context_EndRequest);
}
void context_EndRequest(object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
app.CompleteRequest();
app.Dispose();
}
void context_BeginRequest(object sender, EventArgs e)
{
//your code here
}
#endregion
}
あなたはのIHttpModuleは上記のコードを使用してポストバックにrerequestせずにすべての時間を要求していることが必要な場合。