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
```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<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)));
```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:
- Find definitions:
serena_find_symbol instead of text search
- Understand structure:
serena_get_symbols_overview for file organization
- Track references:
serena_find_referencing_symbols for impact analysis
- 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:
# 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"
1---2name: dotnet-service-communication3category: architecture4subcategory: messaging5description: Chooses inter-service protocols. REST vs gRPC vs SignalR vs SSE decision matrix, tradeoffs.6license: MIT7targets: ['*']8tags: [csharp, dotnet, skill]9version: '0.0.1'10author: 'dotnet-agent-harness'11invocable: true12claudecode:13 allowed-tools: ['Read', 'Grep', 'Glob', 'Bash', 'Write', 'Edit']14codexcli:15 short-description: '.NET skill guidance for csharp tasks'16opencode:17 allowed-tools: ['Read', 'Grep', 'Glob', 'Bash', 'Write', 'Edit']18copilot: {}19geminicli: {}20antigravity: {}21---2223# dotnet-service-communication2425Higher-level routing skill for choosing the right service communication protocol. Provides a decision matrix mapping26requirements (latency, direction, client type, payload format, browser support) to the five primary .NET communication27protocols: gRPC, SignalR, SSE, JSON-RPC 2.0, and REST. Routes to specialized skills for implementation depth.2829## Scope3031- Decision matrix for gRPC, SignalR, SSE, JSON-RPC, REST32- Requirements mapping (latency, direction, client type, format)33- Routing to specialized implementation skills3435## Out of scope3637- HTTP client factory and resilience pipelines -- see [skill:dotnet-http-client] and [skill:dotnet-resilience]38- Native AOT architecture and trimming -- see [skill:dotnet-native-aot] and [skill:dotnet-trimming]3940Cross-references: [skill:dotnet-grpc] for gRPC implementation, [skill:dotnet-realtime-communication] for41SignalR/SSE/JSON-RPC details, [skill:dotnet-http-client] for REST/HTTP client patterns. See42[skill:dotnet-integration-testing] for testing service communication patterns.4344---4546## Decision Matrix4748Use this matrix to choose the right protocol based on your requirements:4950| Requirement | gRPC | SignalR | SSE | JSON-RPC 2.0 | REST |51| ---------------------- | ----------------------- | ------------------------- | ------------------------ | ------------------- | ------------------------- |52| **Direction** | All four patterns | Full-duplex | Server-to-client | Request-response | Request-response |53| **Wire format** | Protobuf (binary) | JSON or MessagePack | Text (JSON lines) | JSON | JSON/XML |54| **Browser support** | gRPC-Web (proxy needed) | Yes (JS client) | Yes (native EventSource) | Via WebSocket | Yes (fetch/XHR) |55| **Contract** | `.proto` schema | Hub interface | Convention | JSON-RPC spec | OpenAPI/Swagger |56| **Latency** | Lowest | Low | Low | Medium | Medium |57| **Throughput** | Highest | High | Moderate | Moderate | Moderate |58| **Streaming** | All 4 patterns | Server + client streaming | Server push only | No | No (chunked transfer) |59| **Connection** | HTTP/2 persistent | WebSocket (with fallback) | HTTP/1.1+ persistent | Transport-dependent | Per-request |60| **Service-to-service** | Excellent | Good | Limited | Niche | Good |61| **AOT-friendly** | Yes (Protobuf) | Yes | Yes | Yes | Yes (with STJ source gen) |6263---6465## Decision Flowchart6667````text6869Is this service-to-service (no browser)?70├── Yes → Do you need streaming?71│ ├── Yes → gRPC streaming [skill:dotnet-grpc]72│ └── No → Is it request-response?73│ ├── High throughput / binary → gRPC (unary) [skill:dotnet-grpc]74│ └── Standard CRUD / public API → REST [skill:dotnet-http-client]75└── No (browser client) → Do you need real-time?76 ├── Yes → Do you need bidirectional?77 │ ├── Yes → SignalR [skill:dotnet-realtime-communication]78 │ └── No (server push only) → SSE [skill:dotnet-realtime-communication]79 └── No → REST [skill:dotnet-http-client]8081Special cases:82- LSP / tooling protocol → JSON-RPC 2.0 [skill:dotnet-realtime-communication]83- Mixed (browser + service-to-service) → REST for browser, gRPC for internal8485```json8687---8889## Protocol Profiles9091### gRPC9293**Best for:** Service-to-service communication, high-throughput streaming, strongly-typed contracts.9495- Schema-first development with `.proto` files96- All four streaming patterns: unary, server streaming, client streaming, bidirectional97- Binary serialization (Protobuf) for smallest payloads and fastest throughput98- Built-in code generation for client and server stubs99- Native load balancing and health check protocol support100101**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.102103See [skill:dotnet-grpc] for full implementation details.104105### SignalR106107**Best for:** Browser-facing real-time applications, interactive dashboards, chat, collaborative features.108109- Automatic transport negotiation (WebSocket → SSE → Long Polling)110- Built-in group management and user targeting111- Hub abstraction with strongly-typed interfaces112- Scales with Redis backplane or Azure SignalR Service113- Supports JSON and MessagePack serialization114115**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.116117See [skill:dotnet-realtime-communication] for SignalR patterns and hub implementation.118119### Server-Sent Events (SSE)120121**Best for:** Simple server-to-client push notifications, live feeds, status updates.122123- Built-in to ASP.NET Core in .NET 10 via `TypedResults.ServerSentEvents`124- Browser-native `EventSource` API -- no client library needed125- Automatic reconnection with `Last-Event-ID`126- Works through HTTP/1.1 proxies that block WebSocket upgrade127- Lightest-weight real-time option128129**When NOT to use:** Bidirectional communication (use SignalR), high-throughput binary streaming (use gRPC), client-to-server messages needed.130131See [skill:dotnet-realtime-communication] for SSE implementation details.132133### JSON-RPC 2.0134135**Best for:** Tooling protocols (Language Server Protocol), structured RPC over simple transports.136137- Transport-agnostic (HTTP, WebSocket, stdio, named pipes)138- Well-defined request/response/notification semantics139- Used by Visual Studio, VS Code, and .NET tooling via StreamJsonRpc140- Lightweight alternative to gRPC when schema management is unwanted141142**When NOT to use:** Real-time streaming (use SignalR or gRPC), high-throughput service-to-service (use gRPC), standard web APIs (use REST).143144See [skill:dotnet-realtime-communication] for JSON-RPC 2.0 patterns.145146### REST (HTTP APIs)147148**Best for:** Public APIs, standard CRUD operations, broad client compatibility.149150- Universal client support (any HTTP client)151- Human-readable payloads (JSON)152- Rich ecosystem (OpenAPI, Swagger UI, API versioning)153- Stateless request-response model154- ASP.NET Core Minimal APIs or MVC controllers155156**When NOT to use:** Real-time push (use SSE or SignalR), high-throughput service-to-service (use gRPC), bidirectional streaming (use SignalR or gRPC).157158See [skill:dotnet-http-client] for HTTP client patterns, resilience, and `IHttpClientFactory`.159160---161162## Common Architecture Patterns163164### API Gateway with Mixed Protocols165166```text167168Browser ─── REST/SignalR ──→ API Gateway ──→ gRPC ──→ Internal Services169 ──→ gRPC ──→ Order Service170 ──→ gRPC ──→ Inventory Service171172```text173174Use 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.175176### Event-Driven with SSE177178```text179180Internal Services ──→ Message Broker ──→ SSE Endpoint ──→ Browser Dashboard181 ──→ gRPC Stream ──→ Monitoring Service182183```text184185Internal events flow through a message broker. Browser dashboards consume via SSE. Other services consume via gRPC streaming for higher throughput.186187### Dual-Protocol Services188189A single ASP.NET Core host can serve both gRPC and REST:190191```csharp192193var builder = WebApplication.CreateBuilder(args);194195builder.Services.AddGrpc();196builder.Services.AddControllers();197198var app = builder.Build();199200// gRPC for internal service-to-service201app.MapGrpcService<OrderGrpcService>();202203// REST for external clients204app.MapControllers();205206// SSE for real-time browser updates207app.MapGet("/events/orders", (OrderEventService svc, CancellationToken ct) =>208 TypedResults.ServerSentEvents(svc.GetEventsAsync(ct)));209210```text211212---213214## Key Principles215216- **Use gRPC for service-to-service** -- it provides the best throughput, strongly-typed contracts, and all streaming patterns217- **Use REST for public APIs** -- universal client support, human-readable, extensive tooling ecosystem218- **Use SignalR for browser real-time** -- automatic transport negotiation and built-in group management219- **Use SSE for simple server push** -- lightest option when bidirectional communication is not needed220- **Mix protocols when appropriate** -- a single ASP.NET Core host can serve gRPC, REST, SignalR, and SSE simultaneously221- **Route based on client type** -- browser clients get REST/SignalR/SSE; internal services get gRPC222223See [skill:dotnet-native-aot] for AOT compilation pipeline and [skill:dotnet-aot-architecture] for AOT-compatible communication patterns.224225---226227## Agent Gotchas2282291. **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.2302. **Do not use SignalR for service-to-service** -- gRPC provides better performance, code generation, and streaming for backend communication.2313. **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.2324. **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.2335. **Do not forget AOT considerations** -- REST endpoints using System.Text.Json need source-generated contexts for AOT. See [skill:dotnet-serialization] for details.2346. **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).235236---237238## References239240- [Choose between gRPC and REST](https://learn.microsoft.com/en-us/aspnet/core/grpc/comparison?view=aspnetcore-10.0)241- [gRPC for .NET](https://learn.microsoft.com/en-us/aspnet/core/grpc/?view=aspnetcore-10.0)242- [SignalR overview](https://learn.microsoft.com/en-us/aspnet/core/signalr/introduction?view=aspnetcore-10.0)243- [Server-Sent Events in .NET 10](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/server-sent-events?view=aspnetcore-10.0)244- [Minimal APIs](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis?view=aspnetcore-10.0)245- [IHttpClientFactory patterns](https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factory)246````247248## Code Navigation (Serena MCP)249250**Primary approach:** Use Serena symbol operations for efficient code navigation:2512521. **Find definitions**: `serena_find_symbol` instead of text search2532. **Understand structure**: `serena_get_symbols_overview` for file organization2543. **Track references**: `serena_find_referencing_symbols` for impact analysis2554. **Precise edits**: `serena_replace_symbol_body` for clean modifications256257**When to use Serena vs traditional tools:**258259- **Use Serena**: Navigation, refactoring, dependency analysis, precise edits260- **Use Read/Grep**: Reading full files, pattern matching, simple text operations261- **Fallback**: If Serena unavailable, traditional tools work fine262263**Example workflow:**264265```text266# Instead of:267Read: src/Services/OrderService.cs268Grep: "public void ProcessOrder"269270# Use:271serena_find_symbol: "OrderService/ProcessOrder"272serena_get_symbols_overview: "src/Services/OrderService.cs"273```