Demonstrates integrating Replane into an ASP.NET Core Web API with:
- Dependency injection
- Feature flags middleware
- Per-request context evaluation
- .NET 8.0 SDK or later
- A running Replane server
- An SDK key from your Replane project
-
Copy this directory to your local machine:
cp -r WebApiIntegration ~/my-replane-example cd ~/my-replane-example
-
Set your environment variables:
export REPLANE_BASE_URL="https://your-replane-server.com" export REPLANE_SDK_KEY="your-sdk-key"
Or use
appsettings.json:{ "Replane": { "BaseUrl": "https://your-replane-server.com", "SdkKey": "your-sdk-key" } } -
Restore packages:
dotnet restore
dotnet runThe API will start at http://localhost:5000 (or the port shown in console).
Open Swagger UI at: http://localhost:5000/swagger
Returns the welcome message from config.
curl http://localhost:5000/
# {"message":"Welcome to the API!"}Health check endpoint (bypasses maintenance mode).
curl http://localhost:5000/health
# {"status":"healthy"}Get a specific config value.
curl http://localhost:5000/config/api-rate-limit
# {"name":"api-rate-limit","value":100}Get user-specific features based on context from headers.
# Free user
curl http://localhost:5000/features \
-H "X-User-Id: user-123" \
-H "X-User-Plan: free"
# {"userId":"user-123","plan":"free","features":{"premiumFeatureEnabled":false,"rateLimit":100}}
# Premium user
curl http://localhost:5000/features \
-H "X-User-Id: user-456" \
-H "X-User-Plan: premium"
# {"userId":"user-456","plan":"premium","features":{"premiumFeatureEnabled":true,"rateLimit":1000}}Register the Replane client as a singleton service:
builder.Services.AddSingleton(replaneClient);Connect to Replane during app startup:
try
{
await replaneClient.ConnectAsync();
}
catch (ReplaneException ex)
{
// Fall back to default values
}Use Replane for middleware decisions:
app.Use(async (context, next) =>
{
var client = context.RequestServices.GetRequiredService<ReplaneClient>();
var maintenanceMode = client.Get<bool>("maintenance-mode");
if (maintenanceMode)
{
context.Response.StatusCode = 503;
return;
}
await next();
});Build context from request headers/JWT:
app.MapGet("/features", (HttpContext http, ReplaneClient client) =>
{
var context = new ReplaneContext
{
["user_id"] = http.Request.Headers["X-User-Id"].FirstOrDefault(),
["plan"] = http.Request.Headers["X-User-Plan"].FirstOrDefault()
};
return client.Get<bool>("premium-feature", context);
});Dispose the client on shutdown:
lifetime.ApplicationStopping.Register(() =>
{
replaneClient.Dispose();
});- Register as singleton - The client maintains a persistent connection
- Connect at startup - Don't connect on first request
- Handle connection failures - Use defaults for resilience
- Build context from request - User ID, plan, region from JWT/headers
- Dispose on shutdown - Clean up the SSE connection
if (client.Get<bool>("new-search-enabled", userContext))
{
return await NewSearchAsync();
}
return await OldSearchAsync();var rateLimit = client.Get<int>("api-rate-limit", userContext);
// Apply rate limitvar variant = client.Get<string>("checkout-flow", userContext);
// "variant-a" or "variant-b" based on user segmentation