Synapse Plans: ParameterInfo Blocks

ParameterInfo blocks are configuration information used to initialize Handler modules (Handler->Config) and pass runtime invocation data to Handler methods (Action->Parameters). Additionally, a ParameterInfo block declares the start-up configuration for SecurityContext modules (RunAs->Config). For clarity, ParameterInfo block are used in the following contexts:

Name: SamplePlan
Actions:
- Name: SampleAction
  Handler:
    Config:
      {ParameterInfo Block}
  Parameters:
    {ParameterInfo Block}
  RunAs:
    Config:
      {ParameterInfo Block}

Overview

Field Description
Name The name of the Config/Parameters block. If supplied, the block will stored as a global variable.
Type The serialization format of the Values section.
InheritFrom References the Name of another, previously stored Config/Parameters block. The inherited values are propagated to the current block.
Uri Retrieves data from a URI; propagates values to Parameters->Values.
Values A custom data structure as defined by the Handler. All the other sections of a ParameterInfo block exist to define or modify the Values section, which is ultimately passed to the Handler->Execute method as runtime invocation data.
Dynamic Retrieves named values (Source) from the cmdline or URL and substitutes them into Values at the Target location. Use Options to provide a predetermined set of values.
ParentExitData Retrieves the Result->ExitData from the parent Handler and propagates the values to Parameters->Values. Use TransformInPlace for light data manipulation prior to CopyToValues.
ForEach Iterates ForEach->Values, substituting the current value into Parameters->Values at the given Target. As ForEach is a list, multiple ForEach items will produce a Cartesian result across the Values sets. Use ParameterSource to access the ParentExitData or another named Config/Parameters block's data, retrieving a list from the Source location to propagate to Values.
Crypto As with other section, use to encrypt selected values with the local Config/Parameters block.
  Parameters:
    Name: NameSupportsInheritance
    Type: Yaml
    InheritFrom: APrecedingNamedParamInfo
    Uri: http://host/path
    Values: Custom values as defined by Handler/Provider
    Dynamic:
    - Source: URI parameter name
      Target: Element:IndexedElement[0]:Element
      Parse: true
      Replace: Regex Expression
      Encode: Base64
      Description: A human-friendly description.
      DataType: String
      Validation: Regex Expression
      RestrictToOptions: true
      Default:
        Value: Simple value or YAML/JSON/XML structure
        AllowNull: true|false
      Options:
      - Key: key
        Value: value
        Description: A human-friendly description.
        IsDefault: true
      - Key: key
        Value: value
        Description: A human-friendly description.
        IsDefault: false
    ParentExitData:
    - TransformInPlace:
        Source: Element:IndexedElement[0]:Element
        Target: Element:IndexedElement[0]:Element
        Parse: true
        Replace: Regex Expression
        Encode: None | Base64
      CopyToValues:
        Source: Element:IndexedElement[0]:Element
        Target: Element:IndexedElement[0]:Element
        Parse: true
        Replace: Regex Expression
        Encode: None | Base64
    ForEach:
    - ParameterSource:
        Name: Named ParameterInfo Block
        Source: Element:IndexedElement[0]:Element
        Parse: false
      Target: Element:IndexedElement[0]:Element
      Replace: Regex Expression
      Encode: None | Base64
      Values:
      - value0
      - value1
    Crypto:
      Key:
        Uri: Filepath to RSA key file; http support in future.
        ContainerName: RSA=supported container name
        CspFlags: NoFlags
      Elements:
      - Element:IndexedElement[0]:Element
      - Element:IndexedElement[1]:Element

Example per SerializationType

Serialization Basic ForEach
YAML Basic ForEach
JSON Basic ForEach
XML Basic ForEach

Detailed Field Description

Name

The friendly name of the current ParameterInfo block. This name is recorded in a dictionary at runtime and is used when referenced by other ParameterInfo block's InheritFrom field. A ParameterInfo block Name should be unique within a Plan, or successive blocks of the same name will replace the dictionary pointer.

Type

Dictates the serialization language of the Uri, Values, Dynamic, and ForEach fields. Options are SerializationType: Yaml, Json, Xml. If Type is omitted, the runtime engine defaults to Yaml.

InheritFrom

The name of another ParameterInfo block within the current Plan. Inheritable ParameterInfo blocks must precede the current ParameterInfo block in the Plan execution cycle.

Uri

A file or http URI from which to fetch values. URI-based values are suitable for storing commonly used, shared data sets and override any values gained from InheritFrom. The format of the file/http payload should be just the plain value set (no Synapse Plan attributes), as in the following examples.

  • YAML Example
    • Uri: file://C:/Synapse.UnitTests/Plans/Parms/yaml_in.yaml
    • The contents of the file yaml_in.yaml are:
PNode0: PValue0_file
PNode1: PValue1_file
PNode2:
  PNode2_1: PValue2_1_file
  PNode2_2: PValue2_2_file
  • XML Example
    • Uri: file://C:/Synapse.UnitTests/Plans/Parms/xml_in.xml
    • The contents of the file xml_in.xml are:
<PXmlDoc>
    <PNode0 PAttr0="PAValue0_file">PValue0_file</PNode0>
    <PNode1>PValue1_file</PNode1>
    <PNode2>
        <PNode2_1>PValue2_1_file</PNode2_1>
        <PNode2_2>PValue2_2_file</PNode2_2>
    </PNode2>
</PXmlDoc>

Values

Locally declared values within a Plan. Local Values are suitable for Plan-level/Plan-specific usage and override any values gained from InheritFrom and Uri.

  • YAML Example:
  Values:
    PNode0: PValue0_inline
    PNode1: PValue1_inline
    PNode3:
      PNode3_1: PValue3_1_inline
      PNode3_2: PValue3_2_inline
  • JSON Example:
  Values:
    {
      "CNode0": "CValue0_inline",
      "CNode1": "CValue1_inline",
      "CNode3": {
        "CNode3_1": "CValue3_1_inline",
        "CNode3_2": "CValue3_2_inline",
      }
    }
  • XML Example:
  Values:
    <CXmlDoc>
        <CNode0>CValue0_inline</CNode0>
        <CNode1>CValue1_inline</CNode1>
        <CNode3>
            <CNode3_1 CAttr3_1="CAValue3_1_inline">CValue3_1_inline</CNode3_1>
            <CNode3_2>CValue3_2_inline</CNode3_2>
        </CNode3>
    </CXmlDoc>

Dynamic

Dynamic supports values which are provided dynamically at runtime, such as through CLI or URL parameters, which can then be mapped to Parameters->Values via Source/Target pairs. Sources are declared in XPath for XML serialization and colon-separated lists (root:node0:node1:...) for YAML/JSON. If the target path exists in the child data, the value updated. If the target path does not exist, it will be created and seeded. Of particular interest, YAML/JSON structures arriving as strings may optionally be Parsed and integrated into the Parameters Values structure itself.

  Dynamic:
  - Source: URI parameter name
    Target: Element:IndexedElement[0]:Element
    Parse: true
    Replace: Regex Expression
    Encode: Base64
    Description: A human-friendly description.
    DataType: String
    Validation: Regex Expression
    RestrictToOptions: true
    Default:
      Value: Simple value or YAML/JSON/XML structure
      AllowNull: true|false
    Options:
    - Key: key
      Value: value
      Description: A human-friendly description.
      IsDefault: true
    - Key: key
      Value: value
      Description: A human-friendly description.
      IsDefault: false
Name Type/Value Required Description
Source String Yes The key name of the value in the dynamic values key-value pair collection.
Target String Yes The path the target location to add/update the value/structure. If the target path does not exist, it will be created and seeded.
Parse Boolean No Tries to parse the Source value as YAML/JSON and integrate the result into the Parameters Values structure. This setting does not apply to XML data structures.
Replace String No Performs a Regular Expression replacement of the Target value with the value from Source, subject to the Regex pattern.
Encode Enum No Specifies how to encode the value before replacement. Options are None and Base64.
Description String No A human-friendly description for the Dynamic Parameter.
DataType String No If specified, validates the value is of the given type. See MSDN for details. If the value fails the DataType evaluator, an exception is thrown.
Validation String No Optional Regex expression to evaluate the value, using Regex.Match. If the value fails the Match evaluator, an exception is thrown.
RestrictToOptions Boolean No If true and Options.Count > 0, then validates the value is contained within the Options->Values (Value property) list.
Default structure No Specifies options for a default value if a dynamic value is not provided at runtime.
- Value Object No A simple value or YAML/JSON/XML structure. The value type must match the Target value type. Note: Default value substitution is executed before Parse, Replace, Encode, DataType, and Validation evaluation, so Value must comply to any specified conditions.
- AllowNull Boolean No Indicates whether Value, if null/empty, can be used to replace the Target value. Default is false.
Options list No A list of available choices for a given Dynamic parameter.
- Key String Yes The business key for the Option.
- Value String Yes The comparison or "display" value for the Option.
- Description String No A human-friendly description for the Dynamic Parameter.
- IsDefault String No If using the Plan to discover Dynamic Parameters and draw a UI, IsDefault could indicate the default selection in a dropdown, for example.

Automatically available Dynamic values

Certain PlanStartInfo values are automatically gathered and populated at runtime, for convenience.

Name Value
PlanStartInfo_Name The Plan Name.
PlanStartInfo_UniqueName The Plan UniqueName.
PlanStartInfo_IsActive The Plan IsActive value (boolean).
PlanStartInfo_InstanceId The Plan execution InstanceId (long).
PlanStartInfo_RequestNumber If provided at execution, the RequestNumber value.
PlanStartInfo_RequestUser The security context value at execution time.

Each of these values is available from a Dynamic structure using the name as shown in table, as follows:

  Dynamic:
  - Source: PlanStartInfo_Name
    Target: ...
  - Source: PlanStartInfo_InstanceId
    Target: ...
  ...
  • YAML Example 1:
    • A variable named pnode0Dynamic will replace the existing value for PNode0
    • A variable named pnode3_1Dynamic will replace the existing value for PNode3 --> PNode3_1
  Values:
    PNode0: PValue0_inline
    PNode1: PValue1_inline
    PNode3:
      PNode3_1: PValue3_1_inline
      PNode3_2: PValue3_2_inline
  Dynamic:
  - Source: pnode0Dynamic
    Target: PNode0
  - Source: pnode2_1Dynamic
    Target: PNode2:PNode2_1
  - Source: pnode3_1Dynamic
    Target: PNode3:PNode3_1

Assuming: pnode0Dynamic = 'new PNode0 value' and pnode3_1Dynamic = 'new PNode3_1 value', the resulting Values will be:

  Values:
    PNode0: new PNode0 value
    PNode1: PValue1_inline
    PNode3:
      PNode3_1: new PNode3_1 value
      PNode3_2: PValue3_2_inline
  • YAML Example 2:

Take the following example Plan, showing an example of Parse and Default for list (indexed) and dictionary structures.

Name: sampleDefaultValues
Description: Parameter Substitution
Actions:
- Name: a0
  Handler:
    Type: Synapse.Core:EmptyHandler
  Parameters:
    Values:
      SleepMilliseconds: 0
      ReturnStatus: Complete
      Case0.0:
      - Identity: 
        Properties: foo bar moo
      Case0.1:
      - Identity: 
        Properties:
      Case1.0:
        Identity:
        Properties:
          dummyvalue:
      Case1.1:
        Identity:
        Properties:
    Dynamic:
    - Source: simple
      Target: Case0.0[0]:Properties
      Replace: bar
      Default:
        Value: sss
        AllowNull: true
      Encode: Base64
      Parse: true
    - Source: properties
      Target: Case0.1[0]:Properties
      Parse: true
    - Source: properties
      Target: Case1.0:Properties
      Parse: true
    - Source: properties
      Target: Case1.1:Properties
      Parse: true

Assume the DynamicParameters runtime values are a JSON structure for properties and null for simple:

DynamicParameters:
  properties: "{\r\n  \"xyz\": \"foo\",\r\n  \"abc\": \"bar\"\r\n}"
  simple:

The result Plan Parameters structure will result with:

  • Case 0.0: bar replaced by sss (default value) and Base64 encoded in the Target
  • Case 0.1: the JSON structure merged into the Properties at index 0.
  • Case 1.0, 1.1: the JSON structure merged into the Properties structure with/without existing values present.
  Parameters:
    Name: 
    Type: Yaml
    InheritFrom: 
    Uri: 
    Values:
      SleepMilliseconds: 0
      ReturnStatus: Complete
      Case0.0:
      - Identity: 
        Properties: foo c3NzDQouLi4NCg== moo
      Case0.1:
      - Identity: 
        Properties:
          xyz: foo
          abc: bar
      Case1.0:
        Identity: 
        Properties:
          dummyvalue: 
          xyz: foo
          abc: bar
      Case1.1:
        Identity: 
        Properties:
          xyz: foo
          abc: bar
  • XML Example:
    • A variable named cnode0Dynamic will replace the existing value for CXmlDoc --> CNode0
    • A variable named cnode3_1Dynamic will replace the existing value for CXmlDoc --> CNode3 --> CNode3_1 --> @CAttr3_1
    • Note: the indexes below are specified for clarity, but not strictly required in XPath syntax.
  Values:
    <CXmlDoc>
        <CNode0>CValue0_inline</CNode0>
        <CNode1>CValue1_inline</CNode1>
        <CNode3>
            <CNode3_1 CAttr3_1="CAValue3_1_inline">CValue3_1_inline</CNode3_1>
            <CNode3_2>CValue3_2_inline</CNode3_2>
        </CNode3>
    </CXmlDoc>
  Dynamic:
  - Source: cnode0Dynamic
    Target: /CXmlDoc[1]/CNode0[1]
  - Source: cnode2_1Dynamic
    Target: /CXmlDoc[1]/CNode2[1]/CNode2_1[1]
  - Source: cnode3_1Dynamic
    Target: /CXmlDoc[1]/CNode3[1]/CNode3_1[1]/@CAttr3_1

Assuming: cnode0Dynamic = 'new CNode0 value' and cnode3_1Dynamic = 'new CNode3_1 attr', the resulting Values will be:

  Values:
    <CXmlDoc>
        <CNode0>new CNode0 value</CNode0>
        <CNode1>CValue1_inline</CNode1>
        <CNode3>
            <CNode3_1 CAttr3_1="new CNode3_1 attr">CValue3_1_inline</CNode3_1>
            <CNode3_2>CValue3_2_inline</CNode3_2>
        </CNode3>
    </CXmlDoc>

ParentExitData

Passing data from a parent Action to its children it accomplished with the ParentExitData section, which is an array of Source/Target pairs (see detail below). If the Target path exists in the child data, the value updated. If the Target path does not exist, it will be created and seeded. As with Dynamic values, YAML/JSON structures arriving as strings may optionally be Parsed and integrated into the Parameters Values structure itself.

  ParentExitData:
  - TransformInPlace:
      Source: Element:IndexedElement[0]:Element
      Target: Element:IndexedElement[0]:Element
      Parse: true
      Replace: Regex Expression
      Encode: None | Base64
    CopyToValues:
      Source: Element:IndexedElement[0]:Element
      Target: Element:IndexedElement[0]:Element
      Parse: true
      Replace: Regex Expression
      Encode: None | Base64

TransformInPlace

The TransformInPlace section provides a method for light data transformation within the ParentExitData itself. This is useful in scenarios where combining 2+ data elements is required before copying data to the Values.

Name Type/Value Required Description
Source String No The path to value/structure from the parent Action's ExitData.
Target String No* The path to the target location to add/update the value/structure within the parent Action's ExitData. This field is required if specifying Source. If the target path does not exist, it will be created and seeded.

CopyToValues

The CopyToValues section copies values from ParentExitData to Parameters->Values.

Name Type/Value Required Description
Source String Yes* The path to value/structure from the parent Action's ExitData. -Note: When specifying TransformInPlace->Source/Target, you may omit this Source setting if it is the same as TransformInPlace->Target; Source will default to the TransformInPlace->Target.
Target String Yes The path to the target location to add/update the value/structure in the current Action's Parameters Values. If the target path does not exist, it will be created and seeded.

Settings with common definitions:

Name Type/Value Required Description
Parse Boolean No Tries to parse the source value as YAML/JSON and integrate the result into the Parameters Values structure.
Replace String No Performs a Regular Expression replacement of the Target value with the value from Source, subject to the Regex pattern.
Encoding Enum No Specifies how to encode the value before replacement. Options are None and Base64.
  • YAML Example:
Name: ParentExitDataTest
DefaultHandlerType: Synapse.Core:EmptyHandler
Actions:
- Name: Parent
  Parameters:
    Values:
      SleepMilliseconds: 1000
      ReturnStatus: Complete
      ExitData:
        Something:
          Wonderful:
            Stars: 2001
        Foo:
          Bar: Tombstoned
        ListMember: [1,2,3]
  Actions:
  - Name: Child
    Parameters:
      ParentExitData:
        CopyToValues:
        - Source: Something:Wonderful:Stars
          Target: SleepMilliseconds
        - Source: Foo:Bar
          Target: ReturnStatus
        - Source: ListMember
          Target: ExitData
          Parse: True
  • XML Example:
Name: ParentExitDataTest
DefaultHandlerType: Synapse.Core:EmptyHandler
Actions:
- Name: Parent
  Parameters:
    Type: Xml
    Values:
      <EmptyHandlerParameters>
        <SleepMilliseconds>1000</SleepMilliseconds>
        <ReturnStatus>Complete</ReturnStatus>
        <ExitData>
          <Something>
            <Wonderful>
              <Stars>2001</Stars>
            </Wonderful>
            <Foo>
              <Bar>Tombstoned</Bar>
            </Foo>
            <ListMember>
              <Servers>
                <Server>localhost0</Server>
                <Server>localhost1</Server>
                <Server>localhost2</Server>
              </Servers>
            </ListMember>
          </Something>
        </ExitData>
      </EmptyHandlerParameters>
  Actions:
  - Name: Child
    Parameters:
      Type: Xml
      ParentExitData:
        CopyToValues:
        - Source: /Something/Wonderful/Stars
          Target: /EmptyHandlerParameters/SleepMilliseconds[1]
        - Source: /Something/Foo/Bar
          Target: /EmptyHandlerParameters/ReturnStatus
        - Source: /Something/ListMember
          Target: /EmptyHandlerParameters/ExitData

ForEach

ForEach blocks calculate the Cartesian product of the declared Target/Values and expands the Action into a set of Actions for each result item. ActionGroup and child Actions relationships are maintained and will be executed per result item, as well. Of note, as both Action.Handler.Config and Action.Parameters can be declared with ForEach blocks, the total execution iterations for an Action is the cartesian product of the expanded Config and expanded Parameters.

  ForEach:
  - ParameterSource:
      Name: Named ParameterInfo Block
      Source: Element:IndexedElement[0]:Element
      Parse: false
    Target: Element:IndexedElement[0]:Element
    Replace: Regex Expression
    Encode: None | Base64
    Values:
    - value0
    - value1
Name Type/Value Required Description
Source String Yes The path to value/structure from the Action's Values.
Target String Yes The path to the target location to add/update the value/structure in the current Action's Parameters Values. If the target path does not exist, it will be created and seeded.
  • YAML Example
  Values:
    PNode0: PValue0_file
    PNode1: PValue1_file
    PNode2:
      PNode2_1: PValue2_1_file
      PNode2_2: PValue2_2_file
    PNode3:
      PNode3_1: PValue3_1_inline
      PNode3_2: PValue3_2_inline
  ForEach:
    CopyToValues:
  - Target: PNode1
    Values:
    - PValue1_foreach_0
    - PValue1_foreach_1
  - Target: PNode2:PNode2_1
    Values:
    - PValue2_2_foreach_0
    - PValue2_2_foreach_1
  • The block above is processed like a nested for loop (pseudo-code):
foreach( string value0 in valueSet0 )
    foreach( string value1 in valueSet1 )
        //substitute value0 in at PNode1, value1 at PNode2:PNode2_1
  • Resulting in four distinct sets of Values, as follows:
  Values:
    PNode0: PValue0_file
    PNode1: PValue1_foreach_0
    PNode2:
      PNode2_1: PValue2_2_foreach_0
      PNode2_2: PValue2_2_file
    PNode3:
      PNode3_1: PValue3_1_inline
      PNode3_2: PValue3_2_inline

  Values:
    PNode0: PValue0_file
    PNode1: PValue1_foreach_0
    PNode2:
      PNode2_1: PValue2_2_foreach_1
      PNode2_2: PValue2_2_file
    PNode3:
      PNode3_1: PValue3_1_inline
      PNode3_2: PValue3_2_inline

  Values:
    PNode0: PValue0_file
    PNode1: PValue1_foreach_1
    PNode2:
      PNode2_1: PValue2_2_foreach_0
      PNode2_2: PValue2_2_file
    PNode3:
      PNode3_1: PValue3_1_inline
      PNode3_2: PValue3_2_inline

  Values:
    PNode0: PValue0_file
    PNode1: PValue1_foreach_1
    PNode2:
      PNode2_1: PValue2_2_foreach_1
      PNode2_2: PValue2_2_file
    PNode3:
      PNode3_1: PValue3_1_inline
      PNode3_2: PValue3_2_inline

Precedence for value resolution

A ParameterInfo block will fetch and resolve values, in order, as follows:

Field Behavior
1. InheritFrom Will copy the named ParameterInfo block from the runtime dictionary. Inheritable ParameterInfo blocks must precede the current ParameterInfo block in the Plan execution cycle.
2. Uri Will read the value set from the URI location. If InheritFrom is declared, URI values will be merged on top of any existing values from InheritFrom as: Result = InheritFrom + Uri.
3. Values Any directly declared data values will be merged on top of existing values as: Result = InheritFrom + Uri + Values, or: Result = Result + Values.
4. Dynamic Any dynamically provided values will be merged on top of existing values as: Result = InheritFrom + Uri + Values + Dynamic, or: Result = Result + Dynamic.
5. ParentExitData Any values mapped from the Parent Action's ExitData will be merged on top of existing values as: Result = InheritFrom + Uri + Values + Dynamic + ParentExitData, or: Result = Result + ParentExitData.
6. ForEach Substitutes specified values into the resultant ParameterInfo block from above steps, calculating: ForEachValues( Result ).

Tying it Together

An example showing Uri, Values, Dynamic, and ForEach processing follows below.

  • YAML Example
  Parameters:
    Name: ParamSet00
    Type: Yaml
    Uri: file://C:/Synapse.UnitTests/Plans/Parms/yaml_in.yaml
    Values:
      PNode0: PValue0_inline
      PNode1: PValue1_inline
      PNode3:
        PNode3_1: PValue3_1_inline
        PNode3_2: PValue3_2_inline
    Dynamic:
    - Source: pnode0Dynamic
      Target: PNode0
    - Source: pnode2_1Dynamic
      Target: PNode2:PNode2_1
    - Source: pnode3_1Dynamic
      Target: PNode3:PNode3_1
    ForEach:
      CopyToValues:
      - Target: PNode1
        Values:
        - PValue1_foreach_0
        - PValue1_foreach_1
      - Target: PNode2:PNode2_1
        Values:
        - PValue2_2_foreach_0
        - PValue2_2_foreach_1
  • Assuming the contents of the yaml_in.yaml are:
PNode0: PValue0_file
PNode1: PValue1_file
PNode2:
  PNode2_1: PValue2_1_file
  PNode2_2: PValue2_2_file
  • And, parameters to synapse.cli.exe include:
synapse.cli.exe plan:sample.yaml dryRun:true pnode0Dynamic:PValue0_dynamic
                pnode2_1Dynamic:PValue2_1_Dynamic pnode3_1Dynamic:PValue3_1_Dynamic

Step 1 - Retrieve the file URI, resulting in:

  Values:
    PNode0: PValue0_file
    PNode1: PValue1_file
    PNode2:
      PNode2_1: PValue2_1_file
      PNode2_2: PValue2_2_file

Step 2 - Merge Locally declared Value with the file URI contents, resulting in:

  Values:
    PNode0: PValue0_inline
    PNode1: PValue1_inline
    PNode2:
      PNode2_1: PValue2_1_file
      PNode2_2: PValue2_2_file
    PNode3:
      PNode3_1: PValue3_1_inline
      PNode3_2: PValue3_2_inline

Step 3 - Merge Dynamic values into current Values, resulting in:

  Values:
    PNode0: PValue0_dynamic
    PNode1: PValue1_inline
    PNode2:
      PNode2_1: PValue2_1_Dynamic
      PNode2_2: PValue2_2_file
    PNode3:
      PNode3_1: PValue3_1_Dynamic
      PNode3_2: PValue3_2_inline

Step 4 - Process the ForEach block, expanding the current Values into four new blocks:

  Values:
    PNode0: PValue0_dynamic
    PNode1: PValue1_foreach_0
    PNode2:
      PNode2_1: PValue2_2_foreach_0
      PNode2_2: PValue2_2_file
    PNode3:
      PNode3_1: PValue3_1_Dynamic
      PNode3_2: PValue3_2_inline

  Values:
    PNode0: PValue0_dynamic
    PNode1: PValue1_foreach_0
    PNode2:
      PNode2_1: PValue2_2_foreach_1
      PNode2_2: PValue2_2_file
    PNode3:
      PNode3_1: PValue3_1_Dynamic
      PNode3_2: PValue3_2_inline

  Values:
    PNode0: PValue0_dynamic
    PNode1: PValue1_foreach_1
    PNode2:
      PNode2_1: PValue2_2_foreach_0
      PNode2_2: PValue2_2_file
    PNode3:
      PNode3_1: PValue3_1_Dynamic
      PNode3_2: PValue3_2_inline

  Values:
    PNode0: PValue0_dynamic
    PNode1: PValue1_foreach_1
    PNode2:
      PNode2_1: PValue2_2_foreach_1
      PNode2_2: PValue2_2_file
    PNode3:
      PNode3_1: PValue3_1_Dynamic
      PNode3_2: PValue3_2_inline

The resulting four Value sets will each be passed to the Action.Handler as runtime parameters (as four independently executed Actions).