从另一个项目导入 .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 请查看更新 听起来您正在寻找&lt;Protobuf&gt; 上的ProtoRoot="whatever" 可选参数,这类似于protoc 上的include arg - 试试&lt;Protobuf ProtoRoot="Protos" ... &gt; 【参考方案1】:

您可以通过将ProtoRoot 属性添加到.csproj 文件中的&lt;Protobuf /&gt; 部分来实现。

假设您在项目 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文件中的&lt;Protobuf /&gt;部分添加ProtoRoot

<ItemGroup>
  <Protobuf Include="ProjectA/<path>/car.proto" Link="<path>/car.proto" ProtoRoot=".." />
</ItemGroup>

&lt;path&gt; 等同于 .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++ 项目从另一个文件导入源文件名?

如何使用gradle从依赖jar导入.proto文件

在 vue 3 中从另一个本地项目导入和显示组件

如何将 python 函数从另一个文件导入 django 视图

Dart - 一个 dart 项目如何在不使用 pub 的情况下从另一个 dart 项目导入代码?