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 forPNode0
- A variable named
pnode3_1Dynamic
will replace the existing value forPNode3
-->PNode3_1
- A variable named
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 forCXmlDoc
-->CNode0
- A variable named
cnode3_1Dynamic
will replace the existing value forCXmlDoc
-->CNode3
-->CNode3_1
-->@CAttr3_1
- Note: the indexes below are specified for clarity, but not strictly required in XPath syntax.
- A variable named
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).