gRPC is an open-source remote process call system developed at Google in 2015.The supporting programming languages like C++, Java (+ Android), Objective-C (iOS), Python, Ruby, Go, C#, NodeJS and others.It uses HTTP / 2 to transfer binary messages and through a default protocol buffer as an interface definition language (IDL) to describe the service interface and the composition of the messages.
service Greeter
{
rpcSayHi (HiRequest) returns (HiReply) {}
}
message HiRequest {
string name = 1;
}
message HiReply {
string message = 1;
}
The gRPC defines two types of service methods,
- Unary RPCs, where the client sends a request to the server and receives the same response.
- Client streaming RPCs wherever the client writes a sequence of messages and sends them to the server, using the re-provided stream.
- Bidirectional streaming RPC where the client and the server exchange messages in both directions.
- Server Streaming RPC wherever the client sends a call for participation message to the server and receives a sequence of replies.
If we compare gRPC to Web API, differences are,
- The Web API is based on the REST architecture where the gRPC proposes RPC model, a model where a remote process is demanded on the server as a client.
- The Web API uses HTTP for transport while the gRPC uses HTTP / 2.
- The data exchanged by the Web API is a human readable format (especially JSON), while the gRPC uses a compact binary format.
Creating a gRPC service
The application we will be going to build is a microservice that calculates a discount based on the type of customer -- Gold or Platinum or Silver -- Which can be advanced.
Let’s start by creating a new folder, gRPC-dotnet-microservice, adding both client and service applications.
Navigate to this folder and create a server project by typing the following command in the console window.
The above command creates a new template. .NET Core gRPC project in the DiscountServices folder.
Defining the Contract
The first step is to define the contract which is an interface that tells you the functionality or functions open by the service. In the gRPC framework, this interface is defined by the protocol buffer or protobuf. This interface is specifically defined in the .proto file.
syntax = "proto3";
option csharp_namespace = "DiscountService";
package Discount;
service DiscountAmount
{
rpc Amount (CalculateRequest) returns (CalculateReply);
}
message CalculateRequest
{
string customertype = 1;
}
message CalculateReply
{
double customerdiscount = 1;
}
Let’s understand line by line. The first two lines use the syntax of the proto buff version in use and C# namespace. The next line tells the package name in this case = Discount.
Once the contract is defined, you need to create the application aware of the new proto file. Update theDiscountService.csproj file below,
<project sdk="Microsoft.NET.Sdk.Web">
<propertygroup>
<targetframework>netcoreapp3.1</targetframework>
</propertygroup>
<itemgroup>
<protobuf grpcservices="Server" include="Protosdiscount-service.proto"></protobuf></itemgroup>
<itemgroup>
<packagereference include="Grpc.AspNetCore" version="2.27.0">
</packagereference></itemgroup>
</project>
Read More: How To Secure Public Apis In Asp.net Core?
Service implementation
Navigate to the services folder, rename the GreeterService.cs file to DiscountService.cs, and change the contents with below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Grpc.Core;
using Microsoft.Extensions.Logging;
namespace DiscountService
{
public class DiscountAmountService :DiscountAmount.DiscountAmountBase
{
private readonlyILogger<discountamountservice> _logger;
public DiscountAmountService(ILogger<discountamountservice> logger)
{
_logger = logger;
}
public override Task<calreply>AmountCalculate(CalRequest request, ServerCallContext context)
{
return Task.FromResult(new CalReply
{
Customerdiscount=ReturnDiscount(request.Customertype)
});
}
private double ReturnDiscount(string customertype)
{
double discount=0.0;
if (customertype=="GOLD")
{
discount=15.6;
}
else if (customertype=="PLATINUM")
{
discount=20.6;
}
else if (customertype=="DIAMOND")
{
discount=25.6;
}
return discount;
}
}
} </calreply></discountamountservice></discountamountservice>
We're implementing to the DiscountAmountService class that's heritable from the DiscountAmount.DiscountAmountBase class. This base class is generated from the data contained in the .proto file at build time.
It has AmountCalculate function which implements the rpc definition in the .proto file and the CalculatorReply and CalculateRequest types as return types and request parameters defined as a message types.
Creating a gRPC client
Navigate to the folder grpc-dotnet-microservice and make a new project by typing the following command in cmd.
The above command will create a console application in the folder created DiscountCalClient. Now move to this folder and add the required dependencies by typing the following commands.
<code>dotnet add DiscountCalClient.csproj package Grpc.Net.Client
dotnet add DiscountCalClient.csproj package Google.Protobuf
dotnet add DiscountCalClient.csproj package Grpc.Tools</code>
Now the client application needs to be aware of the details about how to Request server application, which parameters to pass, and what will be the possible return type.
Searching for Dedicated ASP.NET Core Web Developer? Your Search ends here.
This is done by adding a predefined proto file. First one is to create a proto folder inside DiscountCalClient and copy the discount-service.proto from the gRPC service and update the DiscountCalClient.csproj Project file by adding a reference of .proto file.
<project sdk="Microsoft.NET.Sdk">
<propertygroup>
<outputtype>Exe</outputtype>
<targetframework>netcoreapp3.1</targetframework>
</propertygroup>
<itemgroup>
<packagereference include="Google.Protobuf" version="3.14.0">
<packagereference include="Grpc.Net.Client" version="2.33.1">
<packagereference include="Grpc.Tools" version="2.34.0">
<includeassets>runtime; build; native; contentfiles; analyzers; buildtransitive</includeassets>
<privateassets>all</privateassets>
</packagereference>
</packagereference></packagereference></itemgroup>
<itemgroup>
<protobuf grpcservices="Client" include="Protosdiscount-service.proto">
</protobuf></itemgroup>
</project>
Notice here Protobuf element has the GrpcServices attribute set to client. Now to call the gRPC service from the client, edit the Program.cs file,
using System;
using DiscountService;
using Grpc.Net.Client;
using System.Net.Http;
namespace DiscountCalClient
{
class Program
{
static void Main(string[] args)
{
varhttpHandler = new HttpClientHandler();
httpHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
string customerType="GOLD";
var model=GrpcModel.ForAddress("https://localhost:5000",new GrpcModelOptions{ HttpHandler = httpHandler });
var client=new DiscountAmount.DiscountAmountClient(model);
var request=new CalculateRequest{Customertype=customerType};
var reply= client.AmountCalculate(request);
Console.WriteLine(${customerType} is {( reply.Customerdiscount)}");
Console.ReadKey();
}
}
}
Here we are creating a model which points to the address where the service is running with the addition the required configuration to ignore the invalid certificate or certificate not installed and further passed as a constructor in the gRPC client DiscountAmountClient class. Finally, its function is called by passing the required parameters.
Output in the client application after launching by the command: DotNet Run,
Conclusion
We have covered the basic fundamentals of GRPC in this post. Hopefully, you can now implement gRPC services by yourself. While it's a major drawback in the lack of browser support, there is no shortage of views in which it will shine or at least be a worthy addition to your toolset. Building Microservices, native mobile applications or the Internet of Things (IoT) are just a few examples where gRPC would be perfect.
Top comments (0)