从另一个项目导入 .proto 文件
Posted
技术标签:
【中文标题】从另一个项目导入 .proto 文件【英文标题】:Importing .proto files from another project 【发布时间】:2019-12-20 08:41:41 【问题描述】:我有几个包含不同 protobuf 文件的合约项目,但有些消息类型具有相同的消息类型,例如
message user
Address address = 1
message Address
....
我现在已经创建了一个共享项目并向其中添加了一个 Address.proto 文件,其中仅包含
syntax = "proto3"
option csharp_namespace = "shared.protos"
package AddressPackage
message Address ....
我的问题是弄清楚如何将它导入到我不同合同项目的原型中。 我已将共享项目添加为参考,但我从那里尝试的其他所有操作都导致错误。
我知道我需要使用import
只是还没有弄清楚如何编写字符串。
更新
我正在使用 gRPC.tools nuget 并且所有 .proto 文件都设置为 protobuf 编译器
文件结构如下
User.Contracts 项目
原型 -- 用户.proto 共享项目 原型 -- 地址.proto两个项目都在它自己的文件夹中,并且这些文件夹彼此相邻。
在它说的共享项目中
<ItemGroup>
<None Remove="Protos\Address.proto" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="Protos\Address.proto">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Protobuf>
</ItemGroup>
在 user.contract 中是这样说的
<ItemGroup>
<None Remove="Protos\User.proto" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="Protos\User.proto" />
</ItemGroup>
提前致谢。
【问题讨论】:
您是否为此使用 gRPC.tools?如果是这样:.proto 文件的相关 csproj 片段是什么样的?或者你是直接使用 protoc 吗?或者 ..?并且:相对于项目根目录,各种文件的文件夹结构是什么? @MarcGravell 请查看更新 听起来您正在寻找<Protobuf>
上的ProtoRoot="whatever"
可选参数,这类似于protoc 上的include arg - 试试<Protobuf ProtoRoot="Protos" ... >
?
【参考方案1】:
您可以通过将ProtoRoot
属性添加到.csproj
文件中的<Protobuf />
部分来实现。
假设您在项目 A 中有一个 .proto
文件:
syntax = "proto3";
option csharp_namespace = "Project.A";
import "ProjectB/<path>/Engine.proto"
message Car
Engine engine = 1;
...
在项目 B 中,您有:
syntax = "proto3";
option csharp_namespace = "Project.B";
message Engine
...
如您所见,在 car.proto
中,我们使用 import 语句从另一个项目中导入 .proto
文件。为了成功导入这个文件,我们需要在项目A的.csproj
文件中的<Protobuf />
部分添加ProtoRoot
:
<ItemGroup>
<Protobuf Include="ProjectA/<path>/car.proto" Link="<path>/car.proto" ProtoRoot=".." />
</ItemGroup>
<path>
等同于 .NET 项目中的文件夹结构。 ProtoRoot
需要设置为 .proto
文件中的导入声明正在查找文件的目录。在这种情况下,它是包含项目 A 和项目 B 的两个子文件夹的父文件夹。
更多有趣的东西可以在这里找到: https://chromium.googlesource.com/external/github.com/grpc/grpc/+/HEAD/src/csharp/BUILD-INTEGRATION.md
【讨论】:
这对我没有帮助。我将项目 B 中的原型视为项目 A 中的链接,但是在项目 A 中导入原型文件时,我收到文件未找到错误。 从 nuget 导入 protos 时会是什么样子?【参考方案2】:另一种选择。不使用共享项目更容易。 .proto
文件只需放在服务项目中并指定
<ItemGroup>
<Protobuf Include="Protos\address.proto" GrpcServices="Server" />
</ItemGroup>
在项目中客户只需要像这样指定链接
<ItemGroup>
<Protobuf Include="..\NameServerProject\Protos\address.proto" GrpcServices="Client">
<Link>Protos\address.proto</Link>
</Protobuf>
</ItemGroup>
ProtoRoot
可以错过。
【讨论】:
执行此方法时找不到文件错误。在您尝试将链接文件添加到的原始文件中,导入应该是什么样子?只需执行'import "address.proto";或 'import "Protos\address.proto"' 正如我所期望的那样,在这种情况下似乎不起作用。该链接在我的 IDE 中正确创建到有问题的文件,我可以在我的 C# 代码中引用它,但似乎不是来自我的 .proto 文件。 在服务项目中,需要添加一个proto文件,然后将Protobuf元素添加到ItemGroup中。然后你需要构建项目。之后,在客户的项目中,您需要将 Protobuf 元素添加到 ItemGroup 并构建项目。您还需要确保正确指定包含文件的文件夹的路径。我最后使用 IDE VisualStudio 2019。【参考方案3】:这比我预期的要复杂得多,因为“移动部件”的数量加上文档在某种程度上已经过时了,并且在编写某些属性时似乎与上面的帖子有所不同。
基本上在上面的汽车示例中,使用 Visual Studio 2022 你应该最终得到这个
要获得这个,ProjA 需要相当多的工作,有趣的部分似乎是
<ItemGroup>
<ProjectReference Include="../ProjB/ProjB.csproj" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="..\ProjB\Protos\engine.proto" GrpcServices="None" ProtoCompile="False">
<Link>ProjB\Protos\engine.proto</Link>
</Protobuf>
<Protobuf Include="../ProjA/Protos/car.proto" Link="Protos/car.Proto" GrpcServices="None" ProtoRoot=".." />
</ItemGroup>
请注意,正如 Yury Yatskov 和 Ivan Ivković 所说,重要的部分是设置 ProtoRoot=".."
,但 ProtoRoot 中指定的路径必须是 Include 中路径的前缀 属性。
注意:
ProtoRoot
相对于 .csproj 文件
Import
是相对于.csproj 文件但是需要有ProtoRoot
作为前缀,所以基本上上一级然后再次进入ProjA 内部
这样car.proto
中的include
语句将能够从ProtoRoot
中指定的路径开始搜索要包含的.proto 文件
** ProjA/Protos/car.proto
syntax = "proto3";
import "ProjB/Protos/Engine.proto";
option csharp_namespace = "ProjA";
package ProjA;
message Car
ProjB.Engine engine = 1;
string licensePlate = 2;
** ProjB/Protos/engine.proto
syntax = "proto3";
option csharp_namespace = "ProjB";
package ProjB;
message Engine
string name = 1;
再次注意,您当然需要使用其包引用引擎消息,所以ProjB.Engine
最后,这允许将 ProjB 包含为 ProjA 的正常引用
但 注意 将 Compile Protobuf
选项设置为否(如您在上面报告的 .csproj 中所见),否则将出现类名冲突,因为两个项目将重新定义相同的“引擎”类。
grpc stub classes
属性在这里似乎没有太大作用,我认为如果 .proto 包含服务定义会更有趣。
【讨论】:
【参考方案4】:在您的项目中,使用 Include 和 ProtoRoot 指定 Protobuf,其中应包含带有 proto-files 之类的共享项目的路径
<ItemGroup>
<Protobuf Include="..\NameSharedProject\Protos\address.proto" ProtoRoot="..\NameSharedProject" GrpcServices="Server" />
</ItemGroup>
然后,在构建每个项目后,您将在文件夹“\obj\Debug\net5.0\Protos”中创建类文件。
【讨论】:
类已创建,但我无法在我的 proto 文件中导入它,编译器说找不到文件 John Demetriou,如果您有问题,请展示您的项目。 我决定改用 nuget 包。我把我的原型放在一个 nuget 包中,任何想要它们的人都可以引用 nuget 包 这是放入 nuget 包的好方法。 Mehmet Özkaya 也有一些关于 gRPC 和 .proto 的好材料。 medium.com/aspnetrun/…github.com/aspnetrun/run-aspnet-grpc以上是关于从另一个项目导入 .proto 文件的主要内容,如果未能解决你的问题,请参考以下文章
如何使用审计命令语言 (ACL) 从另一个项目导入 .fil 文件?
是否可以让 vs2008 c++ 项目从另一个文件导入源文件名?