{"id":6323,"date":"2018-06-24T10:00:31","date_gmt":"2018-06-24T10:00:31","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=6323"},"modified":"2018-06-24T10:00:31","modified_gmt":"2018-06-24T10:00:31","slug":"a-little-more-grpc","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/a-little-more-grpc\/","title":{"rendered":"A little more gRPC"},"content":{"rendered":"<p>In my last two posts I looked at using .proto files to define the IDL which protoc.exe along with gRPC generated our preferred language&#8217;s data files and method calls &#8211; in our case this meant generating C# files.<\/p>\n<p>Now let&#8217;s look at how we can extend our code a little further, for example to include meat data\/headers for sending tokens or other state between the client and server.<\/p>\n<p><strong>What was generated for us?<\/strong><\/p>\n<p>When we generated our code using the gRPC plugin, we started with the IDL method written as <\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nservice MusicService {\r\n   rpc Query(NotesRequest) returns (NotesResponse) {\r\n   }\r\n<\/pre>\n<p>however several overloads for this method were generated (I&#8217;ve cleaned them up to remove superfluous namespaces etc. and to make them easier to read in a blog post<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic virtual NotesResponse Query(\r\n   NotesRequest request, \r\n   Metadata headers = null, \r\n   DateTime? deadline = null, \r\n   CancellationToken cancellationToken = \r\n      default(CancellationToken))\r\n{\r\n   return Query(request, \r\n      new CallOptions(\r\n         headers, \r\n         deadline, \r\n         cancellationToken));\r\n}\r\n\r\npublic virtual NotesResponse Query(\r\n   NotesRequest request, \r\n   CallOptions options)\r\n{\r\n   return CallInvoker.BlockingUnaryCall(\r\n       __Method_Query, \r\n       null, \r\n       options, \r\n       request);\r\n}\r\n\r\npublic virtual AsyncUnaryCall&lt;NotesResponse&gt; QueryAsync(\r\n   NotesRequest request, \r\n   Metadata headers = null, \r\n   DateTime? deadline = null, \r\n   CancellationToken cancellationToken = \r\n       default(CancellationToken))\r\n{\r\n   return QueryAsync(\r\n       request, \r\n       new CallOptions(\r\n           headers, \r\n           deadline, \r\n           cancellationToken));\r\n}\r\n\r\npublic virtual AsyncUnaryCall&lt;NotesResponse&gt; QueryAsync(\r\n   NotesRequest request, \r\n   CallOptions options)\r\n{\r\n   return CallInvoker.AsyncUnaryCall(\r\n      __Method_Query, \r\n      null, \r\n      options, \r\n      request);\r\n}\r\n<\/pre>\n<p>We&#8217;ve got several overloads, include async version and there&#8217;s support for passing metadata headers, a <a href=\"https:\/\/grpc.io\/blog\/deadlines\" rel=\"noopener\" target=\"_blank\">deadline<\/a> (similar to a timeout), as well as a cancellation token.<\/p>\n<p><strong>Metadata<\/strong><\/p>\n<p>We might use the Metadata argument to pass in SSO tokens or other relevant information that does not form part of the actual message, here&#8217;s an example of using the Query method in such a way<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/ client code\r\nvar response = client.Query(request, new Metadata\r\n{\r\n   new Metadata.Entry(&quot;SSO&quot;, token)\r\n});\r\n\r\n\/\/ server \r\nvar token = \r\n   context?.RequestHeaders?.FirstOrDefault(e =&gt; e.Key == &quot;sso&quot;);\r\n<\/pre>\n<p><em>Note: Beware, for some reason, the key has been turned to lower case.<\/em><\/p>\n<p>In the server method we implemented in the last post you&#8217;ll notice that along with the request there&#8217;s the ServerCallContext type which contains all the other parameters that might be sent via the client, i.e. headers, cancellation token etc.<\/p>\n<p>The server can return meta data using the ServerContext&#8217;s ResponseTrailers. However the client must use the Async versions of the client methods to receive these extra bits of data. <\/p>\n<p>Here&#8217;s an example of returning something via ResponseTrailers, from the server<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\ncontext.ResponseTrailers.Add(new Metadata.Entry(&quot;SSO&quot;, &quot;Success&quot;));\r\n<\/pre>\n<p>and the client would change to use the QueryAsync overload and possibly look like this<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar response = client.QueryAsync(request, new Metadata\r\n{\r\n   new Metadata.Entry(&quot;SSO&quot;, &quot;abcdefg&quot;)\r\n});\r\n\r\nforeach (var note in response.ResponseAsync.Result.Notes)\r\n{\r\n   Console.WriteLine(note);\r\n}\r\n\r\nvar rt = response\r\n   .GetTrailers()\r\n   .FirstOrDefault(e =&gt; e.Key == &quot;sso&quot;)\r\n   .Value;\r\n<\/pre>\n<p><strong>CallOptions<\/strong><\/p>\n<p>Ultimately the methods that take Metadata and other arguments end up wrapping those arguments in a CallOptions struct. However CallOptions also supports CallCredentials as well as a couple of other types (WriteOptions and ContextPropagationToken which I will not be looking at in this post).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In my last two posts I looked at using .proto files to define the IDL which protoc.exe along with gRPC generated our preferred language&#8217;s data files and method calls &#8211; in our case this meant generating C# files. Now let&#8217;s look at how we can extend our code a little further, for example to include [&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],"tags":[],"class_list":["post-6323","post","type-post","status-publish","format-standard","hentry","category-grpc"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/6323","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=6323"}],"version-history":[{"count":2,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/6323\/revisions"}],"predecessor-version":[{"id":6325,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/6323\/revisions\/6325"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=6323"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=6323"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=6323"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}