CapabilityScope
What Is a Scope?
A CapabilityScope is the container that manages all capability compositions. It holds two registries (composers and compositions) and provides the entry points for composing and querying capabilities.
Creating a Scope
// Default — both registries enabled
var scope = new CapabilityScope();
// With options
var scope = new CapabilityScope(new CapabilityScopeOptions
{
UseComposerRegistry = false,
UseCompositionRegistry = true
});Composing Capabilities
Compose() creates a Composer for a given subject:
var composer = scope.Compose("my-subject");
composer.Add(new SomeCapability()).Build();This registers the subject in the composer registry (if enabled), then Build() stores the resulting composition in the composition registry.
If you call Compose() on a subject that already has a composition, the new composition replaces the existing one in the registry. Use Recompose() instead when you want to build on existing capabilities.
Subject lifetime
When using a reference-type subject, the scope stores it via ConditionalWeakTable — if the subject is garbage collected, the composition silently disappears. Always keep a reference to your subject:
// Bad — temporary object, no reference held
scope.Compose(new MyService()).Add(cap).Build(); // composition may vanish after GC
// Good — reference kept alive
var service = new MyService();
scope.Compose(service).Add(cap).Build(); // composition lives as long as serviceSee Registries for details on reference vs value type storage.
Recomposing
Use Recompose() to create a new composition based on an existing one — it inherits all capabilities from the original:
var existing = scope.Compositions.GetRequired<string>("my-subject");
scope.Recompose(existing)
.Add(new AnotherCapability())
.Build();The new composition replaces the old one in the registry. The difference from calling Compose() again: Recompose() carries over all existing capabilities, while Compose() starts from scratch.
Context Isolation
Different scopes are completely independent worlds:
var scopeA = new CapabilityScope();
var scopeB = new CapabilityScope();
scopeA.Compose("user").Add(new CapA()).Build();
scopeB.Compose("user").Add(new CapB()).Build();
// scopeA only has CapA for "user"
// scopeB only has CapB for "user"Scope Lifetime
Scopes are typically long-lived — created once and shared. Common patterns:
- Application-wide: One scope for the entire app
- Per-tenant: Isolated scope per tenant
- Per-test: Fresh scope per test for isolation
CapabilityScope implements IDisposable to clean up registry resources.
Properties
| Property | Type | Description |
|---|---|---|
Composers | ComposerRegistryApi | Access the composer registry |
Compositions | CompositionRegistryApi | Access the composition registry |
Owner | ScopeOwnerApi | Associate a single owner with the scope |
Anchors | ScopeAnchorsApi | Associate typed or named anchors with the scope |