在我的工作流程项目中途,我们的客户通过一个有趣的曲线球向我们冲来。当我们意识到设计没有针对特定场景的准备时,我们大概完成了70%的代码。用户填写InfoPath表单将触发工作流-该表单具有许多用于收集数据的输入控件,并且其中一些是下拉菜单,这些下拉菜单指示出现的整个工作流的特定路径。这样的下拉列表如下所示:
类型:
- 类型1
- 2型
- 都
所选值由工作流程中的IfElse条件评估-如果"type 1"被选择时,我们进入特定分支,如果"type 2",其他分支等。现在,对于这个特定的下拉菜单,我们意识到我们尚未指定针对"both"条件(对您来说很敏捷!)。出现的新要求是通知和任务应转到 二 teams (i.e. 都 of them), and after further discussion we decided it would be appropriate to kick off 二 separate 工作流程s, one for each team.
大多数工作流程框架都可以通过使用“子”工作流程来解决此问题,Workflow Foundation也不例外。经过几个小时的重构以使用此方法的实现,我的概念证明如下所示:
因此,在关闭“ InvokeWorkflow”活动(即未扩展子工作流程)的同时,您可以希望看到,如果我们在左侧分支下,则启动一个子工作流程,但在右侧分支中(对于"both"),我们并行启动两个子工作流程。
问题
我尝试了几件事,上图显示了使用 顺序的 父工作流程(尽管子工作流程是 状态机),但无法正常工作。使用调试器,我可以看到子工作流程正在初始化-我可以逐步执行InitializeComponent(),但是从未遇到'OnWorkflowActivated'中的断点-没有引发事件。 的SharePoint日志显示:
System.Workflow.Activities.EventDeliveryFailedException:事件"OnWorkflowActivated" on interface type "Microsoft.SharePoint.Workflow.ISharePointService" for instance id "67c4929a-9280-4b8b-9a4c-a1b85b04267c"无法交付。 --->System.InvalidOperationException:事件队列操作失败,消息队列的MessageQueueErrorCode QueueNotFound消息属性接口类型:Microsoft.SharePoint.Workflow.ISharePointService方法名称:OnWorkflowActivated
因此,我开始怀疑在SharePoint工作流中是否可以使用InvokeWorkflow。 Microsoft尚未就此问题与我联系,我所知道的最详细的SharePoint工作流书(2007 Microsoft Office System中的工作流 作者:David Mann)没有讨论InvokeWorkflow。
是时候进行一些横向思考了。
解决方案
我们知道,如果将两个完整的InfoPath表单添加到文档库中,我们肯定会有两个工作流,所以我问客户他们对让系统拆分一个文档的想法。"both"请求分成两个单独的项目-这意味着列表中有两个单独的InfoPath表单。答案是"实际上,对于用户来说,这可能更好",因此我想到的解决方案是:
- 列表事件接收器,该接收器在工作流之前执行-这将执行以下操作:
-以字符串的形式打开InfoPath表单的二进制内容,并从以下位置修改下拉值"both" to "type 1"
-在相同的库中创建原始文件的副本,但从此处修改下拉值"both" to "type 2" - 运行一些临时代码以重新排序列表中的事件接收者-我们需要拆分项目 之前 工作流开始(因此我们得到两个工作流),但是SharePoint以1的顺序添加SPWorkflowAutostartEventReceiver,因此它首先执行。这段代码会切换事件接收器的顺序,因此我们的预处理会首先进行。
关于最后一点,我认为SharePoint团队可能将工作流设置为首先执行是有原因的,但随后又是另一个事件接收者,SharePoint不会阻止这种重新排序(与其他更改一样,例如例如从网络上删除欢迎页面)。无论如何,我们已经进行了广泛的测试,解决方案也丝毫不差。
如果有用,可以使用以下代码来复制和修改文件-可以在列表接收器(如我的情况)或临时代码中使用此代码。我使用简单的字符串操作来执行修改,因为InfoPath表单只是XML,还因为使用XML处理方法导致“专有” InfoPath声明出现问题。只需用您自己的处理替换字符串替换行。
1: private string getFileContentsAsString(SPFile file)
2: {
3: byte[] aFileBytes = file.OpenBinary();
4: string sContents = Encoding.UTF8.GetString(aFileBytes);
5:
6: return sContents;
7: }
8:
9: private void duplicateFile(SPListItem originalListItem, string sNewItemUrl,
10: bool bDeleteOriginal)
11: {
12: SPFile originalFile = originalListItem.File;
13: string sOriginalFileContents = getFileContentsAsString(originalFile);
14:
15: // TODO: replace this line with your own processing..
16: string sNewFileContents = sOriginalFileContents.Replace("oldValue", "newValue");
17:
18: byte[] aNewFileBytes = Encoding.UTF8.GetBytes(sNewFileContents);
19:
20: // we effectively need to add a new file for this operation, and optionally delete
21: // the original..
22: SPFile newFile = originalListItem.ParentList.RootFolder.Files.Add(sNewItemUrl, aNewFileBytes,
23: originalFile.Properties);
24: newFile.Update();
25:
26: if (bDeleteOriginal)
27: {
28: originalListItem.Delete();
29: }
30: }
附言如果有人在SharePoint工作流中使用InvokeWorkflow,请发表评论:-)
7条评论:
克里斯,你好
是的,我将快速浏览一下大约一年前使用子工作流的情况。我得出的结论完全相同-他们似乎没有用。
鉴于此,并且我们在延迟活动中遇到的一些问题从未重启,似乎确实有一个相当令人信服的案例,那就是保持工作流程较小,并根据SharePoint中的事件启动它们。或者根本不使用工作流程,而是通过视图和状态字段推动流程。当然,这些都将直接导致您遇到SharePoint工作流报表方面的问题,但这是另一回事了。
也许我们需要的是有关“避免SharePoint工作流”的用户组会话?
哦,K2 Workflow确实完成了子工作流程-遗憾的是它附带了训练曲线和价格标签:(
情况正常-版本3会正确处理。
是的-K2绝对会满足您的需求。它曾在K2 2003和Blackpearl产品中使用。例如,通过创建带有大量子流程的主流程,我能够创建更多的敏捷流程,以处理不稳定的业务流程。因此,如果某个流程实例要在特定版本上启动,我仍然可以部署新版本的子流程,而不必停止主流程。
一旦您沿着白手起家的道路走,价格标签就可以被证明是合理的。我知道有几个项目已经与非常聪明的人一起尝试过,这可能是一个痛苦的过程。 K2附带了一个完整的框架,当您查看所获得的一切时,价值主张确实会发生变化。 MS为像K2这样的框架提供了类似WF的基础。
Here is something I wrote recently - http://k2distillery.blogspot.com/2008/02/blackpearl-moss-governance-case-study.html
克里斯-很棒的博客-救了我几次...
在SharePoint中,工作流还有很长的路要走
我使用代码活动,而不是使用InvokeWorkflow活动,我将其称为WorkflowManager.StartWorkflow()
和我一起工作很好。
好提示。但是我猜想这将异步执行子工作流程(又称“解雇”),而不是等待子工作流程完成后再继续操作,能够访问返回值等。
有用的一点,谢谢。
克里斯。
如果希望主工作流等待,则将While活动与OnWorkflowItemChanged事件一起使用。然后,主工作流程可以等待子工作流程设置的返回代码。
不漂亮,但能胜任工作...
据我所知,WorkflowManager.StartWorkflow()等待子工作流程。
发表评论