As the world of microservices evolved, the approach and tools around it also evolved. One of the most important aspects of microservices is communication between different services.
One of the approaches for communication that are used is remote procedure call, and gRPC provides a sophisticated framework for it.
gRPC means Google remote procedure call, so it is evident from the name. It was the framework being used by Google before they opened it up to the open-source community. It uses HTTP2 protocol.
It provides a few benefits, such as.
- Lightweight messages.
- It is Fast.
- It provides Full duplex communication.
gRPC is mostly used for internal service communication, but it does have web gRPC that can work on browsers.
Unlike the RESTful services, the client and server both need to be aware of the service signature and message attribute.
It provides flexibility. The client and server can both be implemented in different technology stacks and still be able to communicate seamlessly.
Now, start implementing the gRPC in .Net Core, but before starting the implementation, do remember that the .Net API project can have Rest API and gRPC service together, and in this article, we will add gRPC in the already existing RestFull API Project.
I am using Mediator and CQRS architecture for Rest API, but you can use any approach.
Step 1. Create Proto file
It is like the skeleton of our communication channel. The signature of the method and request/response types will be defined in the Proto file.
Create a ProtoFile
Now, define the RPC Service structure.
service EventCatalogService {
rpc GetAllCategories(GetCategoriesRequest) returns (CategoriesResponse);
}
As we can see, the Name is GetAllCategories, the request it is taking is GetCategoriesRequest, and the Response is sending CategoriesResponse.
Now, Create the request and response messages for services.
message GetCategoriesRequest
{
}
message CategoriesResponse {
repeated CategoryItem Categories = 1;
}
message CategoryItem {
string CategoryId = 1;
string Name = 2;
}
The repeated is defining the collection here.
You can see the number against each attribute defining the position of the attribute in the message. We can also reserve some position for future use.
syntax = "proto3";
option csharp_namespace = "EventCatalog.gRPC";
import "google/protobuf/timestamp.proto";
service EventCatalogService {
rpc GetAllCategories(GetCategoriesRequest) returns (CategoriesResponse);
}
message GetCategoriesRequest {}
message EventByCategoryIdRequest {
string CategoryId = 1;
}
message EventByEventIdRequest {
string EventId = 1;
}
message EventByCategoryIdResponse {
string EventId = 1;
string Name = 2;
int32 Price = 3;
string Artist = 4;
google.protobuf.Timestamp Date = 5;
string Description = 6;
string ImageUrl = 7;
string CategoryId = 8;
string CategoryName = 9;
}
message EventByEventIdResponse {
string EventId = 1;
string Name = 2;
int32 Price = 3;
string Artist = 4;
google.protobuf.Timestamp Date = 5;
string Description = 6;
string ImageUrl = 7;
string CategoryId = 8;
string CategoryName = 9;
}
message CategoriesResponse {
repeated CategoryItem Categories = 1;
}
message CategoryItem {
string CategoryId = 1;
string Name = 2;
}
The proto file is ready.
Step 2. Add gRPC to your .Net project
Add the proto file as a connected service.
Click on project connected service.
Now, create the grpc server by giving the proto file path.
It will add the proto file and all the related Nuget packages to the project.
Step 3. Integrate the gRPC to your service layer
First, you need to create the gRPC service that will inherit the base class of gRPC service, and you can integrate your business layer into this gRPC service.
I am using mediatr so I will receive the message from the gRPC service, pass it to my application layer, and return a response from it.
using EventCatalog.gRPC;
using FOA.Application.Mapper;
using Grpc.Core;
using MediatR;
using TicketManagement.Services.EventCatalog.Application.Feature.Category.Queries;
using static EventCatalog.gRPC.EventCatalogService;
namespace TicketManagement.Services.EventCatalog.RPCServices;
public class EventCatalogRPCService : EventCatalogServiceBase
{
private readonly IMediator _mediator;
public EventCatalogRPCService(IMediator mediator)
{
_mediator = mediator;
}
public override async Task<CategoriesResponse> GetAllCategories(GetCategoriesRequest request,ServerCallContext context)
{
var serviceResult = await _mediator.Send(new GetAllCategoriesRequest());
var result = gRPCMappers.Mapper.Map<List<CategoryItem>>(serviceResult);
var response = new CategoriesResponse();
response.Categories.AddRange(result);
return response;
}
}
Step 5. Add gRPC to your program.cs
// adding grpc
builder.Services.AddGrpc(cfg => cfg.EnableDetailedErrors = true);
After build, add the following line.
app.MapGrpcService<EventCatalogRPCService>();
Now the server is ready, we need a client to test it.
Step 6. Create gRPC Client
Create a new .Net API project and the Client gRPC through the connected service, but this time, instead of the server, select client.
As the client is only going to send and receive messages from the server, there will be not much code other than basic communication.
var channel = GrpcChannel.ForAddress(_serviceURL);
var client = new EventCatalogServiceClient(channel);
var request = new GetCategoriesRequest();
var response = client.GetAllCategories(request);
It is creating a channel through the service URL, which is the URL of our gRPC Server, and then creating a client through that channel and calling the service through that client.
Step 7. Add authorization to your service
So, adding security to your gRPC service is very easy. As the gRPC is added as a middleware to your application, the already implemented authentication or Authorization is already available to you.
You just need to add an Authorization tag to your service.
[Authorize]
public override async Task<CategoriesResponse> GetAllCategories(GetCategoriesRequest request,ServerCallContext context)
{
var serviceResult = await _mediator.Send(new GetAllCategoriesRequest());
var result = gRPCMappers.Mapper.Map<List<CategoryItem>>(serviceResult);
var response = new CategoriesResponse();
response.Categories.AddRange(result);
return response;
}