I’ve been playing with gRPC locally for a little while now and really enjoy the experience. I’ve created a new talk called “Beyond HTTP in ASP.NET Core with gRPC” which covers the fundamentals of how to apply gRPC for client and server scenarios, including various streaming cases. As part of the talk I show some demos based on the code in my gRPC Demos repository on GitHub.
Today, I’ve updated those demos ready for the next presentation of my talk at Techorama NL, after watching Glenn Condron showing off some of the final 3.0 features and gRPC support in Visual Studio 2019 (16.3) during dotNetConf 2019.
In this post, I want to demonstrate how we can quickly and easily create a shared class library which includes the auto-generated gRPC client code. We’ll then reference that class library from our gRPC client applications.
Quick gRPC Refresher
gRPC is based on a service contract defined in a *.proto file. This uses Protocol Buffers as the Interface Definition Language for a gRPC service. Server code is then generated using the contract which we then implement. Similarly, client code can be auto-generated from the same proto file and consumed from client applications.
My early demos shared a single proto file across all projects in my solution. The proto file is included in a folder in the root of my repository called ‘Proto’.
To load this file, the server project references it in the csproj file as follows:
This code includes the weather.proto file from the root of the repository and tells the gRPC tooling to generate the server code from it.
Each client project then also referenced the proto file as follows:
In this case, code was auto-generated for a gRPC client of the service defined in the proto contract.
For a basic console application client, as used in my samples, the following packages were also referenced:
The package references and proto file had to be referenced in each client project, of which there were four in my repository. This leads to some repetition across each project.
Building a Shared Library for gRPC Clients
For demo purposes, the approach I’ve just described was fine. The proto file was accessible to all projects and referencing it directly was a simple solution.
In a more real-world scenario, though, a proto file may well live in a different repository than the client applications. In that case, a way to share the file within the build system would be useful. There are various ways one may look to achieve that at build time which we won’t cover in this post. Instead, I’d like to focus on the first stage of a quite elegant approach; creating a single shared library for use by all clients.
Inside Visual Studio, let’s create a new Class Library project:
I’ve selected .NET Core here since I only need to target .NET Core 3.0 projects.
We can then use the Visual Studio tooling to add a Service Reference to our library.
After selecting Service Reference from the Add menu, we are presented with a choice to add either an OpenAPI service reference or a gRPC service reference. We’ll select the gRPC option.
We can then supply the details for the service reference.
In this case, we can browse to an existing proto file on the filesystem. I chose the proto file from the root of my solution.
We have the option here to also reference a file from a URL.
Finally, we choose the classes we want generated. Our library will be for use by gRPC clients of our service, so we can select “Client”.
After the tooling completes the creation of the service reference, we can view the changes it made to the csproj file by double clicking on it.
We can see that the tooling has included the selected protobuf file and requested the client code generation for this class library project.
It has also added the required gRPC and Google libraries needed to auto-generate the gRPC client code.
We now have a single library which will include the client code generated from the proto file. We can add a project reference to this client library from all client applications.
From a client we can right clicj on Dependencies and choose Add Reference:
We then choose the newly created class library project which contains the code we want to reference.
Our client projects no longer need their own service reference to the proto file, nor do they need to reference all of the gRPC libraries manually. The auto-generated client code and libraries come from our project reference to the client library we have just created.
Here is an example of a simple application which acts as a gRPC client after updating it to use the shared class library project.
It now has a single project reference to the shared class library and no specific mention of the proto file or gRPC libraries.
In this post, we’ve seen how the Visual Studio tooling supports adding a service reference to a class library. We added a gRPC service reference and built the library which caused the auto-generated code to be created. We then referenced that shared library from all proejcts that need to act as a client of the gRPC service. This approach means that we reduce the number of direct references to a single proto file.
Whilst I won’t cover it in this post, you can imagine how in a real-world scenario, we could go on to create a NuGet package for our client library and perhaps push it to an internal feed. We could even apply a package versioning strategy whenever the service contract changes.