From dotnet-skills
Choosing inter-service protocols. REST vs gRPC vs SignalR vs SSE decision matrix, tradeoffs.
npx claudepluginhub wshaddix/dotnet-skillsThis skill uses the workspace's default tool permissions.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
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.
Out of scope: HTTP client factory patterns and resilience pipelines -- see [skill:dotnet-http-client] and [skill:dotnet-resilience]. Native AOT architecture and trimming strategies -- see [skill:dotnet-native-aot] for AOT compilation, [skill:dotnet-aot-architecture] for AOT-first design patterns, and [skill:dotnet-trimming] for trim-safe development.
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.
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) |
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
Best for: Service-to-service communication, high-throughput streaming, strongly-typed contracts.
.proto filesWhen 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.
Best for: Browser-facing real-time applications, interactive dashboards, chat, collaborative features.
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.
Best for: Simple server-to-client push notifications, live feeds, status updates.
TypedResults.ServerSentEventsEventSource API -- no client library neededLast-Event-IDWhen 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.
Best for: Tooling protocols (Language Server Protocol), structured RPC over simple transports.
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.
Best for: Public APIs, standard CRUD operations, broad client compatibility.
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.
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.
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.
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)));
See [skill:dotnet-native-aot] for AOT compilation pipeline and [skill:dotnet-aot-architecture] for AOT-compatible communication patterns.