1# Protocol Buffers/gRPC Codegen Integration Into .NET Build 2 3The [Grpc.Tools](https://www.nuget.org/packages/Grpc.Tools) NuGet package provides C# tooling support for generating C# code from `.proto` files in `.csproj` projects: 4* It contains protocol buffers compiler and gRPC plugin to generate C# code. 5* It can be used in building both grpc-dotnet projects and legacy c-core C# projects. 6 7Using `Grpc.Tools` in `.csproj` files is described below. Other packages providing the runtime libraries for gRPC are described elsewhere. 8 9## Getting Started 10 11The package [Grpc.Tools](https://www.nuget.org/packages/Grpc.Tools) is used automatically to generate the C# code for protocol buffer messages and gRPC service stubs from 12`.proto` files. These files: 13* are generated on an as-needed basis each time the project is built. 14* aren't added to the project or checked into source control. 15* are a build artifact usually contained in the obj directory. 16 17This package is optional. You may instead choose to generate the C# source files from 18`.proto` files by running the `protoc` compiler manually or from a script. 19However this package helps to simplify generating the C# source files by 20integrating the code generation into the build process. It can be used when building both 21the server and client projects, and by both c-core C# projects and grpc-dotnet projects: 22* The `Grpc.AspNetCore` metapackage already includes a reference to `Grpc.Tools`. 23* gRPC for .NET client projects and projects using `Grpc.Core` need to reference `Grpc.Tools` explicity if you want code generation for those projects 24 25`Grpc.Tools` is only used at build-time and has no runtime components. 26It should be marked with `PrivateAssets="All"` to prevent it from being included at runtime, e.g. 27```xml 28<PackageReference Include="Grpc.Tools" Version="2.50.0"> 29 <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> 30 <PrivateAssets>all</PrivateAssets> 31</PackageReference> 32``` 33 34Support is provided for the following platforms: 35* Windows (x86, x64, and arm64 via using the x86 binaries) 36* MacOS (x64 and arm64 via using the x64 binaries) 37* Linux (x86, x64, and arm64) 38 39You may still use the MSBuild integration provided by `Grpc.Tools` for other architectures provided you can supply the codegen binaries for that platform/architecture. 40See [Using Grpc.Tools with unsupported architectures](#unsupported-arch) below. 41 42## Adding `.proto` files to a project 43 44To add `.proto` files to a project edit the project’s `.csproj` file and add an item group with a `<Protobuf>` element that refers to the `.proto` file, e.g. 45 46```xml 47<ItemGroup> 48 <Protobuf Include="Protos\greet.proto" /> 49</ItemGroup> 50``` 51 52Wildcards can be used to select several `.proto` files, e.g. 53 54```xml 55<ItemGroup> 56 <Protobuf Include="**\*.proto" /> 57</ItemGroup> 58``` 59 60By default, a `<Protobuf>` reference generates gRPC client and a service base class from the `service` definitions in the `.proto` files. 61The `GrpcServices` attribute can be used to limit C# asset generation. See the reference section below for all 62options. E.g. to only generate client code: 63 64```xml 65<ItemGroup> 66 <Protobuf Include="Protos\greet.proto" GrpcServices="Client" /> 67</ItemGroup> 68``` 69 70For `.proto` files that are outside of the project directory a link can be added so that the files are visible in Visual Studio. E.g. 71 72```xml 73<ItemGroup> 74 <Protobuf Include="..\Proto\aggregate.proto" GrpcServices="Client" Link="Protos\aggregate.proto"/> 75 <Protobuf Include="..\Proto\greet.proto" GrpcServices="None" Link="Protos\greet.proto"/> 76 <Protobuf Include="..\Proto\count.proto" GrpcServices="None" Link="Protos\count.proto"/> 77</ItemGroup> 78``` 79 80For more examples see the example project files in GitHub: https://github.com/grpc/grpc-dotnet/tree/master/examples 81 82## Sharing `.proto` files between multiple projects (in the same VS solution) 83 84It's common to want to share `.proto` files between projects. For example, a gRPC client 85and gRPC server share the same contract. It is preferable to share contracts without 86copying `.proto` files because copies can go out of sync over time. 87 88There are a couple of ways to use `.proto` files in multiple projects without duplication: 89 90* Sharing `.proto` files between projects with MSBuild links. 91* Generating code in a class library and sharing the library. 92 93### Sharing `.proto` with MSBuild links 94 95`.proto` files can be placed in a shared location and referenced by multiple projects 96using MSBuild's [`Link` or `LinkBase` settings](https://learn.microsoft.com/visualstudio/msbuild/common-msbuild-item-metadata). 97 98```xml 99<ItemGroup> 100 <Protobuf Include="..\Protos\greet.proto" GrpcServices="None" Link="Protos\greet.proto"/> 101</ItemGroup> 102``` 103 104In the example above, `greet.proto` is in a shared `Protos` directory outside 105the project directory. Multiple projects can reference the proto file. 106 107### Generating code in a class library 108 109Create a class library that references `.proto` files and contains generated code. The other 110projects in the solution can then reference this shared class library instead of each project 111having to compile the same `.proto` files. 112 113The advantages of this are: 114- The `.proto` only need to be compiled once. 115- It prevents some projects getting multiple definitions of the same generated code, which can in turn break the build. 116 117There are a couple of examples in GitHub: 118- The [Liber example](https://github.com/grpc/grpc-dotnet/tree/master/examples#liber) 119 demonstrates how common protocol buffers messages can be compiled once and used in other projects: 120 - The *Common* project creates a class library that includes the generates messages contained in `common.proto` 121 - The *Client* and *Server* projects reference the *Common* project. 122 - They do not need to recompile `common.proto` as those .NET types are already in 123 the *Common* class library. 124 - They do however each generate their own gRPC client or server code as both have a 125 `<Protobuf>` reference for `greet.proto`. The *Client* and *Server* projects each having their own version of `greet.proto` is OK since they don't reference each other - they only reference the shared *Common* class library. 126 127- The [RouteGuide example](https://github.com/grpc/grpc/tree/v1.46.x/examples/csharp/RouteGuide) 128 demonstrates how the gRPC client and server code can be generated once and used in other 129 projects: 130 - **Note:** this example uses the *legacy c-core C#* packages, but the principles are the same 131 for *gRPC for .NET* projects. 132 - The *RouteGuide* project has a `<Protobuf>` reference to `route_guide.proto` and 133 generates both the gRPC client and server code. 134 - The *RouteGuideClient* and *RouteGuideServer* projects reference the *RouteGuide* project. 135 - They do not need any `<Protobuf>` references since the code has already been 136 generated in the *RouteGuide* project. 137 138 139# Reference 140 141## Protobuf item metadata reference 142 143The following metadata are recognized on the `<Protobuf>` items. 144 145| Name | Default | Value | Synopsis | 146|----------------|-----------|----------------------|----------------------------------| 147| Access | `public` | `public`, `internal` | Generated class access | 148| AdditionalProtocArguments | | arbitrary cmdline arguments | Extra command line flags passed to `protoc` command. To specify multiple arguments use semi-colons (;) to separate them. See example below | 149| ProtoCompile | `true` | `true`, `false` | If `false`, don't invoke `protoc` to generate code. | 150| ProtoRoot | See notes | A directory | Common root for set of files | 151| CompileOutputs | `true` | `true`, `false` | If `false`, C# code will be generated, but it won't be included in the C# build. | 152| OutputDir | See notes | A directory | Directory for generated C# files with protobuf messages | 153| OutputOptions | | arbitrary options | Extra options passed to C# codegen as `--csharp_opt=opt1,opt2` | 154| GrpcOutputDir | See notes | A directory | Directory for generated gRPC stubs | 155| GrpcOutputOptions | | arbitrary options | Extra options passed to gRPC codegen as `--grpc_opt=opt1,opt2` | 156| GrpcServices | `Both` | `None`, `Client`, `Server`, `Both` | Generated gRPC stubs | 157| AdditionalImportDirs | See notes | Directories | Specify additional directories in which to search for imports `.proto` files | 158 159__Notes__ 160 161* __ProtoRoot__ 162For files _inside_ the project directory or its subdirectories, `ProtoRoot` is set by default to the 163project directory. 164 165 For files _outside_ of the project directory, the value 166is set to the file's containing directory name, individually per file. If you 167include a subtree of `.proto` files that lies outside of the project directory, you 168need to set `ProtoRoot`. There is an example of this below. The path in 169this variable is relative to the project directory. 170 171* __OutputDir__ 172The default value is the value of the property 173`Protobuf_OutputPath`. This property, in turn, unless you set it in your 174project, will be set to the value of the standard MSBuild property 175`IntermediateOutputPath`, which points to the location of compilation object 176outputs, such as `"obj/Release/netstandard1.5/"`. The path in this property is 177considered relative to the project directory. 178 179* __GrpcOutputDir__ 180Unless explicitly set, will follow `OutputDir` for any given file. 181 182* __Access__ 183Sets generated class access on _both_ generated message and gRPC stub classes. 184 185* __AdditionalProtocArguments__ 186Pass additional commandline arguments to the `protoc` command being invoked. 187Normally this option should not be used, but it exists for scenarios when you need to pass 188otherwise unsupported (e.g. experimental) flags to protocol buffer compiler. 189 190* __OutputOptions__ 191Pass additional C# code generation options to `protoc` in the form `--csharp_opt=opt1,opt2`. See [C#-specific options](https://protobuf.dev/reference/csharp/csharp-generated/#compiler_options) for possible values. 192 193* __GrpcOutputOptions__ 194Pass additional options to the `grpc_csharp_plugin` in form of the `--grpc_opt` flag. 195Normally this option should not be used as its values are already controlled by `Access` 196and `GrpcServices` metadata, but it might be useful in situations where you want 197to explicitly pass some otherwise unsupported (e.g. experimental) options to the 198`grpc_csharp_plugin`. 199 200* __AdditionalImportDirs__ 201Specify additional directories in which to search for imports in `.proto` files. The directories are searched in the order given. You may specify directories _outside_ of the 202project directory. The directories are passed to the `protoc` code generator via the `-I/--proto_path` option 203together with `Protobuf_StandardImportsPath` and `ProtoRoot` directories. 204 205__Specifying multiple values in properties__ 206 207Some properties allow you to specify multiple values in a list. The items in a list need to 208be separated by semi-colons (;). This is the syntax that MsBuild uses for lists. 209 210The properties that can have lists of items are: `OutputOptions`, `AdditionalProtocArguments`, 211 `GrpcOutputOptions`, `AdditionalImportDirs` 212 213Example: to specify two additional arguments: `--plugin=protoc-gen-myplugin=D:\myplugin.exe --myplugin_out=.` 214 215```xml 216 <ItemGroup> 217 <Protobuf Include="proto_root/**/*.proto" ProtoRoot="proto_root" 218 OutputDir="%(RelativeDir)" CompileOutputs="false" 219 AdditionalProtocArguments="--plugin=protoc-gen-myplugin=D:\myplugin.exe;--myplugin_out=." /> 220 </ItemGroup> 221``` 222 223## `grpc_csharp_plugin` command line options 224 225Under the hood, the `Grpc.Tools` build integration invokes the `protoc` and `grpc_csharp_plugin` binaries 226to perform code generation. Here is an overview of the available `grpc_csharp_plugin` options: 227 228| Name | Default | Synopsis | 229|---------------- |-----------|----------------------------------------------------------| 230| no_client | off | Don't generate the client stub | 231| no_server | off | Don't generate the server-side stub | 232| internal_access | off | Generate classes with "internal" visibility | 233| file_suffix | Grpc.cs | The suffix that will get appended to the name of the generated file. **Can only be used on the command line.** | 234| base_namespace | none | *Experimental - may change or be removed.* Same as `base_namespace` for `protoc` [C# options](https://protobuf.dev/reference/csharp/csharp-generated/#compiler_options) . **Can only be used on the command line.** | 235 236To use these options with `Grpc.Tools` specify them in the __GrpcOutputOptions__ 237metadata in the `<Protobuf>` item. 238 239Notes: 240- `file_suffix` and `base_namespace` should not be used with `Grpc.Tools`. Using them will break the build. 241 242- using `base_namespace` changes the algorithm for the generated file names to align it with the algorithm used by `protoc`. 243 244 This only affects files with punctuation or numbers in the name. E.g. `hello.world2d.proto` now generates file `HelloWorld2DGrpc.cs` instead of `Hello.world2dGrpc.cs` 245 246To use these options on the command line specify them with the `--grpc_opt` 247option. 248 249Code generated by `protoc` is independent of the plugin and you may also need to specify C# options for this with `--csharp_opt`. 250These are [documented here](https://protobuf.dev/reference/csharp/csharp-generated/#compiler_options). 251 252 e.g.: 253 254```bash 255protoc --plugin=protoc-gen-grpc=grpc_csharp_plugin \ 256 --csharp_out=OUT_DIR \ 257 --csharp_opt=base_namespace=Example \ 258 --grpc_out=OUT_DIR \ 259 --grpc_opt=no_server,base_namespace=Example \ 260 -I INCLUDE_DIR foo.proto 261``` 262## Environment Variables 263 264Environment variables can be set to change the behavior of `Grpc.Tools` - setting the CPU architecture or operating system, or using custom built protocol buffers compiler and gRPC plugin. 265 266| Name | Synopsis | 267|---------------------|-------------------------------------------------------------------------------| 268|`PROTOBUF_TOOLS_OS` | Operating system version of the tools to use: `linux`, `macosx`, or `windows` | 269|`PROTOBUF_TOOLS_CPU` | CPU architecture version of the tools to use: `x86`, `x64`, or `arm64` | 270|`PROTOBUF_PROTOC` | Full path to the protocol buffers compiler | 271|`GRPC_PROTOC_PLUGIN` | Full path to the grpc_csharp_plugin | 272 273For example, to use a custom built protoc compiler and grpc_csharp_plugin: 274```bash 275export PROTOBUF_PROTOC=$my_custom_build/protoc 276export GRPC_PROTOC_PLUGIN=$my_custom_build/grpc_csharp_plugin 277dotnet build myproject.csproj 278``` 279 280## MSBuild Properties 281 282You can set some Properties in your project file or on the MSBuild command line. The 283following properties change the behavior of `Grpc.Tools`: 284 285| Name | Synopsis | 286|---------------------|-------------------------------------------------------------------------------| 287| `Protobuf_ToolsOs` | Same as `PROTOBUF_TOOLS_OS` environment variable | 288| `Protobuf_ToolsCpu` | Same as `PROTOBUF_TOOLS_CPU` environment variable | 289| `Protobuf_ProtocFullPath` | Same as `PROTOBUF_PROTOC` environment variable | 290| `gRPC_PluginFullPath` | Same as `GRPC_PROTOC_PLUGIN` environment variable | 291| `Protobuf_NoWarnMissingExpected` | Default: `false`. If `true` then no warnings are given if expected files not generated. See example below for an explanation. | 292| `Protobuf_OutputPath`| Default: `IntermediateOutputPath` - ususally the `obj` directory. Sets the default value for `OutputDir` on `<Protobuf>` items.| 293| `EnableDefaultProtobufItems` | Default: `false`. If `true` then `.proto` files under the project are automatically included without the need to specify any `<Protobuf>` items. | 294| `Protobuf_StandardImportsPath` | The path for protobuf's [well known types](https://protobuf.dev/reference/protobuf/google.protobuf/) included in the NuGet package. It is automcatically passed to `protoc` via the `-I/--proto_path` option. | 295 296# Scenarios and Examples 297 298For other examples see also the `.csproj` files in the examples in GitHub: 299* [grpc-dotnet examples](https://github.com/grpc/grpc-dotnet/tree/master/examples) 300* [`Grpc.Core` examples](https://github.com/grpc/grpc/tree/v1.46.x/examples/csharp) 301 302Quick links to the examples below: 303 304* [ProtoRoot - Common root for one or more `.proto` files](#ProtoRoot) 305* [AdditionalImportDirs - Setting location of imported `.proto` files](#AdditionalImportDirs) 306* [GrpcServices - Generating gRPC services and protocol buffers messages](#grpcservices) 307* [Automatically including `.proto` files](#autoinclude) 308* [Generate proto and gRPC C# sources from .proto files (no C# compile)](#nocompile) 309* [Visual Studio: setting per-file `.proto` file options](#visualstudio) 310* [Bypassing Grpc.Tools to run the protocol buffers compiler explicitly](#compiler) 311* [Using Grpc.Tools with unsupported architectures](#unsupported-arch) 312* [Including `.proto` files in NuGet packages](#proto-only-nuget) 313 314--- 315## <a name="ProtoRoot"></a>ProtoRoot - Common root for one or more `.proto` files 316 317`ProtoRoot` specifies a common directory that is an ancestor for a set of `.proto` files. 318 319It has two purposes: 320* working out relative directories to preserve the structure when generating `.cs` files 321* adding a directory to be searched for imported `.proto` files 322 323These are explained in an example below. 324 325For `.proto` files under the project directory `ProtoRoot` is by default set to `.`. 326It can also be explicitly set. 327 328For `.proto` files outside of the project the value is set to the file's containing directory name. 329If you include a subtree of `.proto` files then you must set `ProtoRoot` to give the 330parent of the directory tree. 331 332In either case if you are importing a `.proto` file from within another file then you should set 333`ProtoRoot` so that the import paths can be found. (See also `AdditionalImportDirs` below.) 334 335Generated files in the output directory will have the same directory structure as the 336`.proto` files under `ProtoRoot`. 337 338By default the output directory for generated files is `obj\CONFIGURATION\FRAMEWORK\` (e.g. `obj\Debug\net6.0\`) unless `OutputDir` or `GrpcOutputDir` are specified. 339### Example use of `ProtoRoot` 340Specifying: 341```xml 342<Protobuf Include="Protos\Services\**\*.proto" 343 ProtoRoot="Protos" /> 344<Protobuf Include="Protos\Messages\**\*.proto" 345 ProtoRoot="Protos" 346 GrpcServices="None" /> 347<Protobuf Include="..\OutsideProjectProtos\**\*.proto" 348 ProtoRoot="..\OutsideProjectProtos" /> 349``` 350for files: 351``` 352 ProjectFolder\Protos\Services\v1\hello.proto 353 ProjectFolder\Protos\Services\v2\hello.proto 354 ProjectFolder\Protos\Messages\v1\message.proto 355 ..\OutsideProjectProtos\MyApi\alpha.proto 356 ..\OutsideProjectProtos\MyApi\beta.proto 357``` 358will generate files: 359``` 360 ProjectFolder\obj\Debug\net6.0\Services\v1\Hello.cs 361 ProjectFolder\obj\Debug\net6.0\Services\v1\HelloGrpc.cs 362 ProjectFolder\obj\Debug\net6.0\Services\v2\Hello.cs 363 ProjectFolder\obj\Debug\net6.0\Services\v2\HelloGrpc.cs 364 ProjectFolder\obj\Debug\net6.0\Messages\v1\Message.cs 365 ProjectFolder\obj\Debug\net6.0\MyApi\Alpha.cs 366 ProjectFolder\obj\Debug\net6.0\MyApi\AlphaGrpc.cs 367 ProjectFolder\obj\Debug\net6.0\MyApi\Beta.cs 368 ProjectFolder\obj\Debug\net6.0\MyApi\BetaGrpc.cs 369 370``` 371Things to notes: 372* the directory structures under `ProjectFolder\Protos\` and `..\OutsideProjectProtos\` are mirrored in the output directory. 373* the import search paths passed to `protoc` via `-I/--proto_path` option will include 374 `ProjectFolder\Protos` and `..\OutsideProjectProtos` 375--- 376## <a name="AdditionalImportDirs"></a>AdditionalImportDirs - Setting location of imported `.proto` files 377 378In addition to specifying `ProtoRoot` other import directories can be specified for 379directories to search when importing `.proto` files by specifying `AdditionalImportDirs` 380and provide a list of directories. The directories are searched in the order given. 381 382You would use this when you want to import `.proto` files that you don't need to 383separately compile as they are only used in import statements. E.g.: 384 385```xml 386 <Protobuf Include="protos/*.proto" 387 ProtoRoot="protos" 388 AdditionalImportDirs="/folder/protos/mytypes/;/another/folder/" 389 ... /> 390``` 391 392Note: The path for protobuf's [well known types](https://protobuf.dev/reference/protobuf/google.protobuf/) is automatically included. E.g. the `import` below will work without having to explicity specifying the path in `AdditionalImportDirs`: 393```protobuf 394import "google/protobuf/wrappers.proto"; 395``` 396--- 397## <a name="grpcservices"></a>GrpcServices - Generating gRPC services and protocol buffers messages 398The protocol buffers files (`.proto` files) define both the service interface and the 399structure of the payload messages. 400 401Two `.cs` file can be generated from a `.proto` file. For example, if the `.proto` file 402is `myfile.proto` then the two possible files are: 403* `Myfile.cs` - contains the generated code for protocol buffers messages 404* `MyfileGrpc.cs` - contains the generated code for gRPC client and/or server 405 406When a `.proto` file contains service definitions the protocol buffers compiler calls 407the gRPC plugin to generate gRPC client and/or server stub code. Whether or not the `*Grpc.cs` file 408is generated and what it contains is controlled by the `GrpcServices` metadata 409on the `<Protobuf>` item. 410 411* `GrpcServices="Both"` (the default) - `Myfile.cs` and `MyfileGrpc.cs` generated 412* `GrpcServices="None"` - just `Myfile.cs` generated 413* `GrpcServices="Client"` - `Myfile.cs` and `MyfileGrpc.cs` (just client code) 414* `GrpcServices="Server"` - `Myfile.cs` and `MyfileGrpc.cs` (just server code) 415 416However when a `.proto` **does not file contains any service definitions** but only contains 417message definitions then an empty (zero length) `MyfileGrpc.cs` may still be created 418by `Grpc.Tools` unless the `.proto` file is specified with `GrpcServices="None"` in the project file. 419 420This is because `Grpc.Tools` has no way of knowing in advanced of running the protocol buffers 421compiler whether a `.proto` file has a service clause. It creates the empty files as a marker 422for incremental builds so that the `.proto` files are not unnecessarily recompiled. Empty files 423are not a problem on a small project but you may wish to avoid them on a larger project. 424 425Therefore it is better to explicitly mark files with the correct `GrpcServices` metadata if you can. For 426example: 427 428```xml 429<ItemGroup> 430 <Protobuf Include="**/*.proto" GrpcServices="None" /> 431 <Protobuf Update="**/hello/*.proto;**/bye/*.proto" GrpcServices="Both" /> 432</ItemGroup> 433``` 434In the above example all `.proto` files are compiled with `GrpcServices="None"`, except for `.proto` 435files in subdirectories on any tree level named `hello` and `bye`, which will take 436`GrpcServices="Both"`. Note the use of the `Update` attribute instead of `Include` - otherwise 437the files would be added twice. 438 439Another example would be the use of globbing if your service `.proto` files are named according 440to a pattern, for example `*_services.proto`. In this case the `Update` attribute can be written 441as `Update="**/*_service.proto"` to set the attribute `GrpcServices="Both"` only on these files. 442 443### Seeing a warning about a missing expected file 444 445You will see the warning message: 446 ``` 447 Some expected protoc outputs were not generated 448 ``` 449 if all these are true: 450 * the location for the generated files is configured to a directory outside of the project, e.g. `OutputDir="..\outside-project\"` 451 * `*Grpc.cs` files have not been created because the `.proto` file does not contain a 452service definintion 453* you have not specified `GrpcServices="None"` 454 455This is because `Grpc.Tools` only creates empty `*Grpc.cs` files in directories 456within the project (such as the intermediate `obj` directory). Empty files are not created 457outside of the project directory so as not to pollute non-project directories. 458 459This warning can be suppressed by setting the MSBuild property: 460```xml 461<PropertyGroup> 462 <Protobuf_NoWarnMissingExpected>true</Protobuf_NoWarnMissingExpected> 463</PropertyGroup> 464``` 465however it is better to set `GrpcServices="None"` on the `.proto` files affected to avoid 466unnecessary rebuilds. 467 468 469--- 470## <a name="autoinclude"></a>Automatically including `.proto` files 471 472For SDK projects it is possible to automatically include `.proto` files found in the project 473directory or sub-directories, without having to specify them with a `<Protobuf>` item. 474To do this the property `EnableDefaultProtobufItems` has be set to `true` in the project file or on the MSBuild command line. 475 476It is recommended that you do not rely on automatic inclusion of `.proto` files except for 477the simplest of projects since it does not allow you to control other settings such as 478`GrpcServices`. 479 480By default `EnableDefaultProtobufItems` is not set and `<Protobuf>` items must be included 481in the project for the `.proto` files to be compiled. 482 483--- 484 485## <a name="nocompile"></a>Generate proto and gRPC C# sources from .proto files (no C# compile) 486 487If you just want to generate the C# sources from `.proto` files without compiling the C# files 488 (e.g. for use in other projects) then you can do something similar to this to a `.csproj` file: 489 ```xml 490<ItemGroup> 491 <Protobuf Include="**/*.proto" 492 OutputDir="%(RelativeDir)" CompileOutputs="false" /> 493</ItemGroup> 494``` 495 496* `Include` tells the build system to recursively examine project directory and its 497subdirectories (**) include all files matching the wildcard `*.proto`. 498* `OutputDir="%(RelativeDir)"` makes the output directory for each `.cs` file to be 499same as the corresponding `.proto` directory. 500* `CompileOutputs="false"` prevents compiling the generated files into an assembly. 501 502Note that an empty assembly is still generated which can be ignored. 503 504NOTE: To start with an empty project to add your `.proto` files to you can do the following 505at a command prompt: 506```bash 507dotnet new classlib 508rm *.cs # remove .cs files - for Windows the command is: del *.cs /y 509dotnet add package Grpc.Tools 510``` 511 512--- 513## <a name="visualstudio"></a>Visual Studio: setting per-file `.proto` file options 514 515In Visual Studio it is possible to set some frequently used per-file options on `.proto` files 516without editing the `.csproj` file directly. However editing the `.csproj` gives you more 517flexibilty. 518 519### "dotnet SDK" projects 520 521For a "dotnet SDK" project, you have more control of some frequently used options. 522**You may need to open and close Visual Studio** for this form to appear in the 523properties window after adding a reference to `Grpc.Tools` package: 524 525 526 527You can also change options of multiple files at once by selecting them in the 528Project Explorer together. 529 530### "classic" projects 531 532For a "classic" project, you can only add `.proto` files with all options set to 533default. Click on the "show all files" button, add files to project, then 534change file type of the `.proto` files to "Protobuf" in the Properties window 535drop-down. This menu item will appear after you import the `Grpc.Tools` package: 536 537 538 539--- 540## <a name="compiler"></a>Bypassing Grpc.Tools to run the protocol buffers compiler explicitly 541 542It is possible to bypass all the build logic in `Grpc.Tools` and run the protocol buffers compiler 543explicitly in your project file, and just use the `Grpc.Tools` as a means of getting the compiler. 544**This is not recommended** but there may be situations where you want to do this. 545 546You can use the following Properties: 547* `Protobuf_ProtocFullPath` points to the full path and filename of protoc executable, e.g. 548 `"...\.nuget\packages\grpc.tools\2.51.0\build\native\bin\windows\protoc.exe"` 549 550* `gRPC_PluginFullPath` points to the full path and filename of gRPC plugin, e.g. 551 `"...\.nuget\packages\grpc.tools\2.51.0\build\native\bin\windows\grpc_csharp_plugin.exe"` 552 553* `Protobuf_StandardImportsPath` points to the standard proto import directory, e.g. 554 `"...\.nuget\packages\grpc.tools\2.51.0\build\native\include"`. This is 555 the directory where a declaration such as `import "google/protobuf/wrappers.proto";` 556 in a proto file would find its target. 557 558then in your project file: 559 560```xml 561 <Target Name="MyProtoCompile"> 562 <PropertyGroup> 563 <ProtoCCommand>$(Protobuf_ProtocFullPath) --plugin=protoc-gen-grpc=$(gRPC_PluginFullPath) -I $(Protobuf_StandardImportsPath) ....rest of your command.... </ProtoCCommand> 564 </PropertyGroup> 565 <Message Importance="high" Text="$(ProtoCCommand)" /> 566 <Exec Command="$(ProtoCCommand)" /> 567 </Target> 568``` 569Do not include any `<Protobuf>` items in the project file as that will invoke the `Grpc.Tools` build and your files will be compiled twice. 570 571--- 572 573## <a name="unsupported-arch"></a>Using Grpc.Tools with unsupported architectures 574 575You may still use the MSBuild integration provided by `Grpc.Tools` for architectures where 576the binaries are not included in the `Grpc.Tools` NuGet package. 577 578If you are able to build your own binaries for `protoc` and `grpc_csharp_plugin`, or 579find pre-built binaries provided by the community, then you can define a couple of 580environment variables to tell `Grpc.Tools` to use those binaries instead of the ones 581provided in the NuGet package: 582* `PROTOBUF_PROTOC` - Full path to the protocol buffers compiler 583* `GRPC_PROTOC_PLUGIN` - Full path to the `grpc_csharp_plugin` 584 585Things to note: 586* You need `Grpc.Tools` version 2.50.0 or later for these environment variables to 587be recognised. 588 589* The binaries bundled in `Grpc.Tools` already ensure that the correct and mutually 590compatible version of `protoc` and `grpc_csharp_plugin` will be chosen, but when 591providing them yourself, you're in charge. 592 593* If the versions of `protoc` and `grpc_csharp_plugin` you provide are mutually 594incompatible then code generated may not work with your application (e.g. breaks 595the build). 596 597* Specifically, older version of plugins may generate incompatible code 598or may not contain patches/fixes. 599 600_An example for Alpine Linux_ 601 602For Alpine Linux (which uses the *musl* C standard library) there are community 603provided packages for the protocol buffers compiler and gRPC plugins: 604[https://pkgs.alpinelinux.org/packages?name=grpc-plugins](https://pkgs.alpinelinux.org/packages?name=grpc-plugins) 605 606To use these: 607```bash 608# Build or install the binaries for your architecture. 609 610# e.g. for Alpine Linux the grpc-plugins package can be used 611# See https://pkgs.alpinelinux.org/package/edge/community/x86_64/grpc-plugins 612apk add grpc-plugins # Alpine Linux specific package installer 613 614# Set environment variables for the built/installed protoc 615# and grpc_csharp_plugin binaries 616export PROTOBUF_PROTOC=/usr/bin/protoc 617export GRPC_PROTOC_PLUGIN=/usr/bin/grpc_csharp_plugin 618 619# When the dotnet build runs the Grpc.Tools NuGet package will 620# use the binaries pointed to by the environment variables 621dotnet build 622``` 623 624--- 625 626## <a name="proto-only-nuget"></a>Including `.proto` files in NuGet packages 627 628There might be occassions when you are given a NuGet package that contains 629`.proto` files that you wish to use in your own project, or you may wish to 630package your own `.proto` files in a NuGet package for others to use. 631 632There is no automatic way for `Grpc.Tools` to locate and include `.proto` 633files from other NuGet packages. Below is a suggested convention to use 634when creating NuGet packages that contain `.proto` files. 635 636__Note:__ This is not the same as a NuGet package providing a library built from 637the code generated from the `.proto` files. Below just describes how to provide 638the uncompiled `.proto` files in a NuGet package and have `Grpc.Tools` automatically 639use them. 640 641### Creating the NuGet package 642 643The NuGet package should: 644- provide the `.proto` files in a `content\protos` subdirectory in the package 645- provide a `packagename.targets` file in the `build` subdirectory in the package that: 646 - defines an MSBuild property giving the path to the `.proto` files in the 647 installed package 648 - conditionally updates the `Protobuf_StandardImportsPath` property with the 649 above path so that the files can be found by the protocol buffers compiler 650 - it should be made optional forcing users to *opt in* to including 651 the `.proto` files 652 653For example, for the package `My.Example.Protos`: 654 655My.Example.Protos.nuspec: 656```xml 657<?xml version="1.0"?> 658<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"> 659 <metadata> 660 <id>My.Example.Protos</id> 661 <version>1.0.0</version> 662 <title>Example package containing proto files</title> 663 <authors>author</authors> 664 <owners>owner</owners> 665 <licenseUrl>license url</licenseUrl> 666 <projectUrl>project url</projectUrl> 667 <description>See project site for more info.</description> 668 <summary>Example package containing proto files.</summary> 669 <releaseNotes>Example package containing proto files</releaseNotes> 670 <copyright>Copyright 2023, My Company.</copyright> 671 </metadata> 672 673 <files> 674 <!-- copy the My.Example.Protos.targets file for MSBuild integration --> 675 <file src="build\**" target="build" /> 676 <!-- copy the .proto files into the package --> 677 <file src="proto\**" target="content\protos" /> 678 </files> 679</package> 680``` 681 682My.Example.Protos.targets: 683```xml 684<?xml version="1.0"?> 685<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 686 <!-- This targets file allows .proto files bundled in package, 687 to be included in Grpc.Tools compilation. --> 688 689 <PropertyGroup> 690 <!-- Define a property containing the path of the proto files. 691 Content from the nupkg. --> 692 <MyExampleProtos_ProtosPath>$( [System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)../content/protos) )</MyExampleProtos_ProtosPath> 693 </PropertyGroup> 694 695 <!-- Run immediately before the Protobuf_BeforeCompile extension point. --> 696 <!-- Only include protos if project has set <IncludeMyExampleProtosProtos> 697 property to true. --> 698 <Target Name="MyExampleProtos_BeforeCompile" 699 BeforeTargets="Protobuf_BeforeCompile" 700 Condition=" '$(IncludeMyExampleProtosProtos)' == 'true' "> 701 <PropertyGroup> 702 <!-- Add proto files by including path in Protobuf_StandardImportsPath. 703 This path is passed to protoc via the -I option --> 704 <Protobuf_StandardImportsPath>$(Protobuf_StandardImportsPath);$(MyPackage_ProtosPath)</Protobuf_StandardImportsPath> 705 </PropertyGroup> 706 707 <!-- These message are not required but included here for diagnostics --> 708 <Message Text="Included proto files at $(MyExampleProtos_ProtosPath) in import path." Importance="high" /> 709 <Message Text="Updated proto imports path: $(Protobuf_StandardImportsPath)" Importance="high" /> 710 </Target> 711</Project> 712``` 713 714### Using the NuGet package 715 716The project needs to add the package containing the `.proto` files: 717```xml 718<PackageReference Include="My.Example.Protos" Version="1.0.0" /> 719``` 720 721If the project only wants to compile the `.proto` files included in the package 722then all it needs to do is add the `<Protobuf>` items using the property defined 723in the package for the path to the files. For example, if the NuGet package contained 724the file `greet.proto`, then the project should add: 725 726```xml 727<Protobuf Include="$(MyExampleProtos_ProtosPath)/greet.proto" /> 728``` 729 730However if the provided `.proto` files are to be *imported* by the projects own `.proto` 731files then the `Protobuf_StandardImportsPath` needs updated to add the directory 732containing the package's files. This is done by setting to `true` the property 733used in the package. For example, if the project has the local `.proto` file 734`my_services.proto` and it imported a file from the package `common_message.proto`, 735then: 736 737```xml 738<PropertyGroup> 739 <!-- Update the Protobuf_StandardImportsPath --> 740 <IncludeMyExampleProtosProtos>true</IncludeMyExampleProtosProtos> 741</PropertyGroup> 742 743<ItemGroup> 744 <!-- my_services.proto imports common_message.proto from the package 745 My.Example.Protos --> 746 <Protobuf Include="my_services.proto" /> 747</ItemGroup> 748``` 749 750--- 751 752## See also 753 754gRPC project documentation: 755* [gRPC for .NET](https://github.com/grpc/grpc-dotnet) 756* [gRPC C# (legacy implementation using gRPC Core library)](https://github.com/grpc/grpc/blob/master/src/csharp/README.md) 757* [Grpc.Tools internals](Grpc.Tools/implementation_notes.md) - implementation notes for how `Grpc.Tools` works 758 759Microsoft documentation: 760* [Microsoft: Overview for gRPC on .NET](https://learn.microsoft.com/en-us/aspnet/core/grpc/) 761* [Microsoft: C# Tooling support for .proto files](https://learn.microsoft.com/en-us/aspnet/core/grpc/basics#c-tooling-support-for-proto-files) 762