序列化时尝试 post 使用 Protocol Buffers 序列化的数据失败

Attempting to post data serialized using Protocol Buffers fails when serializing

简述

尝试使用 Google 的 Protocol Buffers 序列化对象时出现以下错误:

Type is not expected, and no contract can be inferred:

更多详情

我有三个项目:

  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 文件中定义的 类 之一)然后 return Response 对象(也在这个 proto 文件中定义)。

DotNet 5 测试应用程序

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

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

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

它还有一个对我的 .NET Standard 库的包引用(所以知道 RequestResponse,以及它拥有的 NuGet 包。

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

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

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:line 56 at ProtoBuf.Meta.TypeModel.ThrowUnexpectedType(Type type, TypeModel model) in //src/protobuf-net.Core/Meta/TypeModel.cs:line 1648 at ProtoBuf.Meta.TypeModel.SerializeRootFallback(State& state, Object value) in //src/protobuf-net.Core/Meta/TypeModel.cs:line 282 at ProtoBuf.Meta.TypeModel.SerializeImpl[T](State& state, T value) in //src/protobuf-net.Core/Meta/TypeModel.cs:line 358 at ProtoBuf.Serializer.Serialize[T](Stream destination, T instance, Object userState) in //src/protobuf-net/Serializer.Serialize.cs:line 33 at ProtoBuf.Serializer.Serialize[T](Stream destination, T instance) in //src/protobuf-net/Serializer.Serialize.cs:line 20 at TestNamespace.TempTests.d__0.MoveNext() in c:\SomePath\TempTests.cs:line 53

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

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

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

  1. 模式parser/code生成器
  2. 运行库

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

我认为您所做的是:您在第 1 步中使用了 Google 工具(“protoc”),但在第 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 识别这种情况并至少提供适当的指导