Building a gRPC Client in .NET

Introduction

In this article, we will take a look at how to create a simple gRPC client with .NET and communicate with a server. This is the final post of the blog series where we talk about building gRPC services.

Motivation

This is the second part of an articles series on gRPC. If you want to jump ahead, please feel free to do so. The links are down below.

Introduction to gRPC
Building a gRPC server with Go
Building a gRPC client with .NET
Building a gRPC client with Go

Building a gRPC client with .NET (You are here)

Please note that this is intended for anyone who’s interested in getting started with gRPC. If you’re not, please feel free to skip this article.

Plan

The plan for this article is as follows.

Scaffold a .NET console project.
Implementing the gRPC client.
Communicating with the server.

In a nutshell, we will be generating the client for the server we built in our previous post.


?  As always, all the code samples documentation can be found at: https://github.com/sahansera/dotnet-grpc

Prerequisites

.NET 6 SDK
Visual Studio Code or IDE of your choice
gRPC compiler

Please note that I’m using some of the commands that are macOS specific. Please follow this link to set it up if you are on a different OS.

To install Protobuf compiler:

brew install protobuf

Project Structure

We can use .NET’s tooling to generate a sample gRPC project. Run the following command at the root of your workspace. Remember how we used dotnet new grpc command to scaffold the server project? For this one though, it can simply be a console app.

dotnet new console -o BookshopClient

Your project structure should look like this.


You must be wondering if this is a console app how does it know how to generate the client stubs? Well, it doesn’t. You have to add the following packages to the project first.

dotnet add BookshopClient.csproj package Grpc.Net.Client
dotnet add BookshopClient.csproj package Google.Protobuf
dotnet add BookshopClient.csproj package Grpc.Tools

Once everything’s installed, we can proceed with the rest of the steps.

Generating the client stubs

We will be using the same Protobuf files that we generated in our previous step. If you haven’t seen that already head over to my previous post.

Open up the BookshopClient.csproj file you need to add the following lines:


<ItemGroup>
<Protobuf Include=../proto/bookshop.proto GrpcServices=Client />
</ItemGroup>

As you can see we will be reusing our Bookshop.proto file. in this example too. One thing to note here is that we have updated the GrpcServices attribute to be Client.

Implementing the gRPC client

Let’s update the Program.cs file to connect to and get the response from the server.

using System.Threading.Tasks;
using Grpc.Net.Client;
using Bookshop;

// The port number must match the port of the gRPC server.
using var channel = GrpcChannel.ForAddress(“http://localhost:5000”);
var client = new Inventory.InventoryClient(channel);
var reply = await client.GetBookListAsync(new GetBookListRequest { });

Console.WriteLine(“Greeting: “ + reply.Books);
Console.WriteLine(“Press any key to exit…”);
Console.ReadKey();

This is based on the example given on the Microsoft docs site btw. What I really like about the above code is how easy it is to read. So here’s what happens.


We first create a gRPC channel with GrpcChannel.ForAddress to the server by giving its URI and port. A client can reuse the same channel object to communicate with a gRPC server. This is an expensive operation compared to invoking a gRPC method on the server. You can also pass in a GrpcChannelOptions object as the second parameter to define client options. Here’s a list for that.
Then we use the auto-generated method Inventory.InventoryClient by leveraging the channel we created above. One thing to note here is that, if your server has multiple services, you can still use the same channel object for all of those.
We call the GetBookListAsync on our server. By the way, this is a Unary call, we will go through other client-server communication mechanisms in a separate post.
Our GetBookList method gets called on the server and returns the list of books.

Now that we know how the requests work, let’s see this in action.

Communicating with the server

Let’s spin up the server that we built in my previous post first. This will be up and running at port 5000.

dotnet run –project BookshopServer/BookshopServer.csproj


For the client-side, we invoke a similar command.

dotnet run –project BookshopClient/BookshopClient.csproj

And in the terminal, we will get the following outputs.


Nice! as you can see it’s not that hard to get everything working ? One thing to note is that we left out the details about TLS and different ways to communicate with the server (i.e. Unary, streaming etc.). I will cover such topics in-depth in the future.

Conclusion

In this article, we looked at how to reuse our Protobuf files to create a client to interact with the server we created in the previous post.

I hope this article series cleared up a lot of confusion that you had about gRPC. Please feel free to share your questions, thoughts, or feedback in the comments section below. Until next time ?

References

https://docs.microsoft.com/en-us/aspnet/core/tutorials/grpc/grpc-start?view=aspnetcore-6.0&tabs=visual-studio-code

Flatlogic Admin Templates banner

Building a gRPC Client in Go

Introduction

In this article, we will take a look at how to create a simple gRPC client with Go. We will be using this client to interact with the gRPC server that we created in my previous post. So let’s get into it!

Motivation

This is the second part of an articles series on gRPC. If you want to jump ahead, please feel free to do so. The links are down below.

Introduction to gRPC
Building a gRPC server with Go
Building a gRPC client with .NET

Building a gRPC client with Go (You are here)
Building a gRPC client with .NET

Please note that this is intended for anyone who’s interested in getting started with gRPC, therefore, we will keep things simple.

Plan

The plan for this article is as follows.

Scaffold the client-side stubs and go modules
Implementing the gRPC client
Communicating with the server

In a nutshell, we will be generating the client for the server we built in our previous post.


In the above diagram, we will look at how to achieve the components on the left side.

? As always, the completed code can be found at: https://github.com/sahansera/go-grpc/tree/main/client

Creating client-side Stubs and Go modules

We will be using the same Protobuf files that we generated in our previous step. If you haven’t seen that already head over to my previous post.

We will create a new folder called client at the root of the project and initialize it with a new Go module.

mkdir client && cd client
go mod init bookshop/client

Once we have the go modules we can now generate the Protobufs for the client side.

protoc –proto_path=proto proto/*.proto –go_out=client –go-grpc_out=client

This is very similar to our previous blog post.


Implementing the gRPC client

Now that we have the modules we can go and implement the code for the client.

In order for us to talk to the server, we first need to create a connection. For that, we can use the grpc.Dial() method.

? Note that we are not using TLS here, however, in production environments you must!

The rough skeleton of the client code looks like the following.

main.go

// …
func main() {
conn, err := grpc.Dial(“localhost:8080”, grpc.WithTransportCredentials(insecure.NewCredentials()))

// Code removed for brevity

client := pb.NewInventoryClient(conn)

// Note how we are calling the GetBookList method on the server
// This is available to us through the auto-generated code
bookList, err := client.GetBookList(context.Background(), &pb.GetBookListRequest{})

log.Printf(“book list: %v”, bookList)
}


The explanation of this code is as follows:

grpc.Dial is a way to create a client connection to a given target. In our case, we can send in the path of our server along with its port. Note how we are passing in an option to turn off TLS by using WithTransportCredentials

We then call the server procedure/method just as you’d normally do when calling a local method in your program. This is the thing that sold me on gRPC because we know exactly what we have to pass and how to invoke the call.
Now on the server side, we have a request handler that will respond to the incoming requests.
We finally log the response that we got from the server.

Communicating with the server

And in the terminal, we will get the following outputs.


Nice! as you can see it’s not that hard to get everything working ? One thing to note is that we left out the details about TLS. But I guess, that will be posted for another day ?

Conclusion

In this article, we looked at how to reuse our Protobuf files to create a client to interact with the server we created in the previous post.

I hope this article cleared up a lot of confusion that you had about gRPC. Please feel free to share your questions, thoughts, or feedback in the comments section below. Until next time ?

References

https://www.youtube.com/watch?v=RHWwMrR8LUs&ab_channel=NicJackson
https://learning.oreilly.com/library/view/grpc-up-and/9781492058328/
https://grpc.io/docs/languages/go/basics/#client

Flatlogic Admin Templates banner

Building a gRPC Server in .NET

Introduction

In this article, we will look at how to build a simple web service with gRPC in .NET. We will keep our changes to minimal and leverage the same Protocol Buffer IDL we used in my previous post. We will also go through some common problems that you might face when building a gRPC server in .NET.

Motivation

For this article also we will be using the Online Bookshop example and leveraging the same Protobufs as we saw before. For those who aren’t familiar with or missed this series, you can find them from here.

Introduction to gRPC
Building a gRPC server with Go

Building a gRPC server with .NET (You are here)
Building a gRPC client with Go
Building a gRPC client with .NET

We will be covering steps 1 and 2 in the following diagram.


Plan

So this is what we are trying to achieve.

Generate the .proto IDL stubs.
Write the business logic for our service methods.
Spin up a gRPC server on a given port.

In a nutshell, we will be covering the following items on our initial diagram.

?  As always, all the code samples documentation can be found at: https://github.com/sahansera/dotnet-grpc

Prerequisites

.NET 6 SDK
Visual Studio Code or IDE of your choice
gRPC compiler

Please note that I’m using some of the commands that are macOS specific. Please follow this link to set it up if you are on a different OS.

To install Protobuf compiler:

brew install protobuf

Project Structure

We can use the the .NET’s tooling to generate a sample gRPC project. Run the following command in at the root of your workspace.

dotnet new grpc -o BookshopServer

Once you run the above command, you will see the following structure.


We also need to configure the SSL trust:

dotnet dev-certs https –trust

As you might have guessed, this is like a default template and it already has a lot of things wired up for us like the Protos folder.

Generating the server stubs

Usually, we would have to invoke the protocol buffer compiler to generate the code for the target language (as we saw in my previous article). However, for .NET they have streamlined the code generation process. They use the Grpc.Tools NuGet package with MSBuild to provide automatic code generation, which is pretty neat! ?

If you open up the Bookshop.csproj file you will find the following lines:


<ItemGroup>
<Protobuf Include=Protosgreet.proto GrpcServices=Server />
</ItemGroup>

We are going to replace greet.proto with our Bookshop.proto file.


We will also update our csproj file like so:

<ItemGroup>
<Protobuf Include=../proto/bookshop.proto GrpcServices=Server />
</ItemGroup>

Implementing the Server

The implementation part is easy! Let’s clean up the GreeterService that comes default and add a new file called InventoryService.cs

rm BookshopServer/Services/GreeterService.cs
code BookshopServer/Services/InventoryService.cs

This is what our service is going to look like.

InventoryService.cs


Let’s go through the code step by step.

Inventory.InventoryBase is an abstract class that got auto-generated (in your obj/debug folder) from our protobuf file.

GetBookList method’s stub is already generated for us in the InventoryBase class and that’s why we are overriding it. Again, this is the RPC call we defined in our protobuf definition. This method takes in a GetBookListRequest which defines what the request looks like and a ServerCallContext param which contains the headers, auth context etc.
Rest of the code is pretty easy – we prepare the response and return it back to the caller/client. It’s worth noting that we never defined the GetBookListRequest GetBookListResponse types ourselves, manually. The gRPC tooling for .NET has already created these for us under the Bookshop namespace.

Make sure to update the Program.cs to reflect the new service as well.

// …
app.MapGrpcService<InventoryService>();
// …

And then we can run the server with the following command.

dotnet run –project BookshopServer/BookshopServer.csproj


We are almost there! Remember we can’t access the service yet through the browser since browsers don’t understand binary protocols. In the next step, we will to test our service ?

Common Errors

A common error you’d find on macOS systems with .NET is HTTP/2 and TLS issue shown below.


gRPC template uses TLS by default and Kestrel doesn’t support HTTP/2 with TLS on macOS systems. We need to turn off TLS (ouch!) in order for our demo to work.

? Please don’t do this in production! This is intended for local development purposes only.

On local development

// Turn off TLS
builder.WebHost.ConfigureKestrel(options =>
{
// Setup a HTTP/2 endpoint without TLS.
options.ListenLocalhost(5000, o => o.Protocols =
HttpProtocols.Http2);
});

Testing the service

Usually, when interacting with the HTTP/1.1-like server, we can use cURL to make requests and inspect the responses. However, with gRPC, we can’t do that. (you can make requests to HTTP/2 services, but those won’t be readable). We will be using gRPCurl for that.

Once you have it up and running, you can now interact with the server we just built.

grpcurl -plaintext localhost:8080 Inventory/GetBookList

? Note: gRPC defaults to TLS for transport. However, to keep things simple, I will be using the `-plaintext` flag with `grpcurl` so that we can see a human-readable response.

How do we figure out the endpoints of the service? There are two ways to do this. One is by providing a path to the proto files, while the other option enables reflection through the code.

Using proto files

If you don’t want to enable reflection, we can use the Protobuf files to let gRPCurl know which methods are available. Normally, when a team makes a gRPC service they will make the protobuf files available if you are integrating with them. So, without having to ask them or doing trial-and-error you can use these proto files to introspect what kind of endpoints are available for consumption.

grpcurl -import-path Proto -proto bookshop.proto -plaintext localhost:5000 Inventory/GetBookList


Now, let’s say we didn’t have reflection enabled and try to call a method on the server.

grpcurl -plaintext localhost:5000 Inventory/GetBookList

We can expect that it will error out. Cool!


Enabling reflection

While in the BookshopServer folder run the following command to install the reflection package.

dotnet add package Grpc.AspNetCore.Server.Reflection

Add the following to the Program.cs file. Note that we are using the new Minimal API approach to configure these services

// Register services that enable reflection
builder.Services.AddGrpcReflection();

// Enable reflection in Debug mode.
if (app.Environment.IsDevelopment())
{
app.MapGrpcReflectionService();
}


Conclusion

As we have seen, similar to the Go implementation, we can use the same Protocol buffer files to generate the server implementation in .NET. In my opinion .NET’s new tooling makes it easier to generate the server stubs when a change happens in your Protobufs. However, setting up the local developer environment could be a bit challenging especially for macOS.

Feel free to let me know if you have any questions or feedback. Until next time! ?

References

https://docs.microsoft.com/en-us/aspnet/core/tutorials/grpc/grpc-start?view=aspnetcore-6.0&tabs=visual-studio-code
https://grpc.io/docs/languages/csharp/quickstart/
https://docs.microsoft.com/en-us/aspnet/core/grpc/troubleshoot?view=aspnetcore-6.0#unable-to-start-aspnet-core-grpc-app-on-macos
https://docs.microsoft.com/en-us/aspnet/core/migration/50-to-60-samples?view=aspnetcore-6.0

Flatlogic Admin Templates banner

Building a gRPC Server in Go

Intro

In this article, we will create a simple web service with gRPC in Go. We won’t use any third-party tools and only create a single endpoint to interact with the service to keep things simple.

Motivation

This is the second part of an articles series on gRPC. If you want to jump ahead, please feel free to do so. The links are down below.

Introduction to gRPC
Building a gRPC server with Go (You are here)
Building a gRPC server with .NET
Building a gRPC client with Go
Building a gRPC client with .NET

The plan

So this is what we are trying to achieve.

Generate the .proto IDL stubs.
Write the business logic for our service methods.
Spin up a gRPC server on a given port.

In a nutshell, we will be covering the following items on our initial diagram.


? As always, all the code samples documentation can be found at: [https://github.com/sahansera/go-grpc](https://github.com/sahansera/go-grpc)

Prerequisites

This guide targets Go and assumes you have the necessary go tools installed locally. Other than that, we will cover gRPC specific tooling down below. Please note that I’m using some of the commands that are macOS specific. Please follow this link to set it up if you are on a different OS.

To install Protobuf compiler:

brew install protobuf

To install Go specific gRPC dependencies:

go install http://google.golang.org/protobuf/cmd/[email protected]
go install http://google.golang.org/grpc/cmd/[email protected]

Project structure

There is no universally agreed-upon project structure per se. We will use Go modules and start by initializing a new project. So our business problem is this – we have a bookstore and we want to expose its inventory via an RPC function.

Since this talks about the creation of the server, we will call it bookshop/server

We can create a new folder called server for the server and initialize it by so:

go mod init bookshop/server

In a later post, we will also work on the client-side of this app and call it bookshop/client

This is what it’s going to look like at the end of this post.


Creating the service definitions with .proto files

In my previous post, we discussed what are Protobufs and how to write one. We will be using the same example which is shown below.

A common pattern to note here is to keep your .proto files in their separate folder, so that use them to generate the server and client stubs.

bookshop.proto

syntax = “proto3”;

option go_package = “bookshop/pb”;

message Book {
string title = 1;
string author = 2;
int32 page_count = 3;
optional string language = 4;
}

message GetBookListRequest {}
message GetBookListResponse { repeated Book books = 1; }

service Inventory {
rpc GetBookList(GetBookListRequest) returns (GetBookListResponse) {}
}

Note how we have used the [option](https://developers.google.com/protocol-buffers/docs/proto#options) keyword here. We are essentially saying the Protobuf compiler where we want to put the generated stubs. You can have multiple option statements depending on which languages you are using to generate the stubs for.

? You can find a full list of allowed values at [google/protobuf/descriptor.proto](https://github.com/protocolbuffers/protobuf/blob/2f91da585e96a7efe43505f714f03c7716a94ecb/src/google/protobuf/descriptor.proto#L44)

Other than that, we have 3 messages to represent a Book entity, a request and a response, respectively. Finally we have a service defined called Inventory which has a RPC named GetBookList which can be called by the clients.

If you need to understand how this is structured, please refer to my previous post ?

Generating the stubs

Now that we have the IDL created we can generate the Go stubs for our server. It is a good practice to put it under the make gen command so that we can easily generate them with a single command in the future.

protoc –proto_path=proto proto/*.proto –go_out=. –go-grpc_out=.

Once this is done, you will see the generated files under the server/pb folder.


Awesome! ? now we can use these subs in our server to respond to any incoming requests.

Creating the gRPC server

Now, we will create the main.go file to create the server.

main.go

type server struct {
pb.UnimplementedInventoryServer
}

func (s *server) GetBookList(ctx context.Context, in *pb.GetBookListRequest) (*pb.GetBookListResponse, error) {
return &pb.GetBookListResponse{
Books: getSampleBooks(),
}, nil
}

func main() {
listener, err := net.Listen(“tcp”, “:8080”)
if err != nil {
panic(err)
}

s := grpc.NewServer()
pb.RegisterInventoryServer(s, &server{})
if err := s.Serve(listener); err != nil {
log.Fatalf(“failed to serve: %v”, err)
}
}

We first define a struct to represent our server. The reason why we need to embed pb.UnimplementedInventoryServer is to maintain future compatibility when generating gRPC bindings for Go. You can read more on this in this initial proposal and on README.
As we discussed, GetBookList can be called by the clients, and this is where that request will be handled. We have access to context (such as auth tokens, headers etc.) and the request object we defined.
In the main method, we are creating a listening on TCP port 8080 with the net.Listen method, initialize a new gRPC server instance, register our Inventory service and then start responding to incoming requests.

Interacting with the Server

Usually, when interacting with the HTTP/1.1-like server, we can use cURL to make requests and inspect the responses. However, with gRPC, we can’t do that. (you can make requests to HTTP/2 services, but those won’t be readable). We will be using gRPCurl for that.

Once you have it up and running, you can now interact with the server we just built.

grpcurl -plaintext localhost:8080 Inventory/GetBookList

? Note: gRPC defaults to TLS for transport. However, to keep things simple, I will be using the `-plaintext` flag with `grpcurl` so that we can see a human-readable response.


How do we figure out the endpoints of the service? There are two ways to do this. One is by providing a path to the proto files, while the other option enables reflection through the code.

Enabling reflection

This is a pretty cool feature, where it will give you introspection capabilities to your API.

reflection.Register(gs)

Following screenshot displays some of the commands you can use to introspect the API.


grpcurl -plaintext -msg-template localhost:8080 describe .GetBookListResponse

Using proto files

If you don’t want to to enable it by code we can use the Protobuf files to let gRPCurl know which methods are available. Normally, when a team makes a gRPC service they will make the protobuf files available if you are integrating with them. So, without having to ask them or doing trial-and-error you can use these proto files to introspect what kind of endpoints are available for consumption.

grpcurl -import-path proto -proto bookshop.proto list

gRPCurl is great if you want to debug your RPC calls if you don’t have your client built yet.

Conclusion

In this article we looked at how we can create a simple gRPC server with Go. In the next one we will learn how to do the same with .NET.

Feel free to let me know any feedback or questions. Thanks for reading ✌️

References

https://medium.com/@nate510/structuring-go-grpc-microservices-dd176fdf28d0
https://www.youtube.com/watch?v=RHWwMrR8LUs&ab_channel=NicJackson
https://www.oreilly.com/library/view/grpc-up-and/9781492058328/

Flatlogic Admin Templates banner

Introduction to gRPC

Intro

If you have built RESTful or other OpenAPI-like APIs for some time and wondering what’s next for you, then you have come to the right place. This article series discusses leveraging gRPC to build your next API, even multiple services. We will initially look at the main concepts from a high-level view and then move on to the implementation aspects of it.

Motivation

There are many tutorials on getting started there. But the main issue I faced was either, they even made me more confused as there was a lot of contexts lost in the process and brought in way too many third-party libraries or explained a bunch of steps without emphasizing how different pieces work together. Therefore, I thought to create a guide for anyone who’s interested in getting started with gRPC from a hands-on perspective.

This article is the first part of a series on gRPC. The links are down below. If you want to jump ahead, please feel free to do so.

Introduction to gRPC (You are here)
Building a gRPC server with Go
Building a gRPC server with .NET
Building a gRPC client with Go
Building a gRPC client with .NET

Background

One of the popular choices for building APIs nowadays is creating a RESTful service. However, before even coming to REST API, we need to look back to see other forms we used to have in the past.

SOAP – Popular back in the late-90s for building service-oriented architectures (SOA) systems which are known for exchanging bloated XMLs. The benefits were detrimental for distributed applications where the schema was rigid.

REST – Promoted the resource-oriented architecture (ROA)-style distributed applications. Often bulky with JSONs, and everything that the service provides is represented as resources (Eg: /api/v1/users/ or api/v1/books/1234 etc.). Sometimes this could result in too exposing too little data or too much data at the cost of making multiple HTTP calls.

GraphQL – GraphQL takes a step further and exposes a single endpoint that you can use to query or mutate the data through HTTP verbs. It’s still a request-response model and based on the text-based transport protocol, HTTP 1.x.

What if I want to have some bi-directional communication? None of the above solved that. Then we got technologies like WebSockets and Server Sent Eventing.

WebSockets – Built to support bi-directional communication over a single TCP connection. Known to be a very chatty protocol often sending packets back and forth. If you want to know about WebSockets, here is an article that I wrote.

Server Sent Eventing – Another paradigm where the server sends messages to the client once the initial connection has been set up by the client.

There’s a recurring theme going on in the above technologies. It could be issued with messages being (bulky, not strongly typed etc.), inefficient protocols (text-based such as HTTP 1.x etc.).

Hello gRPC

gRPC was born to address some of the challenges we face in the above approaches. In 2015 Google released gRPC to the open-source world. The idea behind gRPC is to have a single client library – Whoever is maintaining gRPC will maintain the client libraries. Because HTTP/2 works on binary format. So the idea is to abstract away the HTTP/2 stuff from you. The developers only have to define their service contracts through requests, responses and RPC calls, and the gRPC framework will handle the rest for us.

? Even before we start learning about gRPC, you must have also thought about what the “g” in GRPC mean? Some say it stands for “Good”; others say it stands for “Google”. You know what? It doesn’t matter as it doesn’t provide more context. You can find all the different variations here, which is, by the way, hilarious! ?


Source: https://grpc.io/docs/what-is-grpc/introduction/

RPC has been around for some time; however, gRPC approaches RPC much cleaner way.

Another term that you’d come across when learning gRPC is inter-process communication or IPCs. GRPC is mainly built to cater to inter-process communication that lets you connect, invoke, and operate, an excellent choice for micro-services like applications. In distributed computing realm, inter-process communication or, in short, IPC refers to passing messages (synchronously or asynchronously) where any application or a node can act as both client and a server.

Does this mean I should replace my current APIs, which are customer-facing? Absolutely not. If you have customer-facing APIs, they should be actually

Protocol Buffers

They are a language-agnostic way to define what your service does. These are commonly known as “IDLs” or Interface Definition Language(s).

So the steps are,

You write the messages. These messages have statically typed fields
You write your services by defining what comes in, what goes out
Compile the proto files and generate the client libraries for your application

It’s also worth mentioning that Protocol Buffers are not the only way to define our IDLs. There are other formats like FlatBuffers, Bond etc.

This is what a protocol buffer looks like:

syntax = “proto3”;

message Book {
string title = 1;
string author = 2;
int32 page_count = 3;
optional string language = 4;
}

message GetBookListRequest {}
message GetBookListResponse { repeated Book books = 1; }

service Inventory {
rpc GetBookList(GetBookListRequest) returns (GetBookListResponse) {}
}

The above is an example that we will use throughout this blog series.


The first line specifies the Protobuf version we will be using. It will be set to proto2 if you don’t specify it.
The Book is a message definition with some statically typed fields such as title, author etc.

GetBookListRequest and GetBookListResponse are also messages composed of the Book type we defined above.
Inventory is a service that says what methods we expose to the remotely invoked clients.

There are many advantages of using Protobufs compared to something like JSON. Once you write the definitions for your service, you can share them with other teams and use them to generate stubs/code that can interact with your service.

Another advantage is that Protobufs are binary encoded. The payload is smaller than JSON, which means it would be efficient to send. This also means that it will use fewer CPU cycles to serialize/deserialize the messages.

gRPC Server & Client

Now that we have the Protobuf definitions for our service, we could generate the Server side and Client side implementations using the Protoc compiler.


We first create the definition of the service with a .proto file
We then generate the server-side code in our preferred language (Go, C#, Java etc.). This code includes the boilerplate code to serialize, deserialize, functions for receiving and responding to messages.
We then generate the client-side code in our preferred language (doesn’t have to be the same language we chose for the server). This includes methods that we can invoke on our server with additional code to serialize, deserialize messages.
Depending on which gRPC mode we choose, the client-server communication happens over an HTTP/2 connection. We will discuss more on these modes in the next section.

gRPC Modes

There are 4 modes of gRPC communication styles. Following are their brief introductions. Feel free to go more in-depth by reading through the official docs.

Unary RPC – More like our traditional APIs where we send a request and receive a single response.
Server Streaming RPC – Client sends a request and reads until the server stops sending messages via a stream.
Client Streaming – Reverse of the above, the client sends messages through the stream and waits for the server to read and return a response.
Bidirectional streaming RPC – Pretty much both (2) & (3) combined – both client and server streams messages both ways.

Pros and Cons

Any technology comes with a set of advantages and disadvantages. Whether you choose to use gRPC might depend on some of these factors.

Pros

Efficient for inter-process communication with all the good stuff that comes with HTTP/2.
Well defined interfaces to be able to communicate also while supporting polyglot development.
Code-generation of client and server stubs with strong types.

Cons

It may not be suitable for external-facing services since most web browsers’ support is limited.
Changing the service definitions might require rework and regeneration of code.
Could be a steeper learning curve compared to other RESTful or GQL like architectural styles.

Conclusion

In this article, we looked at gRPC from a high level. In the next article, we will look at how we can put these into action and generate a gRPC service with Go. Feel free to let me know any feedback or questions. Thanks for reading ✌️

References

https://developers.google.com/protocol-buffers/docs/proto3
https://www.oreilly.com/library/view/grpc-up-and/9781492058328/

https://github.com/grpc-ecosystem/awesome-grpcyou

Flatlogic Admin Templates banner

What’s new for gRPC in .NET 6

gRPC is a modern, cross-platform, high-performance RPC framework. gRPC for .NET is built on top of ASP.NET Core and is our recommended way to build RPC services using .NET.

.NET 6 further improves gRPC’s already great performance and adds a new range of features that make gRPC better than ever in modern cloud-native apps. In this post I’ll describe these new features as well as how we are leading the industry with the first gRPC implementation to support end-to-end HTTP/3.

gRPC client-side load balancing

Client-side load balancing is a feature that allows gRPC clients to distribute load optimally across available servers. Client-side load balancing can eliminate the need to have a proxy for load balancing. This has several benefits:

Improved performance. No proxy means eliminating an additional network hop and reduced latency because RPCs are sent directly to the gRPC server.

Efficient use of server resources. A load-balancing proxy must parse and then resend every HTTP request sent through it. Removing the proxy saves CPU and memory resources.

Simpler application architecture. Proxy server must be set up and configured correctly. No proxy server means fewer moving parts!

Client-side load balancing is configured when a channel is created. The two components to consider when using load balancing:

The resolver, which resolves the addresses for the channel. Resolvers support getting addresses from an external source. This is also known as service discovery.
The load balancer, which creates connections and picks the address that a gRPC call will use.

The following code example configures a channel to use DNS service discovery with round-robin load balancing:

var channel = GrpcChannel.ForAddress(
“dns:///my-example-host”,
new GrpcChannelOptions
{
Credentials = ChannelCredentials.Insecure,
ServiceConfig = new ServiceConfig { LoadBalancingConfigs = { new RoundRobinConfig() } }
});
var client = new Greet.GreeterClient(channel);

var response = await client.SayHelloAsync(new HelloRequest { Name = “world” });

For more information, see gRPC client-side load balancing.

Transient fault handling with retries

gRPC calls can be interrupted by transient faults. Transient faults include:

Momentary loss of network connectivity.
Temporary unavailability of a service.
Timeouts due to server load.

When a gRPC call is interrupted, the client throws an RpcException with details about the error. The client app must catch the exception and choose how to handle the error.

var client = new Greeter.GreeterClient(channel);
try
{
var response = await client.SayHelloAsync(
new HelloRequest { Name = “.NET” });

Console.WriteLine(“From server: ” + response.Message);
}
catch (RpcException ex)
{
// Write logic to inspect the error and retry
// if the error is from a transient fault.
}

Duplicating retry logic throughout an app is verbose and error-prone. Fortunately, the .NET gRPC client now has built-in support for automatic retries. Retries are centrally configured on a channel, and there are many options for customizing retry behavior using a RetryPolicy.

var defaultMethodConfig = new MethodConfig
{
Names = { MethodName.Default },
RetryPolicy = new RetryPolicy
{
MaxAttempts = 5,
InitialBackoff = TimeSpan.FromSeconds(1),
MaxBackoff = TimeSpan.FromSeconds(5),
BackoffMultiplier = 1.5,
RetryableStatusCodes = { StatusCode.Unavailable }
}
};

// Clients created with this channel will automatically retry failed calls.
var channel = GrpcChannel.ForAddress(“https://localhost:5001”, new GrpcChannelOptions
{
ServiceConfig = new ServiceConfig { MethodConfigs = { defaultMethodConfig } }
});

For more information, see Transient fault handling with gRPC retries.

Protobuf performance

gRPC for .NET uses the Google.Protobuf package as the default serializer for messages. Protobuf is an efficient binary serialization format. Google.Protobuf is designed for performance, using code generation instead of reflection to serialize .NET objects. In .NET 5 we worked with the Protobuf team to add support for modern memory APIs such as Span<T>, ReadOnlySequence<T>, and IBufferWriter<T> to the serializer. The improvements in .NET 6 optimize an already fast serializer.

protocolbuffers/protobuf#8147 adds vectorized string serialization. SIMD instructions allow multiple characters to be processed in parallel, dramatically increasing performance when serializing certain string values.

private string _value = new string(‘ ‘, 10080);
private byte[] _outputBuffer = new byte[10080];

[Benchmark]
public void WriteString()
{
var span = new Span<byte>(_outputBuffer);
WriteContext.Initialize(ref span, out WriteContext ctx);
ctx.WriteString(_value);
ctx.Flush();
}

Method
Google.Protobuf
Mean
Ratio
Allocated

WriteString
3.14
8.838 us
1.00
0 B

WriteString
3.18
2.919 ns
0.33
0 B

protocolbuffers/protobuf#7645 adds a new API for creating ByteString instances. If you know the underlying data won’t change, then use UnsafeByteOperations.UnsafeWrap to create a ByteString without copying the underlying data. This is very useful if an app works with large byte payloads and you want to reduce garbage collection frequency.

var data = await File.ReadAllBytesAsync(@”c:large_file.json”);

// Safe but slow.
var copied = ByteString.CopyFrom(data);

// Unsafe but fast. Useful if you know data won’t change.
var wrapped = UnsafeByteOperations.UnsafeWrap(data);

gRPC download speeds

gRPC users reported sometimes getting slow download speeds. Our investigation discovered that HTTP/2 flow control was constraining downloads when there is latency between the client and server. The server fills the receive buffer window before the client can drain it, causing the server to pause sending data. gRPC messages are downloaded in start/stop bursts.

This is fixed in dotnet/runtime#54755. HttpClient now dynamically scales the receive buffer window. When an HTTP/2 connection is established, the client will send a ping to the server to measure latency. If there is high latency, the client automatically increases the receive buffer window, enabling a fast, continuous download.

private GrpcChannel _channel = GrpcChannel.ForAddress(…);
private DownloadClient _client = new DownloadClient(_channel);

[Benchmark]
public Task GrpcLargeDownload() =>
_client.DownloadLargeMessageAsync(new EmptyMessage());

Method
Runtime
Mean
Ratio

GrpcLargeDownload
.NET 5.0
6.33 s
1.00

GrpcLargeDownload
.NET 6.0
1.65 s
0.26

HTTP/3 support

gRPC on .NET now supports HTTP/3. gRPC builds on top of HTTP/3 support added to ASP.NET Core and HttpClient in .NET 6. For more information, see HTTP/3 support in .NET 6.

.NET is the first gRPC implementation to support end-to-end HTTP/3, and we have submitted a gRFC for other platforms to support HTTP/3 in the future. gRPC with HTTP/3 is a highly requested feature by the developer community, and it is exciting to see .NET leading the way in this area.

Wrapping Up

Performance is a feature of .NET and gRPC, and .NET 6 is faster than ever. New performance-orientated features like client-side load balancing and HTTP/3 mean lower latency, higher throughput, and fewer servers. It is an opportunity to save money, reduce power use and build greener cloud-native apps.

To try out the new features and get started using gRPC with .NET, the best place to start is the Create a gRPC client and server in ASP.NET Core tutorial.

We look forward to hearing about apps built with gRPC and .NET and to your future contributions in the dotnet and grpc repos!

The post What’s new for gRPC in .NET 6 appeared first on .NET Blog.