Flow Studio
ExpressionContext (EvaluationContext)
EvaluationContext is the object built by ExpressionContextFactory and passed to the expression resolver. It aggregates all data sources the resolver needs: tenant identity, execution memory, node input/output data, and flow facts.
EvaluationContext Shape
// BizFirst.Runtime.Expressions.Evaluation.Domain.Models.EvaluationContext
public class EvaluationContext
{
// Identity
public string TenantId { get; set; }
public string? UserId { get; set; }
public string? ApplicationId { get; set; }
public string? CorrelationId { get; set; }
// Expression syntax configuration
public WildcardSyntax ActiveSyntax { get; set; } // AtBrace = @{...}
// Data sources — each is an adapter over the ProcessEngine domain
public IExecutionMemory? Memory { get; set; } // variables
public INodeDataContext? NodeData { get; set; } // input/output data
public INodeExecutionFacts? ExecutionFacts { get; set; } // node timing, status
public IWorkflowFlowFacts? FlowFacts { get; set; } // thread, execution ids
}
How ExpressionContextFactory Builds It
// ExpressionContextFactory.cs
public EvaluationContext Create(ProcessElementExecutionContext elementContext)
{
var thread = elementContext.ParentThreadContext;
var memory = thread?.Memory;
return new EvaluationContext
{
TenantId = elementContext.TenantId?.ToString() ?? string.Empty,
UserId = elementContext.UserId?.ToString(),
ActiveSyntax = WildcardSyntax.AtBrace, // @{...} syntax
CorrelationId = thread?.ParentProcessContext?.CorrelationId,
// ExecutionMemoryAdapter bridges domain ExecutionMemory → IExecutionMemory
Memory = memory is not null ? new ExecutionMemoryAdapter(memory) : null,
// NodeDataContextAdapter exposes input and node outputs
NodeData = new NodeDataContextAdapter(elementContext),
// NodeExecutionFactsAdapter exposes timing/status facts
ExecutionFacts = new NodeExecutionFactsAdapter(elementContext),
// WorkflowFlowFactsAdapter exposes execution/thread IDs
FlowFacts = thread is not null ? new WorkflowFlowFactsAdapter(thread) : null,
};
}
Adapters and What They Expose
| Adapter | Exposes | Directive Prefix |
|---|---|---|
ExecutionMemoryAdapter |
Workflow variables from ExecutionMemory.GetVariable(key) |
@{var:name} |
NodeDataContextAdapter |
Current node's input data + all completed node outputs via NodeOutputs |
@{input:field}, @{output:nodeId.field} |
NodeExecutionFactsAdapter |
Node timing, status, retry count from ProcessElementExecutionContext |
@{facts:...} |
WorkflowFlowFactsAdapter |
ExecutionId, ThreadId, ParentProcessId from the thread context | @{context:executionId} etc. |
When Context Is Partial
If the node has no parent thread context (e.g. in unit tests or trigger-only validation), the adapters for Memory and FlowFacts will be null. The resolver treats null adapters as empty data sources — expressions referencing variables or execution IDs resolve to null/empty rather than throwing.
NodeDataContextAdapter Is Branch-Aware
GetNodeResultData(nodeId) calls GetNodeResultBranches(nodeId) on the execution memory, which returns the correct branch output (success data, not error data) for each completed node. This ensures @{output:nodeId.field} always reads from the success output of that node.