2012-01-30 3 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의 전체 정보는 무엇입니까? –

+0

아 ... 궁금합니다 ... 2 초 –

답변

2

Protobuf-net은 내 의견에 따르면 식별자로 숫자 키를 사용하기 때문에 (protobuf 사양에 따라) 네임 스페이스, 형식 이름 또는 구성원 이름을 신경 쓰지 않습니다. 즉, 숫자가 의미가있는 한 다른 어셈블리에서 완전히 다른 모델을 비 직렬화 할 수 있습니다.

코드를 보면 신뢰성있는 (반복 가능한) 하위 유형 식별자가 없다는 것이 강하게 의심됩니다.당신이있는 경우, 직렬화 때

    • SubFoo1을 (키 = 2)
    • SubFoo2 (키 = 5)

구성 할 때 그리고 그것은 매우 중요합니다 직렬화 복원의 모델, 호환 가능한 키. 예를 들어, 당신은에 역 직렬화 수 :

내 생각이다

    • MegaBar (키 = 2)
    • 가 Ultrabar (= 5 키)이 추가 매커니즘 하위 유형이 일치하는 숫자를 보장하지 않습니다. 일부 단서가 필요합니다.

      • 제거 유형
      • 이름을 변경 유형
      • 재배치 유형
      • 그냥 ... 모든 시간을 유형을 추가합니다 (다음의 경우 그것은 또한 현재 깰 수 있다면 사실, 당신의 코드를 찾고 궁금하다 유형의 순서는 보장되지 않습니다. IIRC)

      내 조언은 다음과 같습니다. 각 키가 하위 유형 에스. 또는 : ProtoIncludeAttribute를 사용하여 코드에서 동일한 작업을 수행하십시오.

+0

이벤트가 디스크에 저장되고 응용 프로그램의 후속 실행에서 다시 읽혀지면 문제가 될 것으로 예상됩니다. 그렇지 않은 경우 응용 프로그램이 시작되고 RuntimeTypeModel이 만들어지고 이벤트가 전송됩니다. 위에서 설명한 상황은 RuntimeTypeModel이 다시 만들어지고 저장소에서 이전에 직렬화 된 메시지를 읽으려고 할 때 응용 프로그램을 계속 실행하는 경우에만 발생하지 않습니까? –

+0

@ SyntaxC4에는 여기에 관련된 AppDomain이 하나뿐입니다. 그렇다면 문제없이 작동해야합니다. ProtoException 세부 사항을 제공 할 수 있습니까? (.Message, .InnerException, .StackTrace 등) –

+0

생각해 보면, 예외를 던지는 메시지는 별도의 AppDomain에로드됩니다. 이것이 문제의 원인 일 가능성이 큽니다 (RuntimeTypeModel은 AppDomain 중 하나에서만 선언 된 것으로 간주됩니다). –

관련 문제