Working With gRPC In .NET Core

Overview

 
This article will do a brief introduction to the gRPC framework, then will see how gRPC services can be created with ASP.NET Core and how we can invoke these services from .NET Core applications.
 

Introduction

 
gRPC is a framework designed and introduced by Google and made an open-source project since 2015. This Framework enables Remote Procedure Calls (RPC) between services using HTTP/2 protocol with binary messages which are serialized/deserialized using Protocol Buffers a new binary protocol designed by Google for generating more compact messages such that it will use less CPU and more performance-oriented while transferring between two endpoints.
 
Working With gRPC In .NET Core 
 
This Framework included in .NET Core since version 3.0 and provided with special gRPC services template in Visual Studio 2019 IDE.
 
gRPC uses proto files to define services and their message contracts information. These contracts will be serialized/de-serialized to binary messages by protocol buffer and pass through the HTTP/2 protocol.
 
Once the developer has written proto files with respective services and message contracts, the tooling library from the gRPC Framework will create strongly typed classes for services and POCO classes for message contracts in proto files. This way we can able to call the methods and variables defined in the proto file in other C# classes as we do in normal with other strongly typed C# classes.
 
Currently, gRPC services are most widely used in Microservice Architecture to communicate between loosely coupled services. Still, we are facing some issues while communicating from browser to services as most of the browsers are still working to include it in the near future.
 
Now we are good enough with understanding this new Framework and now we need to learn more on the practical side from the developer's eye by understanding creating and consuming the services in .NET Core.
 

Creating the gRPC Server

 
As gRPC Framework ships with ASP.NET Core 3.0 along with the gRPC service project template. It is a straightforward task to create it as follows.
 
Working With gRPC In .NET Core 
 
Click Next Button and provide the service name as follows
 
Once the service is created we can see two folders
  1. Protos - this folder will contain all .proto files. As discussed in the introduction section, these files should contain all the services and message contracts in C# terminology, Interfaces, and POCO classes.
  2. Services - this folder will contain concrete strongly typed service classes which inherited from the services/interfaces declared in the proto file(s).
Working With gRPC In .NET Core 
 
When we observe the packages list, we have 3 new packages which are related to gRPC, as follows:
 
Working With gRPC In .NET Core 
  • Google.Probuf contain necessary classes that define the data types which are supported while writing all message contracts in proto buffer files (i.e., *.proto files) and syntaxes.
  • Grpc.Tools contain necessary classes for converting all services and message contracts to C# strongly typed interfaces and POCO classes.
  • Grpc.AspNetCore.Server.ClientFactory contains necessary classes to manage the connections from its client(s).
Following is the default proto file (greet.proto) that will be provided when we create a new gRPCService project.
  1. syntax = "proto3";  
  2. option csharp_namespace = "GrpcCustomerService";  
  3.   
  4. package greet;  
  5.   
  6. // The greeting service definition.  
  7. service Greeter {  
  8.   // Sends a greeting  
  9.   rpc SayHello (HelloRequest) returns (HelloReply);  
  10. }  
  11.   
  12. // The request message containing the user's name.  
  13. message HelloRequest {  
  14.   string name = 1;  
  15. }  
  16.   
  17. // The response message containing the greetings.  
  18. message HelloReply {  
  19.   string message = 1;  
  20. }  
Let's understand it line by line. The first line will contain which syntax version does this file will follow. This is just like a C# version we use to provide.
 
Later we providing a namespace to be available on the file which will be generated by the gRPC tool when we build the application.
 
The third line is the package name, in our case filename.
 
The provided service definition for Greeter is similar in C# as follows.
  1. Class Greeter   
  2. {  
  3.     public abstract HelloReply SayHello(HelloRequest helloRequest);  
  4. }  
I think it is self-explanatory now, here HelloReply and HelloRequest are the message contracts and in C# terminologies those are POCO classes.
 
As we know now all messages in proto files are POCO classes, and when we observe we are giving a numeric number for each field in a message and the reason behind is that it represents the order of the data when serializing and deserializing by protocol buffer.
 
Following is the default generated GreeterService class in services folder
  1. public class GreeterService : Greeter.GreeterBase  
  2. {  
  3.     private readonly ILogger<GreeterService> _logger;  
  4.     public GreeterService(ILogger<GreeterService> logger)  
  5.     {  
  6.         _logger = logger;  
  7.     }  
  8.   
  9.     public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)  
  10.     {  
  11.         return Task.FromResult(new HelloReply  
  12.         {  
  13.             Message = "Hello " + request.Name  
  14.         });  
  15.     }  
  16. }  
When observed, this class inherited from Greeter.GreeterBase. Here, Greeter is the service name from proto file and GreeterBase is the class generated by the gRPC.Tool classes while converting to C# stubs. By pressing F12 we can see these generated classes.
 
Once we create any new services make sure to declare all the services which we are creating in Startup.cs file as follows in Configure() method.
  1. app.UseEndpoints(endpoints =>  
  2.   {  
  3.       endpoints.MapGrpcService<GreeterService>();  
  4.     });  
Also, make sure all new proto files are declared on .csproj file with GrpcServices="Server".
  1. <ItemGroup>  
  2.    <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />  
  3.  </ItemGroup>  
Once we did all our service code, we are ready to run it. Once we run we can see it starts listening on the defined port number.
 
Working With gRPC In .NET Core 
 

Creating a gRPC Client

 
In the above, we created the Server where it starts listening to the client requests. Now we know how can we create a client application where we send a request and receive the responses from the gRPC server application.
 
We will create a sample console-based application and send a request to an existing gRPC server. Once we create a console-based application, we need to add the following NuGet packages,
  • Google.Protobuf As we already discussed above, it contains all necessary classes to define the datatypes and syntax definitions for writing proto buffer files.
  • Grpc.Tools contains necessary classes that will convert all proto files to strongly typed classes.
  • Grpc.Net.Client contains necessary classes that are responsible for creating a connection channel and sending the messages to the given endpoint.
Once we added these 3 NuGet packages we need to copy all the proto files which we needed from the server and paste it hereunder proto folder. This will help us to use strongly typed classes while calling the methods on the server.
 
Now, make sure your proto files having GrpcServices="Client" property set so that the tooling class will generate client stubs for given proto files.
  1. <ItemGroup>  
  2.    <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />  
  3.  </ItemGroup>  
Now, the following is the code base for creating the channel to the server and calling the methods and reading the responses on it.
  1. var channel = GrpcChannel.ForAddress("https://localhost:5001");  
  2. GreeterClient greeterClient = new GreeterClient(channel);  
  3. HelloReply helloReply = greeterClient.SayHello(new HelloRequest(){Name = "Sai"});  
  4. Console.WriteLine("Given Name is " + helloReply.Message);  
  5. //output: Given Name is Hello Sai  
As in the above code, we are creating the channel and then passing this channel as a constructor parameter for GreeterClient class which is generated by gRPC tooling from proto file and we are calling the method and handling the response.
 

Conclusion

 
gRPC Framework is well designed to communicate between services especially on Microservices architecture to avoid heavy REST API requests and provide compact and low CPU usage. It also helps us to read huge data from service as a stream of messages.