-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Fix YAML deserializer to bind inherited properties and handle primitive values in custom step types #1395
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Co-authored-by: danielgerlag <[email protected]>
@copilot you have broken the build |
…stry Co-authored-by: danielgerlag <[email protected]>
Fixed the build issue. The test was incorrectly instantiating |
@copilot it looks like you broke some tests |
…ding flag Co-authored-by: danielgerlag <[email protected]>
Fixed the test failure. The issue was:
All tests now pass - commit 8a9c0ff. |
@copilot boolean values should NEVER be quoted as strings in yaml, unless they are meant to be treated as strings |
…hout quoting Co-authored-by: danielgerlag <[email protected]>
You're absolutely right. Fixed by adding proper handling for primitive values (bool, int, etc.) in the YAML deserializer. Boolean values like |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR fixes a YAML deserializer issue where custom step types inheriting from built-in steps couldn't bind to inherited properties and adds support for primitive input values.
- Changed property lookup to include inherited properties using BindingFlags
- Added support for primitive values (bool, int, long, double, decimal) in YAML inputs
- Enhanced test coverage with integration tests for both successful binding and error cases
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
File | Description |
---|---|
src/WorkflowCore.DSL/Services/DefinitionLoader.cs | Core fix for inherited property binding and primitive value handling |
test/WorkflowCore.UnitTests/Services/DefinitionStorage/YamlInheritedPropertyIntegrationTest.cs | Integration test verifying inherited property binding works and unknown properties still throw exceptions |
test/WorkflowCore.TestAssets/Steps/IterateListStep.cs | Test step class inheriting from Foreach for testing inherited properties |
test/WorkflowCore.TestAssets/DataTypes/CounterBoard.cs | Added DataList property to support test scenarios |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
} | ||
|
||
// Handle primitive values (bool, int, etc.) directly | ||
if (input.Value != null && (input.Value.GetType().IsPrimitive || input.Value is bool || input.Value is int || input.Value is long || input.Value is double || input.Value is decimal)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The condition input.Value is bool || input.Value is int || input.Value is long || input.Value is double || input.Value is decimal
is redundant since these types are already covered by input.Value.GetType().IsPrimitive
. Consider simplifying to just check IsPrimitive
or use a more explicit approach with a dedicated method.
if (input.Value != null && (input.Value.GetType().IsPrimitive || input.Value is bool || input.Value is int || input.Value is long || input.Value is double || input.Value is decimal)) | |
if (input.Value != null && (input.Value.GetType().IsPrimitive || input.Value is decimal)) |
Copilot uses AI. Check for mistakes.
if (stepProperty.PropertyType.IsAssignableFrom(primitiveValue.GetType())) | ||
stepProperty.SetValue(pStep, primitiveValue); | ||
else | ||
stepProperty.SetValue(pStep, System.Convert.ChangeType(primitiveValue, stepProperty.PropertyType)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The System.Convert.ChangeType
call can throw InvalidCastException
or FormatException
for incompatible types, but these exceptions won't provide context about which property or step failed. Consider wrapping this in a try-catch block that provides a more descriptive error message including the property name and step ID.
stepProperty.SetValue(pStep, System.Convert.ChangeType(primitiveValue, stepProperty.PropertyType)); | |
try | |
{ | |
stepProperty.SetValue(pStep, System.Convert.ChangeType(primitiveValue, stepProperty.PropertyType)); | |
} | |
catch (InvalidCastException ex) | |
{ | |
throw new ArgumentException($"Failed to convert input '{input.Key}' for step '{source.Id}' to type '{stepProperty.PropertyType.Name}'.", ex); | |
} | |
catch (FormatException ex) | |
{ | |
throw new ArgumentException($"Failed to convert input '{input.Key}' for step '{source.Id}' to type '{stepProperty.PropertyType.Name}'.", ex); | |
} |
Copilot uses AI. Check for mistakes.
Fixed the YAML deserializer issue where custom step types inheriting from built-in steps (like
Foreach
) couldn't bind to inherited properties, and added proper support for primitive input values.Root Cause
In
DefinitionLoader.cs
line 225,stepType.GetProperty(input.Key)
only looks for properties declared in the exact type, not in base classes. Additionally, the code only handled string and dictionary input types, not primitive values like booleans or integers.Solution
Inherited Properties: Changed to
stepType.GetProperty(input.Key, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
which includes inherited public instance AND static properties (to maintain full compatibility with default GetProperty behavior).Primitive Value Support: Added handling for primitive values (bool, int, long, double, decimal) so they can be used directly in YAML without quoting. These values are now directly assigned to properties without treating them as string expressions.
Examples
The fix now properly handles:
Collection: "data.DataList"
- parsed as dynamic expressionsRunParallel: false
- directly assigned as constantsTest Coverage
Added integration test that verifies:
RunParallel
fromForeach
can now be bound in custom step types using unquoted boolean valuesAll existing tests pass, confirming no regression.
Fixes #1375.
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.