随笔 - 170  文章 - 1 评论 - 2374 trackbacks - 136

本文将针对QuickFlow开发人员经常碰到的问题做一个集中的解释。

1)QuickFlow是什么

QuickFlow是基于SharePoint(2007,2010)的一个工作流设计工具,它包含一个核心的Flowchart流程模型和一个无代码设计器。基于QuickFlow开发SharePoint工作流和直接在SharePoint上开发工作流很类似,使用Quickflow前最好了解下默认的SharePoint工作流是如何开发和运行的。

更多细节,参见:http://cid-7f5a25cdf47d03e6.office.live.com/view.aspx/QuickFlow/Docs/QuickFlow2.0%E7%99%BD%E7%9A%AE%E4%B9%A6.docx

2)QuickFlow如何安装

QuickFlow的安装包含两部分:一部分是一个wsp的解决方案,这个解决方案中,包括所有dll文件和页面文件,这个wsp分两个版本:一个用于SharePoint2007,一个用户SharePoint2010。另外一部分是设计器,设计器无需安装,直接解压后即可打开exe文件,需要指出的是,当前版本的设计器只能在SharePoint服务器上运行。

详细见:http://cid-7f5a25cdf47d03e6.office.live.com/view.aspx/QuickFlow/Docs/QuickFlow%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97.docx

3)Quickflow使用中碰到错误如何解决

有几种类型的错误:

发布流程时:这个时候出错,一般是web.config配置错误,重新激活下QuickFlow feature即可。在SP07下,在网站集功能管理中操作,在SP10下,需要到管理中心激活QuickFlow App Configuration feature,详见安装文档

工作流运行时:有很多种可能性,首先要找到日志信息,日志有两个地方可以看,一个是工作流状态页面--在列表页面,点击工作流链接进入。在这个页面可以看到QuickFlow内部输出的日志。不仅仅是碰到错误,如果工作流没错误,但是运行结果跟预期的不一致,也可以到这个页面查看信息。比如设置了发送邮件,但是测试时却没有收到,那么状态页面会记录邮件发现情况。

另一个查看日志的地方是12/Logs or 14/Logs目录,这是SP自带的日志文件。打开最新的日志文件,在里面搜索Workflow Infrastructure ,可以搜到跟工作流有关的日志信息。

注:日志目录[C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\LOGS]

在页面提交的时出错: 这个时候,如果发现页面上没有详细的错误信息,那么首先要让SP显示出详细错误,这个操作是SP开发第一步就要做的。详细:google SharePoint 详细错误。 需要指出的是:Layouts下的web.config也是需要修改的(set customError mode=’off’)

4)关于工作流变量(workflow variable)

工作流变量是当使用QuickFlow Designer时,允许在流程级别添加一些特定类型的字段,各个活动的属性可以跟工作流变量绑定,UI代码可以直接控制工作流变量的值。

如果您是用VisualStudio+QuickFlow开发,那么是没必要用工作流变量的,工作流变量其实是模拟添加类字段(field)。用vs时,可以很方便的在工作流中添加字段,为什么还要用工作流变量呢?

当然,vs中工作流变量还是可以使用的,那么一般会碰到两个问题:

a)如何在UI代码中控制工作流字段的值:跟控制工作流变量的值是一样的,用QuickFlow.Core.WorkflowContext.Current.UpdateWorkflowVariable("NextApprovors", nextUsers);

b)如何在WF代码中控制工作流变量的值:直接设置字段的值即可,或者,用base.UpdateVariable("NextApprovors", nextUsers);如:

public QuickFlow.NameCollection nextUsers ;
//nexUsers bind to multiTask.Users
private void task_init(object sender, EventArgs e)
{
this.nextUsers = ...;

//or base.UpdateVariable("nextUsers", nextUsers);
}

记住:

在用VS+QF时,工作流变量跟普通的字段是一样的。
永远不要在VS的WF代码中调用WorkflowContext.Current。

如果要在UI代码中传递变量值,只能在几个固定的事件方法中才可行:

1-StartWorkflowButton.Executing事件中,

2-ActionsButton.ActionExecuting事件中,

3-TaskReassignButton.Executing事件中,

4-在启动页面或任务页面的Page_Load事件中,Page_Load中给工作流变量赋值后,必须在以下的操作中启动工作流或提交任务才会有效

无论在哪个方法中,都需要使用QuickFlow.Core.WorkflowContext.Current.UpdateWorkflowVariable来更新变量

注意:在UI代码中,只能设置工作流变量的值而不能获取工作流变量值,如果碰到必须获取工作流变量的情况,那么可以用列表字段传值来实现。

5)关于WorkflowContext.Current

这个类用于在工作流页面中跟工作流交互。非工作流页面不能使用。

6)如果不用QuickFlow提供的控件来开发工作流页面,如何启动流程,提交任务呢?

有两种方式:

a)直接用SharePoint的对象模型来操作。这样做会有些复杂性。

跟Workflow有关的方法有:SPSite.WorkflowManager.StartWorkflow, SPWorkflow.AlterTask,详细见SharePoint SDK.

b)用QuickFlow提供的API操作: WorkflowContext.Current.

用WorkflowContext.Current必须在特定的上下文下运行,包括列表的新建页面,任务的提交页面。

常用WorkflowContext方法如下:

WorkflowContext.Current 获取到当前的工作流上下文
WorkflowContext.CreateContext(SPList dataList) 基于某个列表创建一个上下文, 这样创建的context,自动工作流的时候,会自动在列表中新建一个列表项,用于非NewForm页面上启动工作流
.DataFields[] 获取或设置列表字段值。
.UpdateWorkflowVariable(string name, object value) 工作流启动前或任务提交前更新工作流变量
.StartWorkflow(string wfName) 启动工作流

.CommitTask( string outcome )

完成任务,指定任务的结果(通过,拒绝)
.ReAssignTask(string to) 转发任务
WorkflowContext.Current.Task 获取当前的WorkflowTask(只能获取到上次的数据)
WorkflowContext.Current.TaskFields["field name"] 获取当前的任务字段属性,可以获取到最新数据

提交任务需要用WorkflowTask类

WorkflowTask一般通过WorkflowContext.Current.Task(任务页面代码)或者WorkflowTask.FromListItem(任何地方)获取

常用WorkflowTask方法如下:

WorkflowTask.FromListItem  将任务Item转换成WorkflowTask类
.Actions 获取到任务的动作集合(TaskActions)
bool CanCommit() 当前用户是否可以提交工作流(只有网站集管理员或者任务操作人才能提交任务)
CommitTask(string outcome) 提交任务
   

示例:

在列表的Newform页面启动工作流:

WorkflowContext.Current.StartWorkflow(“My Workflow”)

无论是启动工作流还是提交任务前,都可以传递工作流变量

WorkflowContext.Current.UpdateWorkflowVariable(“vabiableName”,value)

在一个普通的aspx页面启动流程(非NewForm页面):

             var wflist = SPContext.Current.Web.Lists[“List1”];

              WorkflowContext wfCtx = WorkflowContext.CreateContext(wflist);

              wfCtx.DataFields["Title"] = proj.ProjectName; //设置列表项字段
              wfCtx.DataFields["ReferenceNo"] = proj.ReferenceNo;
              wfCtx.DataFields[ProjectID_FieldName] = proj.ID;

              wfCtx.UpdateWorkflowVariable("sendToPCController", true);//设置工作流变量
              wfCtx.UpdateWorkflowVariable("PCController", new NameCollection(pcController));
              wfCtx.UpdateWorkflowVariable("PM", new NameCollection(proj.ProductManager));
              wfCtx.StartWorkflow(Config.WorkflowName);

在任务页面获取任务动作:

TaskActionCollection actons = WorkflowContext.Current.Task.Actions;

在任务页面完成任务:

WorkflowContext.Current.CommitTask(“Approved”); //Approved is a taskAction

在非任务页,如控制台或TimerJob代码中完成任务:

var taskItem = taskList.GetItemById(100);
var task = WorkflowTask.FromListItem(taskItem);
if(task.Actoins.Count>0)  task.Commit(task.Actions[0]); 
else taks.Commit();

7)CommentTaskField这个富文本框能否去掉其样式呢,就是不希望用户在审批意见里添加各种样式,只要输入文字意见好了

在网站内容类型管理中,找到任务内容类型,设置其 描述字段 不使用富文本

8)在Initialized事件中设置了活动的属性,为什么不起作用?

因为QF中的活动可以无限次执行,所以实际执行的活动只是设计器上的活动的副本

如果在活动已经开始执行了,再设置设计器上的活动的属性,可能就无效了。

有两个方法解决这个问题:

 1--事件参数sender始终是执行中的活动,直接给sender赋值,如: ((Task)sender).User = "someUserAccount";

 2--如果要让一个属性可以在活动执行时可以被修改,那么可以把这个属性绑定到一个全局变量,这样--就始终可以修改了.

 3--在这个活动前面一个活动的Completed事件中给这个活动的字段赋值。
9)设置了规则引擎(BeforeRule or AfterRule),发现工作流长时间不结束

原因:规则的计算,改变了规则的条件,造成规则引擎重新运行规则(造成无限循环)

解决:把 重新计算 选项改成 永不(Never) ,  了解WF规则引擎:http://msdn.microsoft.com/zh-cn/library/aa480193.aspx

10)任务被锁定,即使更正了代码错误,任务依然无法重新提交

解决:需要先把任务解锁,然后重新提交即可:

ServerModel code:

using (SPSite site = new SPSite("http://localhost"))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    SPList taskList = web.Lists["Tasks"];
                    var item = taskList.GetItemById(188); //change 188 to the task id
                    web.AllowUnsafeUpdates = true;
                    item[SPBuiltInFieldId.WorkflowVersion] = 1;
                    try
                    {
                        item.SystemUpdate();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.ToString());
                    }
                }
 }

ClientModel code:

try
{
using (ClientContext clientContext =new ClientContext("http://localhost"))
{
Web site
= clientContext.Web;
var list
= site.Lists.GetByTitle("Tasks");
ListItem item
= list.GetItemById(188);
clientContext.Load(item);
clientContext.ExecuteQuery();
Console.WriteLine(
"WorkflowVersion: "+ item["WorkflowVersion"]);
item[
"WorkflowVersion"] =1;
item.Update();
clientContext.ExecuteQuery();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine(
"done");
Console.ReadKey();

注:最新版本任务被锁定后,默认任务页面上会显示一个解锁的链接,如果是自定义的页面,则在页面上加上UnLockTaskLink控件即可。

若解锁后依然无法提交,则重新启动SharePoint Timer服务和数据库服务,然后再次解锁提交.若依然不行,则只能重启工作流。

ref:http://connect.nintex.com/forums/thread/6503.aspx

11)不用QuickFlow的API启动流程,而直接用纯MOSS接口启动,如何传递工作流变量呢?

代码入下:

//using QukckFlow.Core;

WorkflowVariableValues vs = new WorkflowVariableValues();

vs["variableName1"] = "value1";

vs["variableName2"] = "value2";

var eventData = SerializeUtil.Serialize(vs);

SPSite site = SPControl.GetContextSite(HttpContext.Current);

var wfName = "some workflow name";

var wfAss =  list.WorkflowAssociations.GetAssociationByName(wfName, System.Globalization.CultureInfo.CurrentCulture);

wf = site.WorkflowManager.StartWorkflow(listItem, wfAss, eventData);

如果要异步启动工作流,可以调用:

site.WorkflowManager.StartWorkflow(object context, SPWorkflowAssociation association, string eventData, SPWorkflowRunOptions runOptions)

此异步方法只有SP2010支持。

12)如果工作流设置成自动启动(Auto), 用StartWorkflowButton启动工作流时会报错。

首先搞清楚MOSS默认的工作流机制:工作流启动分3种模式:

1)手工启动--就是通过下拉菜单进入工作流启动页面启动

2)自动启动--创建一条Item后自动自动

3)当Item的某个字段值改变后启动

用了StartWorkflowButton时,StartWorkflowButton会调用moss api启动工作流,实际上是模拟手工启动

如果配置成自动自动,那么moss会自动启动一个工作流, StartWorkflowButton会再次启动一个工作流

而一个工作里是不能启动2次的,所以,StartWorkflowButton启动工作流的时候就出错了

所以,用了StartWorkflowButton,或用其他方式调用MOSS API启动工作流,工作流必须设置成手工启动(Manual)
 

13)SP10任务表单上的任务历史记录列表会显示一个复选框,如何取消?

修改任务列表的默认视图设置,取消:Allow individual item checkboxes  复选框 
 

14)在QFD中新建了一个工作流变量,但是在活动属性绑定窗口或规则编辑窗口无法找到这个变量

点下保存按钮,将工作流保存下即可。
 

15)重新发布流程后,流程名称后面出现 (1)

问题原因:是因为老版本的QFD发布流程时流程配置文件的BaseID会变造成的

解决方法:升级到最新版本的QFD,然后用SharePoint Designer打开工作流文件夹,把.xoml.wfconfig.xml的除1.0版本和当前版本外的版本删除,

然后将最新版本.xoml.wfconfig.xml中的BaseID修改成和1.0版本一致),用QFD重新发布流程即可

16)如何控制WorkflowHistory/TaskList显示的字段

如果是在自定义任务表单中,可以通过WorkflowHistory控件的ViewFields控制,如:

<QFL:WorkflowHistory runat="server" ID="hisList"  ShowTaskOfCurrentWorkflow="true"

 ViewFields=""Title,AssignedTo, Status, Body, StartDate, WorkflowOutcome, DelegateFrom"/>

如果是想控制QF自带的TaskList页面,则到网站设置->网站栏管理,将需要显示的字段添加到QuickFlow组中即可。

 17)RuleDriven/TaskWizard设置了超时规则,不起作用
 1-重启iis,重启SharePoint Timer服务,重启服务器

 2-设置定时job扫描间隔: stsadm -o setproperty -propertyname "job-workflow" -propertyvalue "every 2 minutes  between 0 and 59" -url http://dc

 3- 参考:http://www.dev4side.com/community/blog/2010/12/1/bug-using-delay-activity-on-sharepoint-2010-workflow.aspx

 18)采用VS+QF开发工作流时,若已经在生产环境部署,如何更新,才能保证老流程正常运行下去?

若只是修改了方法内部的代码,则正常更新dll或wsp即可。

若增删了活动或变量,则必须先手工备份老程序集,然后将程序集版本升版,更新新程序集或wsp,然后重新部署老程序集,确保新老程序集在gac中同时存在

see:  http://spmat.blogspot.com/2010/11/assembly-versioning-for-sharepoint.html

 19)若发布流程时报QuickFlow or SystemXXX没有授权

认真阅读安装指南,重新激活QuickFlow App Configuration功能

 

 

posted on 2011-06-12 11:09 jianyi 阅读(...) 评论(...) 编辑 收藏