Windows Workflow自定义活动:评估引用变量的表达式时出错

时间:2016-11-22 15:52:21

标签: c# .net workflow-foundation

我已经创建了以下WF活动来测试用一组变量执行(vb)表达式的概念'可以在该表达式中访问。

public class ExpressionEncapsulationActivity : NativeActivity<bool>
  {
    private readonly Collection<Variable> _variables = new Collection<Variable>();
    private readonly Collection<Activity> _activities = new BindingList<Activity>();
    private Assign _expressionEvaluationChild { get; set; }
    private Variable<bool> _expressionResultVariable;

    public Collection<Variable> Variables { get { return _variables; } }
    public InArgument<bool> Expression { get; set; }

    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
      base.CacheMetadata(metadata);
      DisplayName = "Expression Encapsulation";

      metadata.SetVariablesCollection(Variables);
      metadata.SetChildrenCollection(_activities);

      _expressionResultVariable = new Variable<bool>("evalResult");
      _expressionEvaluationChild = new Assign()
      {
        DisplayName = "Expression Encapsulation Assign",
        To = new OutArgument<bool>(_expressionResultVariable),
        Value = new InArgument<bool>((ctx) => Expression.Get(ctx))
      };

      metadata.AddImplementationVariable(_expressionResultVariable);
      metadata.AddImplementationChild(_expressionEvaluationChild);
    }

    protected override void Execute(NativeActivityContext context)
    {
      context.ScheduleActivity(_expressionEvaluationChild, OnExpressionEvaluationComplete);
    }

    protected void OnExpressionEvaluationComplete(NativeActivityContext context, ActivityInstance completedActivity)
    {
      Result.Set(context, _expressionResultVariable.Get(context));
    }

  }

我试图按如下方式测试活动: (类ForEachActivityItem很简单,并且上面有Id属性)

  var testVarItem = new ForEachActivityItem()
  {
    Id = 2
  };
  var workflow = new ExpressionEncapsulationActivity()
  {
    Variables =
    {
      new Variable<ForEachActivityItem>("var", (ctx) => testVarItem)
    },
    Expression = new InArgument<bool>(new VisualBasicValue<bool>("var.Id = 1"))
  };
  var result = WorkflowInvoker.Invoke(workflow);
  Assert.IsFalse(result, "Test #1");

但是这个测试会抛出错误:

  

System.Activities.InvalidWorkflowException:以下错误   处理工作流树时遇到:   &#39; VisualBasicValue&#39;:编译器错误遇到处理   表达&#34; var.Id = 2&#34;。 &#39;无功&#39;没有宣布。它可能无法访问   由于其保护水平。

我无法理解为什么变量(var)对于表达式不可用,因为它在父母的声明中声明了#var;&#39;表达式执行上下文的活动(是在ExpressionEncapsulationActivity活动中创建的Assign子活动)。

值得注意的是,如果传入的表达式不引用变量(例如&#34; 1 = 1&#34;),则测试有效。有趣的是,如果我使用Sequence活动,设置其变量并向其添加Assign子活动,我可以使这种表达有效评估表达式。

1 个答案:

答案 0 :(得分:0)

看起来我的问题源于对私人和公共'元数据'之间的区别缺乏了解。

  

更多相关内容:

     

https://stackoverflow.com/questions/36068737/how-to-call-an-activity-inside-another-activity-in-microsoft-workflow

前者(私有)使用AddIXXXX形式的元数据方法注册,后者使用AddXXX形式的方法(例如AddChild)注册。

私人和公共'区域'混合不好(根本没有?)。例如,私人子活动(我上面提到的类型中的类型)无法访问公共变量。在我的问题测试中设置的变量(在属性Variables中)是公共的。

关于base.CacheMetadata()中发生的事情还有很多需要注意的事项(我在修正中说)使用反射来查找适合您注册的属性。如果您想要更多地控制子项和变量的注册方式,通常最好不要调用base.CacheMetadata()。

我遇到的另一个“扳手”是,在该活动中无法访问活动中定义的公共变量 - 它们只能由(公共)子活动访问。这使得实现返回结果的公共子活动(例如NativeActivity)变得棘手,该活动在其Result属性中返回结果。自然的方法是想通过将'Result'(OutArgument)绑定到变量来提取结果,然后使用variable.Get(context)来提取结果。

你不能这样做。您需要实现一个'Completed'事件方法,该方法接受'result'参数并使用它。例如:

private void OnFuncEvaluationComplete(NativeActivityContext context,
                    ActivityInstance completedinstance, bool result)
{
  Result.Set(context, result); // Set my result to that returned by the child activity
}

所有人都有乐趣!