gRPC для C# (.NET): библиотеки, настройка и примеры кода

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

gRPC для C# (.NET): библиотеки и примеры

gRPC — это современный высокопроизводительный фреймворк для удалённого вызова процедур (RPC), разработанный Google. Он использует HTTP/2 для транспорта и Protocol Buffers (protobuf) для сериализации данных. В экосистеме .NET gRPC стал основным инструментом для построения микросервисной архитектуры, обеспечивая строгую типизацию, двунаправленную потоковую передачу и низкую задержку. В этой статье мы рассмотрим ключевые библиотеки для работы с gRPC в C# и приведём практические примеры.

Основные библиотеки для gRPC в .NET

Для работы с gRPC в .NET используются следующие пакеты NuGet:

  • Grpc.Net.Client — клиентская библиотека для создания gRPC-клиентов. Работает поверх HttpClient и поддерживает все типы вызовов: unary, server streaming, client streaming и bidirectional streaming.
  • Grpc.AspNetCore.Server — серверная библиотека для интеграции gRPC в ASP.NET Core. Позволяет хостить gRPC-сервисы вместе с обычными REST API.
  • Google.Protobuf — библиотека для работы с Protocol Buffers, генерации и десериализации сообщений.
  • Grpc.Tools — набор инструментов для автоматической генерации C#-кода из .proto файлов во время сборки проекта.

Процесс разработки включает три этапа: описание сервиса в .proto-файле, генерация кода и реализация сервера/клиента.

Пример 1: Простой unary-сервис (запрос-ответ)

Создадим простой сервис для получения информации о пользователе. Для этого определим файл user.proto:

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;
}

Добавьте в проект ссылки на пакеты и .proto-файл. После сборки будут сгенерированы классы UserRequest, UserResponse и базовый класс UserServiceBase.

Реализация сервера

using Grpc.Core;
using User;

public class UserServiceImpl : UserService.UserServiceBase
{
    public override Task<UserResponse> GetUser(UserRequest request, ServerCallContext context)
    {
        var user = new UserResponse
        {
            Name = "Иван Петров",
            Email = "ivan@example.com",
            Age = 30
        };
        return Task.FromResult(user);
    }
}

Запуск сервера в ASP.NET Core:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
var app = builder.Build();
app.MapGrpcService<UserServiceImpl>();
app.Run();

Реализация клиента

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($"Пользователь: {response.Name}, Email: {response.Email}");

Пример 2: Серверная потоковая передача (Server Streaming)

Серверная потоковая передача полезна, когда нужно отправить клиенту множество данных, например, список событий или логи. Дополним наш .proto-файл:

service UserService {
  rpc GetUser (UserRequest) returns (UserResponse);
  rpc ListUsers (Empty) returns (stream UserResponse);
}

message Empty {}

Реализация сервера:

public override async Task ListUsers(Empty request, IServerStreamWriter<UserResponse> responseStream, ServerCallContext context)
{
    var users = new List<UserResponse>
    {
        new UserResponse { Name = "Анна", Email = "anna@test.com" },
        new UserResponse { Name = "Борис", Email = "boris@test.com" }
    };

    foreach (var user in users)
    {
        await responseStream.WriteAsync(user);
        await Task.Delay(1000); // Имитация задержки
    }
}

Клиент для получения потока:

var call = client.ListUsers(new Empty());
await foreach (var user in call.ResponseStream.ReadAllAsync())
{
    Console.WriteLine($"Получен пользователь: {user.Name}");
}

Пример 3: Двунаправленная потоковая передача (Bidirectional Streaming)

Этот тип вызова позволяет клиенту и серверу обмениваться сообщениями независимо. Пример — чат-сервис:

service ChatService {
  rpc Chat (stream ChatMessage) returns (stream ChatMessage);
}

message ChatMessage {
  string user = 1;                    

Рекомендаций