8

的背景是如下如何創建二進制格式化一個SerializationBinder,處理的各類移動從一個集和命名空間到另一個

  1. 我想移動它以不同的項目
  2. 重構代碼
  3. 一些這個代碼的包括用於 發送和跨多個終端接收數據序列化的DTO的
  4. 如果我走動的代碼,系列化中斷(因此它是與舊版本我的應用程序的不 向後兼容)

解決這個問題是,讓我在某種意義上從一種類型到另一種「重定向」的SerializationBinder。

因此,我想創建一個SerializationBinder來滿足這種需求。但是它必須通過滿足下列要求

  1. 到SerializationBinder的投入應該是舊型 到新的類型映射列表,這樣做。映射應該包括老總成 名(無版,無公鑰標記)和 類型(名稱空間和名稱)的舊的完整名稱以及新的組件名稱和新 全稱類型的
  2. 對於輸入中的類型,應該忽略程序集的版本號
  3. 它應該處理泛型,如果我的類型碰巧是泛型 (List,Dictionary等),而不需要在泛型中包含輸入
  4. 對於任何不在輸入中的東西(例如,沒有移動的類型或移動的類型或者像數據集那樣的.NET類型),它應該默認爲 使用開箱即用算法的二進制串行器

這是可能的還是我夢想着?有沒有這樣的東西呢?我會認爲這是一個普遍的問題。

到目前爲止,我看到做3沒有簡單的方法,並沒有辦法做的所有4

這裏是企圖

public class SmartDeserializationBinder : SerializationBinder 
{ 
    /// <summary> 
    /// Private class to handle storing type mappings 
    /// </summary> 
    private class TypeMapping 
    { 
     public string OldAssemblyName { get; set; } 
     public string OldTypeName { get; set; } 
     public string NewAssemblyName { get; set; } 
     public string NewTypeName { get; set; } 
    } 

    List<TypeMapping> typeMappings; 

    public SmartDeserializationBinder() 
    { 
     typeMappings = new List<TypeMapping>(); 
    } 

    public void AddTypeMapping(string oldAssemblyName, string oldTypeName, string newAssemblyName, string newTypeName) 
    { 
     typeMappings.Add(new TypeMapping() 
     { 
      OldAssemblyName = oldAssemblyName, 
      OldTypeName = oldTypeName, 
      NewAssemblyName = newAssemblyName, 
      NewTypeName = newTypeName 
     }); 
    } 

    public override Type BindToType(string assemblyName, string typeName) 
    { 
     //Need to handle the fact that assemblyName will come in with version while input type mapping may not 
     //Need to handle the fact that generics come in as mscorlib assembly as opposed to the assembly where the type is defined. 
     //Need to handle the fact that some types won't even be defined by mapping. In this case we should revert to normal Binding... how do you do that? 

     string alternateAssembly = null; 
     string alternateTypeName = null; 
     bool needToMap = false; 
     foreach (TypeMapping mapping in typeMappings) 
     { 
      if (typeName.Contains(mapping.OldTypeName)) 
      { 
       alternateAssembly = mapping.NewAssemblyName; 
       alternateTypeName = mapping.NewTypeName; 
       needToMap = true; 
       break; 
      } 
     } 

     if (needToMap) 
     { 
      bool isList = false; 
      if (typeName.Contains("List`1")) 
       isList = true; 
      // other generics need to go here 

      if (isList) 
       return Type.GetType(String.Format("System.Collections.Generic.List`1[[{0}, {1}]]", alternateTypeName, alternateAssembly)); 
      else 
       return Type.GetType(String.Format("{0}, {1}", alternateTypeName, alternateAssembly)); 
     } 
     else 
      return null; // this seems to do the trick for binary serialization, but i'm not sure if it is supposed to work 
    } 
} 

回答

-2

是它,你必須使用BinaryFormatter的硬性要求爲你的序列化?

如果您不需要使用BinaryFormatter進行序列化,請考慮另一種序列化方法,如JSON.Net或ProtoBuf.Net。 它們中的任何一個都會爲您的數據創建獨立於平臺和版本的序列化。

或者,您也可以自己執行二進制序列化(這既是比BinaryFormatter的速度更快,更小,但一般更多的代碼密集,你必須確保基本上相同寫串行器和解串在一起。

如果您必須使用BinaryFormatter,請確保使用FormatterAssemblyStyle.Simple構造它,以解決版本控制問題。它告訴它不要對程序集版本進行迂腐檢查。

+0

我已經說過,要求是使用BinaryFormatter – Mark

+0

實際上,你沒有(至少不清楚),並明確地詢問是否有什麼東西可以做到你想要的(最終結果是向後 - 兼容的序列化,不是嗎?),作爲開發人員和我,作爲有人試圖幫助在必要時不考慮替代品的人,這將是不負責任的。我都提供了替代解決方案,並給了你一些嘗試,使用BinaryFormatter。您是否爲BinaryFormatter指定了FormatterAssemblyStyle.Simple? – dodexahedron

+1

我看不到如何改變中流串行化方法將允許向後兼容性? – Casey

0

雖然它可能不回答你的問題,這可能解決您的問題:

我能夠序列化所有,但反序列化對象結構要求旁邊一個程序集。訣竅是使用反射來檢查對象結構的類型和它們定義的程序集。然後,可以將程序集作爲二進制數據寫入序列化的對象中,並將它們加載到AppDomain中,在那裏您可以使用它們反序列化其餘的的對象結構。

您必須將AppDomain處理,根對象和一些基類放入不會更改的程序集中,而其他所有內容都是在程序集中根據此「錨點」定義的。

上升空間:

  • 系列化不破只要錨固組件並不改變
  • 可以用於模糊處理,例如某些所需的程序集可隱藏在任何文件中
  • 可用於在線更新,例如,船舶裝配與
  • 至於我很擔心仿製藥沒有問題

缺點任何數據:

  • 安全問題引導可用於注入代碼(組裝一些額外的工作SecurityEvidences)
  • 的AppDomain邊界是一些工作跨越
  • 打擊你的序列化數據(好吧,對於文件 - 壞,通訊)

但是,嘿,溝通不會中斷,除非您擁有不同的客戶端版本,然後您可以在握手時進行引導。

對不起,我不能提供的代碼,因爲它太複雜,太具體。但我分享一些見解在我的這些其他答案:

difference between DataContract attribute and Serializable attribute in .net

Need to hookup AssemblyResolve event when DisallowApplicationBaseProbing = true

5

這可能是工作(而不是您的覆蓋)。

public override Type BindToType(string assemblyName, string typeName) 
     { 
      var m = Regex.Match(typeName, @"^(?<gen>[^\[]+)\[\[(?<type>[^\]]*)\](,\[(?<type>[^\]]*)\])*\]$"); 
      if (m.Success) 
      { // generic type 
       var gen = GetFlatTypeMapping(m.Groups["gen"].Value); 
       var genArgs = m.Groups["type"] 
        .Captures 
        .Cast<Capture>() 
        .Select(c => 
         { 
          var m2 = Regex.Match(c.Value, @"^(?<tname>.*)(?<aname>(,[^,]+){4})$"); 
          return BindToType(m2.Groups["aname"].Value.Substring(1).Trim(), m2.Groups["tname"].Value.Trim()); 
         }) 
        .ToArray(); 
       return gen.MakeGenericType(genArgs); 
      } 
      return GetFlatTypeMapping(assemblyName,typeName); 
     } 

然後,你只需要實現你的方式函數GetFlatTypeMapping(不擔心泛型參數)。

當您被問到時,您將不得不做的是返回typeof(List<>)typeof(Dictionary<,>)(或任何其他您想使用的泛型)。我說typeof(List<>)!不是typeof(List<something>) ......這很重要。

免責聲明:由於正規表達式「(?[^] *)」,這個文檔片斷不支持嵌套泛型類型,如List<List<string>> ...你將不得不調整它一點支持吧!

相關問題