Taxonomy is one of those topics which has been extensively discussed. Andrew Connell did a series of posts about SharePoint 2010 Managed Metadata which is worth reading. Although the huge number of blog posts and forum discussions you can’t find much regarding updating a taxonomy field value for a list item from a sandboxed solution.
I wanted to create a sandboxed solution which loops all lists and updates the field values of items. Among these field values are taxonomy fields. Normally you would use TaxonomyField.SetFieldValue() for updating the field value. But within a sandboxed solution you are not allowed to use the Microsoft.SharePoint.Taxonomy namespace.
If you are interested in the outcome: You CAN’T set the taxonomy field value for an item from a sandboxed solution. When updating a taxonomy field value always use the TaxonomyField.SetFieldValue() method. If you want to know why, enjoy reading!
Research
After reading about taxonomy and taking a closer look at what is actually stored in a list, I noticed a couple of things:
- When creating a taxonomy field, it actually creates 2 fields
- Note (SPFieldMultiLineText) field: Shown in the list as value
- TaxonomyField field: Hidden field in the list
- The actual value stored in the hidden TaxonomyField should look like “<wssid>;#<guid>|<label>”
- The WssId is the list item ID for the local stored TaxonomyHiddenList, which is located at http://<applicationurl>/sites/<sitecollection>/lists/taxonomyhiddenlist/
- When WssId is –1 it means the term is not provisioned in the TaxonomyHiddenList
- Calling TaxonomyFieldValue.ValidatedString triggers an update on the TaxonomyHiddenList to provision the term and returns the validated string “<wssid>;#<guid>|<label>”
- ‘The guid and label are those of an existing term in the Term Store
- The delimiter “;#” between wssid and guid is SPFieldMultiColumnValue.Delimiter
- The delimiter “|” between guid and label is TaxonomyField.TaxonomyGuidLabelDelimiter.
Testing approach
The general idea for figuring it this out was creating a farm solution first and get everything up and running. When successful completing the farm solution, rework everything to a sandboxed solution.
The approach for testing is split up into 2 parts and every part has 4 tests. Part 1 is updating list item properties, part 2 is updating document properties. The pre-requisite for the test is a valid term (guid and label) and the term exists in the TaxonomyHiddenList.
During the tests I’ll talk about the two fields mentioned earlier. For ease of reading let’s name the Note field “taxField” and the TaxonomyField “taxHiddenField”.
Every part consist of 4 tests:
- TaxonomyField.SetFieldValue(item, term)
- item[taxField.Title] with value “<wssid>;#<guid>|<label>”
- item[taxHiddenField.Title] with value “<wssid>;#<guid>|<label>”
- item[taxHiddenField.Title] with value “<guid>|<label>”
I’ll spare the details and focus on the outcome.
Part 1: Updating list item properties
When updating a list item the assumption is that the TaxonomyField.SetFieldValue() is the preferred way of updating a taxonomy field value. When updating a list item this results in updating both the taxField and taxHiddenField.
All four tests result in updating both fields. Although it seems to exclude the WssId in the field value of taxField and taxHiddenField for tests #1 and #4. This looks weird to me for test #1, because looking internally to the decompiled sources, Microsoft uses the ValidatedString value which includes the WssId.
The same result as test #1 is only achieved with test #4, because tests #2 & #3 includes the WssId in the taxHiddenField. This makes sense because we are explicitly updating the field value with the WssId.
For now it look like we are able to update the taxonomy field value in different ways. This is what we would like, because we could use the
item[taxField.Title] = “<wssid>;#<guid>|<label>” within a sandboxed solution. Although it’s not completely consistent behavior.
Part 2: Updating document properties
Once again the assumption is updating a document via TaxonomyField.SetFieldValue() is the preferred way of updating the taxonomy field value. This results in both updating the taxField and taxHiddenField.
When running tests #2, #3 and #4 we run into issues. After the first run of the test everything looks OK. When running the test for a second and third time the taxField and taxHiddenField are out of sync. Both contain different values resulting in unexpected behavior!
Conclusion
I had planned to test the sandboxed solution, but didn’t got to it because the results of updating the document properties (part 2) from a farm solution were pretty clear. I could not find out what magic happens during the TaxonomyField.SetFieldValue(). But I did find out that something is happening, which is important for updating the list item or document properties!
In other words there is no other way of updating the document properties for taxonomy fields than
TaxonomyField.SetFieldValue().
Remember don’t ever use the item[“<taxonomy field name”] = “<wssid>;#<guid>|<label>” statement for updating a taxonomy field value because you can’t rely on it!