在開發 gRPC 服務時,隨著專案規模擴大,將共用的訊息(Message)與列舉(Enum)集中管理,能大幅提升程式碼的可維護性與一致性。下面介紹如何透過目錄結構與 .proto
匯入機制,達成模組化設計,並提供簡化編譯設定的實用技巧。
├── Protos/
│ ├── common/ # 共用層級
│ │ └── common_types.proto
│ └── services/ # 服務層級
│ └── user_service.proto
另外有一個,假如要針對每個 .proto
設定編譯的屬性太麻煩的話,可以在專案的屬性檔裡面增加
<ItemGroup>
<!-- 設定所有根目錄 .proto 都要被處理 -->
<Protobuf Include="Protos\*.proto" GrpcServices="Both" />
<!-- 設定所有子目錄 .proto 都要被處理 -->
<Protobuf Include="Protos\**\*.proto" GrpcServices="Both" />
</ItemGroup>
common_types.proto
syntax = "proto3";
option csharp_namespace = "MyGrpcServer";
package common;
// 共用訊息:User
message User {
string user_id = 1;
string name = 2;
int32 age = 3;
}
// 共用列舉
enum Status {
STATUS_UNKNOWN = 0;
STATUS_ACTIVE = 1;
STATUS_INACTIVE = 2;
}
user_service.proto
// proto 版本,現行都使用第三版
syntax = "proto3";
option csharp_namespace = "MyGrpcServer";
package user;
// 引用其他資料夾內的 .proto 檔
import "Protos/Common/common_types.proto";
// 定義服務
service UserService {
// 定義服務裡面的方法,Request/Response 物件
rpc Login(LoginRequest) returns (LoginResponse);
rpc GetUser (GetUserRequest) returns (GetUserResponse);
}
// Message 格式,屬性使用駝峰式。在 c# 那邊會自動轉成大駝峰開始
message LoginRequest {
string account = 1;
string password = 2;
}
message LoginResponse {
bool isSuccess = 1;
string message = 2;
string token = 3;
}
message GetUserRequest {
string user_id = 1;
}
message GetUserResponse {
common.User user = 1; // ✅ 使用 import 進來的 common.User
common.Status status = 2; // ✅ 使用 import 進來的 common.Status
}
public class UserService : MyGrpcServer.UserService.UserServiceBase
{
public override Task<GetUserResponse> GetUser(GetUserRequest request, ServerCallContext context)
{
return Task.FromResult(new GetUserResponse()
{
User = new User { Age = 30, Name = "John Doe", UserId = request.UserId },
Status = Status.Active
});
}
}v
透過以上方式,可以結構化的整理 .proto
檔