使用 WF4.5 在 try/catch activity 时间包装现有工作流程 运行

Wrap an existing workflow in a try/catch activity at run-time with WF4.5

最近 WF4.5 的使用似乎很可怕,所以对于所有 WF4.5 专家,请花一点时间阅读本文,看看是否可以帮助我。

我正在尝试在 运行 时间围绕现有工作流程 activity 添加 try/catch activity。

为什么这么问?好吧,我需要确保我的工作流程永远不会崩溃,因为我在我需要的所有各种活动中使用数据,我需要 return 无论是否发生未处理的异常,但 OnUnhandledException 不会 return任何值。

我尝试使用命令式编码并通过创建实际的 activity 来实现,但我无法弄清楚如何从 try/catch [=75] 传递参数=] 是在属于 try 部分的工作流程的动态 activity 中创建的。

这是 try/catch 函数:

    public static Activity TryCatchWrap(Activity runtimeActivity)
    {
        var dataObject = new InOutArgument<DataObject>();

        var ex = new DelegateInArgument<Exception> { Name = "Ex" };

        Activity workflowTryCatch = new DynamicActivity()
        {
            Properties =
            {
                new DynamicActivityProperty
                {
                    Name = "DataObject",
                    Type = typeof(InOutArgument<DataObject>),
                    Value = dataObject
                }
            },
            Implementation = () => new Sequence
            {
                Activities =
                {
                    new WriteLine
                    {
                        Text = new InArgument<string>((ctx) => "Hello1 : " +
                               dataObject.Get(ctx).ApplicationName)
                    },
                    runtimeActivity
                }
            }
        };

        return workflowTryCatch;
    }

如您所见,我在 DynamicActivity 中创建了一个 TryCatch activity,创建了一个 属性 调用 DataObject 并将其 Implementation 设置为运行时间活动。

我的 运行timeActivity activity,它也是一个 Dynamic Activity 并包含一个流程图 activity(以及更多活动)是从 XAML 加载的文件使用:

var activity = ActivityXamlServices.Load(
    fileName,
    new ActivityXamlServicesSettings()
    {
       CompileExpressions = false,
    });

我需要的是将 DataObject 从 TryCatch activity 传递到 运行time activity,它在 'try' 部分中提供TryCatch.

我怎样才能做到这一点。我试过很多组合,多到无法一一列举,更不用说各种错误了。我已经阅读了无数文章,但无济于事,但我显然遗漏了一些东西。

如果我使用 workflow designer,我已经准备好所需的场景并在几秒钟内完成 运行,我认为它略有不同,因为我将 TryCatch 添加为FlowChart 中的第一个元素,然后在 TryCatch 中,我将 Try 部分设置为我需要的任何工作流程。

如果有其他方法可以实现此目的,我愿意接受任何建议。

任何帮助将不胜感激,因为我完全停滞不前。

谢谢。

UPDATE-1:

我只是换了一种方式,我以编程方式从我的 DynamicActivity 中提取我的 flowchart。一旦我有了流程图,我就提取 StartNode 并尝试用一个新的替换它,其中包含 try/catch 并且 Try 已设置为最初与 StartNode 关联的任何操作,但这仍然不是正在工作。

        var fullWorkflow = WorkflowInspectionServices.GetActivities(workflow);
        var flowchart = (Flowchart)fullWorkflow.First();
        var startNode = (FlowStep)flowchart.StartNode;
        var startNodeAction = startNode.Action;

        flowchart.StartNode = null;

        var ex = new DelegateInArgument<Exception> { Name = "Exception" };

        var tryCatch = new TryCatch();
        var catchException = new Catch<Exception>();
        var catchActivityAction = new ActivityAction<Exception>();

        catchActivityAction.Argument = ex;
        catchActivityAction.Handler = new Assign<Exception>()
        {
            To = new OutArgument<Exception>(new
            VisualBasicReference<Exception>("DataObject.Exception")),
            Value = new InArgument<Exception>(
            new VisualBasicValue<Exception>("Exception"))
        };

        catchException.Action = catchActivityAction;

        tryCatch.Try = startNodeAction;
        tryCatch.Catches.Add(catchException);

        startNode.Action = tryCatch;
        flowchart.StartNode = startNode;

        Activity workflowTryCatch = new DynamicActivity()
        {
            DisplayName = "HelloWorld",
            Properties =
            {
                new DynamicActivityProperty
                {
                    Name = "DataObject",
                    Type = typeof(InOutArgument<DataObject>),
                    //Value = argDataObject
                }
            },
            Implementation = () => flowchart
        };

我在 运行 时遇到以下错误:

An unhandled exception of type 'System.Activities.InvalidWorkflowException' occurred in 
System.Activities.dll

Additional information: The following errors were encountered while processing the 
workflow tree:

'HelloWorld': The private implementation of activity '1: HelloWorld' has 
the following validation error:   Compiler error(s) encountered processing
expression "DataObject.Exception".

Type 'DataObject' is not defined.

'HelloWorld': The private implementation of activity '1: HelloWorld' has 
the following validation error:   Compiler error(s) encountered processing
expression "DataObject.ApplicationName".

Type 'DataObject' is not defined.

任何 ideas/suggestions?

谢谢。

我终于自己搞定了!!如果你问我,我会很痛苦,我不是 100% 确定这是否是正确的方法,但现在我正在正式创建一个 DynamicActivity,我正在将我的复杂 InOutArgument 依次添加一个 TryCatch activity 触发我传递给它的任何 Flowchart

如果发生任何未处理的异常,这些将被捕获并设置在我的复杂对象中,即 DataObject。

对我来说重要的部分是工作流 运行 是否成功,它总是 return 我的复杂对象以及在特定 Flowchart 中捕获的任何信息。

话说回来,效果很好,但我还没有测试性能,但希望它不会降低太多。

这是我实现它的方法。我创建了以下函数:

    public static Activity CreateNew(Flowchart flowchart)
    {
        var inProperty = new DynamicActivityProperty
        {
            Name = "DataObject",
            Type = typeof(InOutArgument<DataObject>)
        };

        var ex = new DelegateInArgument<Exception> { Name = "exception" };

        var tryCatch = new TryCatch();
        var tryCatchException = new Catch<Exception>()
        {
            Action = new ActivityAction<Exception>()
            {
                Argument = ex,
                Handler =
                new Sequence
                {
                    Activities =
                    {
                        new Assign<Exception>
                        {
                            To = new VisualBasicReference<Exception>() 
                            {ExpressionText = "DataObject.Exception"},
                            Value = new InArgument<Exception>(ex)
                        },
                        new WriteLine()
                        {
                            Text = new InArgument<string>(new VisualBasicValue<string>() 
                           { ExpressionText = "DataObject.Exception.Message"})
                        }
                    }
                }
            }
        };

        var activity = new DynamicActivity()
        {
            Implementation = () => new Flowchart
            {
                StartNode = new FlowStep
                {
                    Action = tryCatch
                }
            },
            Properties = { inProperty }
        };

        tryCatch.Try = flowchart;
        tryCatch.Catches.Add(tryCatchException);

        AddVbSetting(activity);

        return activity;
    }

以上将运行,但我传递给它的流程图包含一个或多个导入的命名空间。我认为它会按原样工作,但事实并非如此。

我不得不将它们重新添加到新的 activity。目前,AddVbSetting 仅 imports/adds 我的复杂对象的命名空间,它工作正常,但在某些情况下,您可能需要添加其他命名空间,因此需要扩展此方法但希望这会足够直接。

AddVbSettings 的代码是:

    private static void AddVbSetting(Activity activity)
    {
        var settings = new VisualBasicSettings
        {
            ImportReferences =
            {
                new VisualBasicImportReference
                {
                    Assembly = typeof(DataObject).Assembly.GetName().Name,
                    Import = typeof(DataObject).Namespace
                }
            }
        };
        VisualBasic.SetSettings(activity, settings);
    }

我花了很多时间在一些本来应该很简单的事情上,现在看起来很明显,把所有的部分放在一起实际上是一场噩梦!!花了(我觉得这么说真的很蠢!)天来弄清楚并阅读了无数文章,天知道写了多少原型,更不用说一个接一个的异常了!!

我希望如果有人还在使用 WF,它会对您有所帮助,让您免去它让我头疼的事情!很高兴它终于结束了......好吧,直到明天 :) 不管怎样!

PS:最终的解决方案是流程图中的流程图,可能不需要它,明天我可能会修改它。我只是想在有人强调这是一个主要缺陷之前我会提到它!