Overview
The HTTP gateway is Silky's external-facing REST interface layer. When an external request reaches the gateway, it passes through four sequential phases: ASP.NET Core routing → parameter extraction → service entry execution → response wrapping, returning the RPC result as a unified JSON format.
Pipeline Structure
External HTTP Request
│
▼
WrapperResponseMiddleware (intercepts Response.Body for unified wrapping)
│
▼
ASP.NET Core Routing (SilkyServiceEntryEndpointDataSource)
│ ──→ No match: 404
▼
MessageReceivedHandlerBase.Handle()
│ 1. Create HttpContextServerCallContext
│ 2. Initialize (set timeout token, activity tracing, resolve user claims)
▼
DefaultHttpMessageReceivedHandler.HandleCallAsyncCore()
│ 1. Parse HTTP parameters → object[]
│ 2. Resolve ServiceKey
│ 3. Start Monitor (optional)
│ 4. Call IHttpExecutor.Execute()
│ 5. Write response body
▼
WrapperResponseMiddleware
│ 1. Read Response.Body content
│ 2. Wrap as { status, code, result / errorMessage }
│ 3. Write back to response
▼
Client receives unified JSON format
Phase 1: Route Matching
At gateway startup, SilkyServiceEntryEndpointDataSource registers all ServiceEntry objects as ASP.NET Core Endpoints. Standard ASP.NET Core routing matches incoming requests by HTTP method + path.
On a successful match, ServiceEntry and ServiceEntryDescriptor are stored in HttpContext.Items for downstream components.
Phase 2: Message Handler
After route matching, the request enters DefaultHttpMessageReceivedHandler:
MessageReceivedHandlerBase.Handle() (Base Class)
Performs unified initialization:
- Creates
HttpContextServerCallContext(binds timeout token and activity tracing) - Sets
CancellationTokenfor the request - Dispatches to the subclass implementation
DefaultHttpMessageReceivedHandler.HandleCallAsyncCore()
Core request processing:
- Parameter extraction: Resolves path parameters, query strings, and request body into
object[]according toParameterDescriptors - ServiceKey resolution: Reads from the request header
X-ServiceKeyorRpcContext - Monitor: Starts RPC call monitoring if
EnableMonitor = true - Execution: Calls
IHttpExecutor.Execute(serviceEntry, parameters, serviceKey) - Response write: Serializes the result to JSON and writes to
Response.Body
Phase 3: Unified Response Wrapping
WrapperResponseMiddleware intercepts the response before it reaches the client:
Success Response
{
"status": 200,
"code": "Success",
"result": { ... }
}
Error Response
{
"status": 500,
"code": "InternalServerError",
"errorMessage": "Business error description",
"validationErrors": [...]
}
Paths Excluded from Wrapping
Configure Gateway:IgnoreWrapperPathPatterns to bypass wrapping for specific paths (static files, health checks, file downloads):
Gateway:
IgnoreWrapperPathPatterns:
- "\\/.*\\.(js|css|html|ico|png)"
- "\\/(healthchecks|healthz)"
- "\\/api\\/file\\/.*"
IHttpExecutor vs. IExecutor
IHttpExecutor extends IExecutor with HTTP-specific parameter binding. For gateway calls:
- If the service is local (gateway host has the implementation): routes to
DefaultLocalExecutor - If the service is remote (most common for gateways): routes to
DefaultRemoteExecutor→ DotNetty RPC → target microservice
The gateway itself typically has no business service implementations — it acts purely as a routing proxy.
Authentication & Authorization at the Gateway
The gateway validates JWT tokens before routing to backend services:
JwtBearerMiddlewarevalidates the token usingGateway:JwtSecret- On success, user claims (
UserId,TenantId, roles, etc.) are extracted and stored inHttpContext.User MessageReceivedHandlerBase.Initialize()readsHttpContext.Userand sets claim values intoRpcContext.Attachments- Attachments are propagated to backend microservices via the RPC transport layer
Backend services can access RpcContext.Context.GetUserId() without receiving JWT tokens directly.
