SAIF.Platform¶
The base "service defaults" package every Forge .NET service depends on. It follows the Aspire service defaults pattern — most of Extensions.cs is stock Aspire template output — with a documented Forge-specific delta on top.
Getting started¶
Stock Aspire behavior¶
The following are unmodified from the Aspire template and documented by Microsoft, not re-explained here:
- OTel base instrumentation for ASP.NET Core,
HttpClient, and the .NET runtime. - OTLP export, enabled when
OTEL_EXPORTER_OTLP_ENDPOINTis set. AddDefaultHealthChecks()and itsselfliveness check.AddServiceDiscovery().AddStandardResilienceHandler(), including its retry-on-POST behavior./healthand/aliveendpoints, mapped byMapDefaultEndpoints().
Forge-specific delta¶
The rest of Extensions.cs is Forge's own addition on top of the template. This is the part worth reading before you rely on it.
ConfigureDistributedCache¶
Reads REDIS_CONNECTION_STRING and falls back to AddDistributedMemoryCache() when it's unset. That Redis branch is currently dead code — nothing in the repo ever sets REDIS_CONNECTION_STRING (no Terraform module, no template, no pipeline), so 100% of Forge apps take the in-memory fallback today. Tracked for removal in #1171.
The practical consequence is that the distributed cache is per-instance. Under scale-out or slot deployments, each instance holds its own cache, which shows up as extra OBO token round trips in the saif.authentication.token_cache.hits/misses counters. This isn't a correctness bug, just a characteristic worth knowing.
The method itself isn't going away even once the Redis branch is removed — SAIF.Platform.Authentication's RequestAccessTokenService depends on IDistributedCache for OBO access-token caching.
AddDefaultCors¶
- Development: permissive — any method, any header, credentials allowed. Allowed origins are auto-discovered by recursively walking the
Servicesconfiguration section. - Production: no CORS policy at all.
This is a dev/prod behavior cliff, not a bug. If a service needs CORS in production, it has to configure its own policy explicitly.
ConfigureOpenTelemetry¶
tracing.SetSampler(new AlwaysOnSampler())— 100% trace retention. This is an ingest-cost/volume tradeoff, not a fixed requirement; it's worth revisiting per-service if trace volume becomes expensive.AddSource("*")/AddMeter("*")— wildcard collection of all sources and meters, opt-out rather than stock Aspire's explicit opt-in instrumentation list.
UseServiceDefaults(WebApplication)¶
A Forge-only wrapper around UseCors() (in Development) plus MapDefaultEndpoints(). Stock Aspire only maps default endpoints; the CORS call is Forge's addition.
Diagnostics.ActivitySource¶
Platform self-instrumentation — AddServiceDefaults and friends emit their own activities tagged with platform.* attributes (e.g. platform.cache.provider, platform.cors.development_policy), separate from the app-level tracing they configure.
Related open work¶
- #1171 — remove the dead Redis path and its now-unused
Microsoft.Extensions.Caching.StackExchangeRedisdependency. Not implemented by this PR; documented here as current behavior only.