3 Stimmen

Serialisierung über mehrere Namespaces mit Protobuf-net

Ich habe an einem System gearbeitet, in dem ich protobuf-net (Version 2.0.0.480) zur Serialisierung von Nachrichten verwende. Diese Anwendung verwendet einen CQRS-Ansatz, bei dem Befehle und Ereignisse in verschiedene Namespaces [und Assemblies] aufgeteilt wurden.

Der Code fügt die Typen dynamisch zur Laufzeit für jede Klasse hinzu, die von MessageBase erbt. Dies geschieht mit Hilfe des folgenden Codes:

    // 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);
        }
    }

Einige Typen werden dem Default RuntimeTypeModel auch manuell hinzugefügt:

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

All das scheint gut zu funktionieren, wenn alle Meldungen eingegangen sind:

LogicalGrouping.Events

Das Projekt kam voran und ein neuer Namensraum wurde hinzugefügt:

ReferenceGrouping.Commands

Sobald ReferenceGrouping.Commands wird hinzugefügt und versucht, eine Nachricht an ProtoException geworfen wird. Die einzige Abhilfe, die ich für dieses Verhalten gefunden habe, ist das Hinzufügen der Commands from ReferenceGrouping.Commands en LogicalGrouping.Events .

Ist dies das erwartete Verhalten oder sollte das RuntimeTypeModel in der Lage sein, Klassen zu unterstützen, die aus völlig unterschiedlichen Namensräumen hinzugefügt werden?

3voto

Marc Gravell Punkte 970173

Protobuf-net kümmert sich, wie in meinem Kommentar erwähnt, nicht um Namensräume, Typnamen oder Member-Namen, da es numerische Schlüssel als Bezeichner verwendet (in Übereinstimmung mit der Protobuf-Spezifikation). Dies bedeutet, dass Sie auf ein völlig anderes Modell in verschiedenen Baugruppen deserialisieren können, solange die Zahlen Sinn machen.

Wenn ich mir den Code ansehe, vermute ich stark, dass das Problem darin besteht, dass Sie keine zuverlässigen (wiederholbaren) Untertypbezeichner haben. Wenn Sie haben, bei der Serialisierung:

  • Foo
    • SubFoo1 (Schlüssel=2)
    • SubFoo2 (Schlüssel=5)

Dann ist es von entscheidender Bedeutung, bei der Konfiguration der Modelle für die Deserialisierung, Schlüssel, die kompatibel sind; zum Beispiel könnten Sie deserialisieren in:

  • Bar
    • MegaBar (Schlüssel=2)
    • UltraBar (Schlüssel=5)

Ich vermute, dass Ihr Mechanismus zum Hinzufügen von Untertypen nicht sicherstellt, dass die Nummern übereinstimmen. Es braucht einige Hinweis. Wenn ich mir Ihren Code ansehe, frage ich mich allerdings, ob er nicht auch kaputt gehen könnte, wenn:

  • Typen hinzufügen
  • Entfernen von Typen
  • Umbenennung von Typen
  • Umzugstypen
  • nur ... Jederzeit (die Reihenfolge der Typen ist nicht garantiert, IIRC)

Mein Rat wäre: Führen Sie irgendwo ein externes Verzeichnis darüber, was jeder Schlüssel in Bezug auf die Untertypen bedeutet. Oder: machen Sie das Gleiche im Code mit ProtoIncludeAttribute.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X