// order.proto -- defines the contract
service OrderService {
rpc GetOrder (GetOrderRequest) returns (OrderResponse);
}
message GetOrderRequest { int32 order_id = 1; }
message OrderResponse { int32 id = 1; string status = 2; }
Topics
31
.NET CLI, SDK & Project Structure (csproj)
.NET vs .NET Framework
API Versioning
ASP.NET Core Middleware & Request Pipeline
Assemblies & NuGet
Authentication & Authorization (Identity, JWT, OAuth)
Background Services
Blazor (Server & WebAssembly)
Caching (In-Memory, Distributed & Redis)
CI/CD, Publishing & Deployment
CLR & Runtime
Configuration & Options
CORS & Cross-Origin Resource Sharing
Dependency Injection
Diagnostics & Performance
Docker & Containerization
Entity Framework Core & Data Access
Generic Host
Global Exception Handling & Middleware
gRPC Services
Health Checks & Readiness/Liveness Probes
Logging
Microservices & Distributed Architecture Patterns
Minimal APIs
MVC & Razor Pages
Rate Limiting & Throttling
RESTful Web APIs & Controllers
Secrets Management & Configuration Providers (Key Vault, User Secrets)
SignalR & Real-Time Communication
Testing in .NET (xUnit, Integration & Unit Testing)
Worker Services & IHostedService
gRPC Services
15 questions found
gRPC is a high-performance RPC (Remote Procedure Call) framework built on HTTP/2, using Protocol Buffers (protobuf) as its binary serialization format for both requests and responses, rather than JSON over HTTP/1.1 as typical REST APIs use. This gives gRPC significantly smaller message sizes (binary vs text), lower latency, native support for streaming (client, server, and bidirectional), and strongly-typed contracts generated from a .proto file -- at the cost of being less human-readable and requiring more tooling than plain REST/JSON, and having limited direct browser support without a proxy layer (gRPC-Web).
Real-world example
A microservices platform uses gRPC for internal service-to-service communication (where performance and strong typing matter most) while still exposing a REST/JSON API at the edge for external, browser-based clients, using each protocol where it's best suited.
ASP.NET Core Middleware & Request Pipeline;Microservices & Distributed Architecture Patterns
How do you define a gRPC service contract using Protocol Buffers (.proto files), and how does code generation work in a .NET project?
IntermediateA .proto file declares message types (structured data with numbered fields) and service definitions (RPC method signatures) using protobuf's interface definition language; the Grpc.Tools NuGet package's MSBuild integration automatically generates strongly-typed C# client and server base classes from the .proto file at build time, which you then implement (server) or call (client) directly in C#.
// Greeter.proto
syntax = "proto3";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest { string name = 1; }
message HelloReply { string message = 1; }
<!-- .csproj -->
<ItemGroup>
<Protobuf Include="Protos\Greeter.proto" GrpcServices="Server" />
</ItemGroup>
Real-world example
A team defines their service contract once in a shared .proto file, and both the C# server project and a separate C# client project reference it with different GrpcServices settings (Server vs Client), generating appropriately-typed code for each side automatically at build time.
ASP.NET Core Middleware & Request Pipeline;.NET CLI
SDK & Project Structure (csproj)
What are the four types of gRPC service methods (unary, server streaming, client streaming, bidirectional streaming), and when is each appropriate?
AdvancedUnary (single request, single response) is the most common, equivalent to a typical REST call. Server streaming (single request, stream of responses) suits scenarios like subscribing to live updates or paginating a large result set efficiently. Client streaming (stream of requests, single response) suits uploading data incrementally, like a large file in chunks. Bidirectional streaming (both sides stream independently and concurrently) suits real-time interactive scenarios like a chat application or live collaborative editing, where either side can send messages at any time.
service DataService {
rpc GetItem (ItemRequest) returns (ItemResponse); // unary
rpc StreamUpdates (SubscribeRequest) returns (stream Update); // server streaming
rpc UploadChunks (stream ChunkRequest) returns (UploadResult); // client streaming
rpc Chat (stream ChatMessage) returns (stream ChatMessage); // bidirectional
}
Real-world example
A real-time stock-trading platform uses server streaming for live price updates (one subscription, continuous stream of price ticks) and bidirectional streaming for an order-matching negotiation channel where both client and server need to send messages independently.
Concurrency (asyncio/threading/multiprocessing);Diagnostics & Performance
How do you implement a gRPC server method in ASP.NET Core, and how does it integrate with the standard hosting model?
IntermediateA gRPC service class extends the code-generated base class (from the .proto file) and overrides its virtual RPC methods, registered via MapGrpcService<T>() in the endpoint routing configuration -- gRPC services run on top of the same Kestrel/ASP.NET Core hosting infrastructure as regular web APIs, meaning they benefit from the same middleware pipeline, dependency injection, logging, and configuration systems.
public class GreeterService : Greeter.GreeterBase {
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context) {
return Task.FromResult(new HelloReply { Message = $"Hello, {request.Name}" });
}
}
// Program.cs
builder.Services.AddGrpc();
app.MapGrpcService<GreeterService>();
Real-world example
A team adds a gRPC service alongside their existing REST controllers in the same ASP.NET Core application, both benefiting from the same registered authentication middleware and dependency-injected services without any duplicated configuration.
Dependency Injection;ASP.NET Core Middleware & Request Pipeline
How does gRPC handle errors and status codes, and how does this differ from HTTP status codes in REST?
AdvancedgRPC uses its own set of standardized status codes (like NotFound, InvalidArgument, PermissionDenied, Internal, Unavailable) distinct from HTTP status codes, communicated via gRPC trailers rather than the HTTP status line -- a server method throws an RpcException with a specific StatusCode and optional detail message, which the client-side generated code surfaces as a corresponding exception, giving a richer, RPC-appropriate error vocabulary than REST's more general-purpose HTTP status codes.
public override Task<OrderResponse> GetOrder(GetOrderRequest request, ServerCallContext context) {
var order = _repository.Find(request.OrderId);
if (order == null) {
throw new RpcException(new Status(StatusCode.NotFound, $"Order {request.OrderId} not found"));
}
return Task.FromResult(MapToResponse(order));
}
// Client-side:
try {
var response = await client.GetOrderAsync(request);
} catch (RpcException ex) when (ex.StatusCode == StatusCode.NotFound) {
// handle specifically
}
Real-world example
A gRPC client library automatically translates a server-thrown RpcException with StatusCode.PermissionDenied into a client-side exception the calling application can catch and handle specifically, distinct from how it would handle a StatusCode.Unavailable indicating a transient network issue.
Exception Handling;Global Exception Handling & Middleware
What is gRPC-Web, and why is it needed for calling gRPC services directly from a browser-based JavaScript client?
IntermediateBrowsers don't provide the low-level HTTP/2 trailer access and full control needed for native gRPC's wire protocol, so gRPC-Web is a protocol variant designed to work within browser constraints (using standard HTTP requests the browser's fetch/XHR APIs can handle), requiring either a proxy (like Envoy) to translate between gRPC-Web and native gRPC, or ASP.NET Core's built-in Grpc.AspNetCore.Web middleware to natively accept gRPC-Web requests without a separate proxy.
builder.Services.AddGrpc();
var app = builder.Build();
app.UseGrpcWeb(); // enables gRPC-Web support directly, no separate proxy needed
app.MapGrpcService<GreeterService>().EnableGrpcWeb();
Real-world example
A Blazor WebAssembly frontend calls a gRPC backend service directly using gRPC-Web support built into ASP.NET Core, avoiding the need to deploy and maintain a separate Envoy proxy just to bridge the browser-to-gRPC gap.
ASP.NET Core Middleware & Request Pipeline;Blazor (Server & WebAssembly)
How does gRPC's use of HTTP/2 multiplexing provide performance advantages over HTTP/1.1-based REST APIs?
AdvancedHTTP/2 allows multiple concurrent requests and responses to be interleaved over a single TCP connection (multiplexing), eliminating HTTP/1.1's head-of-line blocking (where requests on the same connection must complete in order) and avoiding the overhead of establishing multiple TCP connections for concurrent calls -- combined with HTTP/2's header compression (HPACK) and gRPC's compact binary protobuf payloads, this results in meaningfully lower latency and higher throughput for high-volume service-to-service communication compared to typical REST/JSON over HTTP/1.1.
// A single HTTP/2 connection can carry many concurrent gRPC calls
// without head-of-line blocking, unlike sequential HTTP/1.1 requests:
var tasks = new[] {
client.GetOrderAsync(request1),
client.GetOrderAsync(request2),
client.GetOrderAsync(request3)
};
await Task.WhenAll(tasks); // all multiplexed over one connection efficiently
Real-world example
A high-throughput internal service mesh migrates from REST/JSON to gRPC specifically to take advantage of HTTP/2 multiplexing, measurably reducing connection overhead and latency for services making hundreds of concurrent downstream calls per second.
Diagnostics & Performance;Microservices & Distributed Architecture Patterns
How do you implement server-streaming gRPC using C#'s IAsyncEnumerable<T> or IServerStreamWriter<T>?
IntermediateA server-streaming RPC method receives an IServerStreamWriter<TResponse> parameter, calling WriteAsync() repeatedly to send each item in the stream to the client as it becomes available, with the method completing (and thus the stream ending) when the method returns -- this maps naturally onto C#'s async streaming patterns, letting a server push results incrementally rather than requiring the client to wait for the entire result set to be computed before receiving anything.
public override async Task StreamUpdates(SubscribeRequest request, IServerStreamWriter<Update> responseStream, ServerCallContext context) {
await foreach (var update in _updateSource.GetUpdatesAsync(context.CancellationToken)) {
await responseStream.WriteAsync(update);
}
}
Real-world example
A live dashboard subscribes to a server-streaming gRPC method that pushes stock price updates to the client as they occur in real time, rather than requiring the client to repeatedly poll a unary endpoint for the latest price.
Iterators & the Iterator Protocol;Concurrency (asyncio/threading/multiprocessing)
How does gRPC support interceptors for cross-cutting concerns like authentication, logging, and retries, similar to middleware in a REST pipeline?
AdvancedgRPC interceptors (implementing Interceptor, either server-side or client-side) wrap around RPC calls, letting you inject logic before and after the actual call executes -- server-side interceptors handle concerns like authentication/authorization and logging uniformly across all gRPC methods, while client-side interceptors handle concerns like automatic retry logic, adding auth headers, or client-side logging/metrics, registered globally so individual service methods don't need to repeat this logic.
public class LoggingInterceptor : Interceptor {
public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation) {
_logger.LogInformation("Calling {Method}", context.Method);
return await continuation(request, context);
}
}
builder.Services.AddGrpc(options => options.Interceptors.Add<LoggingInterceptor>());
Real-world example
A microservices platform registers a global server-side interceptor validating a JWT token on every incoming gRPC call, ensuring consistent authentication enforcement across dozens of gRPC service methods without duplicating auth-checking code in each one.
ASP.NET Core Middleware & Request Pipeline;Authentication & Authorization (Identity
JWT
OAuth)
What is protobuf field numbering, and why must you never reuse or renumber a field once a message definition has shipped to production?
IntermediateEach field in a protobuf message has a unique number (like `string name = 1;`) that's actually what's encoded on the wire, not the field name itself -- protobuf's binary encoding uses these numbers for identification, so reusing a previously-used number for a different field, or renumbering an existing field, can cause old serialized data (or a client running an older version of the contract) to be misinterpreted as the wrong field entirely, silently corrupting data rather than failing loudly with a clear error.
// Original message (version 1)
message Order { int32 id = 1; string status = 2; }
// SAFE evolution: add new fields with NEW numbers, never reuse 1 or 2
message Order { int32 id = 1; string status = 2; string customer_email = 3; }
// DANGEROUS: never do this -- reusing field number 2 for a different purpose
// message Order { int32 id = 1; int32 status_code = 2; } // BREAKS compatibility silently
Real-world example
A subtle production data corruption bug traced back to a well-meaning developer who renamed and renumbered a deprecated protobuf field for 'cleanliness', unaware this broke binary compatibility with clients still running the previous contract version.
API Versioning;Assemblies & NuGet
Showing 1–10 of 15