使用 CSOM 创建 Project Server 2016 工作流

Posted

技术标签:

【中文标题】使用 CSOM 创建 Project Server 2016 工作流【英文标题】:Creating Project Server 2016 Workflow with CSOM 【发布时间】:2017-10-25 20:44:58 【问题描述】:

查看信息:

https://dev.office.com/sharepoint/docs/general-development/working-with-the-sharepoint-workflow-services-client-side-object-model

https://sharepoint.stackexchange.com/questions/159432/programmatically-create-workflow-with-javascript-jsom-and-sp-workflowservices-w

我正在尝试为 Project Server 2016 创建网站工作流 - 这意味着它的平台类型必须是 SharePoint 2013 Workflow - Project Server

就像 stackexchange 上的问题一样,首先我从 spd 2013 创建了示例工作流,保存为模板并将生成的 xaml 检索到我的 xaml 字符串。

ProjectContext psContext = new ProjectContext(Strings.PWA_Url);
var web = psContext.Web;
var siteCollection = psContext.Site;
var tasksList = web.Lists.GetByTitle("Project Server Workflow Tasks");
var historyList = web.Lists.GetByTitle("Project Server Workflow History");
string xaml = "<Activity mc:Ignorable="mwaw" x:Class="Test.MTW" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities" xmlns:local="clr-namespace:Microsoft.Office.Project.Server.WorkflowActivities" xmlns:local1="clr-namespace:Microsoft.SharePoint.WorkflowServices.Activities" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mwaw="clr-namespace:Microsoft.Web.Authoring.Workflow;assembly=Microsoft.Web.Authoring" xmlns:scg="clr-namespace:System.Collections.Generic;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><Sequence><Sequence><mwaw:SPDesignerXamlWriter.CustomAttributes><scg:Dictionary x:TypeArguments="x:String, x:String"><x:String x:Key="InitBlock">InitBlock-7751C281-B0D1-4336-87B4-83F2198EDE6D</x:String></scg:Dictionary></mwaw:SPDesignerXamlWriter.CustomAttributes></Sequence><Flowchart StartNode="x:Reference __ReferenceID1"><FlowStep x:Name="__ReferenceID1"><mwaw:SPDesignerXamlWriter.CustomAttributes><scg:Dictionary x:TypeArguments="x:String, x:String" /></mwaw:SPDesignerXamlWriter.CustomAttributes><Sequence><mwaw:SPDesignerXamlWriter.CustomAttributes><scg:Dictionary x:TypeArguments="x:String, x:String"><x:String x:Key="StageAttribute">StageContainer-8EDBFE6D-DA0D-42F6-A806-F5807380DA4D</x:String></scg:Dictionary></mwaw:SPDesignerXamlWriter.CustomAttributes><local:EnterProjectStage StageId="296334d9-1621-e711-80c8-00155d014d18"><mwaw:SPDesignerXamlWriter.CustomAttributes><scg:Dictionary x:TypeArguments="x:String, x:String"><x:String x:Key="StageAttribute">StageHeader-7FE15537-DFDB-4198-ABFA-8AF8B9D669AE</x:String></scg:Dictionary></mwaw:SPDesignerXamlWriter.CustomAttributes></local:EnterProjectStage><Sequence DisplayName="Inicjalizacja"><local1:SetWorkflowStatus Disabled="False" Status="Entering stage: Inicjalizacja" /></Sequence><local:ExitProjectStageGate><mwaw:SPDesignerXamlWriter.CustomAttributes><scg:Dictionary x:TypeArguments="x:String, x:String"><x:String x:Key="StageAttribute">StageFooter-3A59FA7C-C493-47A1-8F8B-1F481143EB08</x:String></scg:Dictionary></mwaw:SPDesignerXamlWriter.CustomAttributes></local:ExitProjectStageGate></Sequence><FlowStep.Next><FlowStep x:Name="__ReferenceID0"><mwaw:SPDesignerXamlWriter.CustomAttributes><scg:Dictionary x:TypeArguments="x:String, x:String"><x:String x:Key="Next">4294967294</x:String></scg:Dictionary></mwaw:SPDesignerXamlWriter.CustomAttributes><Sequence><mwaw:SPDesignerXamlWriter.CustomAttributes><scg:Dictionary x:TypeArguments="x:String, x:String"><x:String x:Key="StageAttribute">StageContainer-8EDBFE6D-DA0D-42F6-A806-F5807380DA4D</x:String></scg:Dictionary></mwaw:SPDesignerXamlWriter.CustomAttributes><local:EnterProjectStage StageId="e10db6c9-1721-e711-80c8-00155d014d18"><mwaw:SPDesignerXamlWriter.CustomAttributes><scg:Dictionary x:TypeArguments="x:String, x:String"><x:String x:Key="StageAttribute">StageHeader-7FE15537-DFDB-4198-ABFA-8AF8B9D669AE</x:String></scg:Dictionary></mwaw:SPDesignerXamlWriter.CustomAttributes></local:EnterProjectStage><Sequence DisplayName="Akceptacja"><local1:SetWorkflowStatus Disabled="False" Status="Entering stage: Akceptacja" /></Sequence><local:ExitProjectStageGate><mwaw:SPDesignerXamlWriter.CustomAttributes><scg:Dictionary x:TypeArguments="x:String, x:String"><x:String x:Key="StageAttribute">StageFooter-3A59FA7C-C493-47A1-8F8B-1F481143EB08</x:String></scg:Dictionary></mwaw:SPDesignerXamlWriter.CustomAttributes></local:ExitProjectStageGate></Sequence></FlowStep></FlowStep.Next></FlowStep><x:Reference>__ReferenceID0</x:Reference></Flowchart></Sequence></Activity>"
psContext.Load(web);
psContext.Load(siteCollection);
psContext.Load(tasksList);
psContext.Load(historyList);
psContext.ExecuteQuery();

WorkflowServicesManager wfServiceManager = new WorkflowServicesManager(psContext, web);
WorkflowDeploymentService deployService = wfServiceManager.GetWorkflowDeploymentService();
WorkflowSubscriptionService subscriptionService = wfServiceManager.GetWorkflowSubscriptionService();

WorkflowDefinition wfDefinition = new WorkflowDefinition(psContext);
wfDefinition.DisplayName = "TestWorkflow";
wfDefinition.Description = "TestWorkflow";
wfDefinition.Xaml = xaml;
wfDefinition.RestrictToType = "Site";

deployService.SaveDefinition(wfDefinition);

psContext.Load(wfDefinition, i => i.Id);
psContext.ExecuteQuery();

Guid subscriptionID = Guid.NewGuid();
WorkflowSubscription subscription = new WorkflowSubscription(psContext);
subscription.Id = subscriptionID;
subscription.Name = "TestWorkflow";
subscription.DefinitionId = wfDefinition.Id;
subscription.EventSourceId = web.Id;
subscription.EventTypes = new List<string>()  "WorkflowStart" ;
subscription.SetProperty("HistoryListId", historyList.Id.ToString("B"));
subscription.SetProperty("TaskListId", tasksList.Id.ToString("B"));

subscriptionService.PublishSubscription(subscription);
psContext.ExecuteQuery();

但这给了我最后一行代码的错误:

Microsoft.SharePoint.Client.ServerException: 'Microsoft.Workflow.Client.ActivityNotFoundException:活动 从范围命名为“WorkflowXaml_a2a3ddfc_8e29_488c_a7fa_110ad2e869fd” '/SharePoint/default/ec283308-a234-4501-9df1-99744cf4a5fe/b0993915-25fa-43f6-9839-8aa683f16ef2' 没有找到。从服务器接收到的 HTTP 标头 - ActivityId: e4085f69-addc-4c3e-8bcc-49c2f04daf7c。节点 ID:服务器。范围: /SharePoint/default/ec283308-a234-4501-9df1-99744cf4a5fe/b0993915-25fa-43f6-9839-8aa683f16ef2。 客户端 ActivityId : fa0ef59d-8566-1053-095'

这里没有任何线索。

【问题讨论】:

【参考方案1】:

我通过使用 Fiddler 嗅探 SharePoint Designer 2013 CSOM 通信来实现此功能。

让这个工作的关键是:

wfDefinition.SetProperty("IsProjectMode", "true");
// (...)
subscription.EventSourceId = new Guid("5122D555-E672-4E5D-A7C4-8084E694A257");
subscription.SetProperty("Microsoft.ProjectServer.ActivationProperties.CurrentStageId", "");
subscription.SetProperty("Microsoft.SharePoint.ActivationProperties.ParentContentTypeId", "");
subscription.SetProperty("Microsoft.ProjectServer.ActivationProperties.ProjectId", "");
subscription.SetProperty("Microsoft.ProjectServer.ActivationProperties.RequestedStageId", "");

注释的属性都是SPD设置的,但不是必须的。

工作代码:

ProjectContext psContext = new ProjectContext(Strings.PWA_Url);
var web = psContext.Web;
var siteCollection = psContext.Site;
var tasksList = web.Lists.GetByTitle("Project Server Workflow Tasks");
var historyList = web.Lists.GetByTitle("Project Server Workflow History");

psContext.Load(web, i => i.Id);
psContext.Load(siteCollection, i => i.Id);
psContext.Load(tasksList, i => i.Id);
psContext.Load(historyList, i => i.Id);
psContext.ExecuteQuery();

WorkflowServicesManager wfServiceManager = new WorkflowServicesManager(psContext, web);
WorkflowDefinition wfDefinition = new WorkflowDefinition(psContext);

Guid subscriptionID = Guid.NewGuid();
wfDefinition.DisplayName = "TestWorkflow";
wfDefinition.Description = "TestWorkflow";
wfDefinition.Xaml = Strings.Workflow_Simple;
wfDefinition.SetProperty("isReusable", "false");
wfDefinition.SetProperty("IsProjectMode", "true");
//wfDefinition.SetProperty("AutosetStatusToStageName", "false");
//wfDefinition.SetProperty("SPDConfig.LastEditMode", "TextBased");
wfDefinition.SetProperty("RestrictToType", "Site");
wfDefinition.SetProperty("TaskListId", tasksList.Id.ToString("B"));
wfDefinition.SetProperty("HistoryListId", historyList.Id.ToString("B"));
//wfDefinition.SetProperty("SPDConfig.StartManually", "true");
//wfDefinition.SetProperty("SPDConfig.StartOnCreate", "false");
//wfDefinition.SetProperty("SPDConfig.StartOnChange", "false");
//wfDefinition.SetProperty("FormField", "&lt;Fields /&gt;");
//wfDefinition.SetProperty("RequiresInitiationForm", "false");
//wfDefinition.SetProperty("InitiationUrl", "");
//wfDefinition.SetProperty("SubscriptionId", subscriptionID.ToString("B"));
//wfDefinition.SetProperty("SubscriptionName", "TestWorkflow");
WorkflowDeploymentService deployService = wfServiceManager.GetWorkflowDeploymentService();
deployService.SaveDefinition(wfDefinition);

psContext.Load(wfDefinition, i => i.Id);
psContext.ExecuteQuery();

deployService.PublishDefinition(wfDefinition.Id);
psContext.ExecuteQuery();

WorkflowSubscription subscription = new WorkflowSubscription(psContext);
subscription.Id = subscriptionID;
subscription.Name = "TestWorkflow";
subscription.EventSourceId = new Guid("5122D555-E672-4E5D-A7C4-8084E694A257");
subscription.EventTypes = new List<string>()  "WorkflowStart" ;
subscription.DefinitionId = wfDefinition.Id;
//subscription.SetProperty("CreatedBySPD", "1");
subscription.SetProperty("CurrentWebUri", Strings.PWA_Url_Https);
subscription.SetProperty("HistoryListId", historyList.Id.ToString("B"));
subscription.SetProperty("Microsoft.ProjectServer.ActivationProperties.CurrentStageId", "");
//subscription.SetProperty("SharePointWorkflowContext.ActivationProperties.SiteId", siteCollection.Id.ToString("B"));
subscription.SetProperty("TaskListId", tasksList.Id.ToString("B"));
subscription.SetProperty("Microsoft.SharePoint.ActivationProperties.ParentContentTypeId", "");
//subscription.SetProperty("SharePointWorkflowContext.ActivationProperties.WebId", web.Id.ToString("B"));
subscription.SetProperty("Microsoft.ProjectServer.ActivationProperties.ProjectId", "");
subscription.SetProperty("Microsoft.ProjectServer.ActivationProperties.RequestedStageId", "");

WorkflowSubscriptionService subscriptionService = wfServiceManager.GetWorkflowSubscriptionService();
subscriptionService.PublishSubscription(subscription);
psContext.ExecuteQuery();

【讨论】:

以上是关于使用 CSOM 创建 Project Server 2016 工作流的主要内容,如果未能解决你的问题,请参考以下文章

csharp 使用CSOM创建Sharepoint Wiki页面

Creating fields using CSOM

使用 CSOM 进行初始部署后,将 SharePoint 列表 Web 部件添加到特定页面

使用 CSOM 404 未找到错误通过 Windows 服务将文件上传到 SharePoint 2010

如何使用 CSOM 禁用 SharePoint 2013 警报

如何使用 CSOM 从/向 SharePoint 2013 下载/上传文件?