[SharePoint Designer -4]SharePoint 的无代码工作流在备份还原后不能使用的问题
就我的认识,SharePoint Designer的无代码工作流设计器在SharePoint中有两个作用,一个是设计列表的工作流,另一个是给DataForm Web part提供Custom Action(自定义列表操作)的支持(在上一篇文章中我叙述过相关的内容[SharePoint Designer -3]DataForm Web Part中的数据操作)。
不管是哪种使用方法,使用无代码工作流设计器的最终的结果都是:SharePoint会在网站的Workflows文件夹下面创建相应的文件(有XOML文件,工作流配置的XML文件,规则的rules文件,以及很多的asp页面,xoml和xml文件是一定存在的),然后给列表添加一个工作流关联(association)。其中很重要的一个文件是*.wfconfig.xml文件,其形式大致如下:
<WorkflowConfig> <Template BaseID="{963BA7F4-2105-4793-85BB-C1D90367D961}" DocLibID="{8a493f4e-22e4-4f34-aefd-55325667ef0f}" XomlHref="Workflows/工作流 1/工作流 1.xoml" XomlVersion="V4.0"> </Template> <Association ListID="{32a8da29-ac60-4e06-86b8-70d4780e563a}" TaskListID="{6822A246-52D5-4BA8-BCBE-826D17620BE7}" StartOnChange="true"> </Association> <ContentTypes> </ContentTypes> <Initiation URL="Workflows/工作流 1/工作流 1.aspx"> <Fields /> <Parameters></Parameters> </Initiation> </WorkflowConfig>
其中DocLibID是Workflows文档库的GUID,ListID是这个工作流绑定到的列表的GUID。
我们可以通过备份还原网站来迁移部署SharePoint Designer设计的工作流。
但是,当我们备份还原网站后,SharePoint Designer设计的工作流在新的网站中不能工作!
问题出在两个地方:
1)新的网站中工作流对应的*.wfconfig.xml中的DocLibID和ListID不能更新到新网站的对应列表的GUID;
2)列表与相应工作流的关联(Association)丢失了。
根据对问题的分析,我们可以找到方法来重建并绑定工作流。
1)首先更新*.wfconfig.xml文件的DocLibID和ListID
2)重新绑定工作流
SharePoint Designer设计的工作流绑定需要利用WebPartPagesWebService的ValidateWorkflowMarkupAndCreateSupportObjects和AssociateWorkflowMarkup方法。
基于以上的分析,我的解决方案是:
1)在Workflows的文件夹下面维护一个Lists.xml文件,形式如下:
<?xml version="1.0" encoding="utf-8" ?> <Lists> <List Name="test" ID="{23d0e43d-b6bf-4670-b69f-871a63f77941}"></List> <List Name="custom workflow process" ID="{76ed547a-aa40-4aab-86e2-5e525ea49e1d}"></List> </Lists>
为什么维护这样一个列表呢?因为网站备份在还原后,列表的名字不会变,但是GUID会变!所以,维护一个存储所有绑定了SharePoint Designer无代码工作流的列表的ID和Name对应关系的XML文件,方便之后更新*.wfconfig.xml文件用。
2)在网站还原以后,通过一下的ReAttachWorkflows方法来更新*.wfconfig.xml文件,并绑定工作流到相应的列表,代码如下:
public static void ReAttachWorkflows(SPWeb objWeb) { string strXOML = string.Empty; string strConfig = string.Empty; string strRules = string.Empty; string strConfigPath = string.Empty; string strVersion = string.Empty; string strLists = string.Empty; SPList objWorkflowList = null; try {objWorkflowList = objWeb.Lists["Workflows"];} catch {objWorkflowList = objWeb.Lists["工作流"];} System.IO.StreamReader objReader; SPFile Filelists = objWorkflowList.RootFolder.Files["Lists.xml"]; objReader = new System.IO.StreamReader(Filelists.OpenBinaryStream()); strLists = objReader.ReadToEnd(); objReader.Dispose(); System.Xml.XmlDocument xmlLists = new System.Xml.XmlDocument(); xmlLists.LoadXml(strLists); foreach (SPListItem objItem in objWorkflowList.Folders) { SPFolder objFolder = objItem.Folder; foreach (SPFile objFile in objFolder.Files) { objFile.CheckOut(false, string.Empty); objReader = new System.IO.StreamReader(objFile.OpenBinaryStream()); if (objFile.Name.EndsWith("xoml")) { strXOML = objReader.ReadToEnd(); objReader.Dispose(); } if (objFile.Name.EndsWith("rules")) { strRules = objReader.ReadToEnd(); objReader.Dispose(); } if (objFile.Name.EndsWith("xml")) { strConfig = objReader.ReadToEnd(); objReader.Dispose(); strConfigPath = objFile.ServerRelativeUrl.Substring(objFile.ServerRelativeUrl.IndexOf(objWeb.Name) + objWeb.Name.Length + 1); System.Xml.XmlDocument xmlConfig = new System.Xml.XmlDocument(); xmlConfig.LoadXml(strConfig); //update GUID of the 'Workflows' document library xmlConfig.SelectSingleNode("/WorkflowConfig/Template/@DocLibID").Value = "{" + objWorkflowList.ID.ToString() + "}"; System.Xml.XmlNode xmlNodeList = xmlConfig.SelectSingleNode("/WorkflowConfig/Association/@ListID"); System.Xml.XmlNode xmlNodeListOrigin = xmlLists.SelectSingleNode("/Lists/List[@ID='"+xmlNodeList.Value.ToLower()+"']"); //update GUID of the list to be associated xmlNodeList.Value = "{" + objWeb.Lists[xmlNodeListOrigin.Attributes["Name"].Value].ID.ToString() + "}"; strConfig = xmlConfig.OuterXml; objFile.SaveBinary(System.Text.Encoding.UTF8.GetBytes(strConfig)); } objFile.Update(); objFile.CheckIn(string.Empty); } Microsoft.SharePoint.SoapServer.WebPartPagesWebService objWebPartPages = new Microsoft.SharePoint.SoapServer.WebPartPagesWebService(objWeb); string strResult; strResult = objWebPartPages.ValidateWorkflowMarkupAndCreateSupportObjects(strXOML, strRules, strConfig, "2"); //associate with list string param1 = strConfigPath; string param2 = strVersion; strResult = objWebPartPages.AssociateWorkflowMarkup(param1, param2); } xmlLists = null; }
一些想法:
1)了解了SharePoint Designer工作流的工作原理了,我们似乎是可以在一定程度上重用一下用SPD设计出来的工作流呢?
思路可以是这样:两个列表必须具有相同的字段(至少是与工作流相关的字段要一样,然后把Workflows文件夹下面的对应的工作流的文件夹复制一个,修改*.wfconfig.xml文件(更新路径,把绑定的列表的GUID更新,然后用ReAttachWorkflows把工作流绑定好。
从原理上来说这样做是行得通的,当然我并没有试过:)
posted on 2008-01-15 22:48:00 by ipark 评论(3) 阅读(8330)







