Skip to content

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

builder.AddServiceDefaults();

// ...

app.UseServiceDefaults();

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_ENDPOINT is set.
  • AddDefaultHealthChecks() and its self liveness check.
  • AddServiceDiscovery().
  • AddStandardResilienceHandler(), including its retry-on-POST behavior.
  • /health and /alive endpoints, mapped by MapDefaultEndpoints().

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 Services configuration 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.

  • #1171 — remove the dead Redis path and its now-unused Microsoft.Extensions.Caching.StackExchangeRedis dependency. Not implemented by this PR; documented here as current behavior only.

View source on GitHub