Architecture Design
MicroStack emulates 39 AWS services on a single HTTP port. Every request flows through the same pipeline: middleware reads the raw HTTP request, detects which AWS service is being called, dispatches to the matching handler, and writes the response.
Request Pipeline
HTTP Request
|
v
+-------------------------------+
| ASP.NET Core Middleware |
| (AwsRequestMiddleware) |
| |
| 1. Read raw body |
| 2. Decode AWS chunked enc. |
| 3. Extract account ID |
| 4. Route to service handler |
+-------------------------------+
|
v
+-------------------------------+
| AwsServiceRouter |
| |
| Detection chain: |
| 1. X-Amz-Target header |
| 2. Authorization cred scope |
| 3. Action query parameter |
| 4. URL path patterns |
| 5. Host header patterns |
| 6. Default -> S3 |
+-------------------------------+
|
v
+-------------------------------+
| IServiceHandler |
| (e.g. SqsServiceHandler) |
| |
| - Parses request |
| - Executes action |
| - Returns ServiceResponse |
+-------------------------------+
|
v
HTTP Response (with CORS headers)
Key Components
AwsRequestMiddleware
The central middleware (src/MicroStack/Internal/AwsRequestMiddleware.cs) handles every non-admin request:
- Body reading: Reads the entire request body into a
byte[]. - AWS chunked decoding: The AWS SDK sometimes uses a custom chunked transfer encoding (
STREAMING-*content SHA-256). The middleware decodes this before passing the body to handlers. - Account scoping: Extracts the AWS access key from the
Authorizationheader. If it's a 12-digit number, it becomes the account ID for this request (enabling multi-tenancy). - Pre-router dispatch: Some requests are routed before the main detection chain — virtual-hosted S3 buckets, execute-api data plane, ALB data plane, Cognito well-known endpoints, and others.
- CORS: Every response gets permissive CORS headers. OPTIONS pre-flight requests return 204 immediately.
AwsServiceRouter
The router (src/MicroStack/Internal/AwsServiceRouter.cs) uses a six-step detection chain to identify the target service:
- X-Amz-Target header — Most reliable for JSON-protocol services (DynamoDB, SQS, SNS, KMS, etc.). Maps prefixes like
DynamoDB_20120810todynamodb. - Authorization credential scope — Parses the
Credential=.../service/aws4_requestportion of the AWS Signature V4 header. - Action query parameter — For Query/XML services (EC2, RDS, SES, CloudFormation, etc.), the
Actionparam identifies the service. - URL path patterns — Lambda (
/2015-03-31/functions), API Gateway (/v2/apis), Route 53 (/2013-04-01/), etc. - Host header patterns — Matches subdomains like
sqs.us-east-1.localhost. - Default — Falls back to S3 (path-style bucket operations).
ServiceRegistry
The registry (src/MicroStack/Internal/ServiceRegistry.cs) maps service names to handler instances:
- Handlers register at startup in
Program.cs. - The
SERVICESenvironment variable filters which handlers are active. - Service name aliases are supported (e.g.,
cloudwatch->monitoring,eventbridge->events). - Provides
ResetAll()for the/_microstack/resetendpoint andGetServiceStatus()for health checks.
IServiceHandler
Every service implements IServiceHandler:
internal interface IServiceHandler
{
string ServiceName { get; }
Task<ServiceResponse> HandleAsync(ServiceRequest request);
void Reset();
object? GetState();
void RestoreState(object data);
}HandleAsyncis the main dispatch point. Each handler parses the action from headers/body/path and routes to the appropriate internal method.Resetclears all in-memory state (called by the reset endpoint).GetState/RestoreStateenable JSON persistence.
ServiceRequest / ServiceResponse
Simple value types that abstract the HTTP layer:
- ServiceRequest: method, path, headers dict, body bytes, query params.
- ServiceResponse: status code, headers dict, body bytes. Helpers for JSON, XML, and empty responses.
AWS Protocol Support
MicroStack handles four AWS API protocols:
| Protocol | Services | How It Works |
|---|---|---|
| JSON (X-Amz-Target) | SQS, DynamoDB, SNS, KMS, SSM, Secrets Manager, Step Functions, CloudWatch Logs, ECS, Kinesis, Glue, Athena, Cognito, ECR, WAF | Action extracted from X-Amz-Target header, body is JSON |
| Query/XML | EC2, RDS, ElastiCache, SES, CloudFormation, ELB, CloudWatch, IAM, STS | Action from Action form parameter, response is XML |
| REST/JSON | Lambda, API Gateway, S3 (partially), EFS, AppSync, CloudFront, EventBridge | Action from HTTP method + path, body is JSON |
| REST/XML | S3, Route 53 | Action from HTTP method + path, response is XML |
| CBOR | CloudWatch Metrics (SDK v4) | Binary CBOR encoding for metrics operations |
Admin Endpoints
Three admin endpoints are registered before the AWS middleware:
GET /_microstack/health— Returns service status and version. Also available at/healthand/_localstack/health.POST /_microstack/reset— Clears all in-memory state and deletes persisted state files.POST /_microstack/config— Applies runtime configuration (currently supports Step Functions mock config).
Startup Flow
Program.cs orchestrates startup:
- Bind environment variables into
MicroStackOptions. - Configure
AccountContextwith the default account ID. - Register core infrastructure (router, registry, persistence) in DI.
- Build the
WebApplication. - Restore persisted state from disk (if enabled).
- Instantiate and register all 39 service handlers.
- Map admin endpoints.
- Wire middleware pipeline:
UseRouting()-> OPTIONS handler ->UseMiddleware<AwsRequestMiddleware>()->UseEndpoints(). - Register shutdown hook to save state.
- Run.
Cross-Service Communication
Some services need to call others:
- SNS -> SQS: SNS subscriptions with
sqsprotocol inject messages directly viaSqsServiceHandler.InjectMessage(). - Lambda -> SQS/DynamoDB: Event source mappings poll SQS queues and DynamoDB streams.
- API Gateway -> Lambda: Proxy integrations invoke Lambda functions via
LambdaServiceHandler.InvokeForApiGateway(). - Step Functions -> Lambda: Task states invoke Lambda functions during execution.
- CloudFormation -> All: Resource provisioning dispatches to handlers via
ServiceRegistry.Resolve(). - Service Discovery -> Route 53: DNS namespace operations create hosted zones.
- STS -> IAM: STS reads IAM roles and access keys for assume-role operations.
- Cognito Identity -> Cognito IdP: Identity pools reference user pool tokens.
These dependencies are wired via constructor injection in Program.cs.
MicroStack