11---
22layout : post
3- title : gRPC Meets .NET SDK And Visual Studio
3+ title : gRPC Meets .NET SDK And Visual Studio: Automatic Codegen On Build
44published : true
55permalink : blog/grpc-dotnet-build
66author : Kirill 'kkm' Katsnelson
77author-link : https://github.com/kkm000
88company : SmartAction
99company-link : https://www.smartaction.ai
1010---
11+
1112As part of Microsoft's move towards its cross-platform .NET offering, they have
1213greatly simplified the project file format, and allowed a tight integration of
1314third-party code generators with .NET projects. We are listening, and now proud
1415to introduce integrated compilation of Protocol Buffer and gRPC service
1516` .proto ` files in .NET C# projects starting with the version 1.17 of the
1617Grpc.Tools NuGet package, now available from Nuget.org.
1718
19+ You no longer need separate scripts to generate code from ` .proto ` files: The
20+ .NET build magic handles this for you. The integrated tools locate the proto
21+ compiler and gRPC plugin, standard Protocol Buffer imports, and track
22+ dependencies before invoking the code generators, so that the generated C#
23+ source files are never out of date, at the same time keeping regeneration to
24+ the minimum required. In essence, ` .proto ` files are treated as first-class
25+ sources in a .NET C# project.
26+
1827<!-- more-->
1928
2029## A Walkthrough
2130
22- Now you can include ` .proto ` files along with C# source files into ` .csproj `
23- project files. In this blog post, we'll walk through the simplest and probably
24- the most common scenario of creating a library from ` .proto ` files using the
25- cross-platform ` dotnet ` command. We will implement essentially a clone of the
26- ` Greeter ` library, shared by client and server projects in the [ C# ` Helloworld `
27- example directory
31+ In this blog post, we'll walk through the simplest and probably the most common
32+ scenario of creating a library from ` .proto ` files using the cross-platform
33+ ` dotnet ` command. We will implement essentially a clone of the ` Greeter `
34+ library, shared by client and server projects in the [ C# ` Helloworld ` example
35+ directory
2836] ( https://github.com/grpc/grpc/tree/master/examples/csharp/Helloworld/Greeter ) .
2937
3038Start by creating a new library project.
3139
3240```
33- kkm@yupana: ~/work$ dotnet new classlib -o MyGreeter
41+ ~/work$ dotnet new classlib -o MyGreeter
3442The template "Class library" was created successfully.
3543
36- kkm@yupana: ~/work$ cd MyGreeter
37- kkm@yupana: ~/work/MyGreeter$ ls -lF
44+ ~/work$ cd MyGreeter
45+ ~/work/MyGreeter$ ls -lF
3846total 12
3947-rw-rw-r-- 1 kkm kkm 86 Nov 9 16:10 Class1.cs
4048-rw-rw-r-- 1 kkm kkm 145 Nov 9 16:10 MyGreeter.csproj
4149drwxrwxr-x 2 kkm kkm 4096 Nov 9 16:10 obj/
4250```
4351
44- The ` dotnet new ` command has created the file ` Class1.cs ` that we won't need, so
45- it's ok to remove it. Also, we need some ` .proto ` files to compile. For this
46- exercise, we'll copy an example file [ ` examples/protos/helloworld.proto `
52+ Observe that the ` dotnet new ` command has created the file ` Class1.cs ` that
53+ we won't need, so remove it. Also, we need some ` .proto ` files to compile. For
54+ this exercise, we'll copy an example file [ ` examples/protos/helloworld.proto `
4755] ( https://github.com/grpc/grpc/blob/master/examples/protos/helloworld.proto )
4856from the gRPC distribution.
4957
5058```
51- kkm@yupana: ~/work/MyGreeter$ rm Class1.cs
52- kkm@yupana: ~/work/MyGreeter$ wget -q https://raw.githubusercontent.com/grpc/grpc/master/examples/protos/helloworld.proto
59+ ~/work/MyGreeter$ rm Class1.cs
60+ ~/work/MyGreeter$ wget -q https://raw.githubusercontent.com/grpc/grpc/master/examples/protos/helloworld.proto
5361```
5462
5563(on Windows, use ` del Class1.cs ` , and, if you do not have the wget command,
@@ -60,11 +68,11 @@ and use a *Save As...* command from your Web browser).
6068Next, add required NuGet packages to the project:
6169
6270```
63- kkm@yupana: ~/work/MyGreeter$ dotnet add package Grpc
71+ ~/work/MyGreeter$ dotnet add package Grpc
6472info : PackageReference for package 'Grpc' version '1.17.0' added to file '/home/kkm/work/MyGreeter/MyGreeter.csproj'.
65- kkm@yupana: ~/work/MyGreeter$ dotnet add package Grpc.Tools
73+ ~/work/MyGreeter$ dotnet add package Grpc.Tools
6674info : PackageReference for package 'Grpc.Tools' version '1.17.0' added to file '/home/kkm/work/MyGreeter/MyGreeter.csproj'.
67- kkm@yupana: ~/work/MyGreeter$ dotnet add package Google.Protobuf
75+ ~/work/MyGreeter$ dotnet add package Google.Protobuf
6876info : PackageReference for package 'Google.Protobuf' version '3.6.1' added to file '/home/kkm/work/MyGreeter/MyGreeter.csproj'.
6977```
7078
@@ -73,15 +81,19 @@ file automatically finds all `.cs` files in its directory, although
7381[ Microsoft now recommends suppressing this globbing
7482behavior] ( https://docs.microsoft.com/dotnet/core/tools/csproj#recommendation ) ,
7583so we too decided against globbing ` .proto ` files. Thus the ` .proto `
76- files must be added to the project explicitly. Second of all, it is important
77- to add a property ` PrivateAssets="All" ` to the Grpc.Tools package reference,
78- so that it will not be needlessly fetched by the consumers of your new library.
79- This makes sense, as the package only contains compiler, code generators and
80- import files, which are not needed outside of the project where the ` .proto `
81- files have been compiled. So you must edit the file ` MyGreeter.csproj ` and
82- add the ` helloworld.proto ` to be compiled, and the ` PrivateAssets ` property to
83- the Grpc.Tools package reference. Your resulting project file should now look
84- like this:
84+ files must be added to the project explicitly.
85+
86+ Second of all, it is important to add a property ` PrivateAssets="All" ` to the
87+ Grpc.Tools package reference, so that it will not be needlessly fetched by the
88+ consumers of your new library. This makes sense, as the package only contains
89+ compilers, code generators and import files, which are not needed outside of
90+ the project where the ` .proto ` files have been compiled. While not strictly
91+ required in this simple walkthrough, it must be your standard practice to do
92+ that always.
93+
94+ So edit the file ` MyGreeter.csproj ` to add the ` helloworld.proto ` so that it
95+ will be compiled, and the ` PrivateAssets ` property to the Grpc.Tools package
96+ reference. Your resulting project file should now look like this:
8597
8698``` xml
8799<Project Sdk =" Microsoft.NET.Sdk" >
@@ -93,24 +105,25 @@ like this:
93105 <ItemGroup >
94106 <PackageReference Include =" Google.Protobuf" Version =" 3.6.1" />
95107 <PackageReference Include =" Grpc" Version =" 1.17.0" />
108+ <!-- Add attribute as shown below. -->
96109 <PackageReference Include =" Grpc.Tools" Version =" 1.17.0" PrivateAssets =" All" />
97- <ProtoBuf Include =" helloworld.proto" />
110+ <Protobuf Include =" helloworld.proto" /> <!-- Add this entire line. -- >
98111 </ItemGroup >
99112
100113</Project >
101114```
102115
103- At this point you can build the project with ` dotnet build ` command to compile
104- the ` .proto ` file and the library assembly. For this walkthrough, we'll add a
105- logging switch ` -v:n ` to the command, so we can see that the command to compile
106- the ` helloworld.proto ` file was in fact run. You may find it a good idea to do
107- that the very first time you compile a project!
116+ At this point you can build the project with the ` dotnet build ` command to
117+ compile the ` .proto ` file and the library assembly. For this walkthrough, we'll
118+ add a logging switch ` -v:n ` to the command, so we can see that the command to
119+ compile the ` helloworld.proto ` file was in fact run. You may find it a good
120+ idea to always do that the very first time you compile a project!
108121
109122Note that many output lines are omitted below, as the build output is quite
110123verbose.
111124
112125```
113- kkm@yupana: ~/work/MyGreeter$ dotnet build -v:n
126+ ~/work/MyGreeter$ dotnet build -v:n
114127
115128Build started 11/9/18 5:33:44 PM.
116129 1:7>Project "/home/kkm/work/MyGreeter/MyGreeter.csproj" on node 1 (Build target(s)).
@@ -129,6 +142,12 @@ Build started 11/9/18 5:33:44 PM.
129142Build succeeded.
130143```
131144
145+ If at this point you invoke the ` dotnet build -v:n ` command again, ` protoc `
146+ would not be invoked, and no C# sources would be compiled. But if you change
147+ the ` helloworld.proto ` source, then its outputs will be regenerated and then
148+ recompiled by the C# compiler during the build. This is a regular dependency
149+ tracking behavior that you expect from modifying any source file.
150+
132151Of course, you can also add ` .cs ` files to the same project: It is a regular C#
133152project building a .NET library, after all. This is done in our [ RouteGuide
134153] ( https://github.com/grpc/grpc/tree/master/examples/csharp/RouteGuide/RouteGuide )
@@ -144,7 +163,7 @@ tools like the debugger. You can see other autogenerated sources in that
144163directory, too:
145164
146165```
147- kkm@yupana: ~/work/MyGreeter$ find obj -name '*.cs'
166+ ~/work/MyGreeter$ find obj -name '*.cs'
148167obj/Debug/netstandard2.0/MyGreeter.AssemblyInfo.cs
149168obj/Debug/netstandard2.0/Helloworld.cs
150169obj/Debug/netstandard2.0/HelloworldGrpc.cs
@@ -156,8 +175,8 @@ command prompt).
156175## There Is More To It
157176
158177While the simplest default behavior is adequate in many cases, there are many
159- ways to fine-tune your ` .proto ` compilation process in a large project. Refer
160- to the [ documentation file BUILD-INTEGRATION.md
178+ ways to fine-tune your ` .proto ` compilation process in a large project. We
179+ encourage you to read the [ documentation file BUILD-INTEGRATION.md
161180] ( https://github.com/grpc/grpc/blob/master/src/csharp/BUILD-INTEGRATION.md )
162181for available options if you find that the default arrangement does not suit
163182your workflow. The package also extends the Visual Studio's Properties window,
@@ -172,4 +191,5 @@ your feedback. Did something not work as expected? Do you have a scenario that
172191is not easy to cover with the new tools? Do you have an idea how to improve the
173192workflow in general? Please read the documentation carefully, and then [ open an
174193issue] ( https://github.com/grpc/grpc/issues ) in the gRPC code repository on
175- GitHub.
194+ GitHub. Your feedback is important to determine the future direction for our
195+ build integration work!
0 commit comments