Generate C# Classes from .proto Files Using Protocol Buffers

Protocol Buffers (protobuf) is a language-neutral, platform-independent binary serialization format developed by Google. It offers superior performance over text-based formats like XML or JSON and is widely used in network communication, configuration storage, and cross-platform data exchange.

To generate C# classes from a .proto definition, you can use the protogen.exe tool provided by the protobuf-net library. Here’s a sample .proto file defining a request structure:

syntax = "proto2";

package hrv;

option java_package = "com.example.protobuf";
option java_outer_classname = "RequestProto";

message Request {
    extensions 100 to max;

    enum Type {
        LOGIN = 0;
        CHANGE_PASSWORD = 1;
        START_SCALE = 2;
        STOP_SCALE = 3;
        DATA_PPG = 4;
        DATA_EP = 5;
        DATA_HRV = 6;
        DATA_IBI = 7;
        MARK_SCALE = 8;
        RESOURCE_LIST = 9;
        UPDATE_USER_INFO = 10;
        GET_SCALE_LIST = 11;
        GET_SCALE = 12;
    }

    required Type type = 1;
    optional string timestamp = 2;
}

Run the following command in you're terminal to convert it into a C# class:

protogen.exe -i:Request.proto -o:Request.cs

You can also customize the output namespace and add using directives:

protogen.exe -i:Request.proto -o:Request.cs -ns:MyApp.Models -p:import=MyApp

This generates a strongly-typed C# class decorated with ProtoBuf attributes for serialization:

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
// </auto-generated>
//------------------------------------------------------------------------------

namespace hrv
{
    [global::System.Serializable, global::ProtoBuf.ProtoContract(Name = @"Request")]
    public partial class Request : global::ProtoBuf.IExtensible
    {
        private Type _requestType;
        [global::ProtoBuf.ProtoMember(1, IsRequired = true, Name = @"type", DataFormat = global::ProtoBuf.DataFormat.TwosComplement)]
        public Type requestType
        {
            get => _requestType;
            set => _requestType = value;
        }

        private string _timestamp = "";
        [global::ProtoBuf.ProtoMember(2, IsRequired = false, Name = @"timestamp", DataFormat = global::ProtoBuf.DataFormat.Default)]
        [global::System.ComponentModel.DefaultValue("")]
        public string timestamp
        {
            get => _timestamp;
            set => _timestamp = value;
        }

        [global::ProtoBuf.ProtoContract(Name = @"Type")]
        public enum Type
        {
            [global::ProtoBuf.ProtoEnum(Name = @"LOGIN", Value = 0)] LOGIN = 0,
            [global::ProtoBuf.ProtoEnum(Name = @"CHANGE_PASSWORD", Value = 1)] CHANGE_PASSWORD = 1,
            [global::ProtoBuf.ProtoEnum(Name = @"START_SCALE", Value = 2)] START_SCALE = 2,
            [global::ProtoBuf.ProtoEnum(Name = @"STOP_SCALE", Value = 3)] STOP_SCALE = 3,
            [global::ProtoBuf.ProtoEnum(Name = @"DATA_PPG", Value = 4)] DATA_PPG = 4,
            [global::ProtoBuf.ProtoEnum(Name = @"DATA_EP", Value = 5)] DATA_EP = 5,
            [global::ProtoBuf.ProtoEnum(Name = @"DATA_HRV", Value = 6)] DATA_HRV = 6,
            [global::ProtoBuf.ProtoEnum(Name = @"DATA_IBI", Value = 7)] DATA_IBI = 7,
            [global::ProtoBuf.ProtoEnum(Name = @"MARK_SCALE", Value = 8)] MARK_SCALE = 8,
            [global::ProtoBuf.ProtoEnum(Name = @"RESOURCE_LIST", Value = 9)] RESOURCE_LIST = 9,
            [global::ProtoBuf.ProtoEnum(Name = @"UPDATE_USER_INFO", Value = 10)] UPDATE_USER_INFO = 10,
            [global::ProtoBuf.ProtoEnum(Name = @"GET_SCALE_LIST", Value = 11)] GET_SCALE_LIST = 11,
            [global::ProtoBuf.ProtoEnum(Name = @"GET_SCALE", Value = 12)] GET_SCALE = 12
        }

        private global::ProtoBuf.IExtension extensionObject;
        global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
            => global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing);
    }
}

To automate generation for multiple files, use a Windows batch script:

@echo off
set PROTOGEN_PATH=ProtoGen\protogen.exe

%PROTOGEN_PATH% -i:Request.proto -o:OpenAPIModel\Request.cs
%PROTOGEN_PATH% -i:Response.proto -o:OpenAPIModel\Response.cs
%PROTOGEN_PATH% -i:UserInfo.proto -o:OpenAPIModel\UserInfo.cs
%PROTOGEN_PATH% -i:LoginReq.proto -o:OpenAPIModel\LoginReq.cs
%PROTOGEN_PATH% -i:LoginResp.proto -o:OpenAPIModel\LoginResp.cs

pause

Or recursively process all .proto files in a directory:

@echo off
set PROTOGEN_PATH=ProtoGen\protogen.exe

for %%f in (proto\*.proto) do (
    %PROTOGEN_PATH% -i:"%%f" -o:"cs\%%~nf.cs"
)

pause

Tags: Protobuf csharp serialization Batch-Script protocol-buffers

Posted on Sun, 17 May 2026 23:03:23 +0000 by rachelkoh