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;