In this post I’ll show you how to build a custom workflow activity in Visual Studio that gets managed metadata field values from a SharePoint 2013 list or library. You can use the workflow activity in any SharePoint Designer list workflows, including on Office 365 sites – custom workflow activities in SharePoint 2013 are entirely declarative, so deploying to SharePoint Online is not a problem.
This is the second of a three-part series on working with managed metadata fields in workflows:
- Getting and Setting Managed Metadata Fields in SharePoint 2013 Workflows. In this post, I’ll explain the concepts behind my approach and explain why you can’t use built-in list actions to work with managed metadata fields.
- Custom Workflow Activity for Getting Managed Metadata Field Values (this post). In this post, I’ll walk you through how to build a custom workflow activity in Visual Studio that gets managed metadata field values from a list item.
- Custom Workflow Activity for Setting Managed Metadata Field Values. In this post, I’ll walk you through how to build a workflow activity that sets managed metadata field values on a list item.
I’ll assume you know the basics of how to build and deploy custom workflow activities – if you need a bit more detail on the deployment side of things, have a read through my first post on custom workflow activities. For now, let’s just say I’ve created a new custom workflow activity named Get MMS Field Value in Visual Studio.
Arguments and Variables
I’ll start with a quick run through of the arguments and variables I’ve used in the activity. First the arguments:
The activity will get the value of a managed metadata field from the current list item, so we only need the caller to provide one argument value – the name of the field (mmsFieldName). We want to return two values to the caller: the term GUID (termGuidOut) and the term label integer (labelOut).Now the variables:
We’ll use listItemFields to store a JSON representation of the list item. The DynamicValue type is perfect for storing and manipulating JSON data. We’ll use fieldPathTermGuid and fieldPathLabel to build the XPath expressions we need in order to isolate and extract the term GUID and the term label from the list item JSON.
Activity Design
The workflow activity consists of seven child activities:
![]()
- Get the current list item.
- Build an XPath expression to find the TermGuid property of the specified managed metadata field value.
- Build an XPath expression to find the Label property of the specified managed metadata field value.
- Add a try-catch block so we can catch any errors when we parse the list item.
- Within the try block, use the XPath expression we created earlier to get the TermGuid property from the managed metadata field value.
- Within the try block, use the XPath expression we created earlier to get the Label property from the managed metadata field value.
- Within the catch block, catch invalid operation exceptions and log the details to the workflow history list. (Invalid operation exceptions occur if the specified field does not exist or is not a managed metadata field.)
Let’s walk through each of these in turn.
Step 1 – Get the current list item
The first task is to retrieve the list item from which you want to extract the managed metadata field:
![]()
I’ve used a LookupSPListItem activity to do this. The activity returns the JSON representation of the list item as a DynamicValue instance, which I’ve assigned to the listItemFieldsvariable.
Step 2 – Build an XPath expression to find the TermGuid property
Now we’ve got the JSON representation of the list item, we need to figure out how to extract the properties we need. The only effective way to do this is to use the Visual Studio debugger (or a web debugger such as Fiddler) to take a look at the raw JSON data. In my development environment, it looks something like this:
{“d”:{“results”:[{"__metadata":{"id":"Web\/Lists(guid'77190d4b-c6a4-4e15-ac04-d3124492ca88')\/Items(5)","uri":"http:\/\/team.jason.net\/_api\/Web\/Lists(guid'77190d4b-c6a4-4e15-ac04-d3124492ca88')\/Items(5)","etag":"\"59\"","type":"SP.Data.CustomersListItem"},"FirstUniqueAncestorSecurableObject":{"__deferred":{"uri":"http:\/\/team.jason.net\/_api\/Web\/Lists(guid'77190d4b-c6a4-4e15-ac04-d3124492ca88')\/Items(5)\/FirstUniqueAncestorSecurableObject"}},"RoleAssignments":{"__deferred":{"uri":"http:\/\/team.jason.net\/_api\/Web\/Lists(guid'77190d4b-c6a4-4e15-ac04-d3124492ca88')\/Items(5)\/RoleAssignments"}},"AttachmentFiles":{"__deferred":{"uri":"http:\/\/team.jason.net\/_api\/Web\/Lists(guid'77190d4b-c6a4-4e15-ac04-d3124492ca88')\/Items(5)\/AttachmentFiles"}},"ContentType":{"__deferred":{"uri":"http:\/\/team.jason.net\/_api\/Web\/Lists(guid'77190d4b-c6a4-4e15-ac04-d3124492ca88')\/Items(5)\/ContentType"}},"FieldValuesAsHtml":{"__deferred":{"uri":"http:\/\/team.jason.net\/_api\/Web\/Lists(guid'77190d4b-c6a4-4e15-ac04-d3124492ca88')\/Items(5)\/FieldValuesAsHtml"}},"FieldValuesAsText":{"__deferred":{"uri":"http:\/\/team.jason.net\/_api\/Web\/Lists(guid'77190d4b-c6a4-4e15-ac04-d3124492ca88')\/Items(5)\/FieldValuesAsText"}},"FieldValuesForEdit":{"__deferred":{"uri":"http:\/\/team.jason.net\/_api\/Web\/Lists(guid'77190d4b-c6a4-4e15-ac04-d3124492ca88')\/Items(5)\/FieldValuesForEdit"}},"File":{"__deferred":{"uri":"http:\/\/team.jason.net\/_api\/Web\/Lists(guid'77190d4b-c6a4-4e15-ac04-d3124492ca88')\/Items(5)\/File"}},"Folder":{"__deferred":{"uri":"http:\/\/team.jason.net\/_api\/Web\/Lists(guid'77190d4b-c6a4-4e15-ac04-d3124492ca88')\/Items(5)\/Folder"}},"ParentList":{"__deferred":{"uri":"http:\/\/team.jason.net\/_api\/Web\/Lists(guid'77190d4b-c6a4-4e15-ac04-d3124492ca88')\/Items(5)\/ParentList"}},"FileSystemObjectType":0,"Id":5,"ContentTypeId":"0x0100B48DCF9FDA5C9B4BACDCC7DF84D111480007A91266528ED647BA59883DA1C209A8","Title":"Test5","Customer":{"__metadata":{"type":"SP.Taxonomy.TaxonomyFieldValue"},"Label":"1","TermGuid":"47081a2a-c78d-495c-bea9-e1ba8522e881","WssId":1},"TempCol":null,"MMS_x0020_Test_x0020_2":null,"Test_x0020_Create_x0020_List_x00":{"__metadata":{"type":"SP.FieldUrlValue"},"Description":"Stage 1","Url":"http:\/\/team.jason.net\/_layouts\/15\/wrkstat.aspx?List=77190d4b-c6a4-4e15-ac04-d3124492ca88&WorkflowInstanceName=96478011-ec99-469a-a209-c8b1170d0dc1"},"ID":5,"Modified":"2014-10-15T16:49:42Z","Created":"2014-10-08T13:55:57Z","AuthorId":1,"EditorId":1,"OData__UIVersionString":"1.0","Attachments":false,"GUID":"1e222378-6ebc-421f-b87f-f5374d9b8566"}]}}
I’ve highlighted the bits we’re interested in. In this case, we can figure out that the XPath expression to get to the TermGuid property is as follows:
d/results(0)/Customer/TermGuid
Note that the results property actually contains an array of one result, so we use results(0)to get the first object in the array.We can use an Assign activity to create our XPath expression and assign it to the fieldPathTermGuid variable. If we replace Customer (the MMS field name in this example) with a placeholder for our mmsFieldName variable, the activity looks like this:
Remember that we’re not using the XPath expression at this stage – we’re just building an XPath expression from the workflow variables to use in a later task.
Step 3 – Build an XPath expression to find the Label property
We can use the same approach to build an XPath expression that retrieves the Label property – only the last node of the XPath expression is different. In this case we assign the XPath expression to our fieldPathLabel variable:
Step 4 – Add a try-catch block
When we come to actually parse the list item, there’s quite a lot that could go wrong. If the list item doesn’t contain the specified field name, or the specified field is not a managed metadata field, the XPath expressions will fail and the workflow will throw an InvalidOperationException. As such, we want to build the parsing logic within a TryCatch activity:
![]()
Here you can see that we attempt to get the salient managed metadata field properties within a Try block, and we look for an InvalidOperationException in the Catch block. We’ll look more closely at the activities within the Try and Catch blocks in the next step. For now, notice that the activities within the Try and Catch blocks are wrapped in Sequence activities. In a production scenario you will probably want to implement a more comprehensive error handling strategy, but for this proof-of-concept scenario I’m mainly interested in catching the common invalid operation exceptions.Steps 5 and 6 – Get the TermGuid and Label property valuesWithin our Try block, we can use generic GetDynamicValueProperty<T> activities to get the TermGuid and Label property values:
![]()
In each case:
- The Source property is the JSON representation of our list item.
- The PropertyName property is the XPath expression that finds our TermGuid or Label property.
- The Result property is the output argument that exposes each property to SharePoint Designer workflows.
Step 7 – Catch invalid operation exceptions
Within our InvalidOperationException catch block, all I’m doing at this stage is writing a (hopefully) helpful message to the workflow history list:
The Actions File
The next stage is to build the actions (.actions4) file for the workflow activity. The actions file defines the sentence that appears in SharePoint Designer when you add the custom activity to a workflow, together with the arguments (inputs and outputs) for the custom activity. I’ll assume you know the basics of actions files – if not, check out my
first post on custom workflow activities. In my case, the actions file looks like this:
As you can see from the Sentence attribute in the RuleDesigner element, we require the workflow designer to specify the name of the managed metadata field, and we return the term GUID and the term label integer value. Note that in the parameter definition for the mmsFieldName argument, we specify a DesignerType of FieldNames. This enables the workflow designer to select the name of the managed metadata field from a list of all the fields in the current list item.In the SharePoint Designer workflow designer, the custom activity looks like this:
In this case, I’ve created a really simple SharePoint Designer workflow to test my custom activity. I use the custom activity to get the term GUID and term label integer properties from a managed metadata field named Customer, and I write the values to the workflow history list.
In the next post, I’ll look at the other half of the problem – using these managed metadata field properties to update a managed metadata field in another list.
Share This
The post Custom Workflow Activity for Getting Managed Metadata Field Values appeared first on Content Master.