Add to My Yahoo! | Google Reader or Homepage | Add to Windows Live | Add to Windows Live Alerts

Wictor Wilén

Microsoft Certified Master (MCM) - SharePoint 2010 | Microsoft Most Valuable Professional (MVP) - SharePoint Server MVP | Author

How to provision SharePoint 2010 Managed Metadata columns

Posted at 2010-07-27 03:57 by Wictor Wilén in SharePoint 2010 with 23 comments.

This post will show you how to provision Site Columns that uses Managed Metadata in SharePoint 2010. Managed Metadata is one of the new and exciting features of SharePoint Server 2010. It allows you to centrally manage metadata terms and keywords. Creating Managed Metadata columns using the SharePoint web interface is a simple task but the problem is that it does not allow you to move your Site Columns from one farm to another that easily. The reason is that these Site Columns definitions contains references to the unique IDs of the terms in the current Managed Metadata Service Application (MMS).

Exporting Site Columns

If you export a Managed Metadata Column and a Content Type using it to Visual Studio (SharePoint Designer > Export > Visual Studio Import, you know the drill) then you end up with definitions like below.

The Site Column is based on the TaxonomyFieldType and contains a Customization element which contains an array of properties (I've omitted most of them here). These properties contains IDs of the Managed Metadata group, term store and service application. Since these are unique for each MMS this definition cannot be provisioned to another farm (for instance from dev to stage, stage to prod etc).

<Field 
    Type="TaxonomyFieldType" 
    DisplayName="Custom (web)" 
    List="Lists/TaxonomyHiddenList" 
    WebId="~sitecollection" 
    ShowField="Term1033" 
    Required="FALSE" 
    EnforceUniqueValues="FALSE" 
    Group="_Custom" 
    ID="{fce6a8e2-23e8-49c2-9bad-a534555296bb}" 
    SourceID="{5e68c9eb-5efe-4bcc-b8db-93d38d797fbe}" 
    StaticName="__Custom" 
    Name="__Custom" 
    Overwrite="TRUE">
    <Default />
    <Customization>
        <ArrayOfProperty>
            <Property>
                <Name>SspId</Name>
                <Value 
                    xmlns:q1="http://www.w3.org/2001/XMLSchema" 
                    p4:type="q1:string" 
                    xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">b98dd270-8577-4db8-99e1-b9e894624fdb
                </Value>
            </Property>
            <Property>
                <Name>GroupId</Name>
            </Property>
            <Property>
                <Name>TermSetId</Name>
                <Value 
                    xmlns:q2="http://www.w3.org/2001/XMLSchema" 
                    p4:type="q2:string" 
                    xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">b7ae10cd-6c7c-4386-a1f2-7abec8e759e1
                </Value>
            </Property>
            <Property>
                <Name>AnchorId</Name>
                <Value 
                    xmlns:q3="http://www.w3.org/2001/XMLSchema" 
                    p4:type="q3:string" 
                    xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">00000000-0000-0000-0000-000000000000
                </Value>
            </Property>
            ...
        </ArrayOfProperty>
    </Customization>
</Field>
     

And if you examine the XML further you will also notice that a second field is defined for this Site Column. This field is of the type Note and is hidden.

<Field Type="Note" DisplayName="__Custom_0" StaticName="__CustomTaxHTField0" Name="__CustomTaxHTField0" 
    ID="{a6eae615-9835-4b75-97bf-d4e7a938b892}" ShowInViewForms="FALSE" Required="FALSE"     Hidden="TRUE" CanToggleHidden="TRUE" 
    SourceID="{5e68c9eb-5efe-4bcc-b8db-93d38d797fbe}" Overwrite="TRUE" />

A lot of XML but quite useless for reuse...

So how do I do then?

To provision the Site Columns and Content Types without these hardcoded Guids and IDs you basically have two options:

  1. Create an event receiver (or similar) that creates the Site Columns and Content Types programmatically
  2. A combination of declarative and the programmatic approach above

Solution ExplorerI prefer the second approach and I will show you how to do it (the first one can quite easily be done based on the code that will follow).

First you need to create a new SharePoint 2010 project in Visual Studio 2010, create a new Empty SharePoint project. Then add a new Content Type SharePoint Project Item (SPI) to the project and inherit it from the Item content type. Then add a new XML file to the SPI and name it Fields.xml. This elements manifest will contain the Site Column definition, but in order to make it into a manifest file you need to select the file and press F4 to edit the properties of the file. Change the Deplyment Type from NoDeployment to ElementManifest. Your solution should look like the image to the right. Also make sure to set the feature to be scoped to Site (Site Collection) level - we're talking about deploying Site Columns and Content Types here.

Then it is time to write the declarative part (i.e. the XML). You need to add a new Field element of the type TaxonomyFieldType (or TaxonomyFieldTypeMulti). Configure it as follows or as it suits your needs. Notice that I have set the ShowField attribute to Term1033, this is needed by the MMS to select the correct term value.

xml version="1.0" encoding="utf-8" ?> 
<Elements xmlns="http://schemas.microsoft.com/sharepoint/"> 
  <Field ID="{749DA0D1-4649-4C25-871B-05F0C07221FC}" 
    Type="TaxonomyFieldType" 
    DisplayName="Home Country" 
    ShowField="Term1033" 
    Required="TRUE" 
    EnforceUniqueValues="FALSE" 
    Group="_Custom" 
    StaticName="HomeCountry" 
    Name="HomeCountry" 
     /> 
</Elements>

To add this field to the content type there is no rocket science, just do as you normally do:

<FieldRef ID="{749DA0D1-4649-4C25-871B-05F0C07221FC}" Name="HomeCountry"/>

That's all that you can do declarative. If this would be deployed a field would be created of the type Managed Metadata but you have to manually connect it to the MMS.

Now we have to dig into some programming to connect the field to the MMS. This is done in an Event Receiver for the feature. Right-click the feature and select Add Event Receiver. Uncomment the FeatureActivated method and implement it as follows:

public override void FeatureActivated(SPFeatureReceiverProperties properties) { 
    SPSite site = properties.Feature.Parent as SPSite; 
    Guid fieldId = new Guid("{749DA0D1-4649-4C25-871B-05F0C07221FC}"); 
    if (site.RootWeb.Fields.Contains(fieldId)) { 
        TaxonomySession session = new TaxonomySession(site);

        if (session.TermStores.Count != 0) { 
            var termStore = session.TermStores["Managed Metadata Service"]; 
            var group = termStore.Groups.GetByName("Wictors Group"); 
            var termSet = group.TermSets["Countries"];

            TaxonomyField field = site.RootWeb.Fields[fieldId] as TaxonomyField;

            // Connect to MMS 
            field.SspId = termSet.TermStore.Id; 
            field.TermSetId = termSet.Id; 
            field.TargetTemplate = string.Empty; 
            field.AnchorId = Guid.Empty; 
            field.Update(); 
        } 
    } 
}

MMS configurationThis method will first check if the field has been deployed. The field is retrieved using the Guid of the Field, defined in the XML. Once that is confirmed that the field exists a TaxonomySession object is acquired using the SPSite object. The TaxonomySession object is declared in the Microsoft.SharePoint.Taxonomy assembly - so you have to add a reference to that assembly first. To connect the field to the MMS you need to retrieve the Term Store, Group and Term Set. All this is done using the names of them as defined in the MMS. The image to the right shows how the MMS looks like that this code is connecting the field to. It is very likely that you have the same structure of the MMS in your different environments - if not you have to come up with a more configurable way :-)

Note the GetByName method used above is a custom extension that looks like this:

public static Group GetByName(this GroupCollection groupCollection, string name) { 
    if (String.IsNullOrEmpty(name)) { 
        throw new ArgumentException("Not a valid group name", "name"); 
    } 
    foreach (var group in groupCollection) { 
        if (group.Name == name) { 
            return group; 
        } 
    } 
    throw new ArgumentOutOfRangeException("name", name, "Could not find the group"); 
}

Once you have a hold on the taxonomy objects then it is time to convert the Field to a TaxonomyField object. This object is then configured with a set of properties. Specifically the ID of the Term Store and Term Set is set. Finally the field is updated to reflect the changes.

The Result!

That's it. All you now have to do is deploy it and test it out.

Final result

Comments and trackbacks

#  Google Apps for Government Suite Available; Government Sites Need Better Search; Browser Blowout 2010 by Trackback
Screenshot from websnpr Top News Stories What Does the New Microsoft / ARM Arrangement Mean? (Windows 7 News & Tips) ARM
#  How to provision SharePoint 2010 Rating columns in Content Types by Trackback
Screenshot from websnpr This post continues in the same neighborhood as yesterdays post about provisioning Managed Metadata columns. This time we take a look at the Ratings in lists (and while we're at it check out another e...
#  How to provision SharePoint 2010 Rating columns in Content Types by Trackback
Screenshot from websnpr This post continues in the same neighborhood as yesterdays post about provisioning Managed Metadata columns
#  Weired observation by Sajeewa
Hi Wictor, Thanks for sharing this. But when I use the option 2 to create TaxonomyFields, I found that they are not appearing in the Refinement panel of the search. So, I use the option 1 and it worked. Any thoughts on this?
#  @Sajeewa by Wictor
Screenshot from websnpr Interesting - lemme check that out.
#  Not showing up in refinement panel by Peter Steffensen
Screenshot from websnpr Hi Victor. I have tried this approach, but has the same problem as Sajewa that the refinement panel dows not show the managed metadata. Do you know any fix for this?
#  Additional steps needed by Paul Pascha
Screenshot from websnpr Hi Wictor, I followed the steps you described but when editing a list item based on the ContentType with the ManagedMetadata field I got the following error: Failed to get value of the "MyField" column from the "Managed Metadata" field type control. To prevent this error you have to add en configure an additional Note field as described in the following forum post: http://social.technet.microsoft.com/Forums/en-US/sharepoint2010programming/thread/310692d3-49f2-4c0f-b911-735f24b769b3
#  Declaratively Provision Managed Metadata Column in SharePoint 2010 by Trackback
Screenshot from websnpr As part of a project I have been working on we wanted to assign categories to items in SharePoint 2010
#  Missing step by Daniel
Screenshot from websnpr In order for the taxonomy field to work properly with the Note field it has to be coupled in the feature activation function of your code example. Couple the fields by setting the TextField property of the taxonomy field to the guid of the note field. In this example it would be: field.TextField = new Guid({a6eae615-9835-4b75-97bf-d4e7a938b892});
#  Dissecting the SharePoint 2010 Taxonomy fields by Trackback
Screenshot from websnpr An intense Twitter conversation initiated by Fabian about how Managed Metadata is updated in SharePoint 2010 gave me the idea to note down a few interesting bits about the Taxonomy Fields and how they...
#  Dissecting the SharePoint 2010 Taxonomy fields by Trackback
Screenshot from websnpr An intense Twitter conversation initiated by Fabian about how Managed Metadata is updated in SharePoint
#  No Sandbox? by Tim
Screenshot from websnpr This was a great article and it confirmed my suspicion that you can't "provision" a managed metadata column into a sandbox as the Taxonomy assembly is not supported in a sandbox :(. That will peave a few devs in the upcoming Office 365.
#  @Tim by Wictor
Screenshot from websnpr Yes, that's unfortunatley true. You need to do it the SharePoint Designer way in Office 365
#  Solution to missing search refinements by Ari Bakker
Screenshot from websnpr @Sajeewa and @Peter Steffensen - to get the managed metadata column automatically showing up in the refinement panel you need to add in several extra columns. I've detailed the steps at http://www.sharepointconfig.com/2011/03/the-complete-guide-to-provisioning-sharepoint-2010-managed-metadata-fields/ @Wictor - great article
#  taxonomy field read only by Petrica
Screenshot from websnpr Hi I followed your recipe and got everything working. But then suddenly field became read only. I can't even find where it gets defined being read only.
#  taxonomy field read only by Petrica
Screenshot from websnpr Hi I followed your recipe and got everything working. But then suddenly field became read only. I can't even find where it gets defined being read only.
#  SharePoint 2010 - Managed Metadata: In Depth Look into the Taxonomy Parts by Trackback
Screenshot from websnpr SharePoint 2010 - Managed Metadata: In Depth Look into the Taxonomy Parts
#  SharePoint 2010 Managed Metadata - Creating Managed Metadata Columns by Trackback
Screenshot from websnpr SharePoint 2010 Managed Metadata - Creating Managed Metadata Columns
#  SharePoint 2010 Managed Metadata - Creating Managed Metadata Columns by Trackback
Screenshot from websnpr In this post I want to cover how to create managed metadata columns. The other posts in this series are
#  Helpful by Lee Dale
Screenshot from websnpr Really helpful article, thanks
#  Visualising Provisioning SharePoint 2010 Managed Metadata Fields by Trackback
Screenshot from websnpr Ari Bakker and Wictor Wilen both have done great jobs on documenting what it takes to provision SharePoint
#  read only solution by lupodjam
Screenshot from websnpr when updating the field, the update method must be used with true to propagate the changes through the lists, otherwise the filed will be disabled.
#  Fantastic by Thomas
Screenshot from websnpr Thanks a lot Wictor, you saved me a lot of time...
Make a comment on this post:
Subject:  

Your name:  
Your Url:  
Note: submissions may have to be approved before being visible, so don't submit your comment multiple times.