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
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
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
Browser ─── REST/SignalR ──→ API Gateway ──→ gRPC ──→ Internal Services ──→ gRPC ──→ Order Service ──→ gRPC ──→ Inventory Service
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
Internal Services ──→ Message Broker ──→ SSE Endpoint ──→ Browser Dashboard ──→ gRPC Stream ──→ Monitoring Service
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:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc(); builder.Services.AddControllers();
var app = builder.Build();
// gRPC for internal service-to-service app.MapGrpcService<OrderGrpcService>();
// 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)));
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
-
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.
-
Do not use SignalR for service-to-service -- gRPC provides better performance, code generation, and streaming for backend communication.
-
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.
-
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.
-
Do not forget AOT considerations -- REST endpoints using System.Text.Json need source-generated contexts for AOT. See [skill:dotnet-serialization] for details.
-
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
-
gRPC for .NET
-
SignalR overview
-
Server-Sent Events in .NET 10
-
Minimal APIs
-
IHttpClientFactory patterns