共计 4331 个字符,预计需要花费 11 分钟才能阅读完成。
作者:Kirill’kkm’Katsnelson
作为微软向其跨平台.NET 产品发展的一部分,他们大大简化了项目文件格式,并允许第三方代码生成器与.NET 项目的紧密集成。我们一直倾听,现在很自豪地介绍从 Grpc.Tools NuGet 包的 1.17 版本开始,.NET C# 项目中的 Protocol Buffer 和 gRPC 服务.proto 文件的集成编译。1.17 版本现在可以从 Nuget.org 获得。
你不再需要使用手写脚本从.proto 文件生成代码:.NET 构建神奇地为你处理此问题。集成工具在调用代码生成器之前,定位 proto 编译器和 gRPC 插件,标准 Protocol Buffer 导入和跟踪依赖关系,以便生成的 C# 源文件永远不会过时,同时将重新生成保持在最低要求。实质上,.proto 文件被视为.NET C# 项目中的第一类源。
演练
在这篇博文中,我们将介绍最简单,且可能是最常见的方案,使用跨平台 dotnet 命令从.proto 文件创建库。我们将基本实现 Greeter 库的克隆,由 C#Helloworld 示例目录中的客户端和服务器项目共享。
创建新项目
让我们从创建新的库项目开始。
~/work$ dotnet new classlib -o MyGreeter
The template “Class library” was created successfully.
~/work$ cd MyGreeter
~/work/MyGreeter$ ls -lF
total 12
-rw-rw-r– 1 kkm kkm 86 Nov 9 16:10 Class1.cs
-rw-rw-r– 1 kkm kkm 145 Nov 9 16:10 MyGreeter.csproj
drwxrwxr-x 2 kkm kkm 4096 Nov 9 16:10 obj/
观察到 dotnet new 命令创建了我们不需要的文件 Class1.cs,因此将其删除。另外,我们需要一些.proto 文件来编译。在本练习中,我们将从 gRPC 发行版中复制示例文件 examples/protos/helloworld.proto。
~/work/MyGreeter$ rm Class1.cs
~/work/MyGreeter$ wget -q https://raw.githubusercontent.com/grpc/grpc/master/examples/protos/helloworld.proto
(在 Windows 上,使用 del Class1.cs,如果你没有 wget 命令,只需打开上面的 URL,并使用 Web 浏览器中的“另存为 …”命令)。
接下来,将必需的 NuGet 包添加到项目中:
~/work/MyGreeter$ dotnet add package Grpc
info : PackageReference for package ‘Grpc’ version ‘1.17.0’ added to file ‘/home/kkm/work/MyGreeter/MyGreeter.csproj’.
~/work/MyGreeter$ dotnet add package Grpc.Tools
info : PackageReference for package ‘Grpc.Tools’ version ‘1.17.0’ added to file ‘/home/kkm/work/MyGreeter/MyGreeter.csproj’.
~/work/MyGreeter$ dotnet add package Google.Protobuf
info : PackageReference for package ‘Google.Protobuf’ version ‘3.6.1’ added to file ‘/home/kkm/work/MyGreeter/MyGreeter.csproj’.
将.proto 文件添加到项目中
接下来是一个重要的部分。首先,默认情况下,.csproj 项目文件会自动在其目录中找到所有.cs 文件,尽管 Microsoft 现在建议禁止这种通配行为,所以我们也决定不通配.proto 文件。因此,必须明确地将.proto 文件添加到项目中。
其次,将属性 PrivateAssets=“All”添加到 Grpc.Tools 包参考中是非常重要,这样新库的使用者就不会不必要地获取它。这是有道理的,因为程序包只包含编译器、代码生成器和导入文件,这些在.proto 文件编译的项目之外是不需要的。虽然,在这个简单的演练中并非严格要求,但始终应该是你的标准做法。
因此,编辑文件 MyGreeter.csproj 以添加 helloworld.proto 以便将其编译,并将 PrivateAssets 属性添加到 Grpc.Tools 包参考中。你生成的项目文件现在应如下所示:
<Project Sdk=”Microsoft.NET.Sdk”>
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include=”Google.Protobuf” Version=”3.6.1″ />
<PackageReference Include=”Grpc” Version=”1.17.0″ />
<!– The Grpc.Tools package generates C# sources from .proto files during
project build, but is not needed by projects using the built library.
It’s IMPORTANT to add the ‘PrivateAssets=”All”‘ to this reference: –>
<PackageReference Include=”Grpc.Tools” Version=”1.17.0″ PrivateAssets=”All” />
<!– Explicitly include our helloworld.proto file by adding this line: –>
<Protobuf Include=”helloworld.proto” />
</ItemGroup>
</Project>
构建它!
此时,你可以使用 dotnet build 命令构建项目,以编译.proto 文件和库程序集。在本演练中,我们将在命令中添加日志切换开关 -v:n,所以我们可以看到编译 helloworld.proto 文件的命令是在运行。你可能会发现,在第一次编译项目时,总是这样做是个好主意!
请注意,下面省略了许多输出行,因为构建输出非常详细。
~/work/MyGreeter$ dotnet build -v:n
Build started 11/9/18 5:33:44 PM.
1:7>Project “/home/kkm/work/MyGreeter/MyGreeter.csproj” on node 1 (Build target(s)).
1>_Protobuf_CoreCompile:
/home/kkm/.nuget/packages/grpc.tools/1.17.0/tools/linux_x64/protoc
–csharp_out=obj/Debug/netstandard2.0
–plugin=protoc-gen-grpc=/home/kkm/.nuget/packages/grpc.tools/1.17.0/tools/linux_x64/grpc_csharp_plugin
–grpc_out=obj/Debug/netstandard2.0 –proto_path=/home/kkm/.nuget/packages/grpc.tools/1.17.0/build/native/include
–proto_path=. –dependency_out=obj/Debug/netstandard2.0/da39a3ee5e6b4b0d_helloworld.protodep helloworld.proto
CoreCompile:
[… skipping long output …]
MyGreeter -> /home/kkm/work/MyGreeter/bin/Debug/netstandard2.0/MyGreeter.dll
Build succeeded.
如果此时再次调用 dotnet build -v:n 命令,则不会调用 protoc,也不会编译 C#源。但是,如果你更改了 helloworld.proto 源代码,那么在构建期间它的输出将被重新生成,然后由 C# 编译器重新编译。这是你期望修改任何源文件的常规依赖关系跟踪行为。
当然,你也可以将.cs 文件添加到同一个项目中:毕竟,它是构建.NET 库的常规 C# 项目。我们在 RouteGuide 示例中是这样做的。
生成的文件在哪里?
你可能想知道原型编译器和 gRPC 插件输出 C# 文件的位置。默认情况下,它们与其他生成的文件,放在同一目录中,例如对象(在.NET 构建用语中称为“中间输出”目录),在 obj/ 目录下。这是.NET 构建的常规做法,因此自动生成的文件,不会使工作目录混乱,或意外地置于源代码控制之下。否则,调试器等工具可以访问它们。你也可以在该目录中看到其他自动生成的源:
~/work/MyGreeter$ find obj -name ‘*.cs’
obj/Debug/netstandard2.0/MyGreeter.AssemblyInfo.cs
obj/Debug/netstandard2.0/Helloworld.cs
obj/Debug/netstandard2.0/HelloworldGrpc.cs
(如果你从 Windows 命令提示符下执行此演练,请使用 dir /s obj* .cs)
还有更多
虽然,在许多情况下最简单的默认行为是足够的,但是有很多方法可以在大型项目中,微调.proto 编译过程。如果你发现默认安排不适合你的工作流程,我们建议你阅读文档文件 BUILD-INTEGRATION.md,以获取可用选项。该软件包还扩展了 Visual Studio 的“属性”窗口,因此你可以在 Visual Studio 界面中为每个文件设置一些选项。
“经典”.csproj 项目和 Mono 也有支持。
分享你的经验
与任何复杂功能的初始版本一样,我们很高兴收到你的反馈。有什么不符合预期的工作?你有不容易用新工具覆盖的场景吗?你是否知道如何改善工作流程?请仔细阅读文档,然后在 GitHub 上的 gRPC 代码存储库中提交问题。你的反馈,对于确定构建集成工作的未来发展方向,非常重要!