Skip to content

Instantly share code, notes, and snippets.

@devops-school
Created December 1, 2025 05:44
Show Gist options
  • Select an option

  • Save devops-school/7b69d2f33d972b9b71911033a37eeae9 to your computer and use it in GitHub Desktop.

Select an option

Save devops-school/7b69d2f33d972b9b71911033a37eeae9 to your computer and use it in GitHub Desktop.
DOTNET: RPC with GRPC and REST and its Performance Impact
using System.Diagnostics;
using System.Net.Http.Json;
using Grpc.Net.Client;
using RpcPerfDemo.Grpc;
// Simple POCO matching REST response shape
public class RestPerfResponse
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public List<int> Values { get; set; } = new();
public long ProcessedAtTicks { get; set; }
}
class Program
{
// Adjust if your server prints a different URL on startup
private const string ServerAddress = "https://localhost:5001";
private const int Iterations = 1000;
static async Task Main(string[] args)
{
Console.WriteLine("=== RPC Performance Demo: REST vs gRPC ===");
Console.WriteLine($"Server address: {ServerAddress}");
Console.WriteLine($"Total requests per style: {Iterations}");
Console.WriteLine();
// 1. Test REST (JSON)
await RunRestBenchmark();
Console.WriteLine();
// 2. Test gRPC (Protobuf)
await RunGrpcBenchmark();
Console.WriteLine();
Console.WriteLine("Done.");
}
private static async Task RunRestBenchmark()
{
using var httpClient = new HttpClient { BaseAddress = new Uri(ServerAddress) };
// Warm-up
Console.WriteLine("Warming up REST endpoint...");
var warmupResponse = await httpClient.GetAsync("/rest/perf");
warmupResponse.EnsureSuccessStatusCode();
// Measure payload size of one response
var sampleContent = await warmupResponse.Content.ReadAsStringAsync();
var restPayloadBytes = System.Text.Encoding.UTF8.GetByteCount(sampleContent);
Console.WriteLine($"Sample REST JSON payload size: {restPayloadBytes} bytes");
Console.WriteLine("Running REST benchmark...");
var sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
var response = await httpClient.GetAsync("/rest/perf");
response.EnsureSuccessStatusCode();
// We don't actually use the data, just ensure it's read
_ = await response.Content.ReadAsStringAsync();
}
sw.Stop();
var totalMs = sw.Elapsed.TotalMilliseconds;
var avgMs = totalMs / Iterations;
Console.WriteLine($"REST total time: {totalMs:F2} ms for {Iterations} requests");
Console.WriteLine($"REST avg per request: {avgMs:F4} ms");
}
private static async Task RunGrpcBenchmark()
{
// gRPC requires HTTP/2 – HTTPS endpoint from ASP.NET Core is fine
using var channel = GrpcChannel.ForAddress(ServerAddress);
var client = new PerfService.PerfServiceClient(channel);
// Warm-up
Console.WriteLine("Warming up gRPC endpoint...");
var warmupResponse = await client.GetDataAsync(new PerfRequest
{
Id = 1,
Name = "Warmup"
});
// Measure Protobuf payload size
var grpcPayloadBytes = warmupResponse.CalculateSize();
Console.WriteLine($"Sample gRPC Protobuf payload size: {grpcPayloadBytes} bytes");
Console.WriteLine("Running gRPC benchmark...");
var sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
var response = await client.GetDataAsync(new PerfRequest
{
Id = i,
Name = "Test-" + i
});
// No need to use result; just ensure call completes
}
sw.Stop();
var totalMs = sw.Elapsed.TotalMilliseconds;
var avgMs = totalMs / Iterations;
Console.WriteLine($"gRPC total time: {totalMs:F2} ms for {Iterations} requests");
Console.WriteLine($"gRPC avg per request: {avgMs:F4} ms");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment