首页 > 解决方案 > 序列化时尝试发布使用协议缓冲区序列化的数据失败

问题描述

简单来说

尝试使用 Google 的协议缓冲区序列化对象时,出现以下错误:

类型不是预期的,也不能推断出任何契约:

更多详情

我有三个项目:

  1. 带有 *.proto 文件的 DotNet 标准 2.0 库项目
  2. DotNet 框架 4.8 WebAPI
  3. DotNet 5 测试应用程序

带有 *.proto 文件的 DotNet 标准 2.0 库项目

库包含一个 *.proto 文件。这包含几个不同的message对象,每个对象的属性要么是字符串,要么是 int32。有两个“包装器”对象,一个名为Request(另一个Response)。没有什么明显复杂的。

此库的 NuGet 包是:

<PackageReference Include="Google.Protobuf" Version="3.17.3" />
<PackageReference Include="Grpc" Version="2.40.0" />
<PackageReference Include="Grpc.Tools" Version="2.40.0">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

可能有些是没有必要的......

DotNet 框架 4.8 WebAPI

所以我的想法是我的 .NET 4.8 WebAPI 将接收Request对象(即在 proto 文件中定义的这些类之一),然后返回Response对象(也在此 proto 文件中定义)。

DotNet 5 测试应用程序

但是......我的测试在它有机会对 WebAPI 进行 Http 调用之前就失败了......

我的 .NET 5 测试项目具有以下 NuGet 包:

<PackageReference Include="protobuf-net" version="3.0.101" />

它还包含对我的 .NET Standard 库的包引用(因此了解RequestandResponse以及它拥有的 NuGet 包。

在我的测试中,我创建了一个新Request对象(来自SomeNamespaceproto 文件中定义的命名空间)并填充它的属性。

然后我尝试使用以下方法对其进行序列化:

using MemoryStream stream = new();
ProtoBuf.Serializer.Serialize<Request>(stream, objectToBeSerialized);

这就是发生错误的地方:

System.InvalidOperationException HResult=0x80131509 Message=Type is not expected, and no contract can be inferred: SomeNamespace.Request Source=protobuf-net.Core StackTrace: at ProtoBuf.Internal.ThrowHelper.ThrowInvalidOperationException(String message, Exception innerException) in // src/protobuf-net.Core/Internal/ThrowHelper.cs: 第 56 行在 ProtoBuf.Meta.TypeModel.ThrowUnexpectedType(Type type, TypeModel model) in / /src/protobuf-net.Core/Meta/TypeModel.cs:line 1648在 ProtoBuf.Meta.TypeModel.SerializeRootFallback(State& state, Object value) in / /src/protobuf-net.Core/Meta/TypeModel.cs: 第 282 行在 ProtoBuf.Meta.TypeModel.SerializeImpl[T](State& state, T值)在 //src/protobuf-net.Core/Meta/TypeModel.cs:第 358 行在 ProtoBuf.Serializer.Serialize[T](Stream destination, T instance, Object userState) in / /src/protobuf-net/Serializer.Serialize.cs :ProtoBuf.Serializer.Serialize[T](Stream destination, T instance) in / /src/protobuf-net/Serializer.Serialize.cs 的第 33 行:TestNamespace.TempTests.d__0.MoveNext() in c:\ 的第 20 行SomePath\TempTests.cs:第 53 行

我不清楚为什么这可能会失败。

理想情况下,我想标准化最佳实践,所以如果我没有使用理想的 NuGet 包,请告诉我。

标签: asp.netserializationprotobuf-netprotocol-buffers

解决方案


在 protobuf 中,使用 .proto 时,涉及到两组工具:

  1. 模式解析器/代码生成器
  2. 运行时库

现在,我们需要知道的是 .NET-land 中有多种 protobuf 实现;与这个问题相关的是 Google 实现和 protobuf-net(还有其他的,但它们与这个问题无关)。

我认为您所做的是:您在第 1 步(“protoc”)中使用了 Google 工具,但在第 2 步中使用了 protobuf-net。第 1 步和第 2 步的工具需要匹配:Google 和 Google 都可以;protobuf-net 和 protobuf-net 很好 - 但不是交叉。

所以,要么:

一种。使用 Google 运行时库而不是 protobuf-net(“Google.Protobuf”,作为 nuget 包),或者 b:使用 protobuf-net 的架构工具和代码生成(参见https://protobuf-net.github.io/protobuf -net/contract_first.html,包括底部其他选项的链接)

如果我的预感是对的,请告诉我——我会尝试让 protobuf-net 识别这种情况并至少提供合适的指导


推荐阅读