1

ビジネスレイヤーサーバーにWebフロントエンドがあります。

Web アプリケーションの特定のページは、非常に長時間実行されるタスクをインスタンス化します (最大で 10 分以上かかる場合があります)。これらのリクエストは次のように処理されます: -

(HTTP 要求スレッドで)

  • ビジネスサーバーに接続します。
  • 接続オブジェクトを渡す長時間の呼び出しを行う新しいスレッドを作成します。
  • 次に、HTTP 要求が完了し、ハンドルがブラウザに返されます。
  • ブラウザーは Web サーバーを定期的にポーリングして、実行時間の長いタスクの進行状況に関する最新情報を取得します。

ビジネス サーバーへのすべての要求は認証されます。接続のユーザー プリンシパル ページには、ビジネス サーバー上のメソッドを呼び出す権限が必要です。

このメカニズムは、Web アプリケーションがクラシック モードで実行されている限り正常に機能します。パイプライン モードで実行すると、ブラウザーのポーリング時に ObjectDisposedExceptions が発生します。

System.ObjectDisposedException: Safe handle has been closed
at System.StubHelpers.StubHelpers.SafeHandleC2NHelper(Object pThis, IntPtr CleanupWorkList)
at Microsoft.Win32.Win32Native.GetTokenInformation(SafeTokenHandle TokenHandle, UInt32 TokenInformationClass, SafeLocalAllocHandle TokenInformation, UInt32 TokenInformationLength, ref UInt32 ReturnLength)
at System.Security.Principal.WindowsIdentity.GetTokenInformation(SafeTokenHandle tokenHandle, TokenInformationClass tokenInformationClass, ref UInt32 dwLength)
at System.Security.Principal.WindowsIdentity.get_User()
at System.Security.Principal.WindowsIdentity.GetName()
at System.Security.Principal.WindowsIdentity.get_Name()

問題は、接続を確立するために使用された Windows プリンシパルが、元の要求が終了したときに破棄されることです (これは理解できます - 実際、コードがまったく機能したことに驚いています!)。

この問題を回避する方法として、HTTP リクエスト プリンシパルの複製を作成し、それを使用して接続を作成する (そして、長時間実行されるタスクが完了したら破棄する) ことが可能か、または、プリンシパルが破棄された後でも、ワーカー スレッドの HTTP 要求の原則は?

アップデート

(Aliostad の質問に対する私のコメントは間違っていました。テスト ページは失敗しました。実際の (障害のある) コードと同じコード パスを実行しないように、テスト ページを作成するのに十分な混乱をきたしました。気にしないでください!)

この問題の「回避策」を書きました: - ビジネス サーバーへの呼び出しが行われる前に、ビジネス サーバー ロジックがどのロール/グループを照会するかを知っている幸運な立場にあります。したがって、私の回避策は、これらのロールのリクエストのプリンシパルのメンバーシップに基づいて、新しい汎用プリンシパルを作成することです。長時間実行タスクは、汎用プリンシパルを使用して実行されます。

私はこの回避策に 100% 満足しているわけではありません。なぜなら、これは非常に「ハック」だからです。つまり、プリンシパルの ID が認証されていることを検証する (非常に賢明な) チェックを何らかのロジックで行うと、簡単に失敗することがわかります。

ですから、この問題についての助けや洞察をいただければ幸いです。

ありがとう

4

1 に答える 1

1

OK、これが私のキャッチです。

まず、スレッドを作成すると、現在のスレッドのすべてのセキュリティ コンテキストが新しいスレッドにコピーされます (既定では)。この操作は重いですが、非常に必要です (ほとんどの場合、これがないと機能しません)。それを防ぐ必要があり、コンテキストのコピーが必要ない場合は、それを行う方法があり、CLR を介して Richter の C# で説明されています。幸運なことに、彼はこの本のほんの一部をここで共有し、基本的に静的メソッドを呼び出してコンテキストがflowed.

ExecutionContext.SuppressFlow();

Reflectorを使用していますが、これがWCFで呼び出されているとは思えません。

  [SecuritySafeCritical]
    private IAsyncResult BeginGetContext(bool startListening)
    {
        Exception exception;
        do
        {
            exception = null;
            try
            {
                try
                {
                    if (ExecutionContext.IsFlowSuppressed())
                    {
                        return this.listener.BeginGetContext(this.onGetContext, null);
                    }
                    using (ExecutionContext.SuppressFlow())
                    {
                        return this.listener.BeginGetContext(this.onGetContext, null);
                    }
                }
                // .... the rest

興味深いことに、これは の 3 つの場所で使用されていSharedHttpTransportManagerます。

これで問題が見つかったように見えるかもしれませんが、それはバグですが、私はそれを非常に疑っています.

私の推測では、間にプロセスのリサイクルが発生し、コンテキストが失われます。これを証明または反証する方法は、perfmon を使用してすべてのプロセス リサイクルを登録し、間にあるかどうかを調べることです。

私の解決策は基本的に - あなたが好きではないかもしれません! - 単純にアイテムをキュー (MSMQ または単純なデータベース キュー) に挿入し、Windows サービスにそれを読み取らせる。この操作は非常に重要であるため、IIS が最後まで実行するとは決して信じません。

これがお役に立てば幸いです。

于 2010-11-29T13:30:29.733 に答える