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.

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 know 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 straight forward task to create it as follows.

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).


When observed the packages list, we have 3 new packages which are related to gRPC and following are those

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.

syntax = "proto3";

option csharp_namespace = "GrpcCustomerService";

package greet;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply);
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings.
message HelloReply {
  string message = 1;
}

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.

Class Greeter 
{
    public abstract HelloReply SayHello(HelloRequest helloRequest);
}

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 it represents the order of the data when serializing and deserializing by protocol buffer.

Following is the default generated GreeterService class in services folder

public class GreeterService : Greeter.GreeterBase
    {
        private readonly ILogger<GreeterService> _logger;
        public GreeterService(ILogger<GreeterService> logger)
        {
            _logger = logger;
        }

        public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
        {
            return Task.FromResult(new HelloReply
            {
                Message = "Hello " + request.Name
            });
        }
    }

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 are creating un Startup.cs file as follows in Configure() method.

app.UseEndpoints(endpoints =>
            {
                endpoints.MapGrpcService<GreeterService>();
            });

Also, make sure all new proto files declared on .csproj file with GrpcServices=”Server”.

<ItemGroup>
   <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
 </ItemGroup>

Once we did all our service code, we are ready to run it. Once we run we can see it start listening on the defined port number.

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 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 contain 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.

<ItemGroup>
   <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
 </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.

var channel = GrpcChannel.ForAddress("https://localhost:5001");
GreeterClient greeterClient = new GreeterClient(channel);
HelloReply helloReply = greeterClient.SayHello(new HelloRequest(){Name = "Sai"});

Console.WriteLine("Given Name is " + helloReply.Message);

//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.