DotNet gRPC Getting Started

In the this series of posts I will look into the details of gRPC in ASP.NET Core. In this first post I will be creating a simple service and a corresponding client. In future posts I will focus on the internal implementation of ASP.NET Core's gRPC extension. gRPC (gRPC Remote Procedure Calls is an open source remote procedure call implementation that is based on modern (web) standards. gRPC leverages HTTP2 as transport protocol, and uses Protocol Buffer as a data format and interface definition language. It is typically used for back channel (service-to-service) communication due to its efficiency. However, the efficiency comes at a cost: debugging/decoding messages are not as straightforward as with other protocols.

Creating a gRPC Service

This post provides a getting started and a look into the internals of Grpc.AspNetCore nuget package. The official documentation is spot on to get started:

  • create a proto file: the proto file defines the messages exchanged by server and the client as well as the operations that a client may invoke on a server

  • create a new asp.net core project (using dotnet CLI: dotnet new webapp)

  • add Grpc.AspNetCore nuget package to the project (dotnet add package Grpc.AspNetCore)

  • add the proto file as a Server gRPC service

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

Implement the methods of the service base class. In case of the above proto file, I have implemented a service class deriving from SuperService.SuperServiceBase:

public class SuperServiceImpl : SuperService.SuperServiceBase
{
    // ...
}

The base class is located in the namespacae that is defined in the proto file. The class itself is generated by the gRPC tooling, that comes with the Grpc.AspNetCore nuget package.

The gRPC namespace declaration in the proto file:

option csharp_namespace = "Super";

Next, override the methods (the ones corresponding to the rpc calls in the proto file), and provide your custom service implementation.

Finally, register the gRPC services in the application's service registration, and Map the gRPC endpoints:

var builder = WebApplication.CreateBuilder();
// ...
builder.Services.AddGrpc();
var app = builder.Build();
// ...
app.MapGrpcService<SuperServiceImpl>();
app.Run();

Building and running this application will create a gRPC service. We would need some sort of a client application to invoke any of the gRPC endpoints, for now that could be implemented according to this documentation, or an example has been shown earlier.

Creating gRPC Client

Let's create a simple gRPC Client for the service

  • create a new console app (using dotnet CLI: dotnet new console)

  • add Grpc.Net.Client nuget package to the project (dotnet add package Grpc.Net.Client)

  • add the proto file as a Client gRPC service (it maybe linked to the one used by the server):

<ItemGroup>
  <Protobuf Include="..\..\SuperService.proto" GrpcServices="Client" >
    <Link>SuperService.proto</Link>
  </Protobuf>
</ItemGroup>

Create a gRPC channel, instantiate the client and invoke a service method:

GrpcChannel channel = GrpcChannel.ForAddress("https://localhost:5001");
SuperService.SuperServiceClient client = new SuperService.SuperServiceClient(channel);
var response = await client.DoWorkAsync(new RequestData() { Message = "something" });

The code sample above invokes the DoWork rpc call with parameter: RequestData, awaits the call and gets a response from the service. The request and the reponse are both (de)serialized as Protocol Buffer messages. The messages are sent over HTTP2. In this case the service exposes an endpoint SuperService/DoWork which is invoked by the client. The content of the request and the response is the protocol buffer messages.

gRPC gives options for all sorts of configuration, but this is everything required to get a minimum required to invoke a gRPC method.

Summary

In this post I had a quick introduction for using gRPC with dotnet. The key steps have been outlined to create small service and a corresponding client. In the next posts I will look into the internals of Grpc.AspNetCore package.