{"id":6303,"date":"2018-06-23T19:23:17","date_gmt":"2018-06-23T19:23:17","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=6303"},"modified":"2018-06-23T19:55:12","modified_gmt":"2018-06-23T19:55:12","slug":"using-protocol-buffers","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/using-protocol-buffers\/","title":{"rendered":"Using Protocol Buffers"},"content":{"rendered":"<p>I&#8217;ve written once before about using protocol buffers, using the <a href=\"http:\/\/putridparrot.com\/blog\/using-protobuf-net-in-c\/\" rel=\"noopener\" target=\"_blank\">protobuf-net<\/a> library, but I didn&#8217;t go into any depth regarding the .proto file which is used for the IDL. Let&#8217;s rectify this.<\/p>\n<p><strong>Introduction<\/strong><\/p>\n<p>Protocol buffers are simply a way to define a &#8220;language-neutral, &#8220;platform-neutral, extensible mechanism for serializing structed data&#8221;. What this really means is this is a specification (and tooling) for creating binary data. This data might exist as files or streamed over HTTP or any other type of stream. Think of Protocol Buffers as CSV, XML or the likes, but obviously being binary these resultant streams would generally be more compact than these other formats.<\/p>\n<p><strong>Proto file format<\/strong><\/p>\n<p><em>I&#8217;m not going to cover the .proto syntax in full as it&#8217;s already available at <a href=\"https:\/\/developers.google.com\/protocol-buffers\/docs\/proto3\" rel=\"noopener\" target=\"_blank\">Language Guide (proto3)<\/a>, but as I build up an example .proto file I will cover the pieces that I add to the file as I go.<\/em><\/p>\n<p>We&#8217;re going to want to create a .proto file which we be used to declare our messages\/data. Currently the latest syntax supported is &#8220;proto3&#8221; and we declare the version we support in our .proto file. If you do not specify the syntax, currently this syntax will default to proto2 syntax.<\/p>\n<p>So first off create a file with the .proto extension &#8211; I&#8217;m doing this within Visual Studio which supports Protocol Buffer syntax highlighting etc.<\/p>\n<p>To declare the supported syntax we start off by adding the following line (I&#8217;m going to use proto3 syntax in the post, there are several differences between proto3 and proto2)<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\nsyntax = &quot;proto3&quot;;\r\n<\/pre>\n<p><strong>Packages\/Namespaces<\/strong><\/p>\n<p>Whilst it&#8217;s optional, the next thing we&#8217;ll add is a <em>package<\/em> which, whilst optional, is useful for code generation in your preferred language. For example in Java this maps directly to the Java package name and in C# and C++ this maps to the namespace of the code.<\/p>\n<p>We can actually override the package\/namespace name for Java and C# by using <em>option java_package<\/em> and\/or <em>option csharp_namespace<\/em> instead or as well as the <em>package<\/em> line. Obviously we might wish to have all three in our .proto file so the file can be used to generate for Ruby, Go, C++ etc. as well as explicit definitions of Java and C#<\/p>\n<p>So let&#8217;s add a package<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\npackage music;\r\n\r\noption java_package = &quot;com.putridparrot.music&quot;;\r\noption csharp_namespace = &quot;PutridParrot.Music&quot;;\r\n<\/pre>\n<p><strong>Types<\/strong><\/p>\n<p><a href=\"https:\/\/developers.google.com\/protocol-buffers\/docs\/proto3#scalar\" rel=\"noopener\" target=\"_blank\">Scalar types<\/a> are supported, such as double, float, int32, int64 etc. along with the string type. <\/p>\n<p>Enum&#8217;s are all supported, so let&#8217;s add an enum to our file<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n\/*\r\n Note definitions, where two letters are used,\r\n the first denotes the # (sharp) and the second \r\n the b (flat)\r\n*\/\r\nenum Note {\r\n   C = 0;\r\n   CD = 1;\r\n   D = 2;\r\n   DE = 3;\r\n   E = 4;\r\n   F = 5;\r\n   FG = 6;\r\n   G = 7;\r\n   GA = 8;\r\n   A = 9;\r\n   AB = 10;\r\n   B = 11;\r\n}\r\n<\/pre>\n<p>We need to define the possible values for the enum and these <strong>must<\/strong> have a zero element. This obviously gives us a default value (hence zero should be your enum default value).<\/p>\n<p><em>We&#8217;ve also added a multi-line comment using \/* *\/ syntax, single line comments using \/\/ are also supported.<\/em><\/p>\n<p>A message type can be viewed as a composite type, such as structs, i.e. we can combine types, so let&#8217;s create a request and response type (the response will be used in my next post on gRPC)<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\nmessage NotesRequest {\r\n   Note key = 1;\r\n   string name = 2;\r\n}\r\n\r\nmessage NotesResponse {\r\n   Note key = 1;\r\n   string name = 2;\r\n   repeated Note notes = 3;\r\n}\r\n<\/pre>\n<p>Notice the use of <em>= 1<\/em> etc. these are field numbers and each field must have a unique field number.<\/p>\n<p>As per the Google documentation, fields in the range 1 through 15 take one byte to encode, fields 16 through to 2047 take two bytes. So yes, you could have up to 2047 fields in a message, if you really wanted.<\/p>\n<p>Notice in the <em>NotesResponse<\/em> message we define a repeated keyword which denotes this field can be repeated, think of this like an array (or list) field.<\/p>\n<p><strong>Code Generation<\/strong><\/p>\n<p>One of the key things XML gave developers was a specification which allow developers to write tools for generating code from the data specifications. Protocol Buffers is no different and ofcourse, this makes such specification more usable to the developer.<\/p>\n<p>The tool we use is <em>protoc.exe<\/em>. If you&#8217;re using Visual Studio\/nuget you can install Google.Protobuf.Tools via nuget. This will then be installed to ${SolutionDir)packages\\Google.Protobuf.Tools.3.6.0\\tools\\windows_x86 (or whichever OS you&#8217;re supporting).<\/p>\n<p>Now we can run this tool from nant, or other build tools, or as a pre-build event, i.e. selecting your project in Visual Studio, right mouse clicking, selecting Properties then Build Events. <\/p>\n<p>Here&#8217;s an example command (formatted to make it readable)<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n$(SolutionDir)packages\\Google.Protobuf.Tools.3.6.0\\tools\\windows_x86\\protoc.exe \r\n$(ProjectDir)Proto\\music.proto \r\n-I=$(ProjectDir)Proto \r\n--csharp_out=$(ProjectDir)\r\n<\/pre>\n<p>The first line is obviously the location of the installed <em>protoc.exe<\/em>. Next up we declare where the proto file(s) is\/are. We can use wildcard, i.e. *.proto, but if we have several different location for the files we will probably need to run the command multiple times.<\/p>\n<p>The <em>-I=<\/em> allows us to define import directories. This isn&#8217;t really needed in the example here as we&#8217;re not importing anything. Finally we declare that we want to generate C# code into the project folder. <\/p>\n<p><em>Note: If you want to generate the code into another folder you&#8217;ll need to ensure it already exists, protoc will not create it for you.<\/em><\/p>\n<p>Once run, this command will create a C# file which will include the types\/messages as well as serialization\/deserialization code.<\/p>\n<p>If you&#8217;re using Visual Studio to create an application which uses Protocol Buffers, then you&#8217;ll need to install the nuget package Google.Protobuf to install the library that the generated source references.<\/p>\n<p><strong>Serializing\/Deserializing<\/strong><\/p>\n<p>Let&#8217;s create a Visual Studio Console application, in the project folder add a Proto folder (which will contain our *.proto) files. Now, added the two nuget packages (previously mentioned, Google.Protobuf.Tools and Google.Protobuf). <\/p>\n<p>Next, create a file in the Proto folder named music.proto which should look like this<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\nsyntax = &quot;proto3&quot;;\r\n\r\npackage music;\r\n\r\noption java_package = &quot;com.putridparrot.music&quot;;\r\noption csharp_namespace = &quot;PutridParrot.Music&quot;;\r\n\r\n\/*\r\n Note definitions, where two letters are used,\r\n the first denotes the # (sharp) and the second \r\n the b (flat)\r\n*\/\r\nenum Note {\r\n   C = 0;\r\n   CD = 1;\r\n   D = 2;\r\n   DE = 3;\r\n   E = 4;\r\n   F = 5;\r\n   FG = 6;\r\n   G = 7;\r\n   GA = 8;\r\n   A = 9;\r\n   AB = 10;\r\n   B = 11;\r\n}\r\n\r\nmessage NotesRequest {\r\n   Note key = 1;\r\n   string name = 2;\r\n}\r\n\r\nmessage NotesResponse {\r\n\tNote key = 1;\r\n\tstring name = 2;\r\n\trepeated Note notes = 3;\r\n} \r\n<\/pre>\n<p>Next, add to the Pre-Build event for the solution the command line (listed previously) to generate the C# from the .proto file.<\/p>\n<p>Lastly, let&#8217;s just add the following using clauses to Program.cs<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nusing PutridParrot.Music;\r\nusing Google.Protobuf;\r\n<\/pre>\n<p>and here&#8217;s the code to place in Main<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar request = new NotesRequest\r\n{\r\n   Key = Note.C,\r\n   Name = &quot;Major&quot;\r\n};\r\n\r\nusing (var w = File.Create(@&quot;C:\\Data\\request.dat&quot;))\r\n{\r\n   request.WriteTo(w);\r\n}\r\n\r\nNotesRequest request2;\r\nusing (var r = File.OpenRead(@&quot;C:\\Data\\request.dat&quot;))\r\n{\r\n   request2 = NotesRequest.Parser.ParseFrom(r);\r\n}\r\n<\/pre>\n<p>This will create a file <em>request.dat<\/em> with the <em>request<\/em> instance data and then, if all goes well, load the contents of the file into the <em>request2<\/em> variable and that&#8217;s all there is to it.<\/p>\n<p>We can stream the object using the <em>WriteTo<\/em> and <em>ParseForm<\/em> methods but Protocol Buffers also supports <a href=\"https:\/\/grpc.io\/docs\/guides\/\" rel=\"noopener\" target=\"_blank\">gRPC<\/a> which we&#8217;ll look at in the next post.<\/p>\n<p>Code available here https:\/\/github.com\/putridparrot\/blog-projects\/tree\/master\/ProtocolBuffers\/CSharp<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve written once before about using protocol buffers, using the protobuf-net library, but I didn&#8217;t go into any depth regarding the .proto file which is used for the IDL. Let&#8217;s rectify this. Introduction Protocol buffers are simply a way to define a &#8220;language-neutral, &#8220;platform-neutral, extensible mechanism for serializing structed data&#8221;. What this really means is [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[221,220],"tags":[],"class_list":["post-6303","post","type-post","status-publish","format-standard","hentry","category-grpc","category-protocol-buffers"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/6303","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=6303"}],"version-history":[{"count":5,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/6303\/revisions"}],"predecessor-version":[{"id":6321,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/6303\/revisions\/6321"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=6303"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=6303"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=6303"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}