DEV Community

Cover image for Next-Level Application Development: Mastering gRPC in .NET 8
Ahmed Shah
Ahmed Shah

Posted on

Next-Level Application Development: Mastering gRPC in .NET 8

In the previous article i have talked about how gRPC works and serializes data in .NET. now will create a practical example of gRPC in .NET 8. We will be using Unary (Unary RPC Communiaction) if you dont know about Unary RPC read previous article.
Create Two New Projects One for the client and other for the Server using dotnet cli Command or create a new project of .NET 8 using UI.

dotnet new webapi -n GrpcServer

Image
For Client I will be using my old project that was created for Introduction to Hangfire we will be calling our server from Hangfire background jobs to see how gRPC works.
Link to old HangFire Article Boosting Productivity with HangFire.
Find the code on GitHub Github Code Link
Lets Edit our HangFire project and add Nuget packages for gRPC.



<PackageReference Include="Google.Protobuf" Version="3.23.4" />
<PackageReference Include="Grpc.Net.Client" Version="2.55.0" />
<PackageReference Include="Grpc.Net.Client.Web" Version="2.55.0" />
<PackageReference Include="Grpc.Tools" Version="2.56.0">


Enter fullscreen mode Exit fullscreen mode

Google.Protobuf we can create ProtoBuf files using this package.
Grpc.Net.Client
The Grpc.Net.Client package in .NET provides the tooling you need to generate gRPC services and clients.
Grpc.Net.Client.Web (used due to http hanlder)
The Grpc.Net.Client.Web package in .NET provides a way to call gRPC services from web applications. This package uses the Grpc.Net.Client package to make the calls, but it also provides some additional features that are specific to web applications.
Grpc.Tools
This package provides C# tooling support for generating C# code from .proto files in .csproj projects.
Creating gRPC Files
Lets Create 2 new folder in our HangFire project one for Protos and other one service.

  • Create Hello World proto(Helloworld.proto) in protos folder.
  • In Service Folder Create HangFireJobService (since we will be calling our gRPC from hangfire service)' now our project looks like this.

Image

Right Click HelloWorld.proto file and go to properties. we need to set our grpc Stub Class to Client and Compiler to Protobuf Compiler in order for our client to work.

Image



//This line specifies the version of the Protocol Buffers language that is used in the file.
syntax = "proto3";

//This line specifies the C# namespace that will be used to generate the code for the messages and services defined in the file.
option csharp_namespace = "HangFire.Protos";

//This line specifies the package name for the messages and services defined in the file.
package HelloWorld;

//This line defines a service called HelloWorld. The service has a single method called SayHello. The SayHello method takes a HelloRequest message as input and returns a HelloReply message as output.
service HelloWorld {
  // Sends a Hello to Server
  rpc SayHello (HelloRequest) returns (HelloReply);
}
//This line defines a message called HelloRequest. The HelloRequest message has a single field called message. The message field is a string that contains the input we will send
//request payload
message HelloRequest {
  string message = 1;
}
//This line defines a message called HelloReply. The HelloReply message has a single field called message. The message field is a string that contains the message that the server sent to the client.
//reponse payload
message HelloReply {
  string message = 1;
}


//The number 1 in the line string message = 1; refers to the field number of the message field. In Protocol Buffers, field numbers are used to uniquely identify fields in messages. The field number 1 is the first field in the HelloRequest/HelloReply message.


Enter fullscreen mode Exit fullscreen mode

Right Click and build our project in order for proto file to compile.

Now we need to configure HangFireJobManager file for calling gRPC server using background jobs. the code looks like this



   public class HangFireJobManager
  {
      public async Task<bool> ExecuteFireAndForgetJob()
      {
          try
          {
              //serviceEndpoint contains the address of the gRPC server.
              var serviceEndpoint = "https://localhost:7218";

              //The GrpcChannel.ForAddress() method creates a channel to the gRPC server. The GrpcChannelOptions object specifies that the channel will use the GrpcWebHandler to handle HTTP requests.
              var channel = GrpcChannel.ForAddress(serviceEndpoint, new GrpcChannelOptions
              {
                  HttpHandler = new GrpcWebHandler(new HttpClientHandler())
              });
             // The HelloWorld service is a gRPC service that is defined in the HelloWorld.proto file. The HelloWorld.HelloWorldClient class is a class that provides a client for the HelloWorld service.
             var client = new HelloWorld.HelloWorldClient(channel);
              //The helloRequest variable is a HelloRequest message. The Message field of the helloRequest message is set to the string "Calling Server From Client".
              Console.WriteLine("Sending Request to Server");
              var helloRequest = new HelloRequest
              {
                  Message = "Calling Server From Client"
              };
              //The client.SayHello() method sends the helloRequest message to the server and returns a HelloReply message.
              var ServerResponse = await Task.FromResult(client.SayHello(helloRequest));
             // The Serverresponse variable is a HelloReply message.The Message field of the Serverresponse message is set to the greeting that the server sent to the client.
              Console.WriteLine($"Server Reponse :{ServerResponse.Message}");
              return true;

          }
          catch (Exception ex)
          {
              //logging needs to be implemeented
          }
          return true;
      }

  }


Enter fullscreen mode Exit fullscreen mode

we need to configure our program.cs for registering background job.



//register hangfire service 
builder.Services.AddSingleton<HangFireJobManager>();

//add background job in app builder
var backGroundJobSerivice = app.Services.GetService<IRecurringJobManager>();
backGroundJobSerivice
.AddOrUpdate("MyGrpcJob",() => app.Services.GetService<HangFireJobManager>().ExecuteFireAndForgetJob(),Cron.Daily);


Enter fullscreen mode Exit fullscreen mode

We have created a recurring job that will be executed each day.

Let Dive into our 2nd Project named GrpcServer that we have Created newly.
Add these nuget packages.



<PackageReference Include="Grpc.AspNetCore" Version="2.55.0" />
 <PackageReference Include="Grpc.AspNetCore.Web" Version="2.55.0" />
<PackageReference Include="Grpc.Tools" Version="2.56.0">


Enter fullscreen mode Exit fullscreen mode

Create new folder Protos and add 2 new files HelloWorld.proto and HelloWorldService. ignore the folder structure.

Image

Paste the following Code in HellWorld.proto file



syntax = "proto3";

option csharp_namespace = "GrpcServer.Protos";

package HelloWorld;

// The HelloWorld service definition.
service HelloWorld {
  // Sends a SayHello
  rpc SayHello (HelloRequest) returns (HelloReply);
}

// The request message containing the HelloRequest.
message HelloRequest {
  string message = 1;
}

// The response message containing the HelloReply.
message HelloReply {
  string message = 1;
}


Enter fullscreen mode Exit fullscreen mode

build the project so we can use the proto file in our c# class.
Paste the following code in HelloWorldService.cs class.



//The HelloWorldService class inherits from the HelloWorld.HelloWorldBase class. The HelloWorld.HelloWorldBase class is a base class that provides the implementation for the SayHello() method in HelloWorld.proto that we have created.
public class HelloWorldService : HelloWorld.HelloWorldBase
{
    public override async Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
    {

        HelloReply responseModel = new HelloReply();
        try
        {
            Console.WriteLine($"Request From the Client:{request.Message}");
            responseModel.Message = "Hello From the Server";
            Console.WriteLine("Server Response Sent");
            return responseModel;
        }
        catch (Exception ex)
        {
            //log any error 
            throw;
        }
    }
}


Enter fullscreen mode Exit fullscreen mode

Lets configure our program.cs for gRPC server.



//builder code 

//This line of code registers the Grpc service in the ASP.NET Core application. The Grpc service provides the infrastructure for hosting gRPC services in ASP.NET Core applications.
builder.Services.AddGrpc();

//http request pipeline code 

//This line of code enables gRPC-Web support in the ASP.NET Core application. gRPC-Web is a protocol that allows gRPC services to be accessed over HTTP.
app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true });
//This line of code maps the HelloWorldService class to a gRPC endpoint.
app.MapGrpcService<HelloWorldService>();


Enter fullscreen mode Exit fullscreen mode

we can finished configuring our server for gRPC. now we can run the project right click solution click set startup project.
select multiple startup projects. set startup for GrpcServer and HangFire project and click ok.

Image
now run the project and go to HangFire dashboard for calling our server from the client.(server address maybe different for your project configure it according to your launch settings from GrpcServer Project).

Image

Url for accessing HangFire dashboard.
https://localhost:7077/hangfire

Go to recurring jobs see the MyGrpcJob that we have created.
Image
Execute the trigger button and observe the console of both project the response is being generated.

you can set the break point to further examine the code and use different datatypes.

HangFire Console Reponse (gRPC Client)

Sending Request to Server
Server Reponse :Hello From the Server

Image

GrpcServer Console Reponse (gRPC Server)

Request From the Client:Calling Server From Client
Server Response Sent

Image

gRPC weaknesses

Limited browser support

It's impossible to directly call a gRPC service from a browser today. gRPC heavily uses HTTP/2 features and no browser provides the level of control required over web requests to support a gRPC client. For example, browsers do not allow a caller to require that HTTP/2 be used, or provide access to underlying HTTP/2 frames.
gRPC on ASP.NET Core offers two browser-compatible solutions

gRPC-Web allows browser apps to call gRPC services with the gRPC-Web client and Protobuf. gRPC-Web requires the browser app to generate a gRPC client. gRPC-Web allows browser apps to benefit from the high-performance and low network usage of gRPC.

gRPC JSON transcoding allows browser apps to call gRPC services as if they were RESTful APIs with JSON. The browser app doesn't need to generate a gRPC client or know anything about gRPC. RESTful APIs can be automatically created from gRPC services by annotating the .proto file with HTTP metadata. Transcoding allows an app to support both gRPC and JSON web APIs without duplicating the effort of building separate services for both.

The articles demonstrates how to establish a gRPC communication > Communication between a client (HangFire) and a server
(GrpcServer). using the Unary RPC pattern, where the client
sends a request to the server and receives a single response.
GitHub Repository Link gRPCClient
gRPCServer.

Comment for any Questions.
Subscribe to my newsletter for exclusive content delivered straight to your inbox.πŸ‘‡
https://ahmedshahjr.substack.com/?r=bpctg&utm_campaign=pub&utm_medium=web

Top comments (2)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.