2012-01-30 66 views
2

我一直在使用protobuf-net(版本2.0.0.480)來序列化消息的系統。此應用程序使用CQRS方法,其中命令和事件已被分離到不同的名稱空間[和程序集]中。使用Protobuf-net跨多個命名空間進行序列化

代碼將在運行時爲任何繼承自MessageBase的類動態添加類型。

// Used as a unique reference for each type in a member 
    private static int _sequence = 1000; 
    public static void RegisterAll() 
    { 
     RegisterAllDerivedFrom<MessageBase>(); 
    } 
    public static void RegisterAllDerivedFrom<T>(params Assembly[] assemblies) 
    { 
     if (assemblies == null || assemblies.Length == 0) 
     { 
      assemblies = AppDomain.CurrentDomain.GetAssemblies(); 
     } 

     var type = typeof(T); 
     var model = RuntimeTypeModel.Default; 
     var metaModel = model.Add(type, true); 

     RegisterAllBaseTypes(type, metaModel, model, assemblies); 
    } 
    private static void RegisterAllBaseTypes(Type type, MetaType metaModel, RuntimeTypeModel model, params Assembly[] assemblies) 
    { 
     foreach (var t in assemblies.SelectMany(a => a.GetTypes().Where(t => t.BaseType != null && t.BaseType == type))) 
     { 
      var subModel = model.Add(t, true); 
      metaModel.AddSubType(_sequence, t); 
      _sequence++; 

      RegisterAllBaseTypes(t, subModel, model, assemblies); 
     } 
    } 

幾個類型是手動添加到默認RuntimeTypeModel還有:

RuntimeTypeModel.Default.Add(typeof(ReferenceNumber), true) 
      .AddSubType(100, typeof(Product)) 
      .AddSubType(110, typeof(ProductGroup)); 

上述所有似乎正常工作時,所有的消息均:這是使用下面的代碼完成

LogicalGrouping.Events

項目FORW移動ARD和一個新的命名空間添加:

ReferenceGrouping.Commands

一旦ReferenceGrouping.Commands加入並嘗試發送消息的ProtoException被拋出。我發現此行爲的唯一解決方法是將ReferenceGrouping.Commands中的命令添加到LogicalGrouping.Events

這是預期的行爲還是應該RuntimeTypeModel能夠支持從完全不同的命名空間添加的類?

+0

只要您沒有使用「DynamicType」選項,protobuf-net不會關心名稱空間* *;數據存儲中沒有類型名稱,程序集名稱或字段名稱。 ProtoException中的完整信息是什麼? – 2012-01-30 17:42:21

+0

啊...我想知道... 2秒 – 2012-01-30 17:43:38

回答

2

根據我的評論,Protobuf-net根本不在乎名稱空間,類型名稱或成員名稱,因爲它使用數字鍵作爲標識符(符合protobuf規範)。這意味着只要數字有意義,您就可以對不同組件中完全不同的模型進行反序列化。

看着代碼,我強烈懷疑問題是你沒有可靠的(可重複的)子類型標識符。如果你有,序列化時:

    • SubFoo1(鍵= 2)
    • SubFoo2(鍵= 5)

然後,它是非常重要的,在配置時反序列化的模型,兼容的鍵;例如,你可以反序列化到:

  • 酒吧
    • 兆帕(鍵= 2)
    • UltraBar(鍵= 5)

我的猜測是,你的機構加入子類型不確保數字匹配。它需要一些線索。其實,看你的代碼,我不知道是否也有可能打破目前如果:

  • 添加類型
  • 刪除類型
  • 重命名類型
  • 搬遷類型
  • 只是......任何時間(類型的順序是不能保證的,IIRC)

我的建議是:保持一個外部註冊的某個地方每個關鍵意味着在子類型秒。或者:使用ProtoIncludeAttribute在代碼中執行相同的操作。

+0

如果事件持續存在磁盤並在應用程序的後續運行中回讀,我會認爲這是一個問題。情況並非如此,應用程序已啓動,RuntimeTypeModel已創建,事件已發送。上述情況不僅會在應用程序的後續運行時發生,而且會重新創建RuntimeTypeModel並嘗試從商店中讀取以前序列化的消息? – 2012-01-30 18:50:36

+0

@ SyntaxC4是否只有一個AppDomain在這裏涉及?如果是這樣,是的它應該沒有任何問題的工作;你能提供ProtoException的細節嗎? (.Message,.InnerException,.StackTrace等) – 2012-01-30 19:13:01

+0

想一想,拋出異常的消息將被加載到單獨的AppDomain中。這很可能是問題的原因(考慮RuntimeTypeModel僅在其中一個AppDomains中聲明)。 – 2012-01-30 20:51:50