从另一个项目导入 .proto 文件

Jos*_*hlo 3 c# protocol-buffers protobuf-net

我有几个包含不同 protobuf 文件的合同项目,但是某些消息类型具有相同的消息类型,例如

message user
{
  Address address = 1
}

message Address 
{
  ....
}
Run Code Online (Sandbox Code Playgroud)

我现在创建了一个共享项目并向其中添加了一个 Address.proto 文件,其中仅包含

syntax = "proto3"
option csharp_namespace = "shared.protos"
package AddressPackage
message Address {....}
Run Code Online (Sandbox Code Playgroud)

我的问题是弄清楚如何将其导入到我不同合同项目中的原型中。我已添加共享项目作为参考,但我从那里尝试的所有其他内容都导致错误。

我知道我需要使用import只是还没有弄清楚如何写字符串。

更新

我正在使用 gRPC.tools nuget 并且所有 .proto 文件都设置为 protobuf 编译器

文件结构如下

用户合同项目

  • Protos -- User.proto 共享项目
  • Protos -- Address.proto

两个项目都在它自己的文件夹中,并且这些文件夹彼此相邻。

在它说的共享项目中

<ItemGroup>
  <None Remove="Protos\Address.proto" />
</ItemGroup>

<ItemGroup>
  <Protobuf Include="Protos\Address.proto">
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
  </Protobuf>
</ItemGroup>
Run Code Online (Sandbox Code Playgroud)

并在 user.contract 中说

<ItemGroup>
  <None Remove="Protos\User.proto" />
</ItemGroup>

<ItemGroup>
  <Protobuf Include="Protos\User.proto" />
</ItemGroup>
Run Code Online (Sandbox Code Playgroud)

提前致谢。

Iva*_*vić 8

您可以通过将ProtoRoot属性添加到文件中的<Protobuf />部分来实现.csproj

假设您.proto在项目 A 中有一个文件:

syntax = "proto3";
option csharp_namespace = "Project.A";
import "ProjectB/<path>/Engine.proto"

message Car {
    Engine engine = 1;
    ...
}
Run Code Online (Sandbox Code Playgroud)

在项目 B 中,您有:

syntax = "proto3";
option csharp_namespace = "Project.B";

message Engine {
    ...
}
Run Code Online (Sandbox Code Playgroud)

如您所见,car.proto我们.proto在另一个项目中对文件使用了导入语句。为了成功地导入此文件,我们需要添加ProtoRoot<Protobuf />该节.csproj的项目中的文件:

<ItemGroup>
  <Protobuf Include="ProjectA/<path>/car.proto" Link="<path>/car.proto" ProtoRoot=".." />
</ItemGroup>
Run Code Online (Sandbox Code Playgroud)

<path>相当于 .NET 项目中的文件夹结构。ProtoRoot需要设置为文件中的导入声明.proto正在查找文件的目录。在这种情况下,它是包含两个子文件夹的父文件夹,其中包含项目 A 和项目 B。

更多有趣的东西可以在这里找到:https : //chromium.googlesource.com/external/github.com/grpc/grpc/+/HEAD/src/csharp/BUILD-INTEGRATION.md

  • 从 nuget 导入原型时会是什么样子? (3认同)

Mos*_*ini 8

这比我预见的要复杂得多,因为大量的“移动部件”加上文档在某种程度上已经过时了,并且在撰写本文时,某些属性的行为似乎与上面的帖子不同。

\n

基本上在上面的汽车示例中,使用 Visual Studio 2022 你应该得到这个\n在此输入图像描述

\n

为了实现这一点,ProjA 需要做大量的工作,有趣的部分是

\n
<ItemGroup>\n   <ProjectReference Include="../ProjB/ProjB.csproj" />\n</ItemGroup>\n\n<ItemGroup> \n   <Protobuf Include="..\\ProjB\\Protos\\engine.proto" GrpcServices="None" ProtoCompile="False">\n      <Link>ProjB\\Protos\\engine.proto</Link>      \n   </Protobuf>  \n   <Protobuf Include="../ProjA/Protos/car.proto" Link="Protos/car.Proto" GrpcServices="None" ProtoRoot=".." />\n</ItemGroup>\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,正如 Yury Yatskov 和 Ivan Ivkovi\xc4\x87 所说,重要的部分是设置,ProtoRoot=".."但 ProtoRoot 中指定的路径必须是 Include 属性中路径的前缀。\n注意

\n
    \n
  • ProtoRoot与 .csproj 文件相关
  • \n
  • Import与 .csproj 文件相关,但需要有ProtoRoot前缀,所以基本上上升一级,然后再次进入 ProjA 内部
  • \n
\n

这样,include语句car.proto将能够从指定的路径开始ProtoRoot搜索要包含的 .proto 文件

\n

** ProjA/Protos/car.proto

\n
syntax = "proto3";\n\nimport "ProjB/Protos/Engine.proto";\n\noption csharp_namespace = "ProjA";\n\npackage ProjA;\n\nmessage Car{\n    ProjB.Engine engine = 1;\n    string licensePlate = 2;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

** ProjB/Protos/engine.proto

\n
syntax = "proto3";\noption csharp_namespace = "ProjB";\n\npackage ProjB;\n\nmessage Engine{\n    string name = 1;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

再次注意,当然您需要使用其包来引用引擎消息,以便ProjB.Engine

\n

最后,这允许将 ProjB 作为 ProjA 的正常参考包含在内

\n

在此输入图像描述

\n

要注意设置Compile Protobuf为“否”(如您在上面报告的 .csproj 中看到的),否则会出现类名冲突,因为两个项目将重新定义相同的“Engine”类。

\n

grpc stub classes属性在这里似乎没有发挥很大的作用,我认为如果 .proto 包含服务定义会更有趣。

\n


小智 6

在您的项目中,使用 Include 和 ProtoRoot 指定 Protobuf,其中应包含带有原型文件的共享项目的路径,例如

  <ItemGroup>
    <Protobuf Include="..\NameSharedProject\Protos\address.proto" ProtoRoot="..\NameSharedProject" GrpcServices="Server" />
  </ItemGroup>
Run Code Online (Sandbox Code Playgroud)

然后,在构建每个项目后,您将在文件夹“\obj\Debug\net5.0\Protos”中创建类文件。

  • 我决定改用 nuget 包。我把我的原型放在 nuget 包中,谁想要它们,就引用 nuget 包 (2认同)