使用 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:最终的解决方案是流程图中的流程图,可能不需要它,明天我可能会修改它。我只是想在有人强调这是一个主要缺陷之前我会提到它!
最近 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:最终的解决方案是流程图中的流程图,可能不需要它,明天我可能会修改它。我只是想在有人强调这是一个主要缺陷之前我会提到它!