Skip to main content

Ex 1

The Problem Domain

The example we're going to use a simple "addres book". Each person in the address book has a name, an ID, an email address, and a contact phone number.

When using protocol buffers, you first create a .proto file to define the structure of the data you want to store. The protocol buffer compiler then generates a class that automatically encodes and parses the protocol buffer data using a highly efficient binary format. This generated class includes getter and setter methods for the protocol buffer's fields and handles the complexities of reading and writing the protocol buffer as a single unit.

One of the significant advantages of protocol buffers is their ability to extend their format over time while maintaining compatibility with old formats. This means that code can still read data encoded with previous protocol buffer formats, even as newer formats are introduced

Defining the message structure

The definitions in a .proto file are simple: you add a message for each data structure you want to serialize, then specify a name and a type for each field in the message. In our example, the .proto file that defines the messages will be: addressbook.proto.

  1. under BasicSyntaxConsumer project, resource folder, add a new file named : addressbook.proto

  2. add the syntax line:

    syntax = "proto3";

  3. define the package name : package tutorial;

  4. define the namespace for the generated class as being MyExample.AddressBook:

    option csharp_namespace = "MyExample.AddressBook";

    In C#, the generated classes will be placed in a namespace matching the package name if csharp_namespace is not specified. In our example, the csharp_namespace option has been specified to override the default, so the generated code uses a namespace of MyExample.AddressBook instead of Tutorial

  5. add the Person message below:

Person message
message Person {
string name = 1;
int32 id = 2; // Unique ID number for this person.
string email = 3;

enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}

message PhoneNumber {
string number = 1;
PhoneType type = 2;
}

repeated PhoneNumber phones = 4;

google.protobuf.Timestamp last_updated = 5;
}
  1. import the Well-know type corresponding to timestamp type
import "google/protobuf/timestamp.proto";

  1. Define the "address book"
AddressBook message
message AddressBook {
repeated Person people = 1;
}

Now that we defined the structure, let's go ahead and compile it.

Compile the protocol buffer

  1. Open a cli and navigate to the folder corrsponding to our BasicSyntaxConsumer/resource project folder cd ..\grpc-start\gRPC\BasicSyntax\BasicSyntaxConsumer
  2. run the comand: protoc -I=. --csharp_out=generatedcode addressbook.proto or, if you are using powershell cli .\protoc.exe -I . --csharp_out=generatedcode addressbook.proto

As a result, under generatedcode folder you should see an AddressBook.cs file containing some funny code

Generating Addressbook.cs gives us five useful types:

  • A static Addressbook class that contains metadata about the protocol buffer messages.
  • An AddressBook class with a read-only People property.
  • A Person class with properties for Name, Id, Email and Phones.
  • A PhoneNumber class, nested in a static Person.Types class.
  • A PhoneType enum, also nested in Person.Types.

Use the generated file

Let's use the generated code in our Program.cs to get familiar with it.

Using the generated class

var addressbook = new AddressBook();

addressbook.People.Add(new Person()
{
Name = "John Doe",
Id = 1,
Email = "",
LastUpdated = Timestamp.FromDateTime(DateTime.UtcNow),
Phones = {
new Person.Types.PhoneNumber() {
Number = "123456789",
Type = Person.Types.PhoneType.Mobile
}
}

});


addressbook.People.Add(new Person() { Name = "John Doe", Id = 2, Email = "" });
Console.WriteLine(addressbook);

We can use the using static MyExample.AddressBook.Person.Types; to get rid of the long name qualification Person.Types.PhoneNumber

DON't
syntax = "proto3";
package tutorial;

import "google/protobuf/timestamp.proto";
option csharp_namespace = "MyExample.AddressBook";

message Person {
string name = 1;
int32 id = 2; // Unique ID number for this person.
string email = 3;

enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}

message PhoneNumber {
string number = 1;
PhoneType type = 2;
}

repeated PhoneNumber phones = 4;

google.protobuf.Timestamp last_updated = 5;
}

// Our address book file is just one of these.
message AddressBook {
repeated Person people = 1;
}