Beginning gRPC on ASP.NET Core

Communication Mechanisms

Your browser needs to be JavaScript capable to view this video

Try reloading this page, or reviewing your browser settings

This video segment demonstrates how to make different types of gRPC calls.

Keywords

  • gRPC
  • ASP.NET Core
  • communications mechanisms
  • Microsoft
  • remote procedure call

About this video

Author(s)
Fiodar Sazanavets
First online
06 August 2020
DOI
https://doi.org/10.1007/978-1-4842-6211-5_3
Online ISBN
978-1-4842-6211-5
Publisher
Apress
Copyright information
© Fiodar Sazanavets 2020

Video Transcript

So far, we have covered only one type of gRPC calls. It was just a standard request response model that is similar to HTTP. However, this is not the only communication mechanism that gRPC supports. We have now modified the definition of our greeter service in our original proto file. We have added the following RPCs to it, even though the message definitions remain the same. We use those messages in different way. Our original say hello() method is known as a unary call type. In this case, we are receiving a single response. And once we process the response, we return a single request. Our next RPC method Say Many Hellos() is a server streaming RPC.

To define it, we are using stream keyword next to the return object definition. In this case, we are receiving a single hello request. And we are returning a stream of hello reply objects. Our next RPC is what is known as a client stream in RPC. It’s called say hello to last() request. In our case, the stream keyword is placed next to the message defined in the request rather than the response. Finally, our last RPC, say hello to every() request, is a bi-directional streaming request. It has stream keyword next to both request and the response. Let’s open the definition of our service to have a look how these methods are implemented in C Sharp.

First, let’s reexamine our basic unary call. In our case, it’s Say Hello. Unary call is a task that has a return object. And, as it has been mentioned previously, it accepts two parameters. It’s a blocking call, which means that it will receive the response, do something with it, and return the reply. Let’s now have a look at the next RPC type, service streaming RPC.

In our case, service streaming RPC Say Many Hellos, this time, it doesn’t come with any return object. It is a task, but it is a task that does not have any return object specified. Of the parameter structure, it’s different now. Once again, we are accepting the request as a single object. However, this time, our response is a response stream. It’s an implementation of iServer stream writer interface that takes in hello reply object.

And our final parameter is, once again, service call context because server call context is always present in any RPC call regardless of its type. Response stream objects is something that the client has access to in real time. In our case, we are going through a loop of 10 numbers. And for every one of them, we are writing a new instance of hello reply to the stream with a message set to hello, the name that came from the request, followed by the number of the iteration. In this case, the client will not wait for our entire collection to depopulate it. Once we put a single item into the collection, our client will receive it straight away as fast as the network latency allows it to. And this is precisely why we don’t have an explicitly defined return object.

Our next RPC type is a client streaming RPC. In our case, a client streaming RPC is implemented by say hello to last request method. Because we don’t stream anything from the server, we, once again, have a return object of hello reply. However, this is what our parameters look like now. AsuncStreamReader is a is a stream that we accept followed by server called context. So, once again, both our client and the server have access to this stream. And our client will be able to write as many objects into the stream while this method is running. In our case, our server method reads every single object from the stream. And once there are no more objects in the stream, once the client closes the connection, it will return the data that it received from the very last object in the stream.

Finally, another RPC type that we have, is a bi-directional stream in RPC. In our service this is implemented by say hello to every request method. Once again, because the server returned the stream, we don’t have a return date type defined. In this case, we have both client stream and the server stream followed by the ServerCall context. In this particular case, we process all the data in real time. For every data item that we receive from the client stream, we are writing the reply into the stream that generates from the server.

And now we will have a look at how to call these different RPCs from our client. We have modified our client as follows. We have added some console information to let us know what type of call the client is making. The first one is just a unary call. So we are outputting it as a unary response. For our service side stream, we are wrapping the call into “using” context because streaming may take a long time to execute, we are executing our logic inside of this block of code until the streaming is completed. Our call object, which is our streaming object, has a field called response stream. And to extract data from it, the server has put into the stream, we are calling read all async method. For each of the objects that we found in the stream, we are outputting the response into the console.

Remember that our client stream server method will only reply to the last request. To construct the client stream, we are creating a list of names, the last of which is David. If you remember the definition of say hello to last request method, it will only send the response back once it received the last item of the stream. So in our case, we are expecting David to be written in the console. This is how client streaming works from our client side.

Once again, we are creating a call object by calling this method and wrapping it up in the “using” statement. Then for each of the names that we’ve added to our list, we are writing hello request objects into the stream. Once we are done with our stream, we complete it by calling complete async on request stream of the call object. Once we are done with our stream, we are completing it by calling complete async on request stream field of call object.

And now because it’s a purely client streaming method, it has a single field called response async, which we are reading to put the data into our console. Finally, we have a bi-directional call, which combines two object types together. We are creating the call context by initiating a client stream. We are writing data into our client stream. Then we are completing our client stream. After that, we are reading every single item from the service stream. Now let’s have a look at this logic in action. First, I will make sure that our gRPC service is a startup project. I press Control F5 to launch it. And then I will set our gRPC client to start up. And the launch that as well.

And as you can see, we have received a single unary response. We have received 10 different objects from a service streaming method. We have sent our client stream. And we have only received the response that corresponds to the last object of the client stream. And finally, we have reused the same collection in our client stream. And in our bi-directional call, we have received response to every single name from our client stream. And this concludes our segment on different RPC types in gRPC.