7

ASP.NET アプリケーションにアウト プロセス セッション プロバイダー ( ScaleOut ) を使用していますが、逆シリアル化用に正しく設定されていないオブジェクトが誤ってセッションに入ると、最終的に全体のエラーが発生することに気付きました。終了するプロセス

このシナリオを再現して処理すると、さらに興味深いものになります。

プロセスを終了させる例外はAnyStaObjectsInSessionStateで発生します。その実装は非常に簡単です。

internal static bool AnyStaObjectsInSessionState(HttpSessionState session)
{
    if (session != null)
    {
        int count = session.Count;
        for (int i = 0; i < count; i++)
        {
            object obj2 = session[i];
            if (((obj2 != null) && (obj2.GetType().FullName == "System.__ComObject"))
                && (UnsafeNativeMethods.AspCompatIsApartmentComponent(obj2) != 0))
            {
                return true;
            }
        }
    }
    return false;
}

ここで例外がプロセスを終了する方法を示すスタック トレースを次に示します。

An unhandled exception occurred and the process was terminated.

Application ID: /LM/W3SVC/1/ROOT

Process ID: 4208

Exception: System.Runtime.Serialization.SerializationException

Message: The constructor to deserialize an object of type 'Lucene.Net.QueryParsers.ParseException' was not found.

StackTrace:    at System.Runtime.Serialization.ObjectManager.CompleteISerializableObject(Object obj, SerializationInfo info, StreamingContext context)
   at System.Runtime.Serialization.ObjectManager.FixupSpecialObject(ObjectHolder holder)
   at System.Runtime.Serialization.ObjectManager.DoFixups()
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Web.Util.AltSerialization.ReadValueFromStream(BinaryReader reader)
   at System.Web.SessionState.SessionStateItemCollection.ReadValueFromStreamWithAssert()
   at System.Web.SessionState.SessionStateItemCollection.DeserializeItem(String name, Boolean check)
   at System.Web.SessionState.SessionStateItemCollection.DeserializeItem(Int32 index)
   at System.Web.SessionState.SessionStateItemCollection.get_Item(Int32 index)
   at System.Web.SessionState.HttpSessionStateContainer.get_Item(Int32 index)
   at System.Web.Util.AspCompatApplicationStep.AnyStaObjectsInSessionState(HttpSessionState session)
   at System.Web.HttpApplicationFactory.FireSessionOnEnd(HttpSessionState session, Object eventSource, EventArgs eventArgs)
   at System.Web.SessionState.SessionOnEndTargetWorkItem.RaiseOnEndCallback()
   at System.Web.Util.WorkItem.CallCallbackWithAssert(WorkItemCallback callback)
   at System.Threading.ExecutionContext.runTryCode(Object userData)
   at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal(_ThreadPoolWaitCallback tpWaitCallBack)
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state)

InnerException: System.Runtime.Serialization.SerializationException

Message: The constructor to deserialize an object of type 'Lucene.Net.QueryParsers.ParseException' was not found.

StackTrace:    at System.Runtime.Serialization.ObjectManager.GetConstructor(Type t, Type[] ctorParams)
   at System.Runtime.Serialization.ObjectManager.CompleteISerializableObject(Object obj, SerializationInfo info, StreamingContext context)

次の 2 つのことを理解したいと思います。

  1. アウトプロセス プロバイダーに対してFireSessionOnEndが発生するのはいつで、さらに重要なこととして、負荷のかかっていない開発環境でこれをどのように模倣できるでしょうか。セッション タイムアウトを短くして (1 分に設定)、Abandon() を手動で呼び出し、GC.Collect() を手動で呼び出して実験しましたが、すべて役に立ちませんでした。

  2. アプリ プールを保護するために、このステップで発生したエラーをトラップできますか? ここで発生した例外は、 Source=ASP.NET 2.0.50727.0でログに記録され、global.asax のアプリケーション エラー ハンドラーには到達しません。セッションにバインドされたオブジェクトに適切な抑制と均衡が適用された後でも、このシナリオを防ぐために何ができるでしょうか?

任意の洞察をいただければ幸いです。

4

3 に答える 3

3

SOSS テクニカル サポートの助けを借りて、この問題を解決することができました。非常に役に立ちました。詳細は次のとおりです。

  • セッションの有効期限が切れると、SOSS はそのクライアント ライブラリで有効期限イベントを発生させます。これは、Global.asax で Session_End を起動する役割を果たします (注: ScaleOut はクライアント間で有効期限イベントを負荷分散するため、セッションを作成した Web サーバーは必ずしもそのイベントを受信しない場合があります)。有効期限イベント - これは、これらの問題を再現するために重要です)。
  • これはリクエストのコンテキスト外で発生するため、例外は処理されず、アプリ プールが強制終了されます。
  • これは非常にまれなシナリオですが、今後のメンテナンス リリースで対処する予定です。
  • 救済策は次のとおりです。

    1. System.Exceptionの派生型を修正します(これはシリアル化可能ですが、非シリアル化はできません)。

    2. Global.asax で Session_End イベントを削除するか、有効期限イベントを無効にします ( soss_params.txtで max_event_retries を 0 に設定)。

    3. これらのシナリオでは、ユーザーが 要求の 1 つでSerializationExceptionに遭遇する可能性があります。つまり、 Application_Errorに到達し ます。ここで、セッション キーをクリアするか (すべてのキーをクリアする必要があります)、セッションを完全に破棄できます。

    4. AppDomain.UnhandledExceptionにサブスク ライブして、未処理の例外が発生した場合に通知を受けます (ここでは頼りにならず、ログに記録するだけです)。また、 legacyUnhandledExceptionPolicyを使用して無効にすることもできます (推奨されません)。

于 2010-06-30T13:51:05.110 に答える
1

アプリ プールを保護するために、このステップで発生したエラーをトラップできますか? ここで発生した例外は、Source=ASP.NET 2.0.50727.0 でログに記録され、global.asax のアプリケーション エラー ハンドラーには到達しません。セッションにバインドされたオブジェクトに適切な抑制と均衡が適用された後でも、このシナリオを防ぐために何ができるでしょうか?

これがうまくいくかどうかはわかりませんが、試してみてください

于 2010-06-30T04:47:33.453 に答える
0

SessionEnd メソッドを完全に削除するだけでこれを修正しました。Asp.net はリフレクションを使用してメソッドの存在を検索し、問題のあるコードを実行するため、メソッドの内容を削除するだけでは不十分です。

于 2016-01-27T12:18:02.323 に答える