Contact Us
Magenic
  • What We Do
  • How We Do It
  • Our Thinking
  • Join Us
  • Our Work
  • Industries
  • Cloud
  • Software Development
  • Quality Engineering
  • DevOps
  • Strategy
  • Experience Design
  • Data & Integration
  • Advisory Services
  • Careers
  • Culture
  • Events
  • Success Stories
  • Partnerships
  • Technologies
  • Professional Services
  • Financial Services
  • Retail
  • Health Care

Correctly Provisioning Managed Metadata (Taxonomy) Fields through CAML in SharePoint 2010

April 17, 2015 // By Michael Blumenthal

Imagine that you are creating a content type for a publishing page or a document and you want to have a field in that content type that is a managed metadata field (a.k.a. a taxonomy field). This allows users to select a term from one of the termsets that you have in your Managed Metadata Service’s termstore. There are many steps to do this.

If you get the steps wrong, your taxonomy field won’t work correctly. It will be greyed out or it won’t save the values you pick. If it’s greyed out, it means you’ve forgotten to wire up the field to the termset. If it’s not saving the values, the CAML definition may be wrong, perhaps specifying a HiddenTaxonomyList in another site collection.

If you want to get it right, there are three blog posts you must read in the following order:

  • Correctly Provisioning Managed Metadata Columns by Doug Ware
  • Provisioning SharePoint 2010 Managed Metadata fields by Ari Bakker – Read part two first, then back track to part one
  • How to provision SharePoint 2010 Managed Metadata columns by Wictor Wilén

Perhaps it makes more sense to read them in reverse order, but whichever you decide, the combination of the three will give you a pretty good picture of the CAML that needs to be written. In fact, you might need to read them several times to make sure to get all of the details right.

So, how do we know if the resulting taxonomy field is good? There are three things to check:

1. As mentioned, if the field is greyed out, you probably don’t have it wired up to a termset. This is often done through an event handler called a Feature receiver that runs when the feature is activated. You have to write some code that looks like this:

public static void ConnectTaxonomyField(SPSite site, Guid fieldId, string termGroup, string termSetName)
{
if (site.RootWeb.Fields.Contains(fieldId))
{
TaxonomySession session = new TaxonomySession(site);
if (session.DefaultKeywordsTermStore != null)
{
// get the default metadata service application
var termStore = session.DefaultKeywordsTermStore;
var group = termStore.Groups.GetByName(termGroup);
var termSet = group.TermSets.GetByName(termSetName);
TaxonomyField field = site.RootWeb.Fields[fieldId] as TaxonomyField;
// connect the field to the specified term
field.SspId = termSet.TermStore.Id;
field.TermSetId = termSet.Id;
field.TargetTemplate = string.Empty;
field.AnchorId = Guid.Empty;

field.Update();
}
}

I am quoting this from Ari Bakker’s post almost directly. I highlighted three lines. The first one (where you check to see if Default Keyword Term Store is null or not) ties back to a Managed Metadata Service (MMS) Application configuration option. There’s a checkbox on the service application’s property page (the property page for the indented one) that controls whether or not this is the default keyword term store. If that’s not checked and this is the only MMS application available to your farm, site.DefaultKeywordsTermStore will always be null.

CPMM 1

The second and third highlighted lines I point out because you need to ask, “Are these statements really needed?” I contend that the answer is no, especially not for AnchorId, because you can set that in the CAML.

Unfortunately, this is not the only reason the field could be greyed out. According to Bakker, you also might not have the TaxonomyFieldAdded site Feature.

2. When you have the field on a page or in a list and you fill out that list item, does the value persist? I’ve seen an incorrectly provisioned taxonomy field where it looks like it is working. However, when you actually go to save a list item with data in this field, it fails without error. When you visit the page the next time, the field value has been lost. I believe that happens when you manually specify in the field definition un-tokenized URLs for the hidden taxonomy list. The hidden taxonomy list is at //server/site-path/HiddenTaxonomyList (relatively speaking), but because it’s hidden you won’t see it in the View All Site Content Page. However, if you type in the URL you can see it like any other list. Although it’s possible to specify the location of the HiddenTaxonomyList in your CAML, there is no reason to do so.

3. When you index content that has a value set for the taxonomy field you created, you should see three Crawled Properties, not two. One of the crawled properties should start with “ows_taxId_” and map to a managed property. If it doesn’t, then you won’t get facets showing up correctly in faceted search. Note that not having the TaxCatchAll and TaxCatchAllLabel pair of columns in your list or library or content type can cause that (again, see Bakker’s articles).

Let’s compare three examples:

Example CAML Discussion
Bad <?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Field ID="{14CEB9EC-71E0-4C2F-8BCD-962A2D988F60}"
Type="TaxonomyFieldType"
Name="BrokenField"
StaticName="BrokenField"
DisplayName="BrokenField"
ShowField="Term1033"
Required="TRUE"
EnforceUniqueValues="FALSE"
Group="MyCustomFields">
<Default />
<Customization>
<ArrayOfProperty>
<Property>
<Name>AnchorId</Name>
<Value xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">00000000-0000-0000-0000-000000000000</Value>
</Property>
<Property>
<Name>Open</Name>
<Value xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:boolean">false</Value>
</Property>
<Property>
<Name>TextField</Name>
<Value xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">{84b71948-43c0-4f35-8310-584e68ac8540}</Value>
</Property>
<Property>
<Name>IsPathRendered</Name>
<Value xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:boolean">false</Value>
</Property>
<Property>
<Name>IsKeyword</Name>
<Value xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:boolean">false</Value>
</Property>
</ArrayOfProperty>
</Customization>
</Field>
<Field ID="{84B71948-43C0-4F35-8310-584E68AC8540}"
Type="Note"
Name="g3d2f1bbb50d642d99c1fcad91adf2a21"
StaticName="g3d2f1bbb50d642d99c1fcad91adf2a21"
DisplayName="BrokenField_0"
ShowInViewForms="FALSE"
Required="FALSE"
Hidden="TRUE"
CanToggleHidden="TRUE" />
</Elements>

Why is this bad? It’s missing some key attributes in the elements declaration of the Taxonomy field. It’s creating a note field with GUID-based names, which doesn’t seem like a problem until you realize that the field pair only somewhat works. This field will not generate an “ows_taxId*” crawled property.

In particular, it’s missing the DisplaceOnUpgrade and Overwrite attributes (see the “Good” example below). It also specifies the Note field with a GUID-based Name and Static Name.

Also note that DisplayName becomes the Title property of the Field object.

What can be confusing about this is that the note field that you get looks very similar to the note field that SharePoint would generate. When SharePoint generates a NoteField for a Taxonomy field, it gives the Name and StaticName properties ugly GUID-like names. It does not use TaxHTField in the name, which is necessary for proper functionality. Although again, you are better off not specifying any NoteField at all, but just letting SharePoint generate one from the ID you specify as the TextField of the Taxonomy field.

OK/Maybe <?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Field ID="{8FC43BCF-F7B3-4FFE-AF08-1A057D32665D}"
Type="TaxonomyFieldType"
Name="MediumField"
StaticName="MediumField"
DisplayName="MediumField"
ShowField="Term1033"
Required="TRUE"
EnforceUniqueValues="FALSE"
Group="MyCustomFields">
<Default />
<Customization>
<ArrayOfProperty>
<Property>
<Name>AnchorId</Name>
<Value xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">00000000-0000-0000-0000-000000000000</Value>
</Property>
<Property>
<Name>Open</Name>
<Value xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:boolean">false</Value>
</Property>
<Property>
<Name>TextField</Name>
<Value xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">{A138377E-2516-4BB4-ACE8-5FE1FF371271}</Value>
</Property>
<Property>
<Name>IsPathRendered</Name>
<Value xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:boolean">false</Value>
</Property>
<Property>
<Name>IsKeyword</Name>
<Value xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:boolean">false</Value>
</Property>
</ArrayOfProperty>
</Customization>
</Field>
<Field ID="{A138377E-2516-4BB4-ACE8-5FE1FF371271}"
Type="Note"
Name="MediumFieldTaxHTField0"
StaticName="MediumFieldTaxHTField0"
DisplayName="MediumField_0"
ShowInViewForms="FALSE"
Required="FALSE"
Hidden="TRUE"
CanToggleHidden="TRUE" />
</Elements>
This will get you a working Taxonomy field because the note field is named properly (using “TaxHTField”). However, SharePoint will generate the note field for you if you let it so why write more CAML?
Good <?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Field Type="TaxonomyFieldType"
DisplayName="GoodField"
StaticName="GoodField"
Name="GoodField"
Group="MyCustomFields"
ShowField="Term1033"
Description=""
Required="TRUE"
EnforceUniqueValues="FALSE"
ID="{B5BE7BB3-C60E-4486-AB48-7BCCEEBA9EBD}"
DisplaceOnUpgrade="TRUE"
Overwrite="TRUE"
>
<Customization>
<ArrayOfProperty>
<Property>
<Name>TextField</Name>
<Value xmlns:q6="http://www.w3.org/2001/XMLSchema"
p4:type="q6:string"
xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">{5BD0BA3E-A3CC-45D2-B8F2-AC69CEE8B58D}</Value>
</Property>
</ArrayOfProperty>
</Customization>
</Field>
</Elements>
This is the recommended approach. Every line of code or CAML that you don’t write is one that you don’t have to maintain so fewer lines of code/CAML are better.

Also, to get your Taxonomy fields to work correctly in your content types, you must have the TaxCatchAll and TaxCatchAllLabel field and your hidden text field added to the CAML declaration of your content type. They don’t get added automatically. Let me emphasize that: SharePoint will not add the hidden text field to your content type automatically. You must explicitly add the field reference to your content type and have a minimum of four field references:

  1. Your Taxonomy field
  2. Its hidden note field
  3. TaxCatchAll
  4. TaxCatchAllLabel

How does SharePoint create the hidden note field when you manually add a Taxonomy field to a list or library? Something calls this method:

Microsoft.SharePoint.Taxonomy.TaxonomyField.OnAdded(SPAddFieldOptions op)

If you use a tool like ILSpy to open Microsoft.SharePoint.Taxonomy.dll, which you can find in the <14 hive>\ISAPI folder, you can see what it does. Note the AddHiddenTextField method. One thing I’ve seen, though I haven’t correlated it with the decompiled code, is that you can call this up to two times on the same Taxonomy field. This will generate the corresponding _0 field if it doesn’t exist or _1 if it does (but will throw an error rather than generating a hidden field with a name ending in _2).

The relational connection between the Taxonomy field and the hidden text field is as follows:

taxonomyField.TextField == hiddenField.Id

CPMM 2
CPMM 3

Note that the generated CAML for SchemaXML that you see in SharePoint Manager is NOT what you want to copy and paste into your elements file in your Visual Studio project. It has properties you don’t need, and properties that, when used, must first be tokenized; you don’t want absolute URLs in your CAML, and some of the GUIDs may be wrong. For example, you don’t need to specify the location of the hidden taxonomy list, because SharePoint can figure that out on its own.

Here’s another tip: You can use SharePoint Manager 2010 to view the fields and their properties. When you are using site content types, make sure to look at both the site collection and list level. In the site collection, look at the fields in the Fields (a.k.a. Site Columns) collection and the fields in the fields collection in a particular content type in the Content Types collection. In the list (or library) level, look at the fields in the content types and the fields in the fields collections as well.

CPMM 4

In this picture (above), SharePoint Manager 2010 shows the fields in the content types in the site content-types collection (a.k.a. the Site Content Types Gallery).

Another tip about testing your field: You must populate list items that use it with data and crawl those items to get SharePoint to generate the Crawled Properties. If you change your field names, and re-crawl, it will pick up the new names without removing the old names (although if you do three crawls, it might remove the old ones – I haven’t tested that.) The quickest way I know of to clean out all of the crawled properties is to drop and recreate the Search Service Application, which is not something you can do lightly in most production environments. Just resetting the content index won’t do it - at least from what I saw.

I hope this helps you successfully write the Field CAML that you need!

Categories // Software Development
Tags SharePoint, SharePoint Enterprise Application Development, TaxonomyFieldType, Managed Metadata, Content Types, CAML, SharePoint 2010
SHARE:
THE LATEST:
  • FEBRUARY 23, 2021 // blog
    Stronger Product Owner = Better Software, Faster
  • FEBRUARY 19, 2021 // blog
    Security In Five Bi-Weekly Roundup – 2/19/21
  • FEBRUARY 18, 2021 // blog
    Doesn’t Everybody Know This?
Featured Content:
  • JANUARY 25, 2021 // White Paper
    The Top 7 Technology Trends of 2021

Related Posts

Success Story
Migrating Hundreds of Lotus Notes Apps
Learn More
Blog
Development Patterns of SharePoint
Learn More
Blog
SharePoint - A Quick History
Learn More
Blog
Enterprise Collaboration – Should You Buy an Intranet in a Box?
Learn More

Ready to speak with our experts?

Have a question?

This field is required
This field is required
This field is required
This field is required

Thanks for Contacting Magenic

One of our experts will be contacting you directly within the next business day.

Return To Home
Magenic

info@magenic.com+1.877.277.1044

  • Facebook
  • Twitter
  • LinkedIn
  • YouTube
  • RSS Feed

© Magenic Inc.Privacy NoticeTerms & ConditionsSitemap