This post will give you an overview of “What is gRPC?”, “Why should we consider moving from Restful API to gRPC?” and “The advantages of using gRPC”, after that we will together create a simple implementation of gRPC with .NET Core 3.x
gRPC is an open-source remote procedure call (RPC) framework originally developed by Google in 2015 that can run anywhere. It’s used by developers across many programming languages for modern RPC scenarios. The community and the ecosystem are vibrant and active. For now, gRPC is supporting mostly programming languages like C++, Java (+Android), Objective-C (iOS), Python, Ruby, Go, C#, Node.js and others are coming!
.NET Core 3.0 released a few months ago — (at this moment, when I’m composing this article, Microsoft already released .NET Core 3.1 LTS). The release of .NET Core 3.0 brought to .NET Developers Community a lot of improvements as well as new features. And, gRPC has become a first-class citizen of the ecosystem with Microsoft officially supporting and embracing it. From my point of view, this is a big move of Microsoft to take one more step to closer with Open-source software Community.
Note: Cloud Native Computing Foundation (CNCF) has hosted gRPC from Google since 2017 ( https://www.cncf.io/blog/2017/03/01/cloud-native-computing-foundation-host-grpc-google/). And now, gRPC is one of CNCF’s incubating projects together with Helm, Linkerd…
What is gRPC?
gRPC is a framework uses the HTTP/2 protocol to exchange binary messages, which are serialized/deserialized using Protocol Buffers — this is also designed by Google. Basically, protocol buffers is a binary serialization protocol, it is highly performant by providing a compact binary format that requires low CPU usage. With gRPC, we also can call methods on a server application on a different machine as if were a local object. Nowadays, IoT applications are growing rapidly with a variety of devices/sensors and capabilities, especially small hardware specifications. gRPC becomes the first choice for communications between IoT devices.
Another sample of using gRPC is with Microservice Architecture. When you choose to apply Microservice architecture, it means that you will have to manage a lot of communications between service to service, client to service, service to 3rd party services… RESTful services are often useful for external-facing services, which are directly exposed to consumers. As RESTful service is based on conventional text-based messaging, which are optimized for humans, these are not ideal choices for internal service-to-service communication. In stead using RESTful services for internal communication (service to service), we can consider using gRPC. When we build multiple microservices with different technologies and programming languages, it is important to have a standard way to define service interfaces and underlying message interchange formats. gRPC offers a clean and powerful way to specify service contracts using protocol buffers. That is why gRPC was adopted by CNCF :)
Let’s see, how it works!
You can easily define the service contract by using the gRPC Interface Definition Language (IDL). In other words, as part of the service definition, you can specify the methods that can be invoked remotely and the data structure of the parameters and return types.
Note: The service contract is easy to understand and can be shared between the client and the service. If there’s any change to the service contract, both the service and client-side code has to be regenerated.
gRPC supports four types of communications as below:
- Unary RPC — the client sends a single request and gets back a single response.
- Server streaming RPC — after getting request message from the client, the server sends back the stream of responses.
- Client streaming RPC — opposite to “Server streaming RPC”, where clients send a sequence of messages, wait for the server to process them and receive a single response back.
- Bidirectional streaming RPC — client send a stream of messages to server and server sends back a stream of messages.
It is time to practice!!
Implement a simple gRPC call with ASP.NET Core 3.0
Note: ASP.NET Core gRPC is not currently supported on Azure App Service or IIS. The HTTP/2 implementation of Http.Sys does not support HTTP response trailing headers which gRPC relies on. For more information, see this GitHub issue.
1 — Create a gRPC service (payment service)
- Start Visual Studio and select Create a new project. Alternatively, from the Visual Studio File menu, select New > Project.
- In the Create a new project dialog, select gRPC Service and select Next:
- Name the project GrpcGreeter. It’s important to name the project PaymentService so the namespaces will match when you copy and paste code.
2 — Implement business logic for gRPC service
By default, Visual Studio created “GreeterService” with a simple implementation
The greet.proto file defines the contract. i.e. what are the request/response messages exchanged by client and server.
The generated GreeterService class contains the implementation of the service:
GreeterService is inherited from Greeter.GreeterBase, while HelloRequest and HelloReply classes are used as request and response respectively. These classes are generated by the gRPC tooling, based on the greet.proto file.
Grpc.AspNetCore is a meta-package including the tooling needed at design time and the libraries needed at runtime. The Protobuf item points the tooling to the proto files it needs to generate the service and message classes. The GrpcServices=”Server” attribute indicates that service code should be generated, rather than client code.
Let’s take a quick look at Startup.cs
You can see how the necessary ASP.NET Core services to host a gRPC service are added with services.AddGrpc(), while the GreeterService is mapped to a specific endpoint of the ASP.NET Core service by using endpoints.MapGrpcService<GreeterService>();
Let’s now update default implementation with our imaginary Payment service. This is a simple service that lets users make payment and later ask for the payment status.
There are 2 methods in PaymentService as above, “MakePayment” method is a standard Unary RPC type while “GetPaymentStatus” is a Server streaming RPC method. The request/response messages are fairly self-descriptive but notice how each field has a type and an order, allowing backwards compatibility when creating new service versions.
Implementing the service
The implementation of “MakePayment” method is fairly similar to the previous “Hello” method in Greeter service one. The “GetPaymentStatus” one is a bit more interesting. Being a server streaming method, it receives a ResponseStream parameter that lets you send as many response messages back to the client as needed. The implementation above simulates a real service by sending some messages after certain delays.
3 — Running gRPC service
The template is already adding all the gRPC infrastructure needed to host the service in ASP.NET via the existing services.AddGrpc() call. You should be able to start the server with the “dotnet run” command:
The server will start listening on port 5001 using HTTPS (and 5000 using HTTP) as per the default settings.
Ok, it’s working now. It’s time to create a gRPC Client.
4 — Implement gRPC Client Application
Make sure that you install the following required packages via Nuget:
Then, create “Protos” folder and copy “payment.proto” to this folder.
Next, manually edit the GRPCClientApp.csproj project file to Change “GrpcServices” value from “Server” to “Client”:
It helps us to use stub code instead of service base classes.
Let’s write the code needed to instantiate a client of our service
We simply instantiate a GrpcChannel using the URL of our service using the factory method provided by the Grpc.Net.Client package, and use it to create the instance of the generated class “PaymentService”.
Now we can use paymentClient instance to invoke the “MakePayment” method:
Let’s check the result!
Invoking the server streaming method is also simple :). The “GetPaymentStatus” method returns an AsyncServerStreamingCall<GetOrderStatusResponse>. This is an object with an async iterable that lets you process every message received by the server.
Let’s check the result!
Although this doesn’t cover 4 types of gRPC (Unary, Server streaming, Client streaming, Bidirectional streaming), I expect that it should give you enough information to explore the remaining two by your-self.
Note: You can also explore the gRPC examples in the official grpc-dotnet repo, covering the different RPC styles and more.
5 — Using Grpc.Net.ClientFactory to communicate between services
Note: This scenario is very popular in Microservice Architecture when you need to make a call from service to service.
Let’s add one more service named “Shipping”. This service will be called in Payment service once Payment status is Accepted.
With new “shipping.proto”
And a new “Shipping” service
We will now update the Payment service so it invokes the SendOrder method of the Shippings service as part of its MakePayment method. Update the Payment.csproj file to include a new Protobuf item referencing the shippings.proto file we just created.
Next, install the Grpc.Net.ClientFactory NuGet package
Once installed, you will be able to use the services.AddGrpcClient extension method to register the client. Update the ConfigureServices method of the startup class as follows:
Since we registered “ProductShipment” as a service in the DI container, we can easily request an instance in the constructor of the existing Payment service:
Let’s check the result!
Be careful, gRPC has a major drawback in the lack of browser support!
Here’s a table that summarizes the different features supported ( https://grpc.io/blog/state-of-grpc-web/):
Note: You can find all source-code for this post here:
We’ve covered basic fundamentals of gRPC in this post. Hopefully, you can now implement gRPC services by your self. While it has a major drawback in the lack of browser support, there is no shortage of scenarios in which it can shine or at least become a worthy addition to your toolset. Building Microservices, native mobile apps or Internet of Things (IoT) are just a few of the examples where gRPC would be a good fit.