3
votes

I have several contract projects that contains different protobuf files, but some of the message types have the same message type like

message user
{
  Address address = 1
}

message Address 
{
  ....
}

I have now created a shared project and added an Address.proto file to it only containing

syntax = "proto3"
option csharp_namespace = "shared.protos"
package AddressPackage
message Address {....}

My problem is to figure out how to import it into the protos in my different contract projects. I have added the shared project as a reference, but everything else that I have tried from there has resultet in errors.

I know that I need to use import just haven't figured out how to write the string.

Update

I'm using gRPC.tools nuget and all .proto files is set to protobuf compiler both

The files structure is as following

User.Contracts project

  • Protos -- User.proto Shared project
  • Protos -- Address.proto

both projects is in it's own folder and those folders are placed next to each other.

in the shared project it says

<ItemGroup>
  <None Remove="Protos\Address.proto" />
</ItemGroup>

<ItemGroup>
  <Protobuf Include="Protos\Address.proto">
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
  </Protobuf>
</ItemGroup>

and in the user.contract is says

<ItemGroup>
  <None Remove="Protos\User.proto" />
</ItemGroup>

<ItemGroup>
  <Protobuf Include="Protos\User.proto" />
</ItemGroup>

Thanks in advance.

3
Are you using gRPC.tools for this? If so: what does the relevant csproj pieces look like for the .proto files? Or are you using protoc directly? Or ..? And: what is the folder structure of the various files, relative to the project root? - Marc Gravell♦
@MarcGravell please see the update - Joshlo
It sounds like you're looking for the ProtoRoot="whatever" optional argument on <Protobuf>, which is similar to the include arg on protoc - try <Protobuf ProtoRoot="Protos" ... > ? - Marc Gravell♦

3 Answers

8
votes

You can do so by adding the ProtoRoot attribute to the <Protobuf /> section in your .csproj file.

Let's say you have a .proto file in project A:

syntax = "proto3";
option csharp_namespace = "Project.A";
import "ProjectB/<path>/Engine.proto"

message Car {
    Engine engine = 1;
    ...
}

In project B you have:

syntax = "proto3";
option csharp_namespace = "Project.B";

message Engine {
    ...
}

As you can see, in car.proto we used an import statement to a .proto file from another project. In order to successfully import this file, we need to add ProtoRoot to the <Protobuf /> section in the .csproj file of the project A:

<ItemGroup>
  <Protobuf Include="ProjectA/<path>/car.proto" Link="<path>/car.proto" ProtoRoot=".." />
</ItemGroup>

<path> is equivalent to your folder structure within your .NET project. ProtoRoot needs to be set to the directory where import declarations in the .proto files are looking for files. In this case, it's the parent folder which contains two subfolders with project A and project B.

More interesting stuff can be found here: https://chromium.googlesource.com/external/github.com/grpc/grpc/+/HEAD/src/csharp/BUILD-INTEGRATION.md

1
votes

Another option. It's easier not to use a shared project. The .proto file needs to be placed only in the service project and specified

<ItemGroup>
    <Protobuf Include="Protos\address.proto" GrpcServices="Server" />
</ItemGroup>

and in the project the client only needs to specify the link like this

<ItemGroup>
    <Protobuf Include="..\NameServerProject\Protos\address.proto" GrpcServices="Client">
        <Link>Protos\address.proto</Link>
    </Protobuf>
</ItemGroup>

ProtoRoot can be missed.

0
votes

In your projects, specify Protobuf with Include and ProtoRoot which should contain the path to a shared project with proto-files like

  <ItemGroup>
    <Protobuf Include="..\NameSharedProject\Protos\address.proto" ProtoRoot="..\NameSharedProject" GrpcServices="Server" />
  </ItemGroup>

Then, after building in each project, you will have class files created in the folder "\obj\Debug\net5.0\Protos".