Saturday, May 25, 2013

SharePoint 2013 Workflow: Programmatically Access Workflow Properties

SharePoint 2013 workflow introduced a new API to interact with SharePoint 2013 workflows. The old workflow API will not work for this new workflow model. The most basic API is available as part of the DLL (Microsoft.SharePoint.WorkflowServicesBase.dll) and the basic entry point for accessing workflow data is WorkflowServicesManager class. I’ll explain few uses of API but you can browse the API to find out more details usage.

 

Get all Workflows associated with a list

You need to create a new instance of WorkflowServiceManager and using the list id, you can ask WorkflowSubscriptionService to find all workflows associated with the list as shown below:

WorkflowServicesManager workflowServiceManager = new WorkflowServicesManager(web);
var workflowSubscriptionService = workflowServiceManager.GetWorkflowSubscriptionService();
var subscriptions = workflowSubscriptionService.EnumerateSubscriptionsByList(listId);

You can get subscription properties as shown below. If you association form has any custom properties, you can retrieve these property values by passing property name.

foreach (var subscription in subscriptions)
{
    var assocationName = subscription.Name;
    var propertyValue = subscription.GetProperty("Property_Name");
}

 

Get Workflow Instance

To get workflow instance details we need get the instance of WorkflowInstanceService from WorkflowServiceManager class as shown below:

WorkflowServicesManager workflowServiceManager = new WorkflowServicesManager(web);
var workflowInstanceService = workflowServiceManager.GetWorkflowInstanceService();
var workflowInstances = workflowInstanceService.EnumerateInstancesForListItem(listId, itemId);

Once we get the workflow Instance, we can get the instance properties as shown below. Any properties in Workflow Initiation form will also be available:

foreach (var instance in workflowInstances)
{
    var propertyValue= instance.Properties["Property_Name"];
}

The table below shows few common properties, but you can find out more properties by debugging code:

Property Name

Description

Microsoft.SharePoint.ActivationProperties.ContextListId

List Id

Microsoft.SharePoint.ActivationProperties.CurrentItemUrl

Current Item Url

Microsoft.SharePoint.ActivationProperties.InitiatorUserId

Initiator User login name, for example i:0#.w|domain\username

Microsoft.SharePoint.ActivationProperties.ItemId

List Item Id

 

Send Custom Notification to Workflow

In SharePoint 2013 workflow, there’s a activity ‘WaitForCustomEvent’. Using this activity you can keep your workflow wait for a custom event. In this activity you can pass the event name. To send the custom event to the workflow you can use workflow API as shown below. First you need to find out the workflow Instance.

WorkflowServicesManager workflowServiceManager = new WorkflowServicesManager(web);
var workflowInstanceService = workflowServiceManager.GetWorkflowInstanceService();
workflowInstanceService.PublishCustomEvent(workflowInstance, "CustomEventName", "");

19 comments:

  1. Where does the dll you reference live. I can't find it anywhere on my server. Workflow manager 1.0 is installed, but I do not have that dll.

    ReplyDelete
  2. The dlls are in GAC (C:\windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.SharePoint.WorkflowServicesBase)

    ReplyDelete
  3. Hi, Sohel.
    Sorry for my bad english.

    I have the problem with the rights on WrkStat.aspx (Workflow Status Page).

    I have the site collection. All users except site administration in this site collection have only read level permission (dont't update, create list items in lists).
    There are two lists: list1 and list2. In display form of list1 there is the button. Clicking the button is create item in lists2.
    I activated the feature "Workflows Can Use App Permissions" and do all how writting in this article to"http://sergeluca.wordpress.com/2013/03/26/sharepoint-2013-issue-with-the-new-start-a-task-process-and-how-to-fix-it-with-an-app-step/" to the workflow step to have full control on the site collection.

    The workflow is running after creating item in list2 - all good. But when user clicked on status worklfow (WrkStat.aspx) there is error: access is denied.

    How I can resolve this problem? Users must have readonly rights.




    ReplyDelete
  4. I want to change status url page (WrkStat.aspx) of workflow 2013 designed in sharepoint designer 2013. Can I do this?

    ReplyDelete
    Replies
    1. Same here! Wondering about the same... I have a workflow created in SPD (SharePoint Designer). Tried to import it into VS to set a custom path to the WrkStat.aspx-page there, but no luck there either. Does anyone know this?

      Delete
  5. Hi Sohel.

    I add Microsoft.SharePoint.WorkflowServicesBase.dll.
    But, the WorkflowServicesManager couldn't be found.
    Can you help me, plese?

    ReplyDelete
  6. @Priscila, Is your Visual Studio (VS) project has target framework 4.5? Which type of VS project you are using?

    ReplyDelete
  7. Sohel, my project type is a sharepoint 2013 project and target framework is 4.5.

    ReplyDelete
  8. @Pricila, are you developing sandbox solution or full trust solution? You will not be able to use this api in sandbox solution (office 365/SharePoint online)..

    ReplyDelete
  9. Thanks for this post. Very useful. How do can i get workflowInstance in the below statement.

    workflowInstanceService.PublishCustomEvent(workflowInstance, "CustomEventName", "");

    Thanks.

    ReplyDelete
  10. Hi Sohel, and thanks a lot for you posts. Keep up the good work!

    I'm sending in several custom properties to a new workflow instance in code like this:

    Dictionary param = new Dictionary();
    param.Add("eSignatureQualityLevel", int.Parse(ESignatureQualityLevelList.SelectedValue));

    ...etc...

    var workflowGuid = wfi.StartWorkflowOnListItem(subscription, _itemId, param);

    Then I try to access these parameters later on, in a custom ASP NET page as a substitute for the default workflow task page:

    ...just as yout code...
    var eSignatureQualityLevel = instance.Properties["eSignatureQualityLevel"].ToString();

    But I get a "The given key was not present in the dictionary." error.

    Is this because I add the properties in code, and they are thus not visible, compared to creating the properties in intitiation form in SharePoint Designer for instance?

    ReplyDelete
  11. @Unknown, You are not creating properties here, you are passing properties values to workflow, but if the workflow doesn't have the properties, I believe the properties will be ignored (what's happening in your case, I think). To access the properties, you need to have the properties created in your workflow. So properties need to be defined in workflow xaml, you can only pass properties values from code.

    ReplyDelete
    Replies
    1. Thanks for your reply.

      My setup is that my workflow is created in SharePoint Designer, but I have initiation form and task forms created in Visual Studio. I start the workflow programmatically as explained in my prev post, and send in a dictionary containing all user data from the initiation form to the workflow. If I then create "Local variables" in SharePoint Designer with the same names as I used in the dictionary in the initiation form, SharePoint is able to understand that the parameters from the initiation form should be mapped to the variables created in SharePoint Designer. Thus; I can use the initiation form data in my workflow execution in SharePoint Designer.

      Later on, when assigning tasks to users in my workflow, I use a custom task form developed in VS, using Mikhail's guide on how to do this (http://sp2013.pro/2013/03/creating-spd-2013-workflows-part-23-implementing-custom-asp-net-task-form/).

      Question 1: I would very much like to access the same parameters in the custom task form, that should have been associated (as "properties"?) with the workflow?

      Question 2: I would also like to update these variables that the workflow uses in SharePoint Designer (SPD), from custom ASP.NET pages. For instance: in the intitiation form, the user specifies users that should be given a task. The email adresses of these users are sent to the WF created in SPD and used to assign tasks to. Later on, I would like to change this list of users that should receive tasks. So, from my custom .aspx page I would like to update this list of email-adresses and send it back to the WF in SPD. Is this possible?

      -I really think I should have developed my WF in VS and not in SPD...

      Delete
    2. I would like to confirm whether you are using 'variables' or 'arguments'. Variables are local to workflow and you can't access this from outside, as I understand. To access workflow properties from outside (or to pass value to it), you need to define workflow arguments with 'In' direction. As I can remember you can define parameters from SharePoint Designer too. So please make sure you have defined Parameters not variables, if you would like to access it from workflow api.

      Delete
    3. Hi Sohel, thanks a lot for following me up on this.

      The only option I have in my SPD 2013 is "Initiation form parameters" and "Local variables".

      I have now tried to create a intiation form parameter named "InitFormParamTest" in SPD to see if this parameter is accessible as a property on the workflow instance. I published the workflow to my site collection.

      Then in my custom task form .aspx task form I wrote:

      SPSecurity.RunWithElevatedPrivileges(delegate()
      {
      using (SPSite site = new SPSite(SPContext.Current.Web.Url))
      {
      using (SPWeb web = site.OpenWeb())
      {
      var wsm = new Microsoft.SharePoint.WorkflowServices.WorkflowServicesManager(web);
      WorkflowSubscription subscription = wsm.GetWorkflowSubscriptionService().GetSubscription(subscriptionGuid);

      WorkflowInstanceService workflowInstanceService = wsm.GetWorkflowInstanceService();
      WorkflowInstanceCollection workflowInstances = workflowInstanceService.EnumerateInstancesForListItem(_documentList.ID, _document.ID);

      foreach (var instance in workflowInstances)
      {
      if (instance.Id == _workflowGuid) // This is our workflow
      {
      TestLabel.Text += "Contains key? " + instance.Properties.ContainsKey("InitFormParamTest");
      TestLabel.Text += instance.Properties["InitFormParamTest"];

      //Check if we can add properties to the wf instance and access them later
      instance.Properties.Add("hello", "value");
      }
      }
      }
      }
      });

      The output is that "InitFormParamTest" is not in the properties dictionary in my workflow instance (and yes; it is the correct wf instance). But you say in your blogpost: "Any properties in Workflow Initiation form will also be available"... Hmmm.. What is my err...

      I also tried adding a new entry in the instance.Properties (Dictionary), and get it back later on, but when I tried to get it back it was not there. Why?

      If I loop through the instance.Properties I get the standard output:

      foreach (KeyValuePair prop in instance.Properties)
      {
      TestLabel.Text += prop.Key + ": " + prop.Value + "\r\n";
      }

      FormData:
      Microsoft.SharePoint.ActivationProperties.ContextListId: f560ad6d-8682-465d-87e7-e2daadc265b4
      Microsoft.SharePoint.ActivationProperties.CurrentItemUrl: TestDocuments/ESIG-TEST-TN-0000 - No Signature.pdf
      Microsoft.SharePoint.ActivationProperties.InitiatorUserId: i:0#.w|esignature\brodsjo
      Microsoft.SharePoint.ActivationProperties.ItemGuid: 84b86a9c-9fad-4ed7-a58e-f2b5b71792e3
      Microsoft.SharePoint.ActivationProperties.ItemId: 2
      Microsoft.SharePoint.ActivationProperties.RetryCode: 0
      Microsoft.SharePoint.ActivationProperties.UniqueId: ffdcf9da-a55c-4801-84c0-b2ea8fed6206
      UserStatus: Agreed signers signing

      Delete
  12. Hi Sohel,

    Can you help me get SharePoint 2013 workflow instance tasks from associated task list for an each list item when workflow had started.

    Thank you,
    Praveen.

    ReplyDelete
  13. I have an issue in SharePoint 2013 online where previous workflow approvals no longer show as having been done when a user's (she got married) last name changed. We sync with Active directory nightly. All workflows done after name change appear but nothing prior to name change. Any ideas on how to get those to show? Unfortunately these workflows are an audit trail on documents for our accounting group - so i have to display somehow!!! All help is appreciated.

    Thanks,
    Diana

    ReplyDelete
  14. Thank you very much Sohel,
    This has greatly assisted me.
    Geoffrey Mwanthi.

    ReplyDelete