gRPC

This section documents ASP.NET Core on .NET 10 (LTS), the current release — the minimal hosting model, the middleware pipeline, dependency injection, Minimal APIs, MVC & Razor Pages, Blazor with the current render modes, SignalR and gRPC, EF Core, ASP.NET Core Identity and policy-based authorization, output caching, rate limiting, and Native-AOT-aware building — as described by the official documentation at Microsoft Learn, which is the reference these pages are written and verified against.

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. .NET ships a major release every November and its APIs continue to evolve: the examples here target .NET 10 / C# 14.

This section’s bibliography lists the reference material consulted while preparing these pages.

gRPC is a contract-first, high-performance RPC framework for service-to-service calls. It defines services in a .proto file and generates typed client and server code, over HTTP/2 and Protocol Buffers.

Contract-first .proto

// greet.proto
syntax = "proto3";

service Greeter {
    rpc SayHello (HelloRequest) returns (HelloReply);
}

message HelloRequest { string name = 1; }
message HelloReply   { string message = 1; }

The .NET tooling (Grpc.Tools, referenced automatically by the gRPC service templates) generates a GreeterBase server base class and a GreeterClient from this file at build time:

public sealed class GreeterService : Greeter.GreeterBase
{
    public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
        => Task.FromResult(new HelloReply { Message = $"Hello {request.Name}" });
}

// Program.cs
builder.Services.AddGrpc();
app.MapGrpcService<GreeterService>();

The four call types

service OrderTracker {
    rpc GetOrder (OrderRequest) returns (Order);                          // unary
    rpc WatchOrder (OrderRequest) returns (stream OrderUpdate);           // server streaming
    rpc UploadEvents (stream Event) returns (UploadSummary);              // client streaming
    rpc Chat (stream ChatMessage) returns (stream ChatMessage);           // bidirectional streaming
}
public override async Task WatchOrder(
    OrderRequest request, IServerStreamWriter<OrderUpdate> responseStream, ServerCallContext context)
{
    await foreach (var update in orders.WatchAsync(request.OrderId, context.CancellationToken))
    {
        await responseStream.WriteAsync(update);
    }
}
  • Unary — one request, one response; the default and most common.

  • Server streaming — one request, a stream of responses (progress updates, live data).

  • Client streaming — a stream of requests, one response (batch upload, aggregation).

  • Bidirectional streaming — both sides stream independently (chat, real-time collaboration).

Interceptors

Server and client interceptors wrap every call for cross-cutting logic — logging, auth, metrics — the gRPC analog of MVC filters or middleware:

public sealed class LoggingInterceptor(ILogger<LoggingInterceptor> logger) : Interceptor
{
    public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
        TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation)
    {
        logger.LogInformation("-> {Method}", context.Method);
        return await continuation(request, context);
    }
}

builder.Services.AddGrpc(o => o.Interceptors.Add<LoggingInterceptor>());

gRPC-Web and JSON transcoding

Browsers cannot speak raw HTTP/2 trailers-based gRPC, and REST-only consumers don’t speak Protocol Buffers at all — two different bridges cover each case:

// dotnet add package Grpc.AspNetCore.Web
app.UseGrpcWeb();
app.MapGrpcService<GreeterService>().EnableGrpcWeb();
// JSON transcoding: annotate the .proto with an HTTP mapping
import "google/api/annotations.proto";

service Greeter {
    rpc SayHello (HelloRequest) returns (HelloReply) {
        option (google.api.http) = { get: "/v1/greet/{name}" };
    }
}

gRPC-Web (app.UseGrpcWeb()) lets browsers call gRPC services over a compatible wire format. gRPC JSON transcoding (Grpc.AspNetCore.JsonTranscoding) exposes the same service as a conventional REST/JSON endpoint from one implementation, useful for consumers that expect plain HTTP. See gRPC-Web in ASP.NET Core gRPC apps and gRPC JSON transcoding.

Deadlines and cancellation

A gRPC call carries a deadline the server can observe via context.CancellationToken, so long-running work stops as soon as the caller gives up:

var deadline = DateTime.UtcNow.AddSeconds(5);
var reply = await client.SayHelloAsync(request, deadline: deadline);

Passing no deadline means the call can run indefinitely — always set one for calls that must not hang.

The gRPC client factory

Grpc.Net.ClientFactory integrates with IHttpClientFactory (see HTTP Client and Resilience) for pooled connections and Polly-based resilience:

builder.Services.AddGrpcClient<Greeter.GreeterClient>(o =>
    o.Address = new Uri("https://greeter.internal"));

public sealed class GreetingService(Greeter.GreeterClient client)
{
    public Task<HelloReply> GreetAsync(string name, CancellationToken ct)
        => client.SayHelloAsync(new HelloRequest { Name = name }, cancellationToken: ct).ResponseAsync;
}

Code-first gRPC

protobuf-net.Grpc generates the wire contract from plain C# interfaces and [ServiceContract] attributes instead of a .proto file, letting client and server share the same C# contract assembly — convenient inside a single .NET solution, at the cost of the .proto file other, non-.NET consumers would otherwise rely on.

gRPC vs. REST

Choose When

gRPC

Internal, chatty, strongly-typed service-to-service traffic; streaming; polyglot microservices sharing a .proto contract; performance-sensitive paths (binary payload, HTTP/2 multiplexing).

REST/JSON

Public or browser-facing APIs, cache-friendly reads, or consumers that expect plain HTTP/JSON —  see Web API Controllers and Minimal APIs.

JSON transcoding narrows this trade-off by exposing one gRPC implementation both ways. See gRPC compared to HTTP APIs with JSON.