4

NetDataContractSerializer を使用して型を逆シリアル化しようとすると、 FileLoadException が発生します。

指定されたアセンブリ名またはコードベースが無効でした。(HRESULT からの例外: 0x80131047)

このエラーは、特にシリアライザーとは関係ありません。アセンブリ修飾名によって実行時に型を読み込もうとすると、同じ失敗が発生します。

AssemblyResolve イベントにリスナーをアタッチして、何が起こっているかを確認しました。

ResolveEventHandler reh = (o, e) =>
{
    var tryGet = AppDomain.CurrentDomain.GetAssemblies()
                          .Where(x => x.FullName == e.Name).FirstOrDefault();
    if (tryGet != null)
        return tryGet;
    //EDIT:  Crap, the following line is a stupid bug STUPID!  Ignore!
    return Type.GetType(e.Name).Assembly;
};

using (var stream = System.IO.File.OpenRead(serializedObjectFilename))
{
    try
    {
        AppDomain.CurrentDomain.AssemblyResolve += reh;
        var ser = new NetDataContractSerializer();
        return ser.Deserialize(stream) as MyType;
    }
    finally
    {
        AppDomain.CurrentDomain.AssemblyResolve -= reh;
    }
}

名ばかりの「奇妙な動作」は、ハンドラーを介してデバッグすることで確認できます。tryGet決して(このnull場合、必要なアセンブリは常に AppDomain に読み込まれます) ことはありませんが、そのままにしておくと、操作は常に失敗します。 つまり、呼び出すType.GetType(e.Name).Assemblyと、FileLoadException がスローされます。 編集:アセンブリの厳密な名前を型のアセンブリ修飾名と混同していました。そのバグは無視してください。皮肉なことに、別のエラーはスローされないため、この質問をする前にこれをキャッチできませんでした。

別の情報: Assembly.Load(e.Name)常に有効なアセンブリを返します。逆シリアル化中に舞台裏で使用される方法が失敗するのに、なぜそれが機能するのかわかりません。

Fusion Log は、ローダーが正しいアセンブリを読み込もうとしていると報告していますが、実行可能ファイルのプライベート パス内にアセンブリが見つからないため、失敗しています。

アセンブリが既に AppDomain に読み込まれているのに、アセンブリを読み込もうとするのはなぜですか??


Fusion ロギングの詳細...

例外がスローされる原因となるメソッド呼び出しの前と呼び出し中に、すべてのアセンブリの読み込みをキャプチャしました。関連するログを作成順に示します。

  • 部分バインディングに失敗しました
    • 名前だけでアセンブリを読み込もうとしました
    • アプリベースのみを調査
  • LoadFrom による部分バインディング SUCCEEDED
    • Where-ref バインド。Locationは、ファイルが参照されている場所を指します
    • ソリューションに参照をロードするときにVSがLoadFromを使用すると思います
  • 厳密な名前のバインドに失敗しました
    • この読み込み試行のトリガーとなった原因は不明です
    • アプリベースのみを調査

AFAICT、Visual Studio はアセンブリをソリューションの AppDomain に読み込みます (ffs、ロードが試行された AppDomain を Fusion Log がキャプチャしてほしいと思います。結局のところ、呼び出し元のアセンブリを記録します)。

この後、逆シリアル化呼び出しを行います。結果は、Fusion の単一のログです。

バインド結果: hr = 0x80070002。システムは、指定されたファイルを見つけることができません。

ここでも、Fusion は実行可能ファイルのアプリケーション ベースから厳密な名前でロードしようとしています。1つの良いこと。GAC からロードしようとするため、展開すると同じ問題が発生しない可能性があります。しかし、アセンブリが appdomain に見つからない理由については、まだわかりません。


さらに興味深いもの...

これにより、Deserialize の呼び出しがスローされます。

MyType test = new MyType ();
var serialized = Serializer.ToXml(test);
// the following line fails with a FileLoadException
var deserialized = Serializer.FromXml<MyType>(serialized);

ここで、ToXml と FromXml はどちらも NetDataContractSerializer と Write/ReadObject を使用します。アセンブリは、パッケージのインストール ディレクトリから実行の早い段階で読み込まれますが、NDCS は、何らかの理由で、AppDomain で見つかったアセンブリを使用したくありません。このテストは、バージョン管理の問題ではないことを示しています。

4

1 に答える 1

0

あなたのコードで私が奇妙に思うことの1つは、次のことです。

GetAssemblies().Where(x => x.FullName == e.Name)

eはアセンブリの名前として使用されます。これは、一致Assembly.Nameするため、クラス/タイプの名前が含まれていないため、次のようになります。

return Type.GetType(e.Name).Assembly;

e完全にアセンブリ修飾された型名として使用されます。これには、クラス/型名とアセンブリ名の両方が含まれると思います。

これは意図的なものですか?


編集:

申し訳ありませんが、あなたが投稿を編集して自分で間違いを見つけたので、この返信を投稿しました...

于 2011-05-17T18:41:29.970 に答える