2009-06-04 16 views
3

.NET 2.0では、バージョン寛容シリアル化は、オブジェクトが存在する古いバージョンのアセンブリから直列化オブジェクトを正常に逆シリアル化します。バージョン寛容シリアル化 - 元のAssemblyNameを見つける方法

16進数のビューアを使用してこのようなバイナリ形式のシリアライズされたストリームを開くと(VSには単純なドラッグアンドドロップがあります)、このストリームにアセンブリ情報が含まれていることがわかります。

デシリアライズ時にこの情報を取得する方法はありますか?これは、たとえば、古いコンテンツを読むときに既知の問題にフィックスアップを適用するために使用できます。

更新: それはできないようです(ポールベッツの答えのように、クラス自体を変更する以外は、どちらもテストしませんでした)ので、この値を読み取る方法はありますか?バイナリ形式は公開されていますか?

+0

関連(しかし同一ではない):http://stackoverflow.com/questions/929985#930135 - 短い、Iドンでバージョン間でBinaryFormatterがうまく動作すると思っています...より良いオプションがあります。 –

+0

またはhttp://stackoverflow.com/questions/881766#881898(これはちょうど関連しています - dupなどではありません) –

答えて

5

this CodeProject article(「ディスクからカタログを読み込む」までスクロールして、半分ほど下に)スクロールしながら、これらのシリアル化の問題を直接発見しました。

基本的に私はASP.NETアプリケーションで何かをシリアル化していました - そして、IISアプリケーションを再起動した後にシリアル化されたデータを読み取ることができませんでした。(ASP.NET全体の動的コンパイル/一時アセンブリキャッシュ/おお!

とにかく、私の最初のポイントは、デシリアライゼーション中にスローされた例外は、厳密な名前

を含んある組立h4octhiwを見つけることができません、バージョン= 0.0.0.0、文化=中立、なPublicKeyToken = nullを

あなたが必要とする情報が「どこかに」あることは明らかです。理論的には(そして、これは奇妙なアイデアです)、シリアライゼーションの例外を捕捉し、古いバージョンの詳細のエラーを解析することができます(もちろん、現在のデシリアライゼーションはスローせずに動作します)。

2番目の点は、実装した解決策(this infoを使用)に関連しています。私はカスタムを書いたSystem.Runtime.Serialization.SerializationBinder:例として以下のコードを示しています。

public class CatalogBinder: System.Runtime.Serialization.SerializationBinder 
{ 
    public override Type BindToType (string assemblyName, string typeName) 
    { 
     // get the 'fully qualified (ie inc namespace) type name' into an array 
     string[] typeInfo = typeName.Split('.'); 
     // because the last item is the class name, which we're going to 
     // 'look for' in *this* namespace/assembly 
     string className=typeInfo[typeInfo.Length -1]; 
     if (className.Equals("Catalog")) 
     { 
      return typeof (Catalog); 
     } 
     else if (className.Equals("Word")) 
     { 
      return typeof (Word); 
     } 
     if (className.Equals("File")) 
     { 
      return typeof (File); 
     } 
     else 
     { // pass back exactly what was passed in! 
      return Type.GetType(string.Format("{0}, {1}", typeName, 
           assemblyName)); 
     } 
    } 
} 

は基本的にBindToTypeはもともと、そのオブジェクトをシリアル化するために使用されるもののために知られているタイプの「代替」に、デシリアライゼーション・プロセスによって機会を与えられています。typeNameのみを使用していますが、assemblyNameにはおそらく後の情報が含まれている可能性があります。また、カスタムSerializationBinderは、おそらくそれを使用するために調べるべき方法です。

FYI、上記のように 'アップ有線' れたコード:

System.Runtime.Serialization.IFormatter formatter = 
    new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 
formatter.Binder = new CatalogBinder(); // THIS IS THE IMPORTANT BIT 
object deserializedObject = formatter.Deserialize(stream); 
+0

これはまさに私が探していたものです。 –

1

は。フルネーム

0

使用ルッツRoeders(今レッドゲートの)Reflector)Assembly.GetExecutingAssembly(に設定されますAssemblyInfoと呼ばれる、すべてのシリアル化されたクラスにフィールドを追加します。

System.Runtime.Serialization.Formatters.Binary.__BinaryParserクラスは、実際の解析を行うためにBinaryFormatterDeserialize方法によって内部的に使用されます。

リフレクターを覗いてみると、バイナリーヘッダーをあらかじめ読み込んでバージョン情報を判断する方法がわかります。

関連する問題