工作流日志的记录
工作流日志的记录可以实现两个功能。
l SharePoint工作流代码出错的时候,监控页面的信息很少,为了便于查找错误,可以捕获关键代码抛出的异常,并将其记录到日志中。
l 通过日志,可以记录一些审批的信息。
SharePoint工作流日志的记录有以下两种方法。
l 通过workflowProperties属性调用CreateHistoryEvent方法,代码如下。
private void replicatorActivity1_ChildInitialized(object sender,
ReplicatorChildEventArgs e)
{
TaskActivity activity = e.Activity as TaskActivity;
activity.TaskProperties = new SPWorkflowTaskProperties();
activity.TaskProperties.AssignedTo = e.InstanceData.ToString();
activity.TaskProperties.TaskType = 0;
activity.TaskProperties.Title = "会签审批任务";
//记录日志
this.workflowProperties.Workflow.CreateHistoryEvent((int)
SPWorkflowHistoryEventType.WorkflowError, 0,
this.workflowProperties.OriginatorUser, "会签任务创建" , "审批用户:" +
e.InstanceData , "");
}
l 从ActivityExecutionContext中获取到ISharePointService接口的实现,调用其LogToHistoryList方法,这种方法只适合于重载基类方法的时候使用,代码如下。
protected override ActivityExecutionStatus HandleFault(ActivityExecutionContext
executionContext, Exception exception)
{
ISharePointService hostService = executionContext.GetService
<ISharePointService>();
if (hostService != null)
{ //记录日志
hostService.LogToHistoryList(this.workflowProperties.WorkflowId,
SPWorkflowHistoryEventType.WorkflowError, 0, TimeSpan.MinValue,
exception.Message, exception.StackTrace, "");
}
return base.HandleFault(executionContext, exception);
}
以上方法重载了工作流基类的HandleFault方法,将所有异常信息记录到日志中。
循环审批的实现
以上几节的实例都是标准的顺序工作流,任务依次创建,在实际的开发过程中我们经常要处理循环审批的情形,如图1所示。
图1 循环审批流程
循环审批需要采用While活动来实现。假设要把文档审批流程修改成如图7-127所示的流转逻辑,操作步骤如下。
Step1 设计提交人修改文档任务表单。审批人的审批表单继续使用ApprovalForm.xsn,提交人修改文档时的任务表单需要重新设计,样式如图2所示。上级审批意见文本框用来显示审批人的审批意见,绑定到主数据源的"comments"域,默认值绑定到ItemMetadata辅助数据源的"comments"域中。表单设计好后,将其发布为"ReSubmitForm.xsn"。
Step2 修改工作流配置文件,将ReSubmitForm.xsn跟工作流进行关联。在feature.xml的ElementManifests节点下添加如下配置。
<ElementFile Location="ReSubmitForm.xsn" />
在workflow.xml的MetaData节点下添加如下配置。
<Task1_FormURN>urn:schemas-microsoft-com:office:infopath:ReSubmitForm:
-myXSD-2008-10-02T19-07-06</Task1_FormURN>
Task1_FormURN节点的值通过表单的属性窗口获取。
图2 ReSubmitForm.xsn表单
Step3 添加While活动。拖曳While活动到工作流设计器,如图3所示。
图3添加While活动
设置While活动的Condition为"NeedApproval",代码如下。
private bool isFirstSubmit = true;
private bool task1Result = false;
///<summary>
///循环条件
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
private void NeedApproval(object sender, ConditionalEventArgs e)
{
if (isFirstSubmit) //第一次提交的时候允许循环条件为true
{
e.Result = true;
}
else //审批任务完成后,若审批为通过,则继续循环
{
e.Result = !task1Result;
}
}
当第一次提交时(启动工作流),While活动执行条件为真,若审批任务为通过,则While需要继续执行,以便创建新的审批任务。
Step4 添加审批任务。拖曳Sequence活动到While活动内部。拖曳TaskActivity到Sequence活动内部,如图4所示。
图4 添加审批任务
处理taskActivity1的TaskCreating事件,代码如下。
///<summary>
///审批任务创建
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
private void taskActivity1_TaskCreating(object sender, TaskEventArgs e)
{
string approvalUser = this.GetConfigurationData().ApprovalUser[0].AccountId;
e.TaskProperties.AssignedTo = approvalUser; //指定审批人
e.TaskProperties.Title = "审批任务";
e.TaskProperties.TaskType = 0;
}
审批人从初始化表单配置数据中获取,TaskType指定为0,表示采用Task0_FormURN指定的表单。处理taskActivity1的TaskCompleted事件,代码如下。
private string task1Comments = "";
private void taskActivity1_TaskCompleted(object sender, TaskEventArgs e)
{
//记录审批结果
task1Result = Convert.ToBoolean(e.TaskProperties.ExtendedProperties
["approval"]);
task1Comments = "" + e.TaskProperties.ExtendedProperties["comments"];
isFirstSubmit = false;
//记录日志
string approval = Convert.ToBoolean(e.TaskProperties.ExtendedProperties
["approval"]) ? "批准" : "拒绝";
this.workflowProperties.Workflow.CreateHistoryEvent(
(int)SPWorkflowHistoryEventType.WorkflowComment, 0,
this.workflowProperties.OriginatorUser, approval, "审批用户:" +
e.TaskProperties.AssignedTo + ";审批时间:" + DateTime.Now + ";审批意见:" +
task1Comments, "");
//更新文档内容审批状态
this.UpdateModerationStatus(task1Result, task1Comments);
}
审批任务结束后,将审批结果和审批意见存放到task1Result和task1Comments字段中,并按照审批结果设置文档内容审批状态。
Step5 添加提交人修改任务。审批人审批未通过才给提交人分配修改任务,所以首先需要添加一个IfElse活动来判断是否审批人审批通过。
添加IfElse活动,并设置其第一个条件分支的规则条件为this.task1Result==false,如图5所示。
图5 添加IfElse活动
添加一个TaskActivity到IfElse活动的第一个分支,如图6所示。
图6 添加TaskActivity
处理taskActivity2的TaskCreating事件,代码如下。
///<summary>
///修改任务创建
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
private void taskActivity2_TaskCreating(object sender, TaskEventArgs e)
{
e.TaskProperties.AssignedTo = this.workflowProperties.Originator;
e.TaskProperties.Title = "修改文档";
e.TaskProperties.TaskType = 1; //指定使用Task1_FormURN标识的表单
//设置表单辅助数据源值
e.TaskProperties.ExtendedProperties["comments"] = task1Comments;
}
以上代码创建新的任务,任务分配用户为流程的启动人,并且将审批意见同步到任务表单的辅助数据源。TaskType指定为1,表示采用Task1_FormURN指定的表单。
多状态工作流的实现
多状态工作流指的是在一个审批过程中存在多个审批状态(审批步骤)的工作流,每个状态可以按照条件跳转到其他任意状态,如图7所示。
图7 多状态工作流
WF支持状态机工作流,利用状态机工作流可以很容易地实现这种类型的流程,下一节将会具体讲述。SharePoint状态机工作流对每个状态单个审批任务支持得很好,但是如果某个审批状态需要多人审批,比如一个会签的场景,状态机工作流支持起来就很困难了。
WF提供了一个ConditionedActivityGroup活动,内部可以放置多个子活动,每个子活动都有一个是否执行的条件。利用ConditionedActivityGroup活动,可以采用顺序工作流实现多状态工作流。下面是具体的操作步骤。
Step1 设计任务表单。需要设计两个表单模板:提交人修改文档的表单我们直接采用上一节设计的ReSubmitForm.xsn。状态2和状态3审批任务的表单使用同一个表单,样式如图8所示,approvalState域是一个文本域,采用下拉列表,供审批人选择下一步的审批状态,表单发布为StateApprovalForm.xsn。
图8 StateApprovalForm.xsn
Step2 修改工作流配置文件。在feature.xml的ElementManifests节点下添加以下配置。
<ElementFile Location="StateApprovalForm.xsn" />
<ElementFile Location="ReSubmitForm.xsn" />
在workflow.xml的MetaData节点下添加以下配置。
<Task0_FormURN>urn:schemas-microsoft-com:office:infopath:StateApprovalForm:
-myXSD-2008-10-02T19-07-06</Task0_FormURN>
<Task1_FormURN>urn:schemas-microsoft-com:office:infopath:ReSubmitForm:
-myXSD-2008-10-02T19-07-06</Task1_FormURN>
Task0_FormURN为StateApprovalForm.xsn的ID,Task1_FormURN为ReSubmitForm.xsn的ID。
Step3 声明一个枚举类型,用来表示工作流的状态,代码如下。
///<summary>
///审批状态
///</summary>
public enum ApprovalState
{
//重新修改
ReSubmit,
///文档初审
PreApproval ,
//文档终审
Approval,
//审批完成
Complete
}
在工作流类中添加ApprovalState类型的字段,代码如下。
private ApprovalState approvalState = ApprovalState.PreApproval;
Step4 添加ConditionedActivityGroup活动,如图 9所示。设置其UntilCondition的规则条件为:
this.approvalState == ApprovalState.Complete
当审批状态变成审批完成时,即结束ConditionedActivityGroup的执行。
图9 添加ConditionedActivityGroup活动
Step5 添加文档初审审批任务。在ConditionedActivityGroup中添加一个TaskActivity,名称改为preApprovalActivity,如图10所示。
图10 添加preApprovalActivity
设置preApprovalActivity的WhenCondition为条件规则,条件名称为IsPreApproval,表达式为:
this.approvalState == ApprovalState.PreApproval
这个规则指定当审批状态处于PreApproval时preApprovalActivity执行。
处理preApprovalActivity的TaskCreating事件,代码如下。
private void preApprovalActivity_TaskCreating(object sender, TaskEventArgs e)
{
e.TaskProperties.Title = "文档初审";
e.TaskProperties.TaskType = 0; //指定使用Task0_FormURN标识的表单
e.TaskProperties.AssignedTo = "codeart\\user1";
}
以上代码将文档初审任务分配给user1用户,并指定TaskType为0,使审批任务使用StateApprovalForm.xsn表单。
处理preApprovalActivity的TaskCompleted事件,代码如下。
private void approvalActivity _TaskCompleted(object sender, TaskEventArgs e)
{
////按照表单中approvalState域设置审批状态
this.approvalState = (ApprovalState)Enum.Parse(typeof(ApprovalState),
e.TaskProperties.ExtendedProperties["approvalState"].ToString(), true);
string comments = "" + e.TaskProperties.ExtendedProperties["comments"];
//记录日志
string approval = Convert.ToBoolean(e.TaskProperties.ExtendedProperties
["approval"]) ? "批准" : "拒绝";
this.workflowProperties.Workflow.CreateHistoryEvent(
(int)SPWorkflowHistoryEventType.WorkflowComment, 0,
this.workflowProperties.OriginatorUser, this.approvalState.ToString(),
"审批用户:" + e.TaskProperties.AssignedTo + ";审批时间:" + DateTime.Now + ";
审批意见:" + comments, "");
}
以上代码将审批表单中的审批状态域的值同步到工作流的approvalState字段,并且把审批意见域的值记录到工作流日志中。
Step6 添加文档终审审批任务。在ConditionedActivityGroup中添加一个TaskActivity,名称改为"approvalActivity"。设置approvalActivity的WhenCondition为条件规则,条件名称为"IsApproval",表达式为:
this.approvalState == ApprovalState.Approval
这个规则指定当审批状态处于Approval时approvalActivity执行。处理preApprovalActivity的TaskCreating事件,代码如下。
private void approvalActivity_TaskCreating(object sender, TaskEventArgs e)
{
e.TaskProperties.Title = "文档终审";
e.TaskProperties.TaskType = 0; //指定使用Task0_FormURN标识的表单
e.TaskProperties.AssignedTo = "codeart\\user2";
}
指定approvalActivity的TaskCompleted事件为approvalActivity_TaskCompleted。approvalActivity和preApprovalActivity两个任务活动的任务结束处理逻辑是一样的,所以使用同一个TaskCompleted事件处理函数。
Step7 添加文档修改任务。在ConditionedActivityGroup中添加一个TaskActivity,名称改为"reSubmitActivity"。设置reSubmitActivity的WhenCondition为条件规则,条件名称为"IsApproval",表达式为:
this.approvalState == ApprovalState.ReSubmit
这个规则指定当审批状态处于ReSubmit时reSubmitActivity执行。处理reSubmitActivity的TaskCreating事件,代码如下。
private void reSubmitActivity_TaskCreating(object sender, TaskEventArgs e)
{
e.TaskProperties.Title = "修改文档";
e.TaskProperties.TaskType = 1; //指定使用Task1_FormURN标识的表单
e.TaskProperties.AssignedTo = this.workflowProperties.Originator;
this.approvalState = ApprovalState.PreApproval; //转换审批状态为文档初审
}
以上代码分配任务给流程发起人,并设置审批状态为"PreApproval"。
在本节的示例代码中,每个状态的审批人是一个用户,但是可以很容易地把某个状态修改成多人的会签审批,由于操作比较烦琐,就不在此处描述了。
状态机工作流
本节来了解SharePoint中的状态机工作流。状态机工作流主要跟以下几个活动有关。
l State:表示一个审批状态。内部可以放置StateInitialization、EventDrivenActivity和StateFinalization 3个活动。
l StateInitialization:用来初始化状态,一般在这个活动内部添加CreateTask实现任务的创建。
l StateFinalization:当状态结束时被执行。
l EventDrivenActivity:用来接受事件,一般在内部放置一个OnTaskChange活动等待任务完成。
l SetState:用来实现流程状态的跳转。SetState活动一般放置在OnTaskChange活动后,在任务完成后按照任务表单域设置流程状态。
本节将上一节的多状态工作流采用状态机来实现。首先新建一个SharePoint state machine workflow项目。直接采用上一节开发的StateApprovalForm.xsn和ReSubmitForm.xsn表单模板,将这两个模板发布到项目目录下,修改配置文件,在feature.xml中添加如下配置。
<ElementFile Location="StateApprovalForm.xsn" />
<ElementFile Location="ReSubmitForm.xsn" />
在workflow.xml的MetaData节点下添加如下配置。
<Task0_FormURN>urn:schemas-microsoft-com:office:infopath:StateApprovalForm:
-myXSD-2008-10-02T19-07-06</Task0_FormURN>
<Task1_FormURN>urn:schemas-microsoft-com:office:infopath:ReSubmitForm:
-myXSD-2008-10-02T19-07-06</Task1_FormURN>
在Workflow节点下添加如下属性。
TaskListContentTypeId="0x01080100C9C9515DE4E24001905074F980F93160"
拖曳4个State活动到设计器中。分别改名为preApprovalActivity、approvalActivity、reSubmitActivity和completeActivity。通过右键菜单,将completeActivity活动设置为终止状态,如图11所示。
双击Workflow1InitialState活动中的"EventDriven"活动,在其中添加一个SetState活动,设置其TargetState为"preApprovalActivity"。状态机的每个状态的处理方法基本是一样的,下面是preApprovalActivity活动的实现方法。
图11状态机工作流设计器
Step1 添加CreateTask活动,创建审批任务。拖曳stateInitializationActivity到preApprovalActivity内部,双击"stateInitializationActivity",在stateInitializationActivity内部添加一个CreateTask活动,改名为"createPreApprovalTask",指定其CorrelationToken为"preApprovalTaskToken",将其SpecialPermission属性绑定到工作流的preApprovalTaskSpecialPermissions字段,TaskId属性绑定到工作流的preApprovalTaskId字段,TaskProperties属性绑定到工作流的preApprovalTaskProperties字段,如图12所示。
图12 createPreApprovalTask的属性设置
处理createPreApprovalTask的MethodInvoking方法,代码如下。
private void createPreApprovalTask_MethodInvoking(object sender, EventArgs e)
{
preApprovalTaskId = Guid.NewGuid();
preApprovalTaskProperties.Title = "文档预审";
preApprovalTaskProperties.TaskType = 0; //审批任务采用第一个任务表单
preApprovalTaskProperties.AssignedTo = "codeart\\user1"; //指定审批人
//设置任务编辑权限
preApprovalTaskSpecialPermissions.Clear();
preApprovalTaskSpecialPermissions.Add(preApprovalTaskProperties.
AssignedTo, SPRoleType.Contributor);
}
以上代码将文档预审任务分配给user1。
Step2 添加OnTaskChanged活动,等待任务完成,并进行处理。返回到工作流设计器界面,拖曳EventDriven活动到preApprovalActivity,双击"EventDriven"活动,在EventDriven活动中添加OnTaskChanged活动,改名为"onPreApprovalTaskChanged"。设置CorrelationToken属性跟createPreApprovalTask活动一致,将AfterProperties和BeforeProperties属性均绑定到preApprovalTaskProperties字段,将TaskId属性绑定到preApprovalTaskId字段,如图13所示。
图13 onPreApprovalTaskChanged属性配置
处理Invoked事件,代码如下。
private void onApprovalTaskChanged_Invoked(object sender, ExternalDataEventArgs e)
{
//获取到产生事件的OnTaskChanged活动
OnTaskChanged onTaskChangedActivity = (OnTaskChanged)sender;
SPWorkflowTaskProperties taskProp = onTaskChangedActivity.AfterProperties;
//按照表单中approvalState域设置审批状态
this.approvalState = (ApprovalState)Enum.Parse(typeof(ApprovalState),
taskProp.ExtendedProperties["approvalState"].ToString(), true);
string comments = "" + taskProp.ExtendedProperties["comments"];
//记录日志this.workflowProperties.Workflow.CreateHistoryEvent(
(int) SPWorkflowHistoryEventType.WorkflowComment, 0,
this.workflowProperties.OriginatorUser, this.approvalState.ToString(),
"审批用户:" + taskProp.AssignedTo + ";审批时间:" + DateTime.Now + ";
审批意见:" + comments, "");
}
以上代码在任务完成后,按照任务表单中的值设置approvalState,并把审批意见记录到工作流日志中。本示例中所有OnTaskChanged活动的Invoked事件都可以用此函数来处理。
Step3 设置状态转换逻辑。添加一个IfElse活动到EventDriven活动中,并添加一个条件分支。设置第1个分支的Condition为规则条件,名称为"IsApproval",表达式为:
this.approvalState == ApprovalState.Approval
在第1个分支中添加1个SetState活动,设置其TargetState为approvalActivity。设置第2个分支的Condition为规则条件,名称为"IsReSubmit",表达式为:
this.approvalState == ApprovalState.ReSubmit
在第2个分支中添加1个SetState活动,设置其TargetState为"reSubmitActivity"。设置第3个分支的Condition为规则条件,名称为"IsComplete",表达式为:
this.approvalState == ApprovalState.Complete
在第2个分支中添加1个SetState活动,设置其TargetState为completeActivity。最后的EventDriven活动设计器效果如图14所示。
图14 EventDriven活动设计器效果
Step4 按照同样的步骤,完成approvalActivity活动和reSubmitActivity活动的设置。最终的设计器如图15所示。
图15 最终的设计器
从以上的流程可以看出示例项目中实现的流转逻辑:preApprovalActivity可以转向reSubmitActivity、approvalActivity或completeActivity,而reSubmitActivity只能转回preApprovalActivity,approvalActivity只能转向completeActivity。
状态机工作流相对顺序工作流的一个好处就是它的流程图更能体现实际的业务流程,但是从开发的工作量和简易度来说,顺序工作流实现起来更简单。
[workflow|Visual Studio]多个工作流任务表单如何与工作流步骤关联
一般一个工作流工程里面会包含很多工作流任务表单。我们在Visual Studio 2005开发的时候如何让程序知道在某个任务的时候给用户显示相应的工作流任务表单呢?
我们在设计工作流的时候,创建每个任务项的CreateTask Activity的对应有一个SPWorkflowTaskProperties类型的TaskProperties属性。我们在创建一个Task时候一般的过程类似:
private
void CreateTask1(object sender, EventArgs e)
{
this.taskID_ReviewerApproval = Guid.NewGuid(); //initialize the task id
this.workflowTask1Properties.Title = "Reviewer: Please review this document";
this.workflowTask1Properties.AssignedTo = this.ReviewerName;
this.workflowTask1Properties.Description = this.instruction;
this.workflowTask1Properties.TaskType = 0;
this.workflowTask1Properties.ExtendedProperties["Comment"] = "";
this.workflowTask1Properties.ExtendedProperties["Instruction"] = this.instruction;
this.workflowTask1Properties.ExtendedProperties["CurrentReviewer"] = this.ReviewerName;
}
一般如果你的工作流中只有一个任务表单,上面红色标识的"this.workflowTask1Properties.TaskType = 0;"这句可以不写。
但是,如果你有多个不同的任务表单,就必须包括这句代码来指定使用哪个任务表单。
TaskType的值和Workflow.xml中的Metadata中的Task*_FormURN有如下对应关系:
<MetaData>
<Instantiation_FormURN>urn:schemas-microsoft-com:office:infopath:SMWorkflowDemoStartForm:-myXSD-2006-05-21T19-13-08</Instantiation_FormURN>
<Association_FormURN>urn:schemas-microsoft-com:office:infopath:SMWorkflowDemoStartForm:-myXSD-2006-05-21T19-13-08</Association_FormURN>
<Task0_FormURN>urn:schemas-microsoft-com:office:infopath:SMWorkflowDemoApproveForm:-myXSD-2006-04-27T03-00-28</Task0_FormURN>
<Task1_FormURN>urn:schemas-microsoft-com:office:infopath:SMWorkflowDemoReviseForm:-myXSD-2006-04-27T03-11-15</Task1_FormURN>
<Task2_FormURN>urn:schemas-microsoft-com:office:infopath:SMWorkflowDemoApproveForm:-myXSD-2006-04-27T03-00-28</Task2_FormURN>
<StatusPageUrl>_layouts/WrkStat.aspx</StatusPageUrl>
</MetaData>
TaskType为0的对应Task0_FormURN,TaskType为1的对应Task1_FormURN,以此类推。如果不指定TaskType的值,默认使用Task0_FormURN。
转载:http://book.csdn.net/bookfiles/936/10093629438.shtml