Skip to content

Anchors API

While the Owner API gives a scope a single identity, you often need to associate additional context objects — a database connection, a cache, an environment context. Anchors let you attach multiple named or typed objects to the scope and compose capabilities onto them.

Two kinds exist: typed anchors (keyed by type, one per type) and named anchors (keyed by string, for multiple instances of the same type).

Typed Anchors

Setting

csharp
var db = new DatabaseConnection("connstr");
scope.Anchors.Set<DatabaseConnection>(db);

Getting

csharp
// Get — returns null if not set or collected
var db = scope.Anchors.Get<DatabaseConnection>();

// GetOrThrow — throws if not set or collected
var db = scope.Anchors.GetOrThrow<DatabaseConnection>();

// TryGet — out-parameter pattern
if (scope.Anchors.TryGet<DatabaseConnection>(out var db))
{
    db.Query("SELECT 1");
}

Named Anchors

Setting

csharp
scope.Anchors.Set("primary-db", primaryDb);
scope.Anchors.Set("replica-db", replicaDb);

Getting

csharp
// Get — returns null if not set or collected
var db = scope.Anchors.Get("primary-db");

// GetOrThrow — throws if not set or collected
var db = scope.Anchors.GetOrThrow("primary-db");

// TryGet — out-parameter pattern
if (scope.Anchors.TryGet("primary-db", out var db))
{
    // use db
}

Composing via Anchors

Typed

csharp
scope.Anchors.Set<DatabaseConnection>(db);
scope.Anchors.ComposeFor<DatabaseConnection>()
    .Add(new PoolingCapability { MaxSize = 10 })
    .Build();

Named

csharp
scope.Anchors.Set("cache", cache);
scope.Anchors.Compose("cache")
    .Add(new ExpirationCapability { Ttl = TimeSpan.FromMinutes(5) })
    .Build();

Retrieving Compositions

Typed

csharp
Composition? comp = scope.Anchors.GetCompositionFor<DatabaseConnection>();
Composition required = scope.Anchors.GetRequiredCompositionFor<DatabaseConnection>();

if (scope.Anchors.TryGetCompositionFor<DatabaseConnection>(out var comp))
{
    // use composition
}

Named

csharp
Composition? comp = scope.Anchors.GetComposition("cache");
Composition required = scope.Anchors.GetRequiredComposition("cache");

if (scope.Anchors.TryGetComposition("cache", out var comp))
{
    // use composition
}

Retrieving Composers

Typed

csharp
Composer? c = scope.Anchors.GetComposerFor<DatabaseConnection>();
Composer required = scope.Anchors.GetRequiredComposerFor<DatabaseConnection>();

if (scope.Anchors.TryGetComposerFor<DatabaseConnection>(out var composer))
{
    // composer still in registry
}

Named

csharp
Composer? c = scope.Anchors.GetComposer("cache");
Composer required = scope.Anchors.GetRequiredComposer("cache");

if (scope.Anchors.TryGetComposer("cache", out var composer))
{
    // use composer
}

Fluent Chaining

Anchors methods return ScopeAnchorsApi:

csharp
scope.Anchors
    .Set<DatabaseConnection>(db)
    .Set("cache", cache)
    .Scope  // return to scope
    .Compose("something")
    .Build();

Weak References

Like the Owner API, anchors are stored as weak references. Anchored objects can be garbage collected without the scope preventing it.

Typed vs Named — When to Use

Use CaseTypedNamed
One instance per typeYes
Multiple instances of same typeYes
Compile-time type safetyYes
Dynamic/runtime keysYes

Released under the Apache-2.0 License.