【问题标题】:Protobuf-net: Is it possible to generate a RuntimeTypeModel that is not mapped to concrete types?Protobuf-net:是否可以生成未映射到具体类型的 RuntimeTypeModel?
【发布时间】:2014-04-17 11:04:07
【问题描述】:

我有一个使用 protobuf 与 Web 服务通信的 Web 应用程序。服务本身提供了获取 .proto 描述符的方法。

当我第一次解决这个问题时,我发现的唯一 protobuf 库是 protobuf-net(最近我遇到了 protobuf-csharp-port,但我稍后会谈到)。这个库的文档非常有限,并且没有任何关于 protobuf 的先验知识,我最初采用的方法是应用“ProtoContract”和“ProtoMember”属性自动(通过 T4)生成我的所有 C# 类和枚举。

这很好用,但让我的 Web 应用程序对更改非常脆弱。 Web 应用充当正在开发中的多个 Web 服务版本的接口,因此需要优雅地处理更改。

进一步挖掘,我发现了如何动态生成 TypeModel 并将其绑定到我的预生成类。例如

RuntimeTypeModel model = TypeModel.Create();

model.Add(typeof (MyClass), false).Add(1, "Id").Add(2, "Name");

TypeModel compiledModel = model.Compile();

这确实成功地提高了应用程序对更改的健壮性,例如添加或删除可选字段(Web 服务上的所有内容根据其合同都是可选的),但因为我仍然绑定到具体类型 ('上面示例中的 MyClass') 是预先生成的,我仍然容易受到请求/响应模型名称更改的影响。

所以我的问题...... protobuf-net 有没有办法生成一个不耦合到我项目中任何具体类的 TypeModel?

我知道 google 的 C++/Java/Python 库支持(带有动态消息?)这是 Web 服务开发人员使用的,以及为什么他们期望我重命名一个类不应该破坏我的立场,但目前确实如此。

在使用 protobuf-net 寻找解决方案时,我遇到了 protobuf-csharp-port 项目,它是谷歌的更接近的端口,并且似乎具有我需要的功能(虽然我真的不知道如何实现它在此刻)。因此,在进行所有切换库的工作之前,我认为使用 protobuf-net 检查我所需要的内容是否可行是谨慎的做法。

有没有其他方法可以告诉 TypeModel 使用哪个模型来序列化/反序列化而不绑定到具体类型?例如。我可以从给定版本的 Web 服务器的描述符中获取的名称。

提前感谢您的任何帮助或建议。

【问题讨论】:

    标签: c# protobuf-net


    【解决方案1】:

    您的MyClass 目前在哪里声明?那是从哪里来的?需要明确的是:protobuf 格式不包含名称,因此在不同的地方更改名称无关紧要;但是,在您自己的代码中是完全正常的,如果您重命名MyClass,您将需要更新所有对MyClass 的引用。 IDE 工具通常会对此有所帮助。

    如果您有描述,我不确定您为什么要手动配置类:您不只是从 .proto 生成代码(protogen)并使用它吗?

    【讨论】:

    • 当我第一次开始这个时,我不知道有一个工具可以用来在 C# 中生成我的类以与 protobuf-net 一起使用,无论哪种情况,我对它们的方式都有一些特定的要求生成的结果甚至可能使该工具的输出不如我当前的解决方案理想。我只是使用 T4 来遍历类和枚举消息定义,并为每个定义生成一个 .cs 文件。通过这种方式,我可以使类成为局部类,从而允许我添加特定于域的初始化和属性,以使我从 Web 服务获得的模型更易于使用。
    • 所以回答你的问题……我的类在我的领域类库中声明,项目直接引用和使用。它们来自手动触发的 T4 模板,该模板获取消息描述符并生成 .cs 文件。是的,当生成域模型时,对类名的任何更改都需要我更新对这些类的任何引用。然而,这不是我想要避免的。
    • 在运行时,如果 Web 应用程序与具有较新版本的 Web 服务器通信,并带有重命名的请求消息,我将收到 TypeModel 中不存在给定消息的异常。它不存在的原因是因为我将无法自动将其与域中的模型匹配,因为它尚不存在(我必须按名称匹配它们,因此无法将其与旧的命名类匹配要么)。
    • 所以我问是否有办法在不提供具体类型的情况下构建 RuntimeTypeModel 的原因是,即使我没有模型,我仍然可以添加这些新消息在我的域中预先生成以匹配它。这确实提出了一个问题,然后我将如何告诉序列化程序我想尝试什么消息并将提供的对象序列化为。这就是我建议名称的原因,因为它的新名称是我在运行时知道的。
    • 据我了解,在 google 版本中,您通过按名称请求消息实例来执行此操作,然后您可以将值推送到其中。这将应用程序域中使用的类与 protobuf 序列化程序中定义的消息分离。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-16
    • 1970-01-01
    • 2011-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多