Skip to content

Fix System.Dynamic registration for C# variable accessors#7415

Merged
sfmskywalker merged 3 commits into
elsa-workflows:mainfrom
RalfvandenBurg:fix/7414-system-dynamic-variables-accessor
Apr 27, 2026
Merged

Fix System.Dynamic registration for C# variable accessors#7415
sfmskywalker merged 3 commits into
elsa-workflows:mainfrom
RalfvandenBurg:fix/7414-system-dynamic-variables-accessor

Conversation

@RalfvandenBurg
Copy link
Copy Markdown
Contributor

Fixes #7414

Purpose

This PR fixes a C# expression issue where JSON workflow variables exposed through the generated Variables accessor could require System.Dynamic without that namespace/reference being registered. It also adds focused regression tests for the affected accessor generation path.

Scope

Bug fix (behavior change)

Description

Problem

RunCSharp can access workflow variables through generated C# accessors in the Variables global. When a workflow variable is JSON-backed and exposed as dynamic / ExpandoObject, the variable accessor generator introduces a System.Dynamic dependency into the generated script.

Before this change, that dependency was not registered by the same feature path that generated the accessor, which could cause C# script compilation/evaluation failures when accessing JSON variables through Variables.

Solution

This change registers System.Dynamic and the ExpandoObject assembly inside the workflow variable accessor generation path, but only when an ExpandoObject-backed variable is actually present and wrappers are enabled.

It also adds focused regression tests to verify that:

  • System.Dynamic is added when an ExpandoObject variable is in scope.
  • System.Dynamic is not added for non-JSON variable paths.

Verification

  1. Enable C# expressions with UseCSharp().
  2. Create a workflow with a variable of type json.
  3. Execute a RunCSharp expression that accesses the variable through Variables, for example Variables.Customer.Name.

Expected outcome:
The expression evaluates successfully without requiring manual System.Dynamic registration.

Automated verification performed:

  1. Added focused unit tests for GenerateWorkflowVariableAccessors.
  2. Ran dotnet test test/unit/Elsa.Expressions.UnitTests/Elsa.Expressions.UnitTests.csproj --no-restore --filter GenerateWorkflowVariableAccessorsTests.
  3. Verified both regression tests pass.

Screenshots / Recordings

Not applicable.

Commit Convention

This PR uses conventional commit messages:

  • fix: register System.Dynamic for C# JSON variable accessors
  • test: add C# variable accessor regression coverage

Checklist

  • The PR is focused on a single concern.
  • Commit messages follow the recommended convention.
  • Tests were added for the affected behavior.
  • No unrelated cleanup is included.
  • Focused tests pass.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 24, 2026

Greptile Summary

This PR fixes a missing System.Dynamic registration in the C# workflow variable accessor generator: when a workflow variable is ExpandoObject-backed and wrappers are enabled, the generated accessor now correctly registers the assembly reference and namespace import before the accessor code is appended. The guard condition mirrors the existing DisableWrappers check, keeping both code paths consistent.

Confidence Score: 5/5

Safe to merge — the fix is minimal, well-guarded, and the only remaining finding is a P2 test coverage gap.

The implementation correctly mirrors the existing DisableWrappers guard, registers both the assembly reference and namespace import before the script is appended, and is covered by two focused regression tests. The sole open finding is a missing third test for the DisableWrappers = true branch, which is a P2 suggestion and does not block merge.

No files require special attention.

Important Files Changed

Filename Overview
src/modules/Elsa.Expressions.CSharp/Handlers/GenerateWorkflowVariableAccessors.cs Adds System.Dynamic namespace import and ExpandoObject assembly reference when an ExpandoObject-typed variable is in scope and wrappers are enabled — correctly mirrors the existing DisableWrappers guard used for accessor generation.
test/unit/Elsa.Expressions.UnitTests/Handlers/GenerateWorkflowVariableAccessorsTests.cs New regression tests cover the happy path (ExpandoObject in scope → import added) and the negative path (no ExpandoObject → import absent); missing a third test for the DisableWrappers = true branch.
test/unit/Elsa.Expressions.UnitTests/Elsa.Expressions.UnitTests.csproj Adds Elsa.Expressions.CSharp project reference to the unit test project, required to compile the new handler tests.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[EvaluatingCSharp notification received] --> B[Get variables in scope]
    B --> C{Any ExpandoObject\nvariables?}
    C -- Yes --> D{DisableWrappers?}
    D -- No --> E[Register System.Dynamic\nassembly + namespace import]
    E --> F[Generate WorkflowVariablesProxy\nwith dynamic accessor]
    D -- Yes --> G[Skip registration]
    G --> H[Skip ExpandoObject accessor]
    C -- No --> I[Generate WorkflowVariablesProxy\nwith typed accessor]
    F --> J[AppendScript to notification]
    I --> J
    H --> J
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: test/unit/Elsa.Expressions.UnitTests/Handlers/GenerateWorkflowVariableAccessorsTests.cs
Line: 17-45

Comment:
**Missing test for `DisableWrappers = true` with an ExpandoObject variable**

The fix guards the registration with `if (hasExpandoVariables && !options.Value.DisableWrappers)`, but no test verifies the opposite side of that condition. When `DisableWrappers` is `true`, even if an `ExpandoObject` variable is in scope, neither the reference nor the `System.Dynamic` import should be added. Adding a third test case covering `CSharpOptions { DisableWrappers = true }` with an ExpandoObject variable would give full branch coverage over the new condition.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "chore: add trailing newline to regressio..." | Re-trigger Greptile

@sfmskywalker sfmskywalker merged commit e70850a into elsa-workflows:main Apr 27, 2026
7 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RunCSharp fails for JSON workflow variables because System.Dynamic is not registered by the generated Variables wrapper

3 participants