From 301636dae0b179f76b11377dc05c82808c981e76 Mon Sep 17 00:00:00 2001 From: tony <57042389+tonydnewell@users.noreply.github.com> Date: Wed, 18 Oct 2023 17:39:42 +0100 Subject: [PATCH] [csharp] Grpc.Tools documentation for sharing proto files between projects and nuget packages (#34521) Added documented for Grpc.Tools for sharing proto files - between projects in a solution - in NuGet packages to be used by other projects This addresses the questions raised in: - https://github.com/grpc/grpc-dotnet/issues/1458 - https://github.com/grpc/grpc-dotnet/issues/183 @jtattermusch @JamesNK --------- Co-authored-by: James Newton-King --- src/csharp/BUILD-INTEGRATION.md | 184 ++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) diff --git a/src/csharp/BUILD-INTEGRATION.md b/src/csharp/BUILD-INTEGRATION.md index 644adf38767..279368e49fa 100644 --- a/src/csharp/BUILD-INTEGRATION.md +++ b/src/csharp/BUILD-INTEGRATION.md @@ -79,6 +79,63 @@ For `.proto` files that are outside of the project directory a link can be added For more examples see the example project files in GitHub: https://github.com/grpc/grpc-dotnet/tree/master/examples +## Sharing `.proto` files between multiple projects (in the same VS solution) + +It's common to want to share `.proto` files between projects. For example, a gRPC client +and gRPC server share the same contract. It is preferable to share contracts without +copying `.proto` files because copies can go out of sync over time. + +There are a couple of ways to use `.proto` files in multiple projects without duplication: + +* Sharing `.proto` files between projects with MSBuild links. +* Generating code in a class library and sharing the library. + +### Sharing `.proto` with MSBuild links + +`.proto` files can be placed in a shared location and referenced by multiple projects +using MSBuild's [`Link` or `LinkBase` settings](https://learn.microsoft.com/visualstudio/msbuild/common-msbuild-item-metadata). + +```xml + + + +``` + +In the example above, `greet.proto` is in a shared `Protos` directory outside +the project directory. Multiple projects can reference the proto file. + +### Generating code in a class library + +Create a class library that references `.proto` files and contains generated code. The other +projects in the solution can then reference this shared class library instead of each project +having to compile the same `.proto` files. + +The advantages of this are: +- The `.proto` only need to be compiled once. +- It prevents some projects getting multiple definitions of the same generated code, which can in turn break the build. + +There are a couple of examples in GitHub: +- The [Liber example](https://github.com/grpc/grpc-dotnet/tree/master/examples#liber) + demonstrates how common protocol buffers messages can be compiled once and used in other projects: + - The *Common* project creates a class library that includes the generates messages contained in `common.proto` + - The *Client* and *Server* projects reference the *Common* project. + - They do not need to recompile `common.proto` as those .NET types are already in + the *Common* class library. + - They do however each generate their own gRPC client or server code as both have a + `` 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. + +- The [RouteGuide example](https://github.com/grpc/grpc/tree/v1.46.x/examples/csharp/RouteGuide) + demonstrates how the gRPC client and server code can be generated once and used in other + projects: + - **Note:** this example uses the *legacy c-core C#* packages, but the principles are the same + for *gRPC for .NET* projects. + - The *RouteGuide* project has a `` reference to `route_guide.proto` and + generates both the gRPC client and server code. + - The *RouteGuideClient* and *RouteGuideServer* projects reference the *RouteGuide* project. + - They do not need any `` references since the code has already been + generated in the *RouteGuide* project. + + # Reference ## Protobuf item metadata reference @@ -252,6 +309,7 @@ Quick links to the examples below: * [Visual Studio: setting per-file `.proto` file options](#visualstudio) * [Bypassing Grpc.Tools to run the protocol buffers compiler explicitly](#compiler) * [Using Grpc.Tools with unsupported architectures](#unsupported-arch) +* [Including `.proto` files in NuGet packages](#proto-only-nuget) --- ## ProtoRoot - Common root for one or more `.proto` files @@ -565,6 +623,132 @@ dotnet build --- +## Including `.proto` files in NuGet packages + +There might be occassions when you are given a NuGet package that contains +`.proto` files that you wish to use in your own project, or you may wish to +package your own `.proto` files in a NuGet package for others to use. + +There is no automatic way for `Grpc.Tools` to locate and include `.proto` +files from other NuGet packages. Below is a suggested convention to use +when creating NuGet packages that contain `.proto` files. + +__Note:__ This is not the same as a NuGet package providing a library built from +the code generated from the `.proto` files. Below just describes how to provide +the uncompiled `.proto` files in a NuGet package and have `Grpc.Tools` automatically +use them. + +### Creating the NuGet package + +The NuGet package should: +- provide the `.proto` files in a `content\protos` subdirectory in the package +- provide a `packagename.targets` file in the `build` subdirectory in the package that: + - defines an MSBuild property giving the path to the `.proto` files in the + installed package + - conditionally updates the `Protobuf_StandardImportsPath` property with the + above path so that the files can be found by the protocol buffers compiler + - it should be made optional forcing users to *opt in* to including + the `.proto` files + +For example, for the package `My.Example.Protos`: + +My.Example.Protos.nuspec: +```xml + + + + My.Example.Protos + 1.0.0 + Example package containing proto files + author + owner + license url + project url + See project site for more info. + Example package containing proto files. + Example package containing proto files + Copyright 2023, My Company. + + + + + + + + + +``` + +My.Example.Protos.targets: +```xml + + + + + + + $( [System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)../content/protos) ) + + + + + + + + $(Protobuf_StandardImportsPath);$(MyPackage_ProtosPath) + + + + + + + +``` + +### Using the NuGet package + +The project needs to add the package containing the `.proto` files: +```xml + +``` + +If the project only wants to compile the `.proto` files included in the package +then all it needs to do is add the `` items using the property defined +in the package for the path to the files. For example, if the NuGet package contained +the file `greet.proto`, then the project should add: + +```xml + +``` + +However if the provided `.proto` files are to be *imported* by the projects own `.proto` +files then the `Protobuf_StandardImportsPath` needs updated to add the directory +containing the package's files. This is done by setting to `true` the property +used in the package. For example, if the project has the local `.proto` file +`my_services.proto` and it imported a file from the package `common_message.proto`, +then: + +```xml + + + true + + + + + + +``` + +--- + ## See also gRPC project documentation: