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
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.
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
This is quite more complicated than I've foreseen due the amounts of "moving parts" plus the documentation is somehow outdated and at the moment of writing some attributes appears to behave differently from the post above.
Basically in the car example above, using Visual Studio 2022 you should end up with this
to obtain this, ProjA needs a quite of work, the interesting bits appers to be
<ItemGroup>
<ProjectReference Include="../ProjB/ProjB.csproj" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="..\ProjB\Protos\engine.proto" GrpcServices="None" ProtoCompile="False">
<Link>ProjB\Protos\engine.proto</Link>
</Protobuf>
<Protobuf Include="../ProjA/Protos/car.proto" Link="Protos/car.Proto" GrpcServices="None" ProtoRoot=".." />
</ItemGroup>
Please note that the important part is, as Yury Yatskov and Ivan Ivković said, to set the ProtoRoot=".."
but it is mandatory that the path specified in ProtoRoot is a prefix of the path in the Include attribute.
Note:
ProtoRoot
is relative to the .csproj fileImport
is relative to the .csproj file BUT need to have ProtoRoot
as prefix, so basically one level up and then again enter inside the ProjA againthis way the include
statement in car.proto
will be able to start from the path specified in ProtoRoot
for searching for the .proto files to include
** ProjA/Protos/car.proto
syntax = "proto3";
import "ProjB/Protos/Engine.proto";
option csharp_namespace = "ProjA";
package ProjA;
message Car{
ProjB.Engine engine = 1;
string licensePlate = 2;
}
** ProjB/Protos/engine.proto
syntax = "proto3";
option csharp_namespace = "ProjB";
package ProjB;
message Engine{
string name = 1;
}
Again note that of course you will need to reference Engine message using its package so ProjB.Engine
Finally, this allows to include the ProjB as a normal reference of the ProjA
but PAY ATTENTION to set Compile Protobuf
option to No (as you can see in the .csproj reported above) otherwise there will be class name conflicts as both projects will redefine the same "Engine" class.
grpc stub classes
attributes seems to not play a big role here, it is more interesting if the .proto contains a service definition, I think.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With