Home > Blockchain >  Can't find proto files stored in shared dotnet project
Can't find proto files stored in shared dotnet project

Time:05-05

I've got a core project with a bunch of proto files in it. The core project does not have any GRPC code gen packages installed.

I'm trying to reference these proto files in a service that will compile and consume them.

So I used dotnet-grpc to add these files to this project which resulted in the following itemgroup being added to the csproj

 <ItemGroup>
    <Protobuf Include="..\BonnieAndClydesdale.Core\Protos\Enums\HorseGender.proto" Link="Protos\Enums\HorseGender.proto"/>
    <Protobuf Include="..\BonnieAndClydesdale.Core\Protos\Models\AdDetails.proto" Link="Protos\Models\AdDetails.proto"/>
    <Protobuf Include="..\BonnieAndClydesdale.Core\Protos\Models\HorseDetails.proto" Link="Protos\Models\HorseDetails.proto"/>
    <Protobuf Include="..\BonnieAndClydesdale.Core\Protos\Services\AdService.proto" Link="Protos\Services\AdService.proto"/>
  </ItemGroup>

However, now I'm getting errors that my proto files can't find their various imports.

For example:

syntax = "proto3";
import "HorseDetails.proto";


option csharp_namespace = "BonnieAndClydesdale.Core.Models";
package Ads;

message AdDetails {
  string title = 1;
  double asking_price = 2; //TODO - Custom Decimal
  string short_description = 3;
  string image_url = 4;
  string location = 5;
  HorseDetails horse_details = 6;
}

Can't locate HorseDetails.proto.

I'm kind of confused as to what's going on here since I've not changed any of the file layouts and this works fine if the files are just placed directly in my service project.

Any ideas?


More Details:

Here are the proto files:

HorseGender.proto

syntax = "proto3";

option csharp_namespace = "BonnieAndClydesdale.Core.Enums";
package Ads;

enum HorseGender{
  Stallion = 0;
  Gelding = 1;
  Mare = 2;
}

AdDetails.proto

syntax = "proto3";
import "HorseDetails.proto";


option csharp_namespace = "BonnieAndClydesdale.Core.Models";
package Ads;

message AdDetails {
  string title = 1;
  double asking_price = 2; //TODO - Custom Decimal
  string short_description = 3;
  string image_url = 4;
  string location = 5;
  HorseDetails horse_details = 6;
}

HorseDetails.proto

syntax = "proto3";
import "HorseGender.proto";

option csharp_namespace = "BonnieAndClydesdale.Core.Models";
package Ads;

message HorseDetails
{
  string name = 1;
  int32 age_in_years = 2;
  HorseGender gender = 3;
  string breed = 4;
  float height = 5; // TODO - custom decimal
}

AdService.proto

syntax = "proto3";
import "AdDetails.proto";

option csharp_namespace = "BonnieAndClydesdale.Core";

package Ads;

service AdService {
  rpc GetAds (AdRequest) returns (AdReply);
}

message AdRequest {
}

message AdReply {
  repeated AdDetails AdDetails = 1;
}

And the file-tree:

.
├── BonnieAndClydesdale.AdService
│  ├── BonnieAndClydesdale.AdService.csproj
│  ├── Dockerfile
│  ├── appsettings.Development.json
│  ├── appsettings.json
│  ├── Program.cs
│  ├── Properties
│  │  └── launchSettings.json
│  ├── Repositories
│  │  ├── AdsRepositoryStub.cs
│  │  └── IAdsRepository.cs
│  └── Services
│     └── AdService.cs
├── BonnieAndClydesdale.Core
│  ├── BonnieAndClydesdale.Core.csproj
│  ├── Clients
│  │  ├── AdServiceClientStub.cs
│  │  └── IAdServiceClient.cs
│  ├── Enums
│  │  └── HorseGender.cs
│  ├── Models
│  │  ├── AdDetails.cs
│  │  └── HorseDetails.cs
│  └── Protos
│     ├── Enums
│     │  └── HorseGender.proto
│     ├── Models
│     │  ├── AdDetails.proto
│     │  └── HorseDetails.proto
│     └── Services
│        └── AdService.proto
├── BonnieAndClydesdale.MainSite
│  ├── _Imports.razor
│  ├── App.razor
│  ├── BonnieAndClydesdale.MainSite.csproj
│  ├── Pages
│  │  ├── ForSale.cs
│  │  ├── ForSale.razor
│  │  └── Index.razor
│  ├── Program.cs
│  ├── Properties
│  │  └── launchSettings.json
│  ├── Shared
│  │  ├── Components
│  │  │  ├── AdCard.cs
│  │  │  └── AdCard.razor
│  │  └── Layouts
│  │     ├── MainLayout.cs
│  │     ├── MainLayout.razor
│  │     └── NavMenu.razor
│  └── wwwroot
│     ├── favicon.ico
│     ├── index.html
│     └── sample-data
│        └── weather.json
└── BonnieAndClydesdale.sln

CodePudding user response:

As your .proto files are in different directories, you will need to specify the import directories. You can do that with AdditionalImportDirs in the <Protobuf ... />.

So the ItemGroup became something like this:

<ItemGroup>
    <Protobuf
        Include="..\BonnieAndClydesdale.Core\Protos\Enums\HorseGender.proto"
        Link="Protos\Enums\HorseGender.proto" />
    <Protobuf
        AdditionalImportDirs="..\BonnieAndClydesdale.Core\Protos"
        Include="..\BonnieAndClydesdale.Core\Protos\Models\AdDetails.proto"
        Link="Protos\Models\AdDetails.proto" />
    <Protobuf
        AdditionalImportDirs="..\BonnieAndClydesdale.Core\Protos"
        Include="..\BonnieAndClydesdale.Core\Protos\Models\HorseDetails.proto"
        Link="Protos\Models\HorseDetails.proto" />
    <Protobuf
        AdditionalImportDirs="..\BonnieAndClydesdale.Core\Protos"
        Include="..\BonnieAndClydesdale.Core\Protos\Services\AdService.proto"
        Link="Protos\Models\HorseDetails.proto" />
</ItemGroup>

As you can I decided to specify the import dir to be the root of all the protos. So now, you will need to import like this:

AdDetails.proto

...
import "Models/HorseDetails.proto";
...

HorseDetails.proto

...
import "Enums/HorseGender.proto";
...

AdService.proto

...
import "Models/AdDetails.proto";
...

This is a design choice I made. You could totally be more specific with the AdditionalImportDirs and thus only specify the file name for example but adding the root directory is a little bit more clear in my opinion.

After that you could obviously make that less verbose by adding a path variable to ..\BonnieAndClydesdale.Core\Protos in your PropertyGroup. This will also save you from typo errors.

Let me know if it helped and let me know if you need anything.

  • Related