Question

I have a WF (4.5) workflow activity that creates a child workflow (evaluating a VisualBasicValue expression). I need the result before I complete the parent workflow.

I add the expression to the metadata like this:

private VisualBasicValue<string> _expression;

protected override void CacheMetadata(NativeActivityMetadata metadata)
{
    base.CacheMetadata(metadata); 
    var visualBasicValue = (VisualBasicValue<string>)(_childActivity.Text.Expression);
    var expressionText = visualBasicValue.ExpressionText;
    _expression = new VisualBasicValue<string>(expressionText);
    metadata.AddChild(_expression);
}

I tried scheduling the activity in the Execute method like this:

protected override void Execute(NativeActivityContext context)
{
    context.ScheduleActivity(context, _expression, OnCompleted);
    Result.Set(context, _value);
}

With a callback of:

private void OnCompleted(NativeActivityContext context, ActivityInstance completedInstance, string result)
{
    _value = result;
}

Unfortunately, the _expression activity is only executed after the parent's execution method returns. Adding it as an implementation child doesn't work (it cannot work as an implementation child, as it is supposed to evaluate an expression that contains variables external to the parent).

Any ideas how to overcome this and execute within the execution context?

Was it helpful?

Solution 2

Took me a few days but I managed to resolve my own issue (without breaking the normal of how WF works).

What I ended up doing is, using reflection, iterated over the child's properties and created a LinkedList of evaluation expressions (using VisualBasicValue) of each of its arguments, in the CacheMetadata method. Then in the execution phase, I scheduled the execution of the first evaluation. In its callback I iterate over the remaining evaluations, scheduling the execution of the next evaluations, adding the result to a dictionary, until its done.

Finally, if there are no more evaluations to schedule, I schedule a final activity that takes the dictionary as its argument, and can do whatever it wants with it. Upon its own, it optionally returns the final result to the container's OutArgument.

What I previously failed to understand, is that even though the scheduling occurs after the instantiating activity's execution, the callback runs before control is returned to the host workflow application, and in that space I could work.

OTHER TIPS

In code, as in real life, you can't schedule something to the past (yet :).

ScheduleActivity() will place the activity within an execution queue and execute it as soon as it can. As the parent activity is still running, _expression will only execute after it. Bottom-line, it's an asynchronous call.

If you want to control when _expression is called, just use WorkflowInvoker to execute it, synchronously, whenever you want.

public class MyNativeActivity : NativeActivity
{
    private readonly VisualBasicValue<string> _expression;

    public MyNativeActivity()
    {
        // 'expression' construction logic goes here
        _expression = new VisualBasicValue<string>("\"Hi!\"");
    }

    protected override void Execute(NativeActivityContext context)
    {
        var _value = WorkflowInvoker.Invoke(_expression);

        Console.WriteLine("Value returned by '_expression': " + _value);

        // use '_value' for something else...
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top