1

動的コンパイルを使用してASP.NETWebサイトプロジェクトを使用していますが、最近SQL Serverでバックアップされたセッション状態に移行し、奇妙なエラーが発生し始めました。私はこれを引き起こしている原因を理解しましたが、それを解決するための最良の方法がわかりません。

ローカルホストで再現する手順(SQLセッションを有効にした場合):

  • AppCodeで定義されたオブジェクトを配置し、それDanObjectがセッションにあるとしましょう。

    Session ["x"] = new DanObject();

  • (セッションはデータベースにシリアル化されます)

  • アプリコードの何かを変更して、次のリクエストでサイトを再コンパイルします
  • セッションにアクセスするすべてのページにリクエストを送信します

エラーは「アセンブリが見つかりません'App_SubCode_CS.rmdbqb81、Version = 0.0.0.0、Culture = neutral、PublicKeyToken=null'」です。

何が起こっているのかというと、AppCodeがコンパイルされるたびに、ランダムに名前が付けられたアセンブリに入ります。私のセッションが初めてシリアル化されたとき、AppCodeはたまたまAppCode_123という名前でした。アプリケーションを変更すると、AppCodeはAppCode_456になりました。ただし、データベースに保存されているセッションには、AppCode_123で定義されたオブジェクトがあります。セッションがDanObjectをバイナリ逆シリアル化しようとすると、AppCode_123が見つからないため、爆発します。

これを修正する最も簡単な方法は何ですか?
* Webアプリケーションへの切り替えとは言わないでください-私たちのコードベースは巨大であり、現時点では実行可能ではありません:)

4

3 に答える 3

1

DanObjectの周囲に明示的な名前空間を使用する

于 2011-03-04T17:32:53.047 に答える
0

App_Code問題は、異なるコード言語用に別々のフォルダーがあったことでした。これが、特定のクラスがCSコードフォルダー(c#コードの場合)からのものであるため、エラーメッセージで「App_Code...」ではなく「App_SubCode_CS...」と表示された理由です。これらの各コードフォルダー(web.configで定義)は、独自のアセンブリにコンパイルされます。

通常、複数のコードフォルダーAppCodeがない場合、アセンブリ名( "AppCode.randomstring")はシリアル化されたクラス名とともに格納されるため、ASP.NETは、異なる時間または異なるサーバーでコンパイルされたオブジェクトをシリアル化および逆シリアル化できます。出力。デシリアライズ時に、フレームワークはSystem.Type.GetType()アセンブリ+クラス名を呼び出します。この関数には、で始まるアセンブリ名を処理する特殊なケースApp_Codeがあります。まったく同じ名前のアセンブリが見つからない場合は、App_Codeで始まるアセンブリは見つかります。 、そのアセンブリを使用してクラスをロードします。

に言語フォルダがあるApp_Code場合、生成されたアセンブリの名前は次のようApp_SubCode_FOLDERNAME.randomstringになり、フレームワークはこのケースを処理していないようです。したがって、SQLでバックアップされたセッションを共有する2つのWebサーバーがある場合、クラスFooは"App_SubCode_FN.random1, Foo"サーバーAと"App_SubCode_FN.random2, Foo"サーバーBでコンパイルされます。ユーザーがサーバーAからセッションでFooを取得すると、次のリクエストはサーバーB、サーバーに送信されます。 Bは、という名前のアセンブリが見つからないため、Fooを逆シリアル化できません"App_SubCode_FN.random1"

この問題は、古いVBコードを削除するか(.NETがより適切に機能する単一のアセンブリにアプリコードをコンパイルできるようにする)、カスタムのSerializationBinder+SQLServerでバックアップされたセッションのカスタム実装を作成することで解決できます。

于 2011-06-16T05:33:40.143 に答える
0

さて、2番目に簡単な解決策:
別のアセンブリライブラリではなく、このクラスのコードを移動します。このようにして、シリアライザーがクラスを検出すると、そのクラスは作業に適した既知の名前を持ちます。もちろん、これにより、app_codeディレクトリを直接編集する機能が削除されます...とにかく行うべきではありません。

3番目に簡単な(そして最良の)解決策:
オブジェクトをセッションに入れないでください。必要なプロパティがいくつかある場合、それは1つのことであり、それらのプロパティを通常の文字列として保存します。

<slight_rant>

真剣に、完全なオブジェクトをセッションに入れることは、それが構築された目的ではありません。

これを実行したくない理由の詳細については、ここでの私の回答(セッションとオブジェクトの保存)を参照してください。

そして最後に、この問題は、セッションを永続化し、Webサーバー上のコードに直接変更を加えているためにのみ問題になるようです。あんな事はしないで。ローカルで変更を加えて(そしてそれらをテストして)、サイトをプリコンパイルしてデプロイし、デプロイされたら最後にセッションを無効にします。正規化されたリリーススケジュールでこれを実行して、ダウンタイムがいつであるかを全員が認識できるようにします。

</slight_rant>
于 2011-03-04T18:38:13.777 に答える