作為微軟向其跨平臺.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程式碼儲存庫中提交問題。你的反饋,對於確定構建整合工作的未來發展方向,非常重要!