Сериализация в нескольких пространствах имен с помощью Protobuf-net - PullRequest
3 голосов
/ 30 января 2012

Я работал над системой, в которой я использую protobuf-net (версия 2.0.0.480) для сериализации сообщений.Это приложение использует подход CQRS, в котором команды и события были разделены на разные пространства имен [и сборки].

Код будет динамически добавлять типы во время выполнения для любого класса, который наследуется от 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);
        }
    }

Несколько типов добавляются вручную в Default RuntimeTypeModel, а также:

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

Все вышеперечисленное работает нормально, когда все сообщения былив:

LogicalGrouping.Events

Проект перемещен вперед и добавлено новое пространство имен:

ReferenceGrouping.Commands

Как только ReferenceGrouping.Commands добавляется и пытается отправить сообщение, ProtoException выбрасывается.Единственный обходной путь, который я нашел для этого поведения, состоит в добавлении команд из ReferenceGrouping.Commands в LogicalGrouping.Events .

Это ожидаемое поведение или должно RuntimeTypeModelбыть в состоянии поддерживать классы, добавляемые из совершенно разных пространств имен?

1 Ответ

3 голосов
/ 30 января 2012

Protobuf-net, согласно моему комментарию, просто не заботится о пространствах имен, именах типов или именах членов, поскольку он использует числовые ключи в качестве идентификаторов (в соответствии со спецификацией protobuf).Это означает, что вы можете десериализовать совершенно другую модель в разных сборках, если числа имеют смысл.

Глядя на код, я сильно подозреваю, что проблема в том, что у вас нет надежного (повторяемого) подпрограммыидентификаторыЕсли при сериализации:

  • Foo
    • SubFoo1 (ключ = 2)
    • SubFoo2 (ключ = 5)

Тогда при настройке моделей для десериализации жизненно важно, чтобы ключи были совместимы;Например, вы можете десериализовать в:

  • Бар
    • Мегабар (ключ = 2)
    • UltraBar (ключ = 5)

Я предполагаю, что ваш механизм добавления подтипов не обеспечивает совпадение чисел.Требуется немного подсказкаНа самом деле, глядя на ваш код, мне интересно, может ли он также сломаться в настоящее время, если:

  • добавление типов
  • удаление типов
  • переименование типов
  • перемещениеТипы
  • просто ... В любое время (порядок типов не гарантируется, IIRC)

Мой совет был бы: вести внешнюю регистрацию где-то, что означает каждый ключ в терминахподтипов.Или: сделайте то же самое в коде, используя ProtoIncludeAttribute.

...