2011-07-20 8 views
0

私はここでボックスの外に少し何かしようとしています。私は、それがスレッドの問題だと思うヒットミスの結果を得ています。レスポンス後のASP.NETワーカースレッド

私たちはASP.NET 4アプリケーションを使用して、データベース内の各ページ要求をいくつかのセッション情報とともにログに記録します。また、各ページの生成に要した時間も確認したいので、アプリ内のすべてのページが派生した基本ページを持ち、OnUnloadイベントをオーバーライドします。このハンドラーでは、ページ生成時間を

DateTime.Now.Subtract(HttpContext.Current.Timestamp).TotalSeconds 

から取得します。しかしその後、非同期にしようと決めました。クライアントがそのログレコードの挿入を待つ必要がなければ、ページがより速く配信される可能性があります。だから私はこのような何か試してみました:

ThreadPool.QueueUserWorkItem(new WaitCallback(LogPageRequest)); 

をしかし、私が言ったように、時にはそれが時にはそれがない、動作します。要求が終了したため、サーバーはワーカースレッドを強制終了していますか?これを行うより良い方法はありますか?

答えて

0

私はそれが殺されているワーカースレッドではないと思うが、HttpContext.Currentインスタンス。そのタイムスタンプの値をスレッドプールにキューイングする前に入れてください(言い換えれば、その周りにクロージャを作成します)。その方法は、スレッドプールがロギングメソッドを実行する準備ができているときに、意図した値になります。

... 
// generate response 
var time = DateTime.Now.Subtract(HttpContext.Current.Timestamp).TotalSeconds; 
ThreadPool.QueueUserWorkItem(o => { 
    SaveTimeToDatabase(time); 
}); 

//return response 

あなたはクロージャを使用したくない場合もThreadPool.QueueUserWorkItemに時間値を渡すことができます

var time = DateTime.Now.Subtract(HttpContext.Current.Timestamp).TotalSeconds; 
ThreadPool.QueueUserWorkItem(new WaitCallback(LogPageRequest), time); // the object passed into LogPageRequest will now be the time to save to the database 
... 
1

ThreadPool.QueueUserWorkItemは、ASP.NETで使用すべきではありません。問題は、スレッドプールスレッドがページコンテキストを持っているかもしれないし、持っていないかもしれないということです(ページコンテキストを持っていれば、別のページのためかもしれません!)。また、コールバックが決して実行されない可能性もあります(アプリプールがリサイクルされるたびに)。

BackgroundWorkerおよびその他のSynchronizationContextベースのソリューションは、コールバックでページのコンテキスト(およびIDとカルチャ)を復元するために機能します。 SynchronizationContextがASP.NETでどのように動作するかについては、my MSDN articleを参照してください(なぜ)。ただし、ページリクエストが完了するまでページリクエストもブロックされます。

の後にのページリクエストが完了した後に、別のサービスを使用する必要があります。ローカルのWCFまたはWindowsサービスは良い解決策になります。

関連する問題