gRPC for C# (.NET): Libraries and Examples
gRPC is a modern high-performance remote procedure call (RPC) framework developed by Google. It uses HTTP/2 for transport and Protocol Buffers (protobuf) for data serialization. In the .NET ecosystem, gRPC has become the primary tool for building microservice architectures, providing strong typing, bidirectional streaming, and low latency. In this article, we will review the key libraries for working with gRPC in C# and provide practical examples.
Main Libraries for gRPC in .NET
The following NuGet packages are used for working with gRPC in .NET:
- Grpc.Net.Client — client library for creating gRPC clients. It works on top of HttpClient and supports all call types: unary, server streaming, client streaming, and bidirectional streaming.
- Grpc.AspNetCore.Server — server library for integrating gRPC into ASP.NET Core. It allows hosting gRPC services alongside regular REST APIs.
- Google.Protobuf — library for working with Protocol Buffers, generating and deserializing messages.
- Grpc.Tools — a set of tools for automatically generating C# code from .proto files during project build.
The development process includes three stages: describing the service in a .proto file, generating code, and implementing the server/client.
Example 1: Simple Unary Service (Request-Response)
Let's create a simple service for retrieving user information. To do this, define the user.proto file:
syntax = "proto3";
package user;
service UserService { rpc GetUser (UserRequest) returns (UserResponse);}
message UserRequest { int32 id = 1;}
message UserResponse { string name = 1; string email = 2; int32 age = 3;}Add package references and the .proto file to the project. After building, the UserRequest, UserResponse classes and the UserServiceBase base class will be generated.
Server Implementation
using Grpc.Core;using User;
public class UserServiceImpl : UserService.UserServiceBase{ public override Task<UserResponse> GetUser(UserRequest request, ServerCallContext context) { var user = new UserResponse { Name = "Ivan Petrov", Email = "ivan@example.com", Age = 30 }; return Task.FromResult(user); }}Starting the server in ASP.NET Core:
var builder = WebApplication.CreateBuilder(args);builder.Services.AddGrpc();var app = builder.Build();app.MapGrpcService<UserServiceImpl>();app.Run();Client Implementation
using Grpc.Net.Client;using User;
var channel = GrpcChannel.ForAddress("https://localhost:5001");var client = new UserService.UserServiceClient(channel);
var response = await client.GetUserAsync(new UserRequest { Id = 1 });Console.WriteLine($"User: {response.Name}, Email: {response.Email}");Example 2: Server Streaming
Server streaming is useful when you need to send a lot of data to the client, such as a list of events or logs. Let's extend our .proto file:
service UserService { rpc GetUser (UserRequest) returns (UserResponse); rpc ListUsers (Empty) returns (stream UserResponse);}
message Empty {}Server implementation:
public override async Task ListUsers(Empty request, IServerStreamWriter<UserResponse> responseStream, ServerCallContext context){ var users = new List<UserResponse> { new UserResponse { Name = "Anna", Email = "anna@test.com" }, new UserResponse { Name = "Boris", Email = "boris@test.com" } };