--- name: dotnet-service-communication description: >- Chooses inter-service protocols. REST vs gRPC vs SignalR vs SSE decision matrix, tradeoffs. metadata: short-description: .NET skill guidance for csharp tasks --- # dotnet-service-communication Higher-level routing skill for choosing the right service communication protocol. Provides a decision matrix mapping requirements (latency, direction, client type, payload format, browser support) to the five primary .NET communication protocols: gRPC, SignalR, SSE, JSON-RPC 2.0, and REST. Routes to specialized skills for implementation depth. ## Scope - Decision matrix for gRPC, SignalR, SSE, JSON-RPC, REST - Requirements mapping (latency, direction, client type, format) - Routing to specialized implementation skills ## Out of scope - HTTP client factory and resilience pipelines -- see [skill:dotnet-http-client] and [skill:dotnet-resilience] - Native AOT architecture and trimming -- see [skill:dotnet-native-aot] and [skill:dotnet-trimming] Cross-references: [skill:dotnet-grpc] for gRPC implementation, [skill:dotnet-realtime-communication] for SignalR/SSE/JSON-RPC details, [skill:dotnet-http-client] for REST/HTTP client patterns. See [skill:dotnet-integration-testing] for testing service communication patterns. --- ## Decision Matrix Use this matrix to choose the right protocol based on your requirements: | Requirement | gRPC | SignalR | SSE | JSON-RPC 2.0 | REST | | ---------------------- | ----------------------- | ------------------------- | ------------------------ | ------------------- | ------------------------- | | **Direction** | All four patterns | Full-duplex | Server-to-client | Request-response | Request-response | | **Wire format** | Protobuf (binary) | JSON or MessagePack | Text (JSON lines) | JSON | JSON/XML | | **Browser support** | gRPC-Web (proxy needed) | Yes (JS client) | Yes (native EventSource) | Via WebSocket | Yes (fetch/XHR) | | **Contract** | `.proto` schema | Hub interface | Convention | JSON-RPC spec | OpenAPI/Swagger | | **Latency** | Lowest | Low | Low | Medium | Medium | | **Throughput** | Highest | High | Moderate | Moderate | Moderate | | **Streaming** | All 4 patterns | Server + client streaming | Server push only | No | No (chunked transfer) | | **Connection** | HTTP/2 persistent | WebSocket (with fallback) | HTTP/1.1+ persistent | Transport-dependent | Per-request | | **Service-to-service** | Excellent | Good | Limited | Niche | Good | | **AOT-friendly** | Yes (Protobuf) | Yes | Yes | Yes | Yes (with STJ source gen) | --- ## Decision Flowchart ````text Is this service-to-service (no browser)? ├── Yes → Do you need streaming? │ ├── Yes → gRPC streaming [skill:dotnet-grpc] │ └── No → Is it request-response? │ ├── High throughput / binary → gRPC (unary) [skill:dotnet-grpc] │ └── Standard CRUD / public API → REST [skill:dotnet-http-client] └── No (browser client) → Do you need real-time? ├── Yes → Do you need bidirectional? │ ├── Yes → SignalR [skill:dotnet-realtime-communication] │ └── No (server push only) → SSE [skill:dotnet-realtime-communication] └── No → REST [skill:dotnet-http-client] Special cases: - LSP / tooling protocol → JSON-RPC 2.0 [skill:dotnet-realtime-communication] - Mixed (browser + service-to-service) → REST for browser, gRPC for internal ```json --- ## Protocol Profiles ### gRPC **Best for:** Service-to-service communication, high-throughput streaming, strongly-typed contracts. - Schema-first development with `.proto` files - All four streaming patterns: unary, server streaming, client streaming, bidirectional - Binary serialization (Protobuf) for smallest payloads and fastest throughput - Built-in code generation for client and server stubs - Native load balancing and health check protocol support **When NOT to use:** Direct browser communication (requires gRPC-Web proxy), simple CRUD APIs consumed by external clients, scenarios where human-readable payloads are required. See [skill:dotnet-grpc] for full implementation details. ### SignalR **Best for:** Browser-facing real-time applications, interactive dashboards, chat, collaborative features. - Automatic transport negotiation (WebSocket → SSE → Long Polling) - Built-in group management and user targeting - Hub abstraction with strongly-typed interfaces - Scales with Redis backplane or Azure SignalR Service - Supports JSON and MessagePack serialization **When NOT to use:** Server-to-client-only push (use SSE instead), service-to-service (use gRPC instead), scenarios where the SignalR client library cannot be included. See [skill:dotnet-realtime-communication] for SignalR patterns and hub implementation. ### Server-Sent Events (SSE) **Best for:** Simple server-to-client push notifications, live feeds, status updates. - Built-in to ASP.NET Core in .NET 10 via `TypedResults.ServerSentEvents` - Browser-native `EventSource` API -- no client library needed - Automatic reconnection with `Last-Event-ID` - Works through HTTP/1.1 proxies that block WebSocket upgrade - Lightest-weight real-time option **When NOT to use:** Bidirectional communication (use SignalR), high-throughput binary streaming (use gRPC), client-to-server messages needed. See [skill:dotnet-realtime-communication] for SSE implementation details. ### JSON-RPC 2.0 **Best for:** Tooling protocols (Language Server Protocol), structured RPC over simple transports. - Transport-agnostic (HTTP, WebSocket, stdio, named pipes) - Well-defined request/response/notification semantics - Used by Visual Studio, VS Code, and .NET tooling via StreamJsonRpc - Lightweight alternative to gRPC when schema management is unwanted **When NOT to use:** Real-time streaming (use SignalR or gRPC), high-throughput service-to-service (use gRPC), standard web APIs (use REST). See [skill:dotnet-realtime-communication] for JSON-RPC 2.0 patterns. ### REST (HTTP APIs) **Best for:** Public APIs, standard CRUD operations, broad client compatibility. - Universal client support (any HTTP client) - Human-readable payloads (JSON) - Rich ecosystem (OpenAPI, Swagger UI, API versioning) - Stateless request-response model - ASP.NET Core Minimal APIs or MVC controllers **When NOT to use:** Real-time push (use SSE or SignalR), high-throughput service-to-service (use gRPC), bidirectional streaming (use SignalR or gRPC). See [skill:dotnet-http-client] for HTTP client patterns, resilience, and `IHttpClientFactory`. --- ## Common Architecture Patterns ### API Gateway with Mixed Protocols ```text Browser ─── REST/SignalR ──→ API Gateway ──→ gRPC ──→ Internal Services ──→ gRPC ──→ Order Service ──→ gRPC ──→ Inventory Service ```text Use REST for public-facing APIs and SignalR for real-time browser features. Internal service-to-service communication uses gRPC for performance. The API gateway translates between protocols. ### Event-Driven with SSE ```text Internal Services ──→ Message Broker ──→ SSE Endpoint ──→ Browser Dashboard ──→ gRPC Stream ──→ Monitoring Service ```text Internal events flow through a message broker. Browser dashboards consume via SSE. Other services consume via gRPC streaming for higher throughput. ### Dual-Protocol Services A single ASP.NET Core host can serve both gRPC and REST: ```csharp var builder = WebApplication.CreateBuilder(args); builder.Services.AddGrpc(); builder.Services.AddControllers(); var app = builder.Build(); // gRPC for internal service-to-service app.MapGrpcService(); // REST for external clients app.MapControllers(); // SSE for real-time browser updates app.MapGet("/events/orders", (OrderEventService svc, CancellationToken ct) => TypedResults.ServerSentEvents(svc.GetEventsAsync(ct))); ```text --- ## Key Principles - **Use gRPC for service-to-service** -- it provides the best throughput, strongly-typed contracts, and all streaming patterns - **Use REST for public APIs** -- universal client support, human-readable, extensive tooling ecosystem - **Use SignalR for browser real-time** -- automatic transport negotiation and built-in group management - **Use SSE for simple server push** -- lightest option when bidirectional communication is not needed - **Mix protocols when appropriate** -- a single ASP.NET Core host can serve gRPC, REST, SignalR, and SSE simultaneously - **Route based on client type** -- browser clients get REST/SignalR/SSE; internal services get gRPC See [skill:dotnet-native-aot] for AOT compilation pipeline and [skill:dotnet-aot-architecture] for AOT-compatible communication patterns. --- ## Agent Gotchas 1. **Do not default to gRPC for browser-facing APIs** -- browsers cannot speak HTTP/2 trailers natively. Use gRPC-Web with a proxy or choose REST/SignalR/SSE. 2. **Do not use SignalR for service-to-service** -- gRPC provides better performance, code generation, and streaming for backend communication. 3. **Do not add SignalR when SSE suffices** -- if you only need server-to-client push, SSE is simpler, requires no client library, and has automatic reconnection built into browsers. 4. **Do not use REST for high-throughput internal communication** -- JSON text serialization and per-request connections add overhead vs gRPC's binary format and persistent HTTP/2 connections. 5. **Do not forget AOT considerations** -- REST endpoints using System.Text.Json need source-generated contexts for AOT. See [skill:dotnet-serialization] for details. 6. **Do not expose gRPC services to untrusted clients without gRPC-Web** -- raw gRPC requires HTTP/2, which is not universally available in all environments (e.g., some proxies, older browsers). --- ## References - [Choose between gRPC and REST](https://learn.microsoft.com/en-us/aspnet/core/grpc/comparison?view=aspnetcore-10.0) - [gRPC for .NET](https://learn.microsoft.com/en-us/aspnet/core/grpc/?view=aspnetcore-10.0) - [SignalR overview](https://learn.microsoft.com/en-us/aspnet/core/signalr/introduction?view=aspnetcore-10.0) - [Server-Sent Events in .NET 10](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/server-sent-events?view=aspnetcore-10.0) - [Minimal APIs](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis?view=aspnetcore-10.0) - [IHttpClientFactory patterns](https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factory) ```` ## Code Navigation (Serena MCP) **Primary approach:** Use Serena symbol operations for efficient code navigation: 1. **Find definitions**: `serena_find_symbol` instead of text search 2. **Understand structure**: `serena_get_symbols_overview` for file organization 3. **Track references**: `serena_find_referencing_symbols` for impact analysis 4. **Precise edits**: `serena_replace_symbol_body` for clean modifications **When to use Serena vs traditional tools:** - **Use Serena**: Navigation, refactoring, dependency analysis, precise edits - **Use Read/Grep**: Reading full files, pattern matching, simple text operations - **Fallback**: If Serena unavailable, traditional tools work fine **Example workflow:** ```text # Instead of: Read: src/Services/OrderService.cs Grep: "public void ProcessOrder" # Use: serena_find_symbol: "OrderService/ProcessOrder" serena_get_symbols_overview: "src/Services/OrderService.cs" ```