Introduction
In my previous post (found below) I’ve explained what gRPC is, how it looks compared to the standard RESTful approach, its pros and cons, and what is the best use for it.
Now, let’s take a dive into the code and see how very basic implementation of gRPC Client and Service can look like in .NET Core.
Prequisites
To follow this guide you’ll need:
- Visual Studio 2019 16.4 or later with the ASP.NET and web development workload
- .NET Core 3.1 SDK or later
You can also use Visual Studio Code easily, but you’ll have to use command-line and modify manually your *.csproj
files.
If you’re limited to VS Code or Rider, please use the following guide:
https://docs.microsoft.com/en-us/aspnet/core/tutorials/grpc/grpc-start?view=aspnetcore-3.1&tabs=visual-studio-code
Creating Solution & Project
If you’ve got everything in place, you should be able to find gRPC type of project in Visual Studio and use it. Doing this, you’ll have an opportunity to generate basic Client and/or Service with a sample implementation.

But well, we won’t take this shortcut and we will create everything from “scratch”. First, let’s create an empty ASP.NET Core project.

Fill desired project and solution name (not relevant in this case) and now, since we want to add all necessary components from scratch, let’s pick Empty template:

Adding gRPC NuGet package
Now, having an empty project, let’s add gRPC NuGet package reference. Version might vary, but there shouldn’t be any major differences as for the time of this writing:

Adding Protocol Buffer
As we should know from my Introduction to gRPC post, Protocol Buffer files, known as Protobuf are defining our Service – its operations and payloads.
Let’s create *.proto
file in Protos/
folder of our project. I will name it order.proto
, as it will be responsible for sample order creation. Our Protobuf will look as below:
// Protocol Buffer version
syntax = "proto3";
// Namespace declaration for C# compiler, where service code will be generated
option csharp_namespace = "Example.Grpc.Service.Services";
// Service definition with operations, parameters and returned types
service Ordering {
rpc CreateOrder(CreateOrderRequest) returns (CreateOrderResponse);
}
// Operation types below
message CreateOrderRequest {
Order order = 1;
}
message CreateOrderResponse {
string orderId = 1;
}
message Order {
string id = 1;
string customerName = 2;
double value = 3;
repeated OrderItem items = 4; // 'repeated' keyword declares collections
}
message OrderItem {
string id = 1;
string name = 2;
}
As it can be easily noticed, we’ll have one Service – Ordering, which is exposing one RPC operation – CreateOrder. Furthermore, we declared payload models for that operation.
Adding Service Reference
Having the file, we need to reference it properly to let the compiler know, that this is Protobuf definition of our Service. We can achieve it by adding it as a connected service as shown below.


As the last step, we have to choose location of *.proto
file as well as type of class to generate. In this example, this will be a local Protobuf file.

And we’re done, we should have our Protobuf properly referenced as a definition of the Service. Now after each compilation, Protocol Buffer Compiler should generate base abstract class based on that definition.
We can also achieve the same by i.e. editing project *.csproj
file. After all steps above, it should look as shown below:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<None Remove="Protos\order.proto" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Grpc.AspNetCore" Version="2.31.0" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="Protos\order.proto" GrpcServices="Server" />
</ItemGroup>
</Project>
Implementing the Service
Autogenerated code for our base class should be placed in the namespace declared in csharp_namespace
option of our Protobuf file – in our case is “Example.Grpc.Service.Services“.
All we need to do now is to create a derived class that will override RPC methods of its abstract base definition.
NOTE: In the implementation below you can notice an injection of repository and usage of model classes, which both are missing in this guide. For full implementation of the Service as well as the Client please refer to my example in GitHub repository:
https://github.com/swiftybathero/Example.Grpc
Notice that our class inherits from Ordering.OrderingBase
, which was generated by the Protocol Buffer Compiler. Name Ordering comes from our Service definition in our Protobuf file.
This abstract class contains abstract methods corresponding to our RPC operations. In this case, we are overriding one method – CreateOrder
.
In the example code above, we’re creating an Order based on incoming payload and returning its Id once the Order is created.
Startup.cs
Startup.cs
in ASP .NET Core is responsible for runtime configuration of application dependencies as well as other configurations, like routing.
Firstly, we have to register our gRPC Service. All services that we have will be discovered automatically during runtime and registered in IoC container.
public void ConfigureServices(IServiceCollection services)
{
// Registration of gRPC services
services.AddGrpc();
}
Then, we have to configure routing for our service. Go to Configure
method of Startup.cs
and add the following to endpoint configuration:
// Registering endpoints for gRPC service
endpoints.MapGrpcService<OrderingService>();
We’re ready to go. Our Service should be ready to launch. Let’s create the client.
Adding and implementing the Client
Create a project for our Client implementation. In this case, it will be .NET Core Console App (pretty obvious for example code demonstration 🙂)
Adding Service Reference to the Client
To consume the service the Client needs to know about its contract. And so, we have to add a service reference to the Protobuf file, that’s defined by the gRPC Service.
This will allow Protocol Buffer Compiler to generate the client code. In our client application follow the same steps as in adding a reference in the service, but this time select the Client type of class instead as shown below.

This operation will also add all required gRPC NuGet packages.

Calling the Service
After we properly referenced Protobuf file, C# compiler should be able to generate the client code. Now, the only thing left is to use it.
Firstly, we have to create a gRPC channel, which is an abstraction for connections to remote servers. Since it’s an expensive operation compared to invoking a remote all, we should reuse a single channel for as many calls as possible. gRPC channel should have an address of the Service – this may vary depending on your service configuration.
Created channel should be used to instantiate the client.
// Creating channel and client
using var channel = GrpcChannel.ForAddress(serviceUrl);
var client = new Ordering.OrderingClient(channel);
Having the client, the only thing left is to invoke RPC operation declared in Service contract.
var createOrderResponse = await client.CreateOrderAsync(createOrderRequest);
Our full implementation of the main method in client code can look as below.
Summary
A basic implementation of gRPC Clients and Services in .NET Core is very simple. Once we have our Protobuf file created, all we need is to reference it properly in our project files. Once it’s done, C# and Protocol Buffer Compiler are doing most of the job for us, by generating base class for the Service and typed Client for client applications.