转载
目标:利用VS2008和ASPX表单开发SharePoint工作流,用于档案借阅审批流程。
流程:
档案借阅审批流程
为什么不使用Infopath表单?
Infopath2007设置表单固然方便快捷,但对于复杂的表单,操作起来很繁琐,对于一些特殊需求,只能通过Code来解决。对于业务表单,我还是习惯于将业务数据保存在数据库中。
为什么不使用SharePoint Designer?
SD是可以开发出工作流,对于复杂的流程,仅靠If Else只会让流程更繁琐。SD自带的工作流操作还不够丰富,需要自己去定义,例如发短信的操作。
选用VS2008和ASPX表单来法工作流,虽然也需要做很多编码工作,但流程是可控的,遇到的任何需求,基本都可通过代码来实现。从简便性上来说,熟练这种方式之后,优势还是很明显的。
强烈建议使用VS2008,如果你还没有使用,赶紧吧。需要安装VSeWSS插件。
打开VS2008,新建项目
设计页面如下
代码:
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Linq;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.WorkflowActions;
using Microsoft.Office.Workflow.Utility;
using System.IO;
using System.Collections.Specialized;
using System.Web;
namespace SharePointWorkflowLendApprove
{
public sealed partial class Workflow1 : SequentialWorkflowActivity
{
//定义Task0的guid
public Guid Task0_Id = default(System.Guid);
//定义Task0的属性
public SPWorkflowTaskProperties Task0_Properties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
//定义Task1的属性
public Guid Task1_Id = default(System.Guid);
//定义Task1的属性
public SPWorkflowTaskProperties Task1_Properties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
//日志
public string log = “”;
//While Activity时使用
public bool isOk;
public Workflow1()
{
InitializeComponent();
}
//工作流id和属性,这是自动生成的
public Guid workflowId = default(System.Guid);
public SPWorkflowActivationProperties workflowProperties = new SPWorkflowActivationProperties();
#region “Function”
//日志
private void logs(string msg)
{
string s = “SharePointWorkflowLendApprove:” + DateTime.Now.ToLocalTime() + “"r"n” + msg + “"r"n"r"n”;
File.AppendAllText(“c:""logs.txt”, s);
}
//对Task0分配特殊权限,让分配对象有参与讨论的权限
public HybridDictionary TaskPermission
{
get
{
HybridDictionary taskPermission = new HybridDictionary();
//这个判断很重要,否则会导致工作流错误
if (Task0_Properties.AssignedTo != null)
taskPermission[Task0_Properties.AssignedTo] = SPRoleType.Contributor;
return taskPermission;
}
}
//对Task1分配特殊权限,让分配对象有参与讨论的权限
public HybridDictionary TaskPermission1
{
get
{
HybridDictionary taskPermission = new HybridDictionary();
//这个判断很重要,否则会导致工作流错误
if(Task1_Properties.AssignedTo!=null)
taskPermission[Task1_Properties.AssignedTo] = SPRoleType.Contributor;
return taskPermission;
}
}
#endregion
/// <summary>
/// 启动工作流
/// </summary>
/// <param name=”sender”></param>
/// <param name=”e”></param>
private void onWorkflowActivated1_Invoked(object sender, ExternalDataEventArgs e)
{
log = “工作流已启动“;
logs(“工作流“ + workflowId.ToString() + “已启动“);
}
/// <summary>
/// 创建Task0
/// </summary>
/// <param name=”sender”></param>
/// <param name=”e”></param>
private void createTask0_MethodInvoking(object sender, EventArgs e)
{
isOk = false;
try
{
Task0_Id = Guid.NewGuid();
if (Task0_Properties.Title == null)
Task0_Properties.Title = “档案借阅审批“;
Task0_Properties.AssignedTo = “档案管理员“;
Microsoft.Office.Workflow.Utility.Contact c = Microsoft.Office.Workflow.Utility.Contact.FromName(Task0_Properties.AssignedTo, workflowProperties.Web);
log = “等待“ + c.DisplayName + “审批“;
//
CEAPETFunction.Moss moss = new CEAPETFunction.Moss();
moss.updateContentAppendText(workflowProperties, “等待“ + c.DisplayName + “审批……“);
}
catch (Exception ex)
{
log = “createTask0_MethodInvoking” + ex.ToString();
}
}
/// <summary>
/// 当Task0被改动时
/// </summary>
/// <param name=”sender”></param>
/// <param name=”e”></param>
private void onTaskChanged0_Invoked(object sender, ExternalDataEventArgs e)
{
isOk = TaskEdited(Task0_Properties.TaskItemId);
}
/// <summary>
/// 创建Task1
/// </summary>
/// <param name=”sender”></param>
/// <param name=”e”></param>
private void createTask1_MethodInvoking(object sender, EventArgs e)
{
isOk = false;
try
{
Task1_Id = Guid.NewGuid();
if (Task1_Properties.Title == null)
Task1_Properties.Title = “档案借阅审批“;
Task1_Properties.AssignedTo = “档案经理“;
Microsoft.Office.Workflow.Utility.Contact c = Microsoft.Office.Workflow.Utility.Contact.FromName(Task1_Properties.AssignedTo, workflowProperties.Web);
log = “等待“ + c.DisplayName + “审批“;
CEAPETFunction.Moss moss = new CEAPETFunction.Moss();
moss.updateContentAppendText(workflowProperties, “等待“ + c.DisplayName + “审批……“);
}
catch (Exception ex)
{
log = “createTask1_MethodInvoking” + ex.ToString();
}
}
/// <summary>
/// 当Task1被改动时
/// </summary>
/// <param name=”sender”></param>
/// <param name=”e”></param>
private void onTaskChanged1_Invoked(object sender, ExternalDataEventArgs e)
{
isOk = TaskEdited(Task1_Properties.TaskItemId);
}
/// <summary>
/// 当审批任务修改时
/// </summary>
/// <param name=”itemId”></param>
/// <returns></returns>
private bool TaskEdited(int itemId)
{
try
{
SPList cList = workflowProperties.TaskList;
SPListItem cItem = cList.GetItemById(itemId);
if (cItem.Fields.ContainsField(“审批“) == true)
{
if (cItem["审批"] != null)
{
if (cItem["审批"].ToString() != “”)
{
string str = cItem["修改者"].ToString();
log = “审批已完成,审批人:“ + str.Remove(0, str.IndexOf(“#”) + 1);
str = str.Substring(0, str.IndexOf(“;”));
CEAPETFunction.User ceapetuser = new CEAPETFunction.User();
SPUser u = ceapetuser.getSPUserById(workflowProperties.Site, str);
str = u.LoginName;
if (str.Substring(0, 4).ToLower() == “ceapet”)
{
str = str.Remove(0, 5);
str = “<img src=’http://ceapetmoss/SiteCollectionImages/qianming/” + str + “.png’ border=’0′ alt=’” + u.LoginName + “‘ />”;
}
CEAPETFunction.Moss moss = new CEAPETFunction.Moss();
if (cItem["批注"] == null)
moss.updateContentAppendText(workflowProperties, str + “已完成审批,审批意见:“ + getImage(cItem["审批"].ToString()) + “。完成时间:<span classname=’dateTime’>” + DateTime.Now.ToLocalTime().ToString() +“</span>”);
else
moss.updateContentAppendText(workflowProperties, str + “已完成审批,审批意见:“ + getImage(cItem["审批"].ToString()) + “,批注:“ + cItem["批注"].ToString() + “。完成时间:<span classname=’dateTime’>” + DateTime.Now.ToLocalTime().ToString() +“</span>”);
return true;
}
}
}
}
catch (Exception ex)
{
logs(ex.ToString());
}
return false;
}
/// <summary>
/// 工作流完成时,更新报表
/// </summary>
/// <param name=”sender”></param>
/// <param name=”e”></param>
private void _WorkFlowCompleted(object sender, EventArgs e)
{
CEAPETFunction.Moss moss = new CEAPETFunction.Moss();
moss.updateContentAppendText(workflowProperties, “工作流已完成,完成时间:“ + DateTime.Now.ToLocalTime().ToString());
logs(“工作流“ + workflowId.ToString() + “已完成“);
}
private void _Task0ResultCondition1Code(object sender, EventArgs e)
{
doWorkFlowRefusaled();
}
private void _Task1ResultCondition1Code(object sender, EventArgs e)
{
doWorkFlowRefusaled();
}
/// <summary>
/// 工作流被拒绝或退回时的操作
/// 1、停止工作流、2给申请人发送邮件。
/// </summary>
private void doWorkFlowRefusaled()
{
try
{
CEAPETFunction.Moss moss = new CEAPETFunction.Moss();
moss.updateContentAppendText(workflowProperties, “审批被拒绝或退回,工作流随即停止“);
string body = moss.getItemContent(workflowProperties);
string name = moss.getItemName(workflowProperties);
CEAPETFunction.User ceapetuser = new CEAPETFunction.User();
ceapetuser.mailtoUser(body, name + “未通过审批“, workflowProperties.Workflow.AuthorUser.LoginName);
log =“审批被拒绝或退回,工作流随即停止“ + workflowProperties.Workflow.AuthorUser.LoginName;
}
catch (Exception ex)
{
logs(“doWorkFlowRefusaled” + ex.ToString());
}
}
#region “条件判断“
private void _Task0ResultCondition1(object sender, ConditionalEventArgs e)
{
bool r = doTaskResult(workflowProperties.TaskList, Task0_Properties.TaskItemId);
e.Result = !r;
}
private void _Task0ResultCondition2(object sender, ConditionalEventArgs e)
{
bool r = doTaskResult(workflowProperties.TaskList, Task0_Properties.TaskItemId);
e.Result = r;
}
private void _Task1ResultCondition1(object sender, ConditionalEventArgs e)
{
bool r = doTaskResult(workflowProperties.TaskList, Task1_Properties.TaskItemId);
e.Result = !r;
}
private void _Task1ResultCondition2(object sender, ConditionalEventArgs e)
{
bool r = doTaskResult(workflowProperties.TaskList, Task1_Properties.TaskItemId);
e.Result = r;
}
/// <summary>
/// 处理审批结果
/// </summary>
/// <param name=”cList”></param>
/// <param name=”itemId”></param>
/// <returns></returns>
private bool doTaskResult(SPList cList, int itemId)
{
SPListItem cItem = cList.GetItemById(itemId);
if (cItem["审批"].ToString() == “批准“)
return true;
else
return false;
}
#endregion
/// <summary>
/// 取得图片url
/// </summary>
/// <param name=”str”></param>
/// <returns></returns>
private string getImage(string str)
{
string r = “”;
if (str == “批准“)
r = “<img src=’http://ceapetmoss/SiteCollectionImages/qianming/tongyi.png’ border=’0′ alt=’同意‘ />”;
if (str == “拒绝“)
r = “<img src=’http://ceapetmoss/SiteCollectionImages/qianming/jujue.png’ border=’0′ alt=’拒绝‘ />”;
if (str == “退回“)
r = “<img src=’http://ceapetmoss/SiteCollectionImages/qianming/tuihui.png’ border=’0′ alt=’退回‘ />”;
return r;
}
/// <summary>
/// 条件判断
/// </summary>
/// <param name=”sender”></param>
/// <param name=”e”></param>
private void whileTasko_Code(object sender, ConditionalEventArgs e)
{
e.Result = !isOk;
logs(“工作流“ + workflowId.ToString() + “Task0:” + isOk.ToString());
}
private void whileTask1_Code(object sender, ConditionalEventArgs e)
{
e.Result = !isOk;
logs(“工作流“ + workflowId.ToString() + “Task1:” + isOk.ToString());
}
}
}
值得说明的几点
设计好ASPX业务表单,将其放在Layout目录下,这样就不用在web.config中配置,允许该aspx页面执行代码。
新建一个内容发布页面的内容类型,命名为档案借阅申请。新建一个文档库,用于保存申请表单,在这个文档库中增加刚才新建的内容类型,将工作流设置到该文档库。档案借阅申请内容类型指定的模板应该修改成aspx页面。
每当一个表单提交后,aspx页面处理完表单数据后,生成一个静态页面保存在刚才建的那个文档库中。工作流启动。
每个申请单,只能由申请人、档案管理员、档案经理看得见,其他人无法看见,这就要求对生成的静态页面重新分配权限,这个应当放在ASPX页面中完成,如果放在工作流中,就不能使用文档创建时启动工作流的选项,因为工作流启动需要一定的时间,直接去对静态页面分配权限会返回Null异常。
通过F5调试
设置Task的SpecialPermissions时,要单击那个黄色小图标,单击输入框中的…按钮没有反应,据说这是Bug。
我在任务列表中添加了两个字段,一个是审批字段,有批准、拒绝、退回三个值,另一个是批注字段。这样,每当任务被修改时,就去判断审批字段的值时候为空,如果不为空,要判断其是批准、拒绝还是退回,然后选择分支。通过While Activity来判断是否继续循环。
我创建了log变量,当需要在Workflow History List中添加日志时,我就设置log的值,我把logToHistoryListActivity拖到相应的地方,将HistoryDescription设置成log。