Book Image

Microservices Communication in .NET Using gRPC

By : Fiodar Sazanavets
Book Image

Microservices Communication in .NET Using gRPC

By: Fiodar Sazanavets

Overview of this book

Explore gRPC's capabilities for faster communication between your microservices using the HTTP/2 protocol in this practical guide that shows you how to implement gRPC on the .NET platform. gRPC is one of the most efficient protocols for communication between microservices that is also relatively easy to implement. However, its official documentation is often fragmented and.NET developers might find it difficult to recognize the best way to map between C# data types and fields in gRPC messages. This book will address these concerns and much more. Starting with the fundamentals of gRPC, you'll discover how to use it inside .NET apps. You’ll explore best practices for performance and focus on scaling a gRPC app. Once you're familiar with the inner workings of the different call types that gRPC supports, you'll advance to learning how to secure your gRPC endpoints by applying authentication and authorization. With detailed explanations, this gRPC .NET book will show you how the Protobuf protocol allows you to send messages efficiently by including only the necessary data. You'll never get confused again while translating between C# data types and the ones available in Protobuf. By the end of the book, you’ll have gained practical gRPC knowledge and be able to use it in .NET apps to enable direct communication between microservices.
Table of Contents (17 chapters)
1
Section 1: Basics of gRPC on .NET
5
Section 2: Best Practices of Using gRPC
9
Section 3: In-Depth Look at gRPC on .NET

Understanding how proto files generate C# code

Normally, you wouldn't need to worry about how C# classes are generated from proto files. The compiler does it all for you. But occasionally, there may be a problem with the process. Therefore, it would be useful to know how to find the generated code and what the expected output should be.

Where is auto-generated code stored?

At this point, you know that the .NET compiler generates code from the proto files. This can then be referenced from inside your application code. And you can also get it to share the same namespace as your application. But despite the ability of this code to inter-operate with your application code, it's not part of your application.

The auto-generated code is placed in the obj folder inside your project folder. The purpose of this folder is to store intermediate resources that are required to compile your application. Since auto-generated classes aren't part of your main application, but your application cannot be compiled without them, they are placed alongside other intermediate files in this folder.

More precisely, the location of those auto-generated files is as follows. This represents the path on the Windows system. For a Unix-based system, such as macOS or Linux, replace back-slashes (\) with forward-slashes (/):

{your project folder}\obj\{build configuration}\{framework 
  name}\Ptotos

So, for our BasicGrpcService project, which is based on .NET 5's built-in Debug mode, the path would be as follows:

BasicGrpcService\obj\Debug\net5.0\Ptotos

For each proto file that you reference in your project, a pair of files containing C# code will be generated:

  • {PascalCase proto file name}.cs
  • {PascalCase proto file name}Grpc.cs

The {PascalCase proto file name}.cs file contains a C# representation of the proto messages that your services use, while {PascalCased proto file name}Grpc.cs contains a C# representation of the services themselves, whether it's overridable base classes for the server or ready-made classes for the client.

In our example, which uses the greeter.proto file, we would end up with two files with the following names:

  • Greeter.cs
  • GreeterGrpc.cs

The content of those auto-generated files would be similar to the following:

Figure 1.11 – An example of auto-generated gRPC C# code

Figure 1.11 – An example of auto-generated gRPC C# code

You can examine the structure of these files if you like. Now, let's learn how making changes to the namespaces in Protobuf will affect the auto-generated code.

Modifying Protobuf namespaces

So far, we have been using the csharp_namespace option inside our proto files to set the namespaces of auto-generated code classes to the same root namespace that our application uses. But it doesn't have to be this way. You can set the namespaces in auto-generated code to absolutely anything.

You can also omit the csharp_namespace option entirely. If you do so, the namespace that will be applied to your auto-generated code will be the PascalCase version of the package name that's specified in the package element of the proto file.

In our case, since the package is called greeter, the C# namespace that's generated from it will be Greeter.

Now, go ahead and remove the csharp_namespace element from both the client and server versions of the greeter.proto file. Both copies of the files should now look as follows:

syntax = "proto3";
 package greeter;
 
// The greetings manager service definition.
service GreetingsManager {
  // Request the service to generate a greeting message.
  rpc GenerateGreeting (GreetingRequest) returns 
    (GreetingResponse);
}
 
// The request message definition containing the name to be 
  addressed in the greeting message.
message GreetingRequest {
  string name = 1;
}
 
// The response message definition containing the greeting 
  text.
message GreetingResponse {
  string greetingMessage = 1;
}

Now, if you try to compile the projects, they will show errors. What you need to do is add a using statement to both the client and the server code referencing this namespace.

The content of the GreetingsManagerService.cs file inside the BasicGreeterService project should now look as follows:

using System.Threading.Tasks;
using Greeter;
using Grpc.Core;
namespace BasicGrpcService
{
     public class GreetingsManagerService : 
       GreetingsManager.GreetingsManagerBase
    {
        public override Task<GreetingResponse> 
          GenerateGreeting(GreetingRequest 
            request, ServerCallContext context)
        {
            return Task.FromResult(new GreetingResponse
            {
                GreetingMessage = "Hello " + request.Name
            });
        }
    }
}

The content of the Program.cs file inside the BasicGreeterClient project should now look as follows:

using System;
using System.Threading.Tasks;
using Greeter;
using Grpc.Net.Client;
namespace BasicGrpcClient
{
    class Program
    {
        static async Task Main()
        {
             // The port number(5001) must match the port of 
             the gRPC server.
             using var channel = 
               GrpcChannel.ForAddress("https://
                 localhost:5001");
             var client = new 
               GreetingsManager.
                 GreetingsManagerClient(channel);
             var reply = await client.GenerateGreetingAsync(
             new GreetingRequest { Name = "BasicGrpcClient" });
             Console.WriteLine("Greeting: " + 
               reply.GreetingMessage);
             Console.WriteLine("Press any key to exit...");
             Console.ReadKey();
        }
    }
}

Now, you know how easy it is to regenerate relevant code after making changes to the Protobuf definition. At this point, you have two copies of the greeter.proto file that are identical.

At this stage, you may be wondering whether having separate copies of this file would violate the don't repeat yourself (DRY) principle, which is a commonly accepted best practice when writing software. Will any problems occur if you update one of these files while forgetting to update the other? Isn't it possible to keep a single shared copy of the file that both the client and the server use?

Fortunately, you can share the same file between multiple applications in .NET. Let's have a look at how.