Custom Workflow Activity for Setting Managed Metadata Field Values

In this post I'll show you how to build a custom workflow activity in Visual Studio that can update managed metadata field values in a SharePoint 2013 list or library. This is the final part 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 introduce the scenario, explain why you can't use built-in list actions to work with managed metadata fields, and provide a conceptual overview of the custom workflow activities approach.
  • Custom Workflow Activity for Getting Managed Metadata Field Values. 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 (this post). 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've said it before, but it's worth repeating - you can use these custom workflow activities 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 series of posts tackles the scenario where you want to extract a managed metadata field value from an item in one list (previous post), and then apply that value to a managed metadata field in another list (this post). The main constraint is that the managed metadata fields in the source list and the destination list must both use the same term set. 

Arguments and Variables

If you've been following the series of posts you'll be familiar with the scenario and the concepts, so let's assume we've created a brand new custom workflow activity named Set MMS Field Value in Visual Studio and jump straight into defining arguments and variables. First the arguments:














I want to be able to use this activity update a managed metadata field on any SharePoint list or library, so the first piece of information we need is an identifier for the target list or library (selectedList). Next, we need to know which list item to update. List items are commonly identified using either a GUID identifier (listItemGuid) or an integer identifier (listItemIdIn) - I've defined arguments for both so the workflow designer can use either approach to identify the target list item. Next, we need to know the name of the managed metadata field in the target list item (mmsFieldName). Finally, we need the two property values that uniquely identify our managed metadata term (termGuid and termLabelInteger).

Now the variables:













We'll use listItemId to store the integer identifier for the target list item. The emptyGuid variable is just an empty GUID that we'll use for comparison purposes, and the remaining variables (metadataDV, propertiesDV and fieldValueDV) are DynamicValue properties that we'll use to progressively build the correct JSON structure to update a managed metadata field.

Activity Design

The workflow activity consists of seven child activities that correspond to three main tasks:







































  1. Get the integer identifier of the target list item. (If the workflow designer has provided an integer identifier, use it directly. Alternatively, if the workflow designer has provided a GUID identifier, use the GUID to look up the integer identifier.)
  2. Build up the JSON payload we must provide in order to update the specified managed metadata field.
  3. Update the specified managed metadata field on the specified list item.
Let's take a closer look at these three high-level tasks.

Task 1 - Get an integer identifier for the target list item

Our first task is to get an integer identifier for the target list item. Remember that we're giving the workflow designer two options: he or she can provide either a GUID identifier or an integer identifier to specify the target list item. To cater for both scenarios, we use an If activity. If the list item GUID is equal to an empty GUID, we can assume the workflow designer has used an integer identifier to specify the target list item. In this case, we use an Assign activity to set the the listItemId variable to the value of the listItemIdIn argument. If not, we use a LookupSPListItemId activity to look up the integer identifier using the specified GUID and then set the listItemId variable accordingly.


























Task 2 - Build a JSON payload for the target managed metadata field

Our next task is to build a JSON payload for the target managed metadata field. The payload must take the following format, where <Field name> is the name of the target managed metadata field, <Term label integer> is the term label integer of the managed metadata term, and <Term GUID> is the term GUID of the managed metadata term:


{"<Field name>":{
   "__metadata":{"type":"SP.Taxonomy.TaxonomyFieldValue"},
   "Label":"<Term label integer>",
   "TermGuid":"<Term GUID>",
   "WssId":-1 }}


To take advantage of the built-in child activities in Visual Studio, we need to create our JSON payload using DynamicValue structures. Because of the nested nature of this payload, we need to build the structure progressively from the inside out. First we use a BuildDynamicValue activity to build the contents of the innermost braces (the value of the __metadata property):





















Next, we use a BuildDynamicValue activity to build the value of the middle set of braces (the value of the <Field name> property):






















Notice how we set the __metadata key to the metadataDV value we created in the previous step, thereby creating a nested DynamicValue instance.

Finally, we use a CreateDynamicValue activity to build the value of the outer set of braces:














Note: We use a CreateDynamicValue activity rather than a BuildDynamicValue activity in this task because it allows us to set the dictionary key (PropertyName) to a variable value (mmsFieldName in this case). The BuildDynamicValue activity only allows you to type static string text for the dictionary key (Path). That wouldn't work in this scenario as we don't know the name of the target managed metadata field at compile time.

Task 3 - Update the target list item

Now that we've identified our target list item and build our JSON payload, all that remains is to perform the update operation on the list item. We can use the built-in UpdateListItem activity to do this:















The Actions File

The next stage is to build the actions (.actions4) file for the workflow activity, to specify how our activity should behave when we add it in SharePoint Designer. My actions file looks like this:


















I won't go into more detail on the structure of the actions file right now, as there's nothing out of the ordinary in it and I don't want to get too repetitive. When you deploy the activity and use it in SharePoint Designer, it looks like this:















In this case, I'm using my Get MMS Field Value activity to get the term GUID and the term label integer from a managed metadata field named Customer in the current list item. I'm then using the Set MMS Field Value activity to set the value of the Client field on a list item in the Clients list to the same term. Because the source Customer field and the destination Client field both use the same term set, the workflow is able to copy the value across as desired.

Comments

  1. Great blog this has been extremely helpful. I have been recreating this on my end for something very similar but I get a problem with using 'GUID' in the LookupSPListItmId Property name. It produces an error in visual studio "The name 'GUID' does not exist in the current context." Was just wondering if you had seen this before or know why my Visual Studio is giving me this where yours did not. Again Great article it has been extremely helpful.

    ReplyDelete
    Replies
    1. Hi Groller - I think I know what the problem is... when you use the editor to set the PropertyName value, you need to put GUID in quotes - i.e. "GUID". That way it treats it as a string value. Otherwise it's looking for a local variable named GUID. The Properties window will still show GUID without the quotes, which is probably where the confusion arose.

      Delete
  2. Hi,
    I'll definitely have a look at your solution ;-) One question that comes to my mind, what about Multi value managed metadata ? How difficult is it to handle these also ?

    ReplyDelete
    Replies
    1. Hi Marc - setting multi-value MMS fields isn't something I've tried yet, but it shouldn't be a problem if you follow a similar process. Start by using the REST API to have a look at the structure of list items with multi-value MMS fields in the browser window. Once you know how the multi-value fields are structured in JSON, you can create a workflow activity that builds up a field value in the right format.

      Delete
    2. Hi Jason, using SharePoint Designer only I was not able to do it. The problem is that you cannot add a collection of dictionaries in SPD, and that is what you need for a multi value. That is exactly why I will have a more in depth look at your custom activity to see if it is possible to extend it.

      Delete
    3. Multi value MMS field update does not work. Structure of the field is like:

      "MyField": {
      "__metadata": {
      "type": "Collection(SP.Taxonomy.TaxonomyFieldValue)"
      },
      "results": [
      {
      "Label": "SC02",
      "TermGuid": "fa573c4a-f6fe-421d-84e5-af0ce303fe01",
      "WssId": 6
      },
      {
      "Label": "ReadByTest",
      "TermGuid": "a778fae6-16e1-42b8-8111-19282f211e46",
      "WssId": 3
      }
      ]
      }

      Error I am getting is:
      Microsoft.SharePoint.Client.ClientServiceException: Cannot deserialize data for type Microsoft.SharePoint.Taxonomy.TaxonomyFieldValueCollection

      Any idea?

      Delete
    4. Hi Nauman. I won't have chance to look at this for a couple of weeks, but I can make an educated guess. So it looks like it's expecting an object of type SP.Taxonomy.TaxonomyFieldValueCollection. That's going to make things messy. The TaxonomyFieldValueCollection object has a single useful property named "item". I believe the value of "item" is a concatenated string in the following format:

      ;#|;#;#|;# ...etc

      So the first thing I would try is structuring the field something like this (using your example):

      {"MyField: {
      "__metadata": { "type": "SP.Taxonomy.TaxonomyFieldValueCollection" },
      "item": "6;#SC02|fa573c4a-f6fe-421d-84e5-af0ce303fe01;#3;#ReadByTest|a778fae6-16e1-42b8-8111-19282f211e46;#" }
      }

      Can't promise it will work, but that would be my starting point. I'll give it a try and write a post on it when I have some time.

      Delete
    5. Sorry - forgot that Blogger strips out angle brackets. The field format should read:

      [WssId1];#[Label1]|[TermGuid1];#[WssId2];#[Label2]|[TermGuid2];# ... etc

      where [Label1] is your first term label and so on.

      Delete
  3. Hi Jason, so far I was not able setting the "item" property. After looking at https://msdn.microsoft.com/en-us/library/office/dn312554.aspx I guess it is readonly. Have you had time figuring out how a managed metadata field (multiple values) can be set?
    Best Regards,
    Christian

    ReplyDelete
    Replies
    1. Hi Christian - sadly I'm slammed at the moment, so I've had no chance to sit down and try to figure out the multi-value MMS scenario. It's on my to-do list for the next time I get a quiet day!

      Delete
    2. Any luck on getting this to work? I've tried many variations, but can't seem to get the right combination yet.

      Delete
  4. Here's a solution that worked for me: http://www.aerieconsulting.com/blog/update-using-rest-to-update-a-multi-value-taxonomy-field-in-sharepoint

    ReplyDelete

Post a Comment

Popular posts from this blog

Server-side activities have been updated

The target principal name is incorrect. Cannot generate SSPI context.

Custom Workflow Activity for Creating a SharePoint Site