{"id":54284,"date":"2025-12-01T05:46:17","date_gmt":"2025-12-01T05:46:17","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=54284"},"modified":"2025-12-01T05:46:17","modified_gmt":"2025-12-01T05:46:17","slug":"dotnet-rpc-with-grpc-and-rest-and-its-performance-impact","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/dotnet-rpc-with-grpc-and-rest-and-its-performance-impact\/","title":{"rendered":"DOTNET: RPC with GRPC and REST and its Performance Impact"},"content":{"rendered":"\n<p>Below is a <strong>complete, runnable .NET 8 demo<\/strong> where:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>One server<\/strong> exposes:\n<ul class=\"wp-block-list\">\n<li>A <strong>REST (JSON)<\/strong> endpoint<\/li>\n\n\n\n<li>A <strong>gRPC (Protobuf)<\/strong> endpoint<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>One console client<\/strong>:\n<ul class=\"wp-block-list\">\n<li>Sends <strong>N requests to REST<\/strong><\/li>\n\n\n\n<li>Sends <strong>N requests to gRPC<\/strong><\/li>\n\n\n\n<li>Prints <strong>total time, average latency, and payload sizes<\/strong><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>You\u2019ll be able to <em>feel<\/em> the difference.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">1. Solution structure<\/h2>\n\n\n\n<p>We\u2019ll build this:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">RpcPerfDemo\/\n  RpcPerfDemo.sln\n  RpcPerfDemo.Server\/     (ASP.NET Core \u2013 REST + gRPC)\n    Program.cs\n    Services\/\n      PerfServiceImpl.cs\n    Models\/\n      RestPerfResponse.cs\n    Protos\/\n      perf.proto\n    RpcPerfDemo.Server.csproj\n  RpcPerfDemo.Client\/     (Console \u2013 benchmark client)\n    Program.cs\n    RpcPerfDemo.Client.csproj\n<\/code><\/span><\/pre>\n\n\n<p>Target: <strong>.NET 8.0<\/strong> (works with future .NET 10+ too).<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">2. Step-by-step setup<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 Step 0 \u2013 Prerequisites<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Install <strong>.NET 8 SDK<\/strong> <code>dotnet --version<\/code> Make sure it shows <code>8.x.x<\/code>.<\/li>\n\n\n\n<li>Ensure dev HTTPS cert is trusted (only needed once): <code>dotnet dev-certs https --trust<\/code><\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 Step 1 \u2013 Create solution + projects<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">mkdir RpcPerfDemo\ncd RpcPerfDemo\n\n<span class=\"hljs-comment\"># Create solution<\/span>\ndotnet <span class=\"hljs-keyword\">new<\/span> sln -n RpcPerfDemo\n\n<span class=\"hljs-comment\"># Create server (web app)<\/span>\ndotnet <span class=\"hljs-keyword\">new<\/span> web -n RpcPerfDemo.Server\n\n<span class=\"hljs-comment\"># Create client (console app)<\/span>\ndotnet <span class=\"hljs-keyword\">new<\/span> console -n RpcPerfDemo.Client\n\n<span class=\"hljs-comment\"># Add to solution<\/span>\ndotnet sln add RpcPerfDemo.Server\/RpcPerfDemo.Server.csproj\ndotnet sln add RpcPerfDemo.Client\/RpcPerfDemo.Client.csproj\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 Step 2 \u2013 Add packages<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Server packages<\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">cd<\/span> <span class=\"hljs-selector-tag\">RpcPerfDemo<\/span><span class=\"hljs-selector-class\">.Server<\/span>\n<span class=\"hljs-selector-tag\">dotnet<\/span> <span class=\"hljs-selector-tag\">add<\/span> <span class=\"hljs-selector-tag\">package<\/span> <span class=\"hljs-selector-tag\">Grpc<\/span><span class=\"hljs-selector-class\">.AspNetCore<\/span>\n<span class=\"hljs-selector-tag\">dotnet<\/span> <span class=\"hljs-selector-tag\">add<\/span> <span class=\"hljs-selector-tag\">package<\/span> <span class=\"hljs-selector-tag\">Grpc<\/span><span class=\"hljs-selector-class\">.Tools<\/span>\n<span class=\"hljs-selector-tag\">dotnet<\/span> <span class=\"hljs-selector-tag\">add<\/span> <span class=\"hljs-selector-tag\">package<\/span> <span class=\"hljs-selector-tag\">Google<\/span><span class=\"hljs-selector-class\">.Protobuf<\/span>\n<span class=\"hljs-selector-tag\">cd<\/span> ..\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h4 class=\"wp-block-heading\">Client packages<\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">cd<\/span> <span class=\"hljs-selector-tag\">RpcPerfDemo<\/span><span class=\"hljs-selector-class\">.Client<\/span>\n<span class=\"hljs-selector-tag\">dotnet<\/span> <span class=\"hljs-selector-tag\">add<\/span> <span class=\"hljs-selector-tag\">package<\/span> <span class=\"hljs-selector-tag\">Grpc<\/span><span class=\"hljs-selector-class\">.Net<\/span><span class=\"hljs-selector-class\">.Client<\/span>\n<span class=\"hljs-selector-tag\">dotnet<\/span> <span class=\"hljs-selector-tag\">add<\/span> <span class=\"hljs-selector-tag\">package<\/span> <span class=\"hljs-selector-tag\">Grpc<\/span><span class=\"hljs-selector-class\">.Tools<\/span>\n<span class=\"hljs-selector-tag\">dotnet<\/span> <span class=\"hljs-selector-tag\">add<\/span> <span class=\"hljs-selector-tag\">package<\/span> <span class=\"hljs-selector-tag\">Google<\/span><span class=\"hljs-selector-class\">.Protobuf<\/span>\n<span class=\"hljs-selector-tag\">cd<\/span> ..\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 Step 3 \u2013 Define the Protobuf contract<\/h3>\n\n\n\n<p>Create folder and file:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">mkdir -p RpcPerfDemo.Server\/Protos\n<\/code><\/span><\/pre>\n\n\n<p>Create <strong><code>RpcPerfDemo.Server\/Protos\/perf.proto<\/code><\/strong>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">syntax = <span class=\"hljs-string\">\"proto3\"<\/span>;\n\noption csharp_namespace = <span class=\"hljs-string\">\"RpcPerfDemo.Grpc\"<\/span>;\n\npackage perf;\n\n<span class=\"hljs-comment\">\/\/ Request for performance test<\/span>\nmessage PerfRequest {\n  int32 id = <span class=\"hljs-number\">1<\/span>;\n  string name = <span class=\"hljs-number\">2<\/span>;\n}\n\n<span class=\"hljs-comment\">\/\/ Response from server<\/span>\nmessage PerfResponse {\n  int32 id = <span class=\"hljs-number\">1<\/span>;\n  string name = <span class=\"hljs-number\">2<\/span>;\n  repeated int32 values = <span class=\"hljs-number\">3<\/span>;\n  int64 processedAtTicks = <span class=\"hljs-number\">4<\/span>;\n}\n\n<span class=\"hljs-comment\">\/\/ gRPC service<\/span>\nservice PerfService {\n  rpc GetData(PerfRequest) returns (PerfResponse);\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 Step 4 \u2013 Wire proto into both projects<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">4.1 Server <code>.csproj<\/code><\/h4>\n\n\n\n<p>Open <strong><code>RpcPerfDemo.Server\/RpcPerfDemo.Server.csproj<\/code><\/strong> and make it look like this (keep your PropertyGroup as generated, just ensure these ItemGroups exist):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Project<\/span> <span class=\"hljs-attr\">Sdk<\/span>=<span class=\"hljs-string\">\"Microsoft.NET.Sdk.Web\"<\/span>&gt;<\/span>\n\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PropertyGroup<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">TargetFramework<\/span>&gt;<\/span>net8.0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">TargetFramework<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Nullable<\/span>&gt;<\/span>enable<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Nullable<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ImplicitUsings<\/span>&gt;<\/span>enable<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ImplicitUsings<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">PropertyGroup<\/span>&gt;<\/span>\n\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ItemGroup<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PackageReference<\/span> <span class=\"hljs-attr\">Include<\/span>=<span class=\"hljs-string\">\"Grpc.AspNetCore\"<\/span> <span class=\"hljs-attr\">Version<\/span>=<span class=\"hljs-string\">\"*\"<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PackageReference<\/span> <span class=\"hljs-attr\">Include<\/span>=<span class=\"hljs-string\">\"Grpc.Tools\"<\/span> <span class=\"hljs-attr\">Version<\/span>=<span class=\"hljs-string\">\"*\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PrivateAssets<\/span>&gt;<\/span>All<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">PrivateAssets<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">PackageReference<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PackageReference<\/span> <span class=\"hljs-attr\">Include<\/span>=<span class=\"hljs-string\">\"Google.Protobuf\"<\/span> <span class=\"hljs-attr\">Version<\/span>=<span class=\"hljs-string\">\"*\"<\/span> \/&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ItemGroup<\/span>&gt;<\/span>\n\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ItemGroup<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Protobuf<\/span> <span class=\"hljs-attr\">Include<\/span>=<span class=\"hljs-string\">\"Protos\\perf.proto\"<\/span> <span class=\"hljs-attr\">GrpcServices<\/span>=<span class=\"hljs-string\">\"Server\"<\/span> \/&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ItemGroup<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Project<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><code>Version=\"*\"<\/code> is fine \u2013 the real versions were already resolved by <code>dotnet add package<\/code>.<\/p>\n<\/blockquote>\n\n\n\n<h4 class=\"wp-block-heading\">4.2 Client <code>.csproj<\/code><\/h4>\n\n\n\n<p>Open <strong><code>RpcPerfDemo.Client\/RpcPerfDemo.Client.csproj<\/code><\/strong>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Project<\/span> <span class=\"hljs-attr\">Sdk<\/span>=<span class=\"hljs-string\">\"Microsoft.NET.Sdk\"<\/span>&gt;<\/span>\n\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PropertyGroup<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">OutputType<\/span>&gt;<\/span>Exe<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">OutputType<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">TargetFramework<\/span>&gt;<\/span>net8.0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">TargetFramework<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ImplicitUsings<\/span>&gt;<\/span>enable<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ImplicitUsings<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Nullable<\/span>&gt;<\/span>enable<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Nullable<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">PropertyGroup<\/span>&gt;<\/span>\n\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ItemGroup<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PackageReference<\/span> <span class=\"hljs-attr\">Include<\/span>=<span class=\"hljs-string\">\"Grpc.Net.Client\"<\/span> <span class=\"hljs-attr\">Version<\/span>=<span class=\"hljs-string\">\"*\"<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PackageReference<\/span> <span class=\"hljs-attr\">Include<\/span>=<span class=\"hljs-string\">\"Grpc.Tools\"<\/span> <span class=\"hljs-attr\">Version<\/span>=<span class=\"hljs-string\">\"*\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PrivateAssets<\/span>&gt;<\/span>All<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">PrivateAssets<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">PackageReference<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PackageReference<\/span> <span class=\"hljs-attr\">Include<\/span>=<span class=\"hljs-string\">\"Google.Protobuf\"<\/span> <span class=\"hljs-attr\">Version<\/span>=<span class=\"hljs-string\">\"*\"<\/span> \/&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ItemGroup<\/span>&gt;<\/span>\n\n  <span class=\"hljs-comment\">&lt;!-- Reuse the same proto for client stubs --&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ItemGroup<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Protobuf<\/span> <span class=\"hljs-attr\">Include<\/span>=<span class=\"hljs-string\">\"..\\RpcPerfDemo.Server\\Protos\\perf.proto\"<\/span>\n              <span class=\"hljs-attr\">Link<\/span>=<span class=\"hljs-string\">\"Protos\\perf.proto\"<\/span>\n              <span class=\"hljs-attr\">GrpcServices<\/span>=<span class=\"hljs-string\">\"Client\"<\/span> \/&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ItemGroup<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Project<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 Step 5 \u2013 Implement the server (REST + gRPC)<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">5.1 REST model<\/h4>\n\n\n\n<p>Create folder:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">mkdir -p RpcPerfDemo.Server\/Models\n<\/code><\/span><\/pre>\n\n\n<p>Create <strong><code>RpcPerfDemo.Server\/Models\/RestPerfResponse.cs<\/code><\/strong>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">namespace RpcPerfDemo.Server.Models;\n\npublic <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">RestPerfResponse<\/span>\n<\/span>{\n    public int Id { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    public string Name { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; } = string.Empty;\n    public List&lt;int&gt; Values { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; } = new();\n    public long ProcessedAtTicks { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">5.2 gRPC service implementation<\/h4>\n\n\n\n<p>Create folder:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">mkdir -p RpcPerfDemo.Server\/Services\n<\/code><\/span><\/pre>\n\n\n<p>Create <strong><code>RpcPerfDemo.Server\/Services\/PerfServiceImpl.cs<\/code><\/strong>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\">using Grpc.Core;\nusing RpcPerfDemo.Grpc;\n\nnamespace RpcPerfDemo.Server.Services;\n\npublic class PerfServiceImpl : PerfService.PerfServiceBase\n{\n    public override Task<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PerfResponse<\/span>&gt;<\/span> GetData(PerfRequest request, ServerCallContext context)\n    {\n        \/\/ Simulate some CPU work\n        var values = Enumerable.Range(0, 200).ToList();\n\n        var response = new PerfResponse\n        {\n            Id = request.Id,\n            Name = request.Name,\n            ProcessedAtTicks = DateTime.UtcNow.Ticks\n        };\n        response.Values.AddRange(values);\n\n        return Task.FromResult(response);\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">5.3 Minimal API + gRPC configuration<\/h4>\n\n\n\n<p>Replace <strong><code>RpcPerfDemo.Server\/Program.cs<\/code><\/strong> with:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">using RpcPerfDemo.Server.Models;\nusing RpcPerfDemo.Server.Services;\n\n<span class=\"hljs-keyword\">var<\/span> builder = WebApplication.CreateBuilder(args);\n\n<span class=\"hljs-comment\">\/\/ Add gRPC services<\/span>\nbuilder.Services.AddGrpc();\n\n<span class=\"hljs-keyword\">var<\/span> app = builder.Build();\n\n<span class=\"hljs-comment\">\/\/ Map REST endpoint<\/span>\napp.MapGet(<span class=\"hljs-string\">\"\/rest\/perf\"<\/span>, () =&gt;\n{\n    <span class=\"hljs-comment\">\/\/ Simulate some work, similar to gRPC<\/span>\n    <span class=\"hljs-keyword\">var<\/span> values = Enumerable.Range(<span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">200<\/span>).ToList();\n\n    <span class=\"hljs-keyword\">var<\/span> response = <span class=\"hljs-keyword\">new<\/span> RestPerfResponse\n    {\n        Id = <span class=\"hljs-number\">1<\/span>,\n        Name = <span class=\"hljs-string\">\"REST-JSON\"<\/span>,\n        Values = values,\n        ProcessedAtTicks = DateTime.UtcNow.Ticks\n    };\n\n    <span class=\"hljs-keyword\">return<\/span> Results.Ok(response);\n});\n\n<span class=\"hljs-comment\">\/\/ Map gRPC endpoint<\/span>\napp.MapGrpcService&lt;PerfServiceImpl&gt;();\n\n<span class=\"hljs-comment\">\/\/ Optional health check endpoint<\/span>\napp.MapGet(<span class=\"hljs-string\">\"\/\"<\/span>, () =&gt; <span class=\"hljs-string\">\"RPC Performance Demo Server (REST + gRPC)\"<\/span>);\n\napp.Run();\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>ASP.NET Core will host <strong>both REST and gRPC<\/strong> on the same app and ports.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 Step 6 \u2013 Implement the benchmark client<\/h3>\n\n\n\n<p>Replace <strong><code>RpcPerfDemo.Client\/Program.cs<\/code><\/strong> with:<\/p>\n\n\n\n<script src=\"https:\/\/gist.github.com\/devops-school\/7b69d2f33d972b9b71911033a37eeae9.js\"><\/script>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\"><\/code><\/span><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">3. Build and run<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 Step 7 \u2013 Build everything<\/h3>\n\n\n\n<p>From the <strong>solution root<\/strong> (<code>RpcPerfDemo<\/code>):<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">dotnet build\n<\/code><\/span><\/pre>\n\n\n<p>You should see <strong>Build succeeded<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 Step 8 \u2013 Run the server<\/h3>\n\n\n\n<p>From the solution root:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">dotnet<\/span> <span class=\"hljs-selector-tag\">run<\/span> <span class=\"hljs-selector-tag\">--project<\/span> <span class=\"hljs-selector-tag\">RpcPerfDemo<\/span><span class=\"hljs-selector-class\">.Server<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>You\u2019ll see output similar to:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">info: Microsoft.Hosting.Lifetime&#91;<span class=\"hljs-number\">14<\/span>]\n      Now listening on: https:<span class=\"hljs-comment\">\/\/localhost:5001<\/span>\ninfo: Microsoft.Hosting.Lifetime&#91;<span class=\"hljs-number\">14<\/span>]\n      Now listening on: http:<span class=\"hljs-comment\">\/\/localhost:5000<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<ul class=\"wp-block-list\">\n<li>Confirm <strong><code>https:\/\/localhost:5001<\/code><\/strong> is there.<\/li>\n\n\n\n<li>If it prints a different HTTPS port, either:<ul><li>Change <code>ServerAddress<\/code> constant in the client, <strong>or<\/strong><\/li><li>Set <code>ASPNETCORE_URLS<\/code>: <code>set ASPNETCORE_URLS=https:\/\/localhost:5001;http:\/\/localhost:5000 # Windows export ASPNETCORE_URLS=\"https:\/\/localhost:5001;http:\/\/localhost:5000\" # Linux\/macOS<\/code><\/li><\/ul>and re-run the server.<\/li>\n<\/ul>\n\n\n\n<p>Leave the server running.<\/p>\n\n\n\n<p>You can quickly test the REST endpoint in a browser:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Visit: <code>https:\/\/localhost:5001\/rest\/perf<\/code><br>You should see JSON like:<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\">{\n  <span class=\"hljs-attr\">\"id\"<\/span>: <span class=\"hljs-number\">1<\/span>,\n  <span class=\"hljs-attr\">\"name\"<\/span>: <span class=\"hljs-string\">\"REST-JSON\"<\/span>,\n  <span class=\"hljs-attr\">\"values\"<\/span>: &#91;...],\n  <span class=\"hljs-attr\">\"processedAtTicks\"<\/span>: <span class=\"hljs-number\">638000000000000000<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 Step 9 \u2013 Run the client benchmark<\/h3>\n\n\n\n<p>In a <strong>new terminal<\/strong>, from solution root:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">dotnet<\/span> <span class=\"hljs-selector-tag\">run<\/span> <span class=\"hljs-selector-tag\">--project<\/span> <span class=\"hljs-selector-tag\">RpcPerfDemo<\/span><span class=\"hljs-selector-class\">.Client<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>You should see something like:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">=== RPC Performance Demo: REST vs gRPC ===\nServer address: https:<span class=\"hljs-comment\">\/\/localhost:5001<\/span>\nTotal requests per style: <span class=\"hljs-number\">1000<\/span>\n\nWarming up REST endpoint...\nSample REST <span class=\"hljs-built_in\">JSON<\/span> payload size: <span class=\"hljs-number\">2350<\/span> bytes\nRunning REST benchmark...\nREST total time: <span class=\"hljs-number\">950.32<\/span> ms <span class=\"hljs-keyword\">for<\/span> <span class=\"hljs-number\">1000<\/span> requests\nREST avg per request: <span class=\"hljs-number\">0.9503<\/span> ms\n\nWarming up gRPC endpoint...\nSample gRPC Protobuf payload size: <span class=\"hljs-number\">640<\/span> bytes\nRunning gRPC benchmark...\ngRPC total time: <span class=\"hljs-number\">480.15<\/span> ms <span class=\"hljs-keyword\">for<\/span> <span class=\"hljs-number\">1000<\/span> requests\ngRPC avg per request: <span class=\"hljs-number\">0.4802<\/span> ms\n\nDone.\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>(Exact numbers will vary by machine.)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">4. How to interpret the results<\/h2>\n\n\n\n<p>You\u2019ll get <strong>two kinds of insights<\/strong>:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1\ufe0f\u20e3 Payload size<\/h3>\n\n\n\n<p>From log:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>REST JSON payload size<\/strong> \u2013 e.g. <code>2350 bytes<\/code><\/li>\n\n\n\n<li><strong>gRPC Protobuf payload size<\/strong> \u2013 e.g. <code>640 bytes<\/code><\/li>\n<\/ul>\n\n\n\n<p>\ud83d\udc49 This shows <strong>gRPC messages are much smaller<\/strong>, even for the same data (id, name, 200 ints, timestamp).<\/p>\n\n\n\n<p>Smaller payloads \u2192 less bandwidth \u2192 better performance, especially over slow networks.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">2\ufe0f\u20e3 Latency per request<\/h3>\n\n\n\n<p>You\u2019ll see:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>REST total time<\/code> and <code>REST avg per request<\/code><\/li>\n\n\n\n<li><code>gRPC total time<\/code> and <code>gRPC avg per request<\/code><\/li>\n<\/ul>\n\n\n\n<p>Typically:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>gRPC average per request will be <strong>lower<\/strong><\/li>\n\n\n\n<li>Total time for N requests will also be <strong>lower<\/strong><\/li>\n<\/ul>\n\n\n\n<p>On localhost the difference may be modest, but:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Add more iterations (<code>Iterations = 10000<\/code>)<\/li>\n\n\n\n<li>Or run on separate machines<\/li>\n\n\n\n<li>Or add more data in <code>values<\/code> (e.g. <code>Enumerable.Range(0, 2000)<\/code>)<\/li>\n<\/ul>\n\n\n\n<p>\u2192 you\u2019ll see gRPC scaling better.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">5. What you just experienced<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Same server<\/strong>, same business logic size, same data.<\/li>\n\n\n\n<li><strong>REST vs gRPC<\/strong> differ only in:\n<ul class=\"wp-block-list\">\n<li>Data format (JSON vs Protobuf)<\/li>\n\n\n\n<li>Protocol (HTTP\/1.1 vs HTTP\/2)<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Your measurements showed:\n<ul class=\"wp-block-list\">\n<li><strong>gRPC = smaller payloads<\/strong><\/li>\n\n\n\n<li><strong>gRPC = lower average latency &amp; total time<\/strong><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>This is <strong>exactly<\/strong> the impact you care about for:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>High-throughput microservices<\/li>\n\n\n\n<li>Telemetry, streaming, real-time APIs<\/li>\n\n\n\n<li>Cloud Run \u2192 EKS migration with full gRPC support<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Below is a complete, runnable .NET 8 demo where: You\u2019ll be able to feel the difference. 1. Solution structure We\u2019ll build this: Target: .NET 8.0 (works with&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[11138],"tags":[],"class_list":["post-54284","post","type-post","status-publish","format-standard","hentry","category-best-tools"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/54284","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=54284"}],"version-history":[{"count":1,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/54284\/revisions"}],"predecessor-version":[{"id":54285,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/54284\/revisions\/54285"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=54284"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=54284"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=54284"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}