Wednesday, December 30, 2009

SharePoint Managed Metadata Developer Experience

This post is part four in a series that I’m writing about SharePoint 2010 Enterprise Managed Metadata (EMM or ‘taxonomy’). If you haven’t set up a SharePoint 2010 development environment yet, you may also want to check out SharePoint 2010 Beta 2 install.

Update: I have posted a video demo on the Metalogix blog showing how to create a SharePoint 2010 Taxonomy Web Part.

SharePoint Taxonomy Part One – Introduction to SharePoint Managed Metadata
SharePoint Taxonomy Part Two – End-User Experience
SharePoint Taxonomy Part Three – Administrator Experience
(including Using SharePoint Term Stores and SharePoint Taxonomy Hierarchy)
SharePoint Taxonomy Part Four – Developer Experience
(including SharePoint 2010 Visual Web Parts and SharePoint 2010 Taxonomy Reference Issues)

Opening Microsoft.SharePoint.Taxonomy in the Visual Studio Object Browser reveals a long list of objects, but you won’t need to worry about a number of them. In this post, I’m going to start with the most useful and then add others if I find that they’re worth covering.

image
- Exploring the Taxonomy DLL in the Object Browser

But if you’re curious, here’s the full list:

ChangedGroup
ChangedItem
ChangedItemCollection
ChangedItemType
ChangedOperationType
ChangedSite
ChangedTerm
ChangedTermSet
ChangedTermStore
FeatureIds
Group (used in the sample below)
GroupCollection
HiddenListFullSyncJobDefinition
ImportManager
Label
LabelCollection
MobileTaxonomyField
StringMatchOption
TaxonomyField
TaxonomyFieldControl
TaxonomyFieldEditor
TaxonomyFieldValue
TaxonomyFieldValueCollection
TaxonomyItem (base class for classes such as Term and TermSet)
TaxonomyRights
TaxonomySession (used in the sample below)
TaxonomyWebtaggingControl
Term (used in the sample below)
TermCollection
TermSet (used in the sample below)
TermItem
TermStore (used in the sample below)
TermStoreCollection
TermStoreOperationException
TreeControl

TaxonomySession

The first class to cover is TaxonomySession. To use the taxonomy API to manipulate managed metadata, you’ll first need to instantiate a TaxonomySession object. Microsoft describes the class in this way:

“The TaxonomySession class creates a new session in which to instantiate objects and commit changes transactionally to the TermStore object. A TaxonomySession object can have zero or more TermStore objects associated with it. TermStore objects are associated with the Web application of the parent SPSite object.”

I’m going to continue with the example I started in SharePoint 2010 Visual Web Parts, but don’t worry if you’re not interested in building a web part, I just happened to choose that as the example. You can use the same code from a number of different places (e.g., a Windows Form application). I won’t be covering remote access to the taxonomy API in this post since that will topic is worthy of its own attention.

The starting point for this conversation is VisualWebPart1UserControl.ascx.cs from the simple web part example. I covered issues adding the references in SharePoint 2010 Taxonomy Reference Issues.

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

// Added references
using Microsoft.SharePoint;
using Microsoft.SharePoint.Taxonomy;

public partial class VisualWebPart1UserControl : UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
using (SPSite site = new SPSite("
http://localhost/"))
{
//Instantiates a new TaxonomySession for the current site.
TaxonomySession session = new TaxonomySession(site);

//Instantiates the connection for the current session
TermStore termStore = session.TermStores["Managed Metadata Service"];

// Write out the names of the term stores to a label
Label1.Text = “”;
foreach (TermStore termstore in session.TermStores)
{
Label1.Text += termstore.Name.ToString() + " … ";
}

// Write the name of the term store to a label
Label1.Text += " Finished";
}
}
}

As you can see, this is a pretty straightforward example of how to get a TaxonomySession object and employ it. Once loaded, this web part will immediately write out the names of each term store available on the server.

So let’s break it down. The first thing that happens inside the Page_Load method is getting an SPSite object. As mentioned above, TermStore objects are associated with the Web application of the parent SPSite object. By running the code within a using statement, you can rest assured that dispose() will be properly called on your objects. Since this web part project is using the SharePoint Visual Web part template, the only references I had to add were Microsoft.SharePoint (for the SPSite object) and Microsoft.SharePoint.Taxonomy (for the taxonomy objects).

Now that you have a taxonomy session, you can start to use the taxonomy classes. In this case we’ll loop through each available term store on the server and write the results to a label. The label was simply dragged onto VisualWebPart1UserControl.ascx from the Toolbox onto design view for the web part.

image
- After dragging the label from the toolbox

Pressing F5 will start the debugger and allow you to run the code as described in SharePoint 2010 Visual Web Parts.

image
- Running the web part to see the term store name

In this case, there is only one term store, so only one name is returned. It’s a simple example but useful since you will need to know the name of your term store before you instantiate a term store object and start reading from or writing to your taxonomy.

Note: If you get the name of your term store wrong, the error you see may not immediately tip you off that you’re fat fingered the text value. The error is:

System.ArgumentOutOfRangeException was unhandled by user code
Message=Specified argument was out of the range of valid values.
Parameter name: index
Source=Microsoft.SharePoint.Taxonomy
ParamName=index
StackTrace: at Microsoft.SharePoint.Taxonomy.Generic.IndexedCollection`1.get_Item(String index)

The Hierarchy of Managed Metadata

As explained in SharePoint Taxonomy Part One – Introduction to SharePoint Managed Metadata, the SharePoint 2010 EMM is organized into a hierarchy. The objects within this hierarchy are term stores, groups, term sets, and terms. For more info about the EMM hierarchy, refer to my SharePoint Taxonomy Hierarchy post.

There are the rules for the taxonomy hierarchy (the latter three are from Microsoft):
When a Managed Metadata service is created, a term store will be created. Once you have a term store, you can create a group. The Taxonomy API cannot create a term store (it is done through Central Administration or with a PowerShell script). However, the rest of the EMM containers can be created using the Taxonomy API.
• After a Group object is created, the first TermSet object can be created. A TermSet object must be the child of a single parent Group object.
• After a TermSet object is created, the first Term object can be created. A Term object can be the child of a TermSet object, or of another Term object.
• After a Term object is created, another Term object can be created and added as a child Term object.

Method to the Madness

Here are some common methods that you’ll use when working with the EMM API:

termStore.CreateGroup()
group.CreateTermSet();
termSet.CreateTerm()
term.SetDescription()
term.CreateLabel()
term.Delete()
termStore.CommitAll()

Let’s start with the last one first: the CommitAll method. After performing write operations to a TermStore object, you must call CommitAll to commit the transactions. The taxonomy API is transactional so either every operation will be successfully committed, or none of the changes will be applied. As you saw in the list of classes above, the object model also includes changes. For example, ChangedItem and ChangedGroup. These are used to record what has happened.

The SetDescription method allows you to create a description for the term and you can use CreateLabel to create synonyms. You can choose whether the label will be the default using a true or false Boolean. Of course, the Delete method will delete an object.

Note that when creating a term or label, EMM provides the ability to supply the same term in different languages. This provides a number of multilingual features, but it also means that you’ll need to supply a Locale Identifier (LCID) when using some of the create methods. Windows uses the LCID to choose the language and culture when displaying information. The ID for English is 1033.

Here’s a longer version of the using statement from above--it shows an example of these methods in action:

using (SPSite site = new SPSite("http://localhost/"))
{
//Instantiates a new TaxonomySession for the current site.
TaxonomySession session = new TaxonomySession(site);

//Instantiates the connection named "Managed Metadata Service" for the current session.
TermStore termStore = session.TermStores["Managed Metadata Service"];

Group group = termStore.CreateGroup("Africa");
TermSet termSet = group.CreateTermSet("South Africa");
Term term = termSet.CreateTerm("Cape Town", 1033);
term.SetDescription("This is the city term for Cape Town", 1033);
term.CreateLabel("Cape of Good Hope", 1033, false);
Term termChild = term.CreateTerm("Newlands", 1033);
termChild.Delete();
termStore.CommitAll();

Label1.Text = " Finished";
}

image
- The hierarchy has been created and the description and label were set

[Disclaimer: This information is based on SharePoint 2010 Beta 2 and may differ from the RTM build.]

No comments: