Search code examples
.net-coremsbuildprotocol-buffersgrpcgrpc-dotnet

How to include custom directory when building gRPC dotnet core project with MSBuild


I have a dotnet core gRPC project and I'm trying to include route annotations in my proto files like below:

import "google/api/annotations.proto";

file structure is like this (for the reason being that I imported googleapis repository as a git submodule):

protos/
    myproto.proto

    googleapis/
        google/
           api/
               annotations.proto
               ...

in a go project it can be done by:

protoc -I . -I ./googleapis --go_out=plugins=grpc:. *.proto

where -I ./googleapis gives compiler the dir where it can find annotations.proto file and its dependencies.

But when I'm using MSBuild in a dotnet grpc project using config like below, I could not figure out how to include custom directories.

<ItemGroup>
    <Protobuf Include="protos/*.proto" GrpcServices="Server" />
</ItemGroup>

Official doc mentioned an alternative to customize target build so that I can use protoc:

protoc --plugin=protoc-gen-grpc=$(gRPC_PluginFullPath)  -I $(Protobuf_StandardImportsPath) ...

but above command ignores service definition and does not generate server stub code as mentioned here, while MSBuild does.

A workaround I found but not ideal:

I realize Grpc.Tools dotnet package distributes some commonly used proto files, so I copied annotations.proto and its dependencies there (in macOS) and it worked:

`~\.nuget\packages\grpc.tools\2.25.0\build\native\include`

Updates:

Another workaround:

The project root directory is included by default, so use it as the base path and copy the imported proto files there also works (better but still not ideal).

Any ideas how to include custom directories like above through MSBuild?


Solution

  • Finally figured out. As Jan Tattermusch suggested, ProtoRoot specifies the directories from which msbuild Include property as well as the proto import keyword will be looking for files, whereas the way ProtoRoot works for Include is different from how it works for import. Thus in order to customize the proto file structures to be like this, ProtoRoot must include all different paths which should be:

    <Protobuf Include="protos/*.proto" ProtoRoot="./protos; ./protos/googleapis" ... />
    

    Updates:

    Above works fine for grpc-dotnet version prior to v2.31.0. For newer versions, warnings will show up saying ProtoRoot path is not a prefix of Include path. To fix it, use below config instead:

    <Protobuf Include="protos/*.proto" ProtoRoot="protos" AdditionalImportDirs="protos/googleapis" ... />