.NET 8 Series Starting Soon! Join the Waitlist

20 min read

Getting Started with gRPC in ASP.NET Core - Ultimate Guide

#dotnet

There is quite a lot of talk around gRPC lately. This article will introduce you to gRPC, what it actually is, how does it compare to REST Protocol, and really when to use it, some concepts on Protocol Buffers. Further, we will also go through a demonstration of working with gRPC in ASP.NET Core to get a complete picture of this trending technology coupled with ASP.NET Core. You can find the complete source code of the the below built application here.

It’s quite an un-deniable fact that REST APIs has ruled over the data communication world for quite a long now. Although it’s been the go-to approach for providing data linkage between client and server, there are quite a lot of drawbacks too. It may be minor, but here are a few.

  1. The response payload size may grow drastically due to the usage of JSON formatted data. Add some bad code practices to this, and you end up with much slower request-response times.
  2. Do we all really follow the REST principles? It’s quite hard and not very practical to follow the REST Principles while building a realtime application. Getting your colleagues co-relate with your thought process can be quite challenging, yeah?
  3. The market already has a better variant that is much faster and easier to develop.

This is where gRPC comes into the game.

Introducing gRPC in ASP.NET Core

gRPC or g Remote Procedure Calls in an Open Source RPC technology that was initially developed by Google back in 2015. Probably the g in gRPC stands for Google, but it is still not coined officially. The key idea was to make a service that is much faster than the existing services like WebAPI, WCF. GraphQL and so on. With gRPC, the performance was the top priority when it was designed. It’s roughly 7-10 times faster than a standard WebAPI! It supports bi-directional communication and really everything that you would need from a CRUD Application to an Enterprise-level solution, or maybe building another Youtube (data streaming services).

To understand the context of gRPC, let’s first understand that it is a protocol to send and receive data over a network in the same way Web APIs and WCFs operates, but in a more efficient manner. Let’s get started.

The two important features of gRPC to keep in mind is that it runs on the HTTP/2 Protocol and uses the Protocol Buffer to transport data. We will talk about Protocol Buffers in a later section. gRPC is supported by a lot of frameworks including Microsoft that introduced gRPC Projects from .NET Core 3.0 and above. So make sure that you are running on the latest .NET Core SDK.

To understand gRPC easier, let’s relate it to an ASP.NET Core WebAPI, as we are all quite comfortable with the data flow within the WebAPI, right? gRPC is a very similar technology that takes in a Request message and gives back a Response to the caller over the web/network. The difference mainly lies in how the data is being transported and how efficiently it does so.

What are Protocol Buffers?

Protocol Buffers or protobuf are essentialy a way to serialize data, somewhat like JSON Serialization but much simpler, compact and faster. To get a better picture, protos are Google’s language-neutral, platform-neutral, extensible mechanism for serializing structured data. As mentioned earlier, gRPC relies on Protocol Buffers or protos for communication. Protos support a huge variety of languages including C#, Python, Java, Go, Dart, Ruby and so much more. The latest version of the protos is proto3.

Protobuf format is designed in a way that it is much faster than JSON or XML formats. Thanks to smaller file sizes due to serialized binary strings. The definition of the messages / data to be seriliazed is written into proto files. The protobuf files usually have a .proto file extension.

How gRPC Works?

The flow starts with creating a gRPC Server. Next, you create proto files that not only contains definitions of the response and requests but also services that has to implemented by the server. Once the proto files are ready, you would have to add a reference to these files as a service in both the client and server projects.

As soon as the client invokes the Services defined within the Proto file and requests to the port where the server is running, the Service implementation at the server side gets invokes and retuns the data in binary format which will be further de-serialized to the response object that is defined in the configuration file (proto). This is the basic idea. You will be more clear with the concept when we start implementing.

What we will build

We will be building a service that can return a simple recordset of data. We will be using the gRPC Project type to build the gRPC Server. Then, we will consume this service using a simple console application. Keep in mind that the client could be anything that supports the gRPC protocols. So basically, we will be going through an entire cycle of data communication between the client and the server. Along the way we will also go through important concepts like building protos and sharing with the client, the gRPC folder structure and more. Let’s get started.

Working with gRPC in ASP.NET Core

Let’s get started with gRPC in ASP.NET Core and build ourself a neat implementation to demonstrtate the gRPC in a greater detail. As mentioned earlier, gRPC is already available as a Project Template with Visual Studio 2019, given that you have the latest SDK of .NET Core 3.x installed on your machine.

Open up Visual Studio 2019 and create a new gRPC Project. You can do so by searching for ‘gRPC’. This brings up a project template selection for creating a gRPC in ASP.NET Core. Click Next.

grpc-in-aspnet-core-getting-started

We will be building both gRPC Server that basically runs on the ASP.NET Core container and also a gRPC Client that can be anything. For demonstration we will be building a simple console application that would act as a gRPC Client.

Note that we are building both the Client and Server within the same Solution named gRPC.Dotnet.Learner. This is only to keep the project and repository organized for this article. In Practical cases, the client and server should be built on separate Solutions. The only Resource that is to be shared is the Protobuf file which we will deal in the upcoming sections.

Here we are creating the Server first and naming it gRPCServer.

grpc-in-aspnet-core-getting-started

Select the gRPC Service in the Selection below and click next.

grpc-in-aspnet-core-getting-started

Visual Studio does it’s magic and creates the gRPC Project for you and installs all the required dependencies.

Getting used to the gRPC Project Structure

The first thing you would notice in a gRPC ASP.NET Core Service is the similarity with other ASP.NET Core projects. You get to see the same Program.cs , Startup.cs and other files. The new inclusions are Protos and the Services Folder.

grpc-in-aspnet-core-getting-started

Let’s explore the Startup class first. There are a few things to note here.

public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc();
}

Here we are adding gRPC to the ASP.NET Core Service Container.

app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<GreeterService>();
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
});
});

At Line 3, you can see that we are mapping the gRPC Service to the GreeterService which is a class that is already available in our Server Project under the Services Folder. Note that you will have to add new mapping here everytime you create a new Service. We will be creating a new service later in this article as well.

Protos folder holds all the protos files that we had talked about earlier. This will make much more sense when you go through a proto file. Visual Studio creates a default proto file named greet.proto in the Protos folder.

syntax = "proto3";
option csharp_namespace = "gRPCServer";
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;
}

Line #1 - Here you define which syntax version to use. proto3 is the latest version of the proto language.
Line #3 specifies the namespace we are going to use for this proto.
Line #5 defines the name of the proto package.

You do not have to modiy the above lines. Here comes the fun part.

Line #8-11 Defines the supported services of this particular proto file. To talk more within the context. We have a proto file named Greet that has a service definition of SayHello. Get it? Now it can have multiple services like SayBye and so on.
Line #10 specifies a rpc Service with the name SayHello that takes in a ‘Message’ object named HelloRequest and responds with a HelloReply

What are Messages?

Message objects in proto files are similar to the Entity / DTO / Model Classes in C#. They basically hold the properties that relate to a particular message object. In our case, we have a message object with property name of type string. You can also nest further message objects within another message object that can act like a nested C# class.

Wonder what string message = 1; means?

1 refers to the order in which the property will be serialized and sent to the client. The next property will have the index of 2 and so on. Get the point, yeah?

Summing up, the proto file has some proto specific defintions, service definitions which include methods that can take in message objects and send back a processed message object as the response. Makes sense, yeah?

With that out of the way, let’s talk about the Service Implementation. Remember we defined a Greeter service with a rpc method named SayHello? So what happens in the background as soon as you save this proto file is that Visual Studio auto-generates the actual service implementation for you. You can find the auto generated files usually at the path - gRPC.Dotnet.LearnergRPCServerobjDebugnetcoreapp3.1. The important file to check here is the GreetGrpc.cs file. We will be seeing this file later in this section.

DO NOT Edit any of these auto generated files. It may break your gRPC application.

Let’s open up the GreeterService class in the Services folder.

public class GreeterService : Greeter.GreeterBase
{
}

Line #1 is a standard C# definition of a class. The point to note is that it interits from a Greeter class that we never created. So Visual Studio is responsible to create a C# Class that has the same name as that of the service object name we had created earlier in the proto file. Remember there was a service definition by the name Greeter?

Let’s navigate to the Greeter.GreeterBase. Move your cursor to the line and press F12.

There is quite a lot of generated code that barely makes any sense to the end user for the first. I want you to concentrate on the following lines of code that is available in the Greeter class.

public abstract partial class GreeterBase
{
public virtual global::System.Threading.Tasks.Task<global::gRPCServer.HelloReply> SayHello(global::gRPCServer.HelloRequest request, grpc::ServerCallContext context)
{
throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
}
}

At line 3 you can see our method definition, SayHello. Note that it is an Unimplemented method. Understand the context? So, we are inhereting this particular class as the base to the actual service class and will override the SayHello method and finish off with our implementation there.

Coming back to the basics of gRPC, it depends on the proto files for the contracts that will be implemented as a Service within the Server. All this might seem complicated, but it is actually cool how everything is wired up.

Let’s go back to our GreeterService.cs now.

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
});
}
}

Here is a very standard C# with all the expected pieces of code like the constructor injection of ILogger. The interesting part here is the implementation of the SayHello method.

As said earlier, you can find that it override the SayHello method of the base class and implements the method. It accepts parameters like the HelloRequest and a special ServerCallContext object that belongs to the gRPC Core Library. Finally it returns a message of type Hello reply with the particular business logic. Simple, yeah?

That’s quite everything with regards to the project structure and default code of the gRPC Server. Let’s build it and run the application.

You can notice that it simply pops up a console that says that the server is up and running at a particular port.

grpc-in-aspnet-core-getting-started

Let’s try to navigate to this location.

grpc-in-aspnet-core-getting-started

As mentioned earlier, gRPC services cannot be invoked by just visiting the port / URL. It needs a gRPC Client to communicate with the gRPC Server. This is one of the major differences you will find between gRPC and REST APIs.

So that’s where the article goes next.

Building a gRPC Client

a gRPC Client could be anything from a simple console application to another ASP.NET Core Web Application. To keep this demonstration simple, let’s go with a Console Application Project.

grpc-in-aspnet-core-getting-started

Now that we have our Console application ready, the first thing you would have to do is to install the required packages that enables your application to become a gRPC Client.

Open up the Package Manager Console and install the following packages.

Note that these packages are applicable for any type of gRPC Client.

Install-Package Grpc.Tools
Install-Package Grpc.Net.Client
Install-Package Google.Protobuf

With all the required packages installed, let’s copy over the protos folder from the Server Project to the Client Project. With that done, open the properties of the greet.proto in the Client Console Project. Make sure that you set the Stub class to Client Only.

grpc-in-aspnet-core-getting-started

Now you have essentially changed the property of a proto file. Be aware that the proto file is responsible for generating the base class codes. Since you have modified a proto file, it is important to rebuild the application so that Visual Studio can regenerate the required new files to the obj folder. Remember that this is very important in gRPC and can often break the application if not rebuilt.

Let’s make the required modifications to the CLient Application to establish communication with the gRPC Server now. Open up Program.cs of the Console application and make the following changes.

{
static async Task Main(string[] args)
{
var data = new HelloRequest { Name = "Mukesh" };
var grpcChannel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Greeter.GreeterClient(grpcChannel);
var response = await client.SayHelloAsync(data);
Console.WriteLine(response.Message);
Console.ReadLine();
}
}

Line 5 creates a request object.
Line 6 creates a new grpc Channel that enables server communication. Here we provide the URL on which gRPC server in up and running.

Line 7 uses the created channel and creates a new client object that is connected to the gRPC Server.Imagine this like creation of the HTTP Client Object. Makes sense, yeah?
Finally, we retrieve the response in Line 8 via the client object. Now the client object has access to methods like SendHello and SendHelloAsync. We will be using the async variant just for the sake of it.

At Line 9, we are writing the response message back to the console. Let’s run the application and check if we are getting the expected result.

grpc-in-aspnet-core-getting-started

Before running the project, Make sure you have selected the Multiple Startup project options and made the changes so as to run both the Server and Client Project at the same time.

grpc-in-aspnet-core-getting-started

From the above image it is quite clear that we have received the expected response with the least amount of configuration. Trust me, gRPC is going to be dominate the Web Services industry for the next few decades.

Let’s build our own gRPC Service

Now that we got a basic idea on how to work with gRPC in ASP.NET Core and setting up a client and server connection, let’s try to re-do the entire process by creating a new proto and Service class. Let’s make a proto that returns a list of Products that are hardcoded. You can also connect the server to the Database via Entity Framework Core, but you get the idea, yeah?

We will have methods to return a single product by ID and another method that can return a list of Products back to the client.

The first step in implementing our own Product Service in a gRPC Application is to add a new proto. Open up the Server Project and add a new proto file under the Protos folder. Name it products.proto.

grpc-in-aspnet-core-getting-started

This will give you a new proto file with the syntax and namespace already ready. We will just have to add in the Service Definition and Message Objects here.

Before continuing make sure that yo u change the properties of the proto file similar to the below screenshot. Remember to do this step everytime you create a new proto file.

grpc-in-aspnet-core-getting-started

Let’s add in our required service definition and the associated Message objects to the products.proto file.

syntax = "proto3";
option csharp_namespace = "gRPCServer.Protos";
service Product{
rpc GetProductById (GetProductByIdModel) returns (ProductModel);
rpc GetAllProducts (GetAllProductsRequest) returns (stream ProductModel);
}
message GetProductByIdModel{
int32 productId = 1;
}
message GetAllProductsRequest{
}
message ProductModel{
int32 productId = 1;
string name = 2;
string description = 3;
float price =4;
}

Line 3 to 6 is where you define the Service and it’s method. Here we have 2 Methods under the Product Service. The first one takes in a Message object (productId) and returns a single product. The other method takes a blank Message object and returns a stream of ProductModel objects.

What is a stream? gRPC usually is used for streaming in and out data. In our context we use it to stream the data one product at a time from the server to the client. This is quite similar to IEnumerable<ProductModel> but with lot more flexibilty.

Line 13, we define the actual model of the product. Note that you cannot use int, decimal like you would do back in C#. Remember that proto is a completely different language and has nothing to do with C# or even Microsoft. You can find the allowed object types here.

We need a list of Product data to work with, right? In order to mimic the existence of a Database, i am creating a new class with a list of hardcoded value for the Product model. you can find it in the Data Folder of the Server Project.

Note that I am using such an approach only to save time. You can install the Entity Framework Core package, establish a connection and use the dbContext to pull in product data from your database as well.

public static class ProductData
{
public static List<ProductModel> ProductModels = new List<ProductModel>
{
new ProductModel
{
ProductId = 1,
Name = "Pepsi",
Description = "Soft Drink",
Price = 10
},
new ProductModel
{
ProductId = 2,
Name = "Fanta",
Description = "Soft Drink",
Price = 13
},
new ProductModel
{
ProductId = 3,
Name = "Pizza",
Description = "Fast Food",
Price = 25
},
new ProductModel
{
ProductId = 4,
Name = "French Fries",
Description = "Fast Food",
Price = 20
}
};
}

With the Product data ready, let’s create a service class that could serve data from the ProductData Class to the client. In the server project add a new class named ProductService under the Services folder.

public class ProductService : Product.ProductBase
{
private readonly ILogger<ProductService> _logger;
public ProductService(ILogger<ProductService> logger)
{
_logger = logger;
}
public override Task<ProductModel> GetProductById(GetProductByIdModel request, ServerCallContext context)
{
var product = ProductData.ProductModels.Where(p => p.ProductId == request.ProductId).FirstOrDefault();
if(product!=null)
{
return Task.FromResult(product);
}
else
{
return null;
}
}
public override async Task GetAllProducts(GetAllProductsRequest request, IServerStreamWriter<ProductModel> responseStream, ServerCallContext context)
{
var allProducts = ProductData.ProductModels.ToList();
foreach(var product in allProducts)
{
await responseStream.WriteAsync(product);
}
}
}

QUICK TIP - You can type in public override which would then given you a list of override-able methods. Simply navigate to the required method and tap on Tab. It creates the template of the entire function for you. That’s quite a lot of development time saved.

Line 9 to 20 is the method that returns a single product based on the Id that is sent by the client. I guess this is a very straightforward method that used LINQ to fetch the data from the product List.

Remember we used something called a stream in the proto file? Line 21 to 28 is the function that can return a stream of Product data back to the client. Note that we are sending data one by one in a stream to the response. As long as the control remains in the foreach loop, the client continues to listen for the data stream.

Finally, open up the starup.cs and add the mapping to the new gRPC Service under the app.UseEndpoints(…)

endpoints.MapGrpcService<ProductService>();

What remains is the client implementation. But before that, let’s rebuild our Server project.

With gRPC, make sure that you rebuild the entire project every time there is a change made. This is because there is a lot of auto generation of code that happens in the background.

At the client side, the first thing to copy over the products.proto file from the Server to the client. Make sure you change the properties of the client proto as follows. Make this a practice as soon as copy over the proto files.

grpc-in-aspnet-core-getting-started

Now, open up the Program.cs in our Console application and add in the following.

static async Task Main(string[] args)
{
var data = new GetProductByIdModel { ProductId = 2 };
var grpcChannel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Product.ProductClient(grpcChannel);
var response = await client.GetProductByIdAsync(data);
Console.WriteLine(response);
Console.ReadLine();
using (var clientData = client.GetAllProducts(new GetAllProductsRequest()))
{
while(await clientData.ResponseStream.MoveNext(new System.Threading.CancellationToken()))
{
var thisProduct = clientData.ResponseStream.Current;
Console.WriteLine(thisProduct);
}
}
Console.ReadLine();
}

For demonstration purposes, we will be using both the methods here in the Main Function.

Line 3 creates a new GetProductByIdModel with a productId of 2. This will be something the client will be sending dynamically.
Line 4 creates a new gRPC channel pointing to the address where the gRPC server runs.

Line 5 creates a new client object using the gRPC channel. Note that we will be using this client object to access both the GetByID and GetAll methods.

Line 6, we pass in the data to the client, which returns back the required response.

Similarly, from Line 9 to 16, we return a stream of product data one line at a time.

Let’s run both the Server and Client Project and check out the responses.

grpc-in-aspnet-core-getting-started

As you see, we have received exactly what we wanted. Feel free to play along with different variations of this awesome technology. Let’s wrap up this article for now. You can find the complete source code here.

Summary

In this article, we covered several awesome concepts that are good to have in your tech-stack. We learnt all about the basics of gRPC, Protocol Buffers, the difference between gRPC and REST, building proto files, working with gRPC in ASP.NET Core. We also built ourself a sample application that consists of both Server and Client Implementation of gRPC.

In the upcoming articles, we will learn more about gRPC in regards with authentication, maybe building a CRUD API and much more. Feel free to suggest.

Leave behind your valuable queries, suggestions in the comment section below. Also, if you think that you learned something new from this article, do not forget to share this within your developer community. Happy Coding!

Frequently Asked Questions

Is gRPC faster than REST API?

Thanks to the added advantage of using Protocol Buffers and HTTP/2 , gRPCs are roughly around 7 to 10 times faster than an average WebAPI.

Source Code ✌️
Grab the source code of the entire implementation by clicking here. Do Follow me on GitHub .
Support ❤️
If you have enjoyed my content and code, do support me by buying a couple of coffees. This will enable me to dedicate more time to research and create new content. Cheers!
Share this Article
Share this article with your network to help others!
What's your Feedback?
Do let me know your thoughts around this article.

Boost your .NET Skills

I am starting a .NET 8 Zero to Hero Series soon! Join the waitlist.

Join Now

No spam ever, we are care about the protection of your data. Read our Privacy Policy