【问题标题】:WF4 - Composite custom activity throw an strange exception when using OutArgumentWF4 - 使用 OutArgument 时复合自定义活动抛出一个奇怪的异常
【发布时间】:2012-07-18 23:41:45
【问题描述】:

我正在尝试使用应用正则表达式并在匹配时返回布尔值的复合自定义活动。 模式是在设计时编码的东西。 源文本来自一个活动。此活动也在设计时指定(我制作了一个允许将活动作为源删除的活动设计器)

但我还需要返回与表达式匹配的子字符串,所以我添加了一个 OutArgument 来检索匹配的字符串,并捕获字符串。

代码如下:

public class RegularExpression : NativeActivity<bool>
{
    [RequiredArgument]
    public string Pattern { get; set; }

    public OutArgument<string> Captured { get; set; }

    [RequiredArgument]
    public Activity<string> RetrieveTextActivity { get; set; }

    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
        metadata.AddChild(this.RetrieveTextActivity);
    }

    protected override void Execute(NativeActivityContext context)
    {
        if (this.RetrieveTextActivity != null)
            context.ScheduleActivity<string>(this.RetrieveTextActivity, this.onRetrieveComplete);
    }

    private void onRetrieveComplete(NativeActivityContext context, ActivityInstance completedInstance, string result)
    {
        var regexp = new Regex(this.Pattern);
        var match = regexp.Match(result);

        this.Result.Set(context, match.Success);
        if (this.Captured != null)
            this.Captured.Set(context, match.Value);
    }
}

如果我执行此活动没有将变量绑定到 Captured 参数,它会按预期工作(结果设置正确)。
但是如果我使用设计器添加一个变量,那么我将变量绑定到 Captured 参数这个错误弹出窗口:

不能使用“System.String”类型的参数。确保 它是在一个活动上声明的。

执行此行时抛出异常:

this.Captured.Set(context, match.Value);

有人知道为什么我不能设置参数吗?
我还读到我不应该测试 Captured 是否为空,运行时应该自动设置默认值。但是如果我不测试,当我没有将变量绑定到参数时,我有一个 NullReference...

编辑:
我想添加有关工作流程本身的更多信息。我在another topic 中读到它可能是VS。在这里,我只想指定我正在使用重新托管的设计器来创建工作流(以及 not VS)。然后将工作流作为 XML 保存在数据库中。
当我需要启动一个新的工作流时,我会读取数据库,使用 XamlService.Load 并运行创建的工作流。

【问题讨论】:

    标签: workflow-foundation-4 workflow-foundation workflow-activity


    【解决方案1】:

    如果您在CacheMetadata 中声明参数,错误会消失吗?

    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
        metadata.AddChild(this.RetrieveTextActivity);
    
        RuntimeArgument argument = new RuntimeArgument("Captured", typeof(string), ArgumentDirection.Out);
        metadata.Bind(this.Captured, argument);
        metadata.AddArgument(argument);
    
    }
    

    编辑:我太快了。上面的代码现在应该可以编译并有望解决您的问题。

    【讨论】:

    • 我不能这样做它不编译:错误 27 'System.Activities.NativeActivityMetadata.AddArgument(System.Activities.RuntimeArgument)' 的最佳重载方法匹配有一些无效参数错误 28参数 1:无法从 'System.Activities.OutArgument' 转换为 'System.Activities.RuntimeArgument'
    • 我已经编辑添加了一些关于工作流的信息(不知道它是否可以帮助你知道问题出在哪里)。泰
    • 乍一看它有效!您对为什么需要这样做有任何解释吗?为什么 InArgument 我不需要这个?现在我会花一些时间来全面测试,然后我会标记为答案。泰!
    • @Fabske InArgument 也需要相同的代码。您在此 Activity 中没有它,但如果您在另一个 Activity 中使用它并且它可以工作,那么您可能没有覆盖 CacheMetadata。基本实现负责处理 InArgument 和 OutArgument 属性,因此您也可以调用 base.CacheMetadata(metadata) 来解决您的问题。如果您指的是 Pattern 属性,它并不是真正的 InArgument,因此您不需要向运行时声明它。
    • 上述代码无法编译,因为参数顺序错误。它应该是: RuntimeArgument argument = new RuntimeArgument("Captured", typeof(string), ArgumentDirection.Out);和 metadata.Bind(this.Captured, argument);
    【解决方案2】:

    当我在添加后调用 base.CachMetadata(metadata) 时,我的问题就消失了。试试:

    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
        metadata.AddChild(this.RetrieveTextActivity);
        base.CacheMetadata(metadata);
    }
    

    您希望在添加后执行此操作,因为您希望基类在您调用它时知道您添加了什么。我认为基类使用反射自动为您完成 Damir Arh 的回答。这样,您不必在每次添加或修改属性时都添加或修改所有代码。如果你有很多属性,那很快就会变得很痛苦。

    【讨论】:

    • 它是在 cmets 中指定的,但你把它作为强调这一点的答案是正确的,因为重用基本方法以确保一致性很重要。
    • 哦,我现在看到评论了,因为你让我好奇地更加努力地挖掘它。在我的网络浏览器中,该评论隐藏在“显示更多 cmets”链接下。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-16
    • 2011-05-30
    • 1970-01-01
    • 1970-01-01
    • 2010-09-16
    相关资源
    最近更新 更多