1

Update: So I'm giving up on the code below and starting new. The suggestion from a more experienced SharePoint developer was to use Nintex Workflow. I'm currently testing it, and so far it looks promising.


I am trying to start a standard Sharepoint 2010 approval workflow using c#. Currently I’m facing difficulties in adding or updating approvers/ users programmatically for the highlighted fields in the initiation form, as shown in the screenshot below. Since no users are added, no tasks are assigned and the workflow is rejected.

enter image description here

The following is the code that I use to start the workflow (based on this blog post: Start a SharePoint 2010 List Workflow with CSOM):

using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Workflow;
using Microsoft.SharePoint.Client.WorkflowServices;
…
…

string SharepointURL = "https://testSharepointSite.com/sites/Test";

//Name of the List to which the Workflow is Associated
string targetListName = "Documents";

//connect to Sharepoint URL with Windows Credentials
ClientContext clientContext = new ClientContext(SharepointURL);
List list = clientContext.Web.Lists.GetByTitle(targetListName);

// load list
clientContext.Load(list);
clientContext.Load(list.Fields);
clientContext.ExecuteQuery();

// get list item (a document in sharepoint to approve)
ListItem item = list.GetItemById("17");

// load item
clientContext.Load(item);
clientContext.ExecuteQuery();

// Name of approval workflow
string workflowName = "ApprovalProcessTest";

Web web = context.Web;

// Guid of the List to which the Workflow is Associated
Guid targetListGUID = new Guid("b89e266c-5f20-4b83-9f95-10a42c629e84");

// GUID of list item (DPM file) on which to start the workflows
Guid itemGuid = (Guid)item.FieldValues["GUID"];

// Workflow Services Manager which will handle all the workflow interaction 
WorkflowServicesManager workflowServicesManager = new WorkflowServicesManager(context, web);

// Return all Workflow Associations which are running on the SharePoint 2010 Engine
WorkflowAssociationCollection workflowAssociations = list.WorkflowAssociations;
context.Load(workflowAssociations);
context.ExecuteQuery();

// Get the required Workflow Association
WorkflowAssociation workflowAssociation = workflowAssociations.GetByName(workflowName);
context.Load(workflowAssociation);
context.ExecuteQuery();

// Get the instance of the Interop Service which will be used to create an instance of the Workflow
InteropService workflowInteropService = workflowServicesManager.GetWorkflowInteropService();

// Start the Workflow
ClientResult<Guid> resultGuid = workflowInteropService.StartWorkflow(
        workflowAssociation.Name,
        new Guid(), 
        targetListGUID, 
        itemGuid, 
        SharePointListItem_RW // <- dictionary<string, object> to pass initiation data/ workflow parameters
      );
 context.ExecuteQuery();

As you can see in the very last part of the code, I can use a dictionary to pass initiation data to the form above. I’ve looked in the association data of the workflow to get an idea of how the dictionary should look like. Following is the XML of the association data that I get from workflowAssociation.AssociationData:

<dfs:myFields xmlns:d="http://schemas.microsoft.com/office/infopath/2009/WSSList/dataFields"
    xmlns:dfs="http://schemas.microsoft.com/office/infopath/2003/dataFormSolution" 
    xmlns:dms="http://schemas.microsoft.com/office/2009/documentManagement/types" 
    xmlns:ma="http://schemas.microsoft.com/office/2009/metadata/properties/metaAttributes" 
            xmlns:pc="http://schemas.microsoft.com/office/infopath/2007/PartnerControls" 
            xmlns:q="http://schemas.microsoft.com/office/infopath/2009/WSSList/queryFields" 
            xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <dfs:queryFields/>
    <dfs:dataFields>
        <d:SharePointListItem_RW>
            <d:Approvers>
                <d:Assignment>
                    <d:Assignee>
                        <pc:Person>
                            <pc:DisplayName>User Name</pc:DisplayName>
                            <pc:AccountId>domain\user</pc:AccountId>
                            <pc:AccountType>User</pc:AccountType>
                        </pc:Person>
                        <pc:Person>
                            <pc:DisplayName>User name2</pc:DisplayName>
                            <pc:AccountId>domain\user2</pc:AccountId>
                            <pc:AccountType>User</pc:AccountType>
                        </pc:Person>
                    </d:Assignee>
                    <d:Stage xsi:nil="true"/>
                    <d:AssignmentType>Serial</d:AssignmentType>
                </d:Assignment>
            </d:Approvers>
            <d:ExpandGroups>true</d:ExpandGroups>
            <d:NotificationMessage>A comment</d:NotificationMessage>
            <d:DueDateforAllTasks>2019-09-29T22:00:00.0000000Z</d:DueDateforAllTasks>
            <d:DurationforSerialTasks>2</d:DurationforSerialTasks>
            <d:CC>
                <pc:Person>
                    <pc:DisplayName>User name</pc:DisplayName>
                    <pc:AccountId>domain\user</pc:AccountId>
                    <pc:AccountType>User</pc:AccountType>
                </pc:Person>
            </d:CC>
            <d:CancelonRejection>false</d:CancelonRejection>
            <d:CancelonChange>false</d:CancelonChange>
            <d:EnableContentApproval>false</d:EnableContentApproval>
        </d:SharePointListItem_RW>
    </dfs:dataFields>
</dfs:myFields>

Based on the XML, I created the following dictionary:

User user = web.EnsureUser(@"domain\user");
context.Load(user);
context.ExecuteQuery();

// does not work
Dictionary<string, object> Person = new Dictionary<string, object>();
Person["DisplayName"] = user.Title;
Person["AccountId"] = user.LoginName; 
Person["AccountType"] = "User";

// does not work
Dictionary<string, object> Assignment = new Dictionary<string, object>();
Assignment["Assignee"] = assignee;
Assignment["AssignmentType"] = "Serial";

// does not work
Dictionary<string, object> Approvers = new Dictionary<string, object>();
Approvers["Assignment"] = Assignment;

Dictionary<string, object> SharePointListItem_RW = new Dictionary<string, object>();
SharePointListItem_RW["Approvers"] = Approvers; // does not work
SharePointListItem_RW["NotificationMessage"] = "Lorem Ipsum v3"; // works
SharePointListItem_RW["DueDateforAllTasks"] = "2019-09-25"; // works
SharePointListItem_RW["DurationforSerialTasks"] = 2; // no idea, cannot test
SharePointListItem_RW["DurationUnits"] = "Days"; // no idea, cannot test

// does not work
Dictionary<string, object> cc = new Dictionary<string, object>();
cc["Person"] = Person;
SharePointListItem_RW["CC"] = cc;

Using the dictionary, I can pass a comment and the due date, but not the users for approval and cc.

I’ve been stuck on this problem now for a couple of days. Googling around did not return any positive results. The above codes are the last that I tried.

Any ideas now on how can I add one or more users to pass to the workflow?

0

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.