Skip to content

Commit f68d049

Browse files
committed
Fixed bug with Converter.ChangeType being called on object type
1 parent 7d10016 commit f68d049

File tree

2 files changed

+64
-2
lines changed

2 files changed

+64
-2
lines changed

src/WorkflowCore/Services/WorkflowExecutor.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,15 @@ private void ProcessOutputs(WorkflowInstance workflow, WorkflowStep step, IStepB
183183
var resolvedValue = output.Source.Compile().DynamicInvoke(body);
184184
var data = workflow.Data;
185185
var setter = ExpressionHelpers.CreateSetter(output.Target);
186-
var convertedValue = Convert.ChangeType(resolvedValue, setter.Parameters.Last().Type);
186+
var targetType = setter.Parameters.Last().Type;
187+
188+
var convertedValue = resolvedValue;
189+
// We need to make sure the resolvedValue is of the correct type.
190+
// However if the targetType is object we don't need to do anything and in some cases Convert.ChangeType will throw.
191+
if (targetType != typeof(object))
192+
{
193+
convertedValue = Convert.ChangeType(resolvedValue, targetType);
194+
}
187195

188196
if (setter.Parameters.Count == 2)
189197
{

test/WorkflowCore.UnitTests/Services/WorkflowExecutorFixture.cs

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,58 @@ public void should_map_outputs_dynamic()
271271
data["Value1"].Should().Be(7);
272272
}
273273

274+
/// <summary>
275+
/// This test verifies that storing an object that does not implement IConvertable, in a step variable of type object works.
276+
/// The problem is that calling for example Convert.ChangeType(new DataClass(), typeof(object)) throws, even though the convertion should be trivial.
277+
/// </summary>
278+
[Fact(DisplayName = "Should map object outputs, without calling Convert.ChangeType")]
279+
public void should_map_outputs_object()
280+
{
281+
//arrange
282+
Expression<Func<IStepWithProperties, object>> p1 = x => x.Property4;
283+
Expression<Func<DataClass, IStepExecutionContext, object>> v1 = (x, context) => x.Value4;
284+
285+
var step1Body = A.Fake<IStepWithProperties>();
286+
A.CallTo(() => step1Body.Property4).Returns(new DataClass());
287+
A.CallTo(() => step1Body.RunAsync(A<IStepExecutionContext>.Ignored)).Returns(ExecutionResult.Next());
288+
WorkflowStep step1 = BuildFakeStep(step1Body, new List<DataMapping>(), new List<DataMapping>()
289+
{
290+
new DataMapping()
291+
{
292+
Source = p1,
293+
Target = v1
294+
}
295+
}
296+
);
297+
298+
Given1StepWorkflow(step1, "Workflow", 1);
299+
300+
var data = new DataClass()
301+
{
302+
Value4 = 4
303+
};
304+
305+
var instance = new WorkflowInstance
306+
{
307+
WorkflowDefinitionId = "Workflow",
308+
Version = 1,
309+
Status = WorkflowStatus.Runnable,
310+
NextExecution = 0,
311+
Id = "001",
312+
Data = data,
313+
ExecutionPointers = new List<ExecutionPointer>()
314+
{
315+
new ExecutionPointer() { Active = true, StepId = 0 }
316+
}
317+
};
318+
319+
//act
320+
Subject.Execute(instance);
321+
322+
//assert
323+
data.Value4.Should().BeOfType<DataClass>();
324+
}
325+
274326
[Fact(DisplayName = "Should handle step exception")]
275327
public void should_handle_step_exception()
276328
{
@@ -372,14 +424,16 @@ public interface IStepWithProperties : IStepBody
372424
{
373425
int Property1 { get; set; }
374426
int Property2 { get; set; }
375-
int Property3 { get; set; }
427+
int Property3 { get; set; }
428+
DataClass Property4 { get; set; }
376429
}
377430

378431
public class DataClass
379432
{
380433
public int Value1 { get; set; }
381434
public int Value2 { get; set; }
382435
public int Value3 { get; set; }
436+
public object Value4 { get; set; }
383437
}
384438

385439
public class DynamicDataClass

0 commit comments

Comments
 (0)