.NET Microservices — gRPC in .NET Microservices
Protobuf, Streaming, APIM gRPC Passthrough
Introduction
gRPC (Google Remote Procedure Call) is a high-performance, language-agnostic protocol that uses Protocol Buffers (protobuf) for serialization. It's ideal for:
- Low-latency communication — Faster than REST
- Streaming — Bidirectional streaming support
- Cross-platform — Multiple language support
- Strong typing — Contract-first development
Protobuf Contract
Define Service
syntax = "proto3";
package order;
service OrderService {
// Unary call
rpc CreateOrder (CreateOrderRequest) returns (OrderResponse);
// Server streaming
rpc GetOrders (GetOrdersRequest) returns (stream Order);
// Client streaming
rpc ProcessBatch (stream OrderItem) returns (BatchResponse);
// Bidirectional streaming
rpc StreamOrderUpdates (stream OrderUpdateRequest) returns (stream OrderUpdate);
}
message CreateOrderRequest {
string customer_id = 1;
repeated OrderItem items = 2;
string shipping_address = 3;
}
message OrderItem {
string product_id = 1;
int32 quantity = 2;
double unit_price = 3;
}
message OrderResponse {
string order_id = 1;
string status = 2;
double total = 3;
google.protobuf.Timestamp created_at = 4;
}
Server Implementation
Create gRPC Service
public class OrderGrpcService : OrderService.OrderServiceBase
{
private readonly IOrderRepository _repository;
private readonly ILogger<OrderGrpcService> _logger;
public OrderGrpcService(
IOrderRepository repository,
ILogger<OrderGrpcService> logger)
{
_repository = repository;
_logger = logger;
}
public override async Task<OrderResponse> CreateOrder(
CreateOrderRequest request,
ServerCallContext context)
{
_logger.LogInformation("Creating order for customer {CustomerId}",
request.CustomerId);
var order = new Order
{
CustomerId = request.CustomerId,
ShippingAddress = request.ShippingAddress,
Items = request.Items.Select(i => new OrderItem
{
ProductId = i.ProductId,
Quantity = i.Quantity,
UnitPrice = i.UnitPrice
}).ToList(),
Status = OrderStatus.Pending,
CreatedAt = DateTime.UtcNow
};
await _repository.CreateAsync(order);
return new OrderResponse
{
OrderId = order.Id.ToString(),
Status = order.Status.ToString(),
Total = order.TotalAmount,
CreatedAt = Google.Protobuf.WellKnownTypes.Timestamp.FromDateTime(order.CreatedAt)
};
}
public override async Task GetOrders(
GetOrdersRequest request,
IServerStreamWriter<Order> responseStream,
ServerCallContext context)
{
var orders = await _repository.GetByCustomerAsync(request.CustomerId);
foreach (var order in orders)
{
if (context.CancellationToken.IsCancellationRequested)
break;
await responseStream.WriteAsync(MapToProto(order));
}
}
}
Configure in Program.cs
builder.Services.AddGrpc(options =>
{
options.MaxReceiveMessageSize = 16 * 1024 * 1024; // 16MB
options.MaxSendMessageSize = 16 * 1024 * 1024;
options.Interceptors.Add<LoggingInterceptor>();
});
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<OrderGrpcService>();
});
Client Implementation
Create gRPC Client
public class OrderGrpcClient
{
private readonly OrderService.OrderServiceClient _client;
public OrderGrpcClient(GrpcChannel channel)
{
_client = new OrderService.OrderServiceClient(channel);
}
public async Task<OrderResponse> CreateOrderAsync(CreateOrderRequest request)
{
return await _client.CreateOrderAsync(request);
}
public async IAsyncEnumerable<Order> GetOrdersStreamAsync(string customerId)
{
var call = _client.GetOrders(new GetOrdersRequest
{
CustomerId = customerId
});
await foreach (var order in call.ResponseStream.ReadAllAsync())
{
yield return order;
}
}
}
APIM gRPC Passthrough
Configure APIM Policy
<backend>
<set-backend-service base-url="grpc://order-service:5001" />
<!-- gRPC to HTTP/2 backend -->
<round-robin>
<address>https://grpc-primary.example.com</address>
<address>https://grpc-secondary.example.com</address>
</round-robin>
</backend>
Best Practices
| Practice | Description |
|---|---|
| Use streaming | For bulk operations |
| Set message limits | Prevent large payloads |
| Add interceptors | Logging, auth, metrics |
| Use channels | Reuse connections |
Azure Integration Hub - Advanced Level