Class SessionContext
Dual-identity session context: Actor (who triggered) + the data-owner pair (TenantId, UserId). For 95% of operations Actor equals the data-owner; the distinction only diverges for PlatformAdmin cross-tenant operations, anonymous endpoints, and system/saga flows.
Convention across the codebase: unprefixed properties (TenantId,
UserId) identify the data owner; Actor* properties identify
the principal who triggered the write (audit / "who did this"). This matches
every other IMultiTenant entity in the system.
[ExcludeFromCodeCoverage]
public sealed record SessionContext : IEquatable<SessionContext>
- Inheritance
-
SessionContext
- Implements
- Inherited Members
- Extension Methods
Constructors
SessionContext(string, string?, string?, Guid, Guid, Guid, Guid?, Guid?)
Dual-identity session context: Actor (who triggered) + the data-owner pair (TenantId, UserId). For 95% of operations Actor equals the data-owner; the distinction only diverges for PlatformAdmin cross-tenant operations, anonymous endpoints, and system/saga flows.
Convention across the codebase: unprefixed properties (TenantId,
UserId) identify the data owner; Actor* properties identify
the principal who triggered the write (audit / "who did this"). This matches
every other IMultiTenant entity in the system.
public SessionContext(string CorrelationId, string? CausationId, string? ClientConnectionId, Guid ActorTenantId, Guid ActorUserId, Guid TenantId, Guid? UserId, Guid? ClientId = null)
Parameters
CorrelationIdstringStable correlation identifier (typically a v7 GUID string) — propagated across hops for log/trace correlation.
CausationIdstringCausation identifier (the upstream command/event id) — propagated for causality chains.
ClientConnectionIdstringOptional connection identifier (SignalR / WebSocket / call session) — used for proactive push.
ActorTenantIdGuidTenant id of the principal who triggered the operation (audit dimension).
ActorUserIdGuidUser id of the principal who triggered the operation (audit dimension).
TenantIdGuidTenant the data belongs to (data-owner dimension; routing, encryption AAD, query filter).
UserIdGuid?Optional user the data belongs to (null for tenant-scoped aggregates).
ClientIdGuid?Optional client identifier (browser tab / phone call / SSR session) — the connection identity, neither actor nor subject; use it to address one connection.
Fields
SystemActorTenantId
Sentinel for service/saga flows that have no inherited Actor. Distinguishable from Guid.Empty (which is used for anonymous endpoints).
public static readonly Guid SystemActorTenantId
Field Value
SystemActorUserId
Sentinel for service/saga flows that have no inherited Actor. Distinguishable from Guid.Empty (which is used for anonymous endpoints).
public static readonly Guid SystemActorUserId
Field Value
Properties
ActorTenantId
Tenant id of the principal who triggered the operation (audit dimension).
[JsonPropertyName("ActorTenantId")]
public Guid ActorTenantId { get; init; }
Property Value
ActorUserId
User id of the principal who triggered the operation (audit dimension).
[JsonPropertyName("ActorUserId")]
public Guid ActorUserId { get; init; }
Property Value
CausationId
Causation identifier (the upstream command/event id) — propagated for causality chains.
[JsonPropertyName("CausationId")]
public string? CausationId { get; init; }
Property Value
ClientConnectionId
Optional connection identifier (SignalR / WebSocket / call session) — used for proactive push.
[JsonPropertyName("ClientConnectionId")]
public string? ClientConnectionId { get; init; }
Property Value
ClientId
Optional client identifier (browser tab / phone call / SSR session) — the connection identity, neither actor nor subject; use it to address one connection.
[JsonPropertyName("ClientId")]
public Guid? ClientId { get; init; }
Property Value
- Guid?
CorrelationId
Stable correlation identifier (typically a v7 GUID string) — propagated across hops for log/trace correlation.
[JsonPropertyName("CorrelationId")]
public string CorrelationId { get; init; }
Property Value
TenantId
Tenant the data belongs to (data-owner dimension; routing, encryption AAD, query filter).
[JsonPropertyName("TenantId")]
public Guid TenantId { get; init; }
Property Value
UserId
Optional user the data belongs to (null for tenant-scoped aggregates).
[JsonPropertyName("UserId")]
public Guid? UserId { get; init; }
Property Value
- Guid?
Methods
Empty()
Returns an empty/anonymous session-context value with freshly generated correlation + causation ids.
public static SessionContext Empty()
Returns
ForPlatform(Guid, Guid?)
Returns a session for work the platform starts on a tenant's behalf — a durable timer, a saga step, a sweep — with the reserved system actor identities, a fresh correlation identity and a causation identity of its own.
public static SessionContext ForPlatform(Guid tenantId, Guid? userId = null)
Parameters
tenantIdGuidThe tenant the work is done for — the data owner.
userIdGuid?The user the work concerns, or null for tenant-scoped work.
Returns
- SessionContext
A session naming the platform as the actor and
tenantIdas the data owner.
Remarks
The audit trail then records that the platform acted for the tenant, rather than recording the tenant as having acted. Strict tenant isolation recognises the shape and does not refer it to the cross-tenant authorizer, because the platform acting for a tenant is not one tenant acting on another.
The causation identity is minted here because no command preceded the work and the event store requires one of every entry it records.