Issue
Today I was troubleshooting a customer farm where Managed Metadata would remain empty in SharePoint, even though it was filled in correctly in the document’s Document Information Panel.
Digging through the internal XML structures of the DOCX and also the Content Type Schema and Field XML, I couldn’t find a reasonable explanation.
The library was configured with multiple Content Types, but the issue occurred only on some of them. It appeared that for those Content Types, the Managed Metadata field was Optional, not Required.
I tried reproducing that configuration in a new document library but there everything kept working, so the issue had to be with the existing library.
Further analysis, comparison and reflection showed that the problematic library was missing some Taxonomy-related Event Receivers.
There appear to be four (4) Taxonomy Event Receivers:
-
TaxonomyItemSynchronousAddedEventReceiver (ItemAdding) and TaxonomyItemUpdatingEventReceiver (ItemUpdating) are added when a Managed Metadata field is added to the List
-
TaxonomyItemAddedAsyncEventReceiver (ItemAdded) and TaxonomyItemUpdatedEventReceiver (ItemUpdated) are added when “Metadata Publishing” is enabled in the List Settings
The problematic library at the customer was lacking the first set of Event Receivers, which are responsible for syncing the hidden field.
Fix
I’ve written a one-off script (Console App) that loops all lists with a Managed Metadata field on all sites in the site collection and ensures the Taxonomy event receivers. That code was taken directly from TaxonomyField.AddEventReceiverIfNotExists.
using System; using System.IO; using System.Text; using System.Windows.Forms; using Microsoft.SharePoint; using Microsoft.SharePoint.Taxonomy; class Taxonomy_Fix { public static StringBuilder sb = new StringBuilder(); public static string nl = "\r\n"; public static string url = "http://intranet"; public static void FIXALL() { using (SPSite site = new SPSite(url)) { foreach (SPWeb web in site.AllWebs) { FixTaxonomyReceiverOnWebLists(web); web.Close(); } } File.AppendAllText(String.Format("c:\\{0:HH_mm_ss}.txt", DateTime.Now), sb.ToString()); MessageBox.Show(sb.ToString()); } private static void FixTaxonomyReceiverOnWebLists(SPWeb web) { for (int i = 0; i < web.Lists.Count; i++) { SPList list = web.Lists[i]; if (HasTaxonomyField(list)) { sb.AppendFormat("{0}{1} has Taxonomy Field{2}", url, list.RootFolder.ServerRelativeUrl, nl); EnsureTaxonomyHandlers(list); } } } private static bool HasTaxonomyField(SPList list) { bool result = false; foreach (SPField field in list.Fields) { if (field is TaxonomyField) { result = true; break; } } return result; } private static void EnsureTaxonomyHandlers(SPList list) { AddEventReceiverIfNotExists(list.EventReceivers, SPEventReceiverType.ItemAdding, typeof(TaxonomyField).Assembly.FullName, "Microsoft.SharePoint.Taxonomy.TaxonomyItemEventReceiver", "TaxonomyItemSynchronousAddedEventReceiver", SPEventReceiverSynchronization.Synchronous); AddEventReceiverIfNotExists(list.EventReceivers, SPEventReceiverType.ItemUpdating, typeof(TaxonomyField).Assembly.FullName, "Microsoft.SharePoint.Taxonomy.TaxonomyItemEventReceiver", "TaxonomyItemUpdatingEventReceiver", SPEventReceiverSynchronization.Synchronous); } private static void AddEventReceiverIfNotExists(SPEventReceiverDefinitionCollection eventReceiverCollection, SPEventReceiverType type, string assembly, string className, string receiverName, SPEventReceiverSynchronization sync) { if (eventReceiverCollection == null) { throw new ArgumentNullException("eventReceiverCollection"); } if (string.IsNullOrEmpty(assembly)) { throw new ArgumentNullException("Valid assembly name required"); } foreach (SPEventReceiverDefinition erd in eventReceiverCollection) { if (erd.Assembly == assembly && className == erd.Class && type == erd.Type && erd.Synchronization == sync) { sb.AppendFormat("\t>> no action required{0}", nl); return; } } SPEventReceiverDefinition erd2 = eventReceiverCollection.Add(); erd2.Name = receiverName; erd2.Type = type; erd2.Assembly = assembly; erd2.Class = className; erd2.Synchronization = sync; erd2.Update(); sb.AppendFormat("\t>> Added TaxonomyEvent Receiver{0}", nl); } }
Disclaimer: not responsible for this code. Run at own risk. Feel free to adapt or improve as desired or required.
Conclusion
I can’t really explain why only some Content Types were affected. I’m guessing the Optional/Required setting of the Managed Metadata field is involved somehow, but I didn’t really confirm that through testing.
Also not sure why the Event Receivers were missing in the first place. It could be because some “questionable” actions happened during the setup of the site, but it could as well be a bug in SharePoint 2010 RTM or later.