입력 (.proto 스키마)

출력 (C#)

이 도구가 하는 일

Protocol Buffers 스키마와, 그에 맞는 DTO가 필요한 C# 서비스나 클라이언트를 가지고 있는 상황입니다. 정석은 protoc에 C# 플러그인을 깔거나(또는 .csprojGrpc.Tools를 엮어서), MSBuild가 빌드 시점에 partial 클래스를 생성하게 하는 것입니다. 이건 잘 동작하지만, 그냥 스키마를 읽거나 타입을 한번 그려보거나 Razor 페이지나 일회성 통합에 메시지를 붙여 넣고 싶을 뿐인 경우엔 과합니다. 이 변환기는 같은 종류의 작업을 해줍니다 — 붙여 넣고, 복사하고, Types.cs에 떨구면 끝.

타입 매핑은 지루하지만 정확한 종류입니다. string은 그대로 string(nullable reference 프로젝트에서 트집 잡지 않도록 = "" 이니셜라이저 포함). bool, int32, int64, uint32, uint64, float, double은 각각 bool, int, long, uint, ulong, float, double로. bytesbyte[]가 됩니다. repeated TList<T>, map<K, V>Dictionary<K, V>가 되고, google.protobuf.Timestamp 같은 well-known 래퍼는 string으로 출력됩니다(proto3 JSON에서 타임스탬프 인코딩은 RFC 3339라서, 와이어 레벨에선 그냥 문자열입니다 — 자세한 내용은 proto3 JSON 스펙을 보세요).

필드 이름은 표준 PascalCase 처리를 받습니다 — order_idOrderId, shipping_addressShippingAddressC# protobuf 공식 레퍼런스가 생성하는 것과 똑같습니다. enum 값은, 스키마가 각 값을 enum 이름으로 SCREAMING_SNAKE 접두사를 붙이는 관례를 따를 때 그 접두사가 떨어집니다(그래서 enum OrderStatus 안의 ORDER_STATUS_PENDINGOrderStatus.Pending이 됩니다). 출력 클래스는 플랫합니다 — 모든 중첩 메시지가 최상위로 끌어올려져, 스코프를 풀어 헤치지 않고도 분리하거나 재배열할 수 있습니다. 변환은 전부 브라우저 안에서 일어나고, 스키마에 대한 어떤 정보도 업로드되지 않습니다.

사용 방법

세 단계입니다. 출력은 바로 컴파일 가능합니다 — 프로젝트의 <code>Types.cs</code> 파일에 붙여 넣으세요.

1

.proto 스키마를 붙여 넣기

왼쪽 에디터에 스키마를 떨어뜨리세요. 맨 위의 syntax = "proto3";는 선택입니다. 파서는 중첩된 message 블록, enum 선언, oneof, map<K, V>, 필드 옵션, 그리고 흔한 package/import/option 지시문을 처리합니다. import는 인식은 하지만 건너뛰니, 스키마가 의존하는 타입이 있다면 그 타입들도 인라인으로 같이 붙여 넣으세요.

필드 이름 변환은 자동입니다: .protocustomer_name은 C#에서 CustomerName이 됩니다. 클래스 이름과 enum 이름은 그대로 둡니다(관례상 이미 PascalCase).

2

출력 읽기

오른쪽: 각 메시지마다 { get; set; } auto-property를 가진 public class 선언, 그리고 각 enum마다 public enum 선언이 나옵니다. 스키마가 repeatedmap 필드를 쓰면 using System.Collections.Generic; 한 줄이 추가됩니다(그래야 List와 Dictionary가 해결됩니다). 파일을 프로젝트에 떨구고, 본인의 namespace로 감싸면 끝.

3

연결하기

순수 DTO 용도라면, 클래스는 System.Text.Json이나 Newtonsoft.Json으로 바로 직렬화할 수 있는 상태입니다. 진짜 gRPC C# 작업 — 서비스 구현, 스트리밍, 데드라인 — 에는 wire-format 타입을 위해 Grpc.Tools를 계속 쓰고, 이 변환기는 손으로 쓴 래퍼, 매핑 레이어, 테스트 픽스처 용도로 생성된 코드와 함께 활용하세요.

실제로 시간이 절약되는 순간

새 gRPC 서비스를 위한 DTO 스케치

ASP.NET Core gRPC 서비스를 시작하려는데, Grpc.Tools를 도입하기 전에 메시지가 C#에서 어떤 모양이 될지 보고 싶습니다. .proto를 붙여 넣고, 클래스를 훑어보고, 필드 네이밍이 팀 스타일과 맞는지 판단한 다음, 코드 생성을 제대로 엮으세요.

손으로 쓴 매핑 레이어

생성된 gRPC 타입은 자기들 namespace에 살고 있고, 도메인 레이어용으로는 깔끔한 DTO가 따로 필요합니다. 여기 출력은 생성된 코드 특유의 메타데이터 잡음 없이 깨끗한 클래스를 줘서, AutoMapper나 직접 만든 컨버터로 양방향 매핑하기에 편합니다.

Protobuf 스키마 변경 리뷰

팀원이 PR에서 메시지에 필드를 추가했습니다. 브랜치를 체크아웃해서 빌드하지 않고도 C# 쪽 모양에 미치는 영향을 보고 싶습니다. 새 스키마를 붙여 넣고 현재 C# 타입과 diff를 떠서, 핵심을 짚는 리뷰 코멘트를 남기세요.

테스트 픽스처와 빠른 스크립트

일회성 LinqPad 스크립트나 gRPC-gateway로 POST하는 콘솔 앱을 짜고 있습니다. 테스트 코드 50줄을 위해 Protobuf 풀 툴체인을 엮는 건 과합니다. 여기서 클래스를 가져와 JSON으로 직렬화하고, 요청을 보낸 다음, 다음 일로 넘어가세요.

자주 묻는 질문

제 스키마가 어디론가 전송되나요?

아니요. 파서와 C# 에미터는 전부 브라우저 안에서 JavaScript로 동작합니다. 붙여 넣을 때 DevTools의 Network 탭을 보세요 — 요청이 0건입니다. 스키마에 사내 타입 이름, 패키지 경로, 또는 서드파티 서비스로 보내고 싶지 않은 무언가가 들어 있을 때 유용합니다.

이 클래스들이 Grpc.Tools 생성 코드와 함께 동작하나요?

동등한 모양을 만들지만, 바이트 단위로 똑같지는 않습니다. Grpc.Tools는 partial 클래스, parser 등록, descriptor 배선, Google.Protobuf.IMessage로부터의 조상 타입을 생성합니다 — 그건 여기 없습니다. 진짜 gRPC 와이어 프로토콜 작업에는 Grpc.Tools를 쓰세요. DTO 전용 코드(예: JSON-over-HTTP 게이트웨이, 매핑 레이어, 테스트 데이터)에는 이 출력으로 충분합니다.

왜 int64와 uint64를 string이 아니라 long과 ulong으로 타입 지정하나요?

C#에선 그냥 들어가니까요. JavaScript의 Number와 달리(2^53 위에선 정밀도를 잃습니다), C#의 long은 int64 전 범위를 네이티브로 다룹니다. 그러니 string으로 떨어질 이유가 없죠. 64비트 정수가 문자열로 도착하는 proto3 JSON을 역직렬화하고 있다면(JSON 매핑 스펙에 따라), JsonNumberHandling.AllowReadingFromString을 함께 쓴 System.Text.Json이 변환을 처리해줍니다.

SCREAMING_SNAKE enum 값 관례는 어떻게 처리하나요?

Protobuf 스타일 가이드는 모든 enum 값에 enum 이름을 SCREAMING_SNAKE 접두사로 붙이라고 권장합니다. 변환기는 이를 감지해서 떼어 냅니다. enum OrderStatusORDER_STATUS_UNSPECIFIEDOrderStatus.Unspecified가 됩니다. enum이 그 관례를 따르지 않으면(일부 값엔 접두사가 있고 일부엔 없는 등), 접두사 제거를 건너뛰고 값들은 그대로 PascalCase 처리됩니다.

oneof를 처리하나요?

oneof의 각 필드는 평범한 auto-property로 출력됩니다. 출력은 oneof가 암시하는 "정확히 하나" 제약을 강제하진 않습니다 — C# 언어엔 아직 네이티브 discriminated union이 없으니까요. 더 엄격한 모델링이 필요하면 NuGet의 OneOf 같은 라이브러리를 보거나, 출력을 손으로 편집해서 베이스 클래스 + 서브클래스 구조로 바꾸세요.

google.protobuf.Timestamp와 well-known 타입들은 어떻게 되나요?

Timestamp는 string으로 출력됩니다(proto3 JSON은 타임스탬프를 RFC 3339 문자열로 인코딩합니다). EmptyAnyobject 플레이스홀더가 됩니다 — 프로젝트가 WKT 패키지를 끌어 쓰는 경우엔 Google.Protobuf.WellKnownTypes.Any나 더 강한 타입으로 손봐 주세요. 출력은 의도적으로 프레임워크에 의존하지 않으니, NuGet 의존성을 강요하지 않고도 어떤 C# 프로젝트에든 떨굴 수 있습니다.

관련 도구

Protobuf, JSON, C# 사이를 오가고 있다면 다음 도구들이 잘 어울립니다: