In my previous post, I have discussed the Managed Metadata Service, or MMS. The service can be used to centralize and manage metadata that is used throughout an organization. In that article, I also mentioned that SharePoint 2010 introduced a new special column called the Managed Metadata column that can utilize terms from the Terms Store in the MMS. This post continues on that road and explores some of the concepts of centralizing another aspect of SharePoint, Content Types.
Sharing
To be honest, content types are not the only entities you can share using the MMS across multiple site collections. In fact, associated concepts can also be shared. These are:
- Content Types
- Policies
- Document Set Content Type
- Workflow associations
The latter is a special one. You can share the associations, but not the workflows themselves. You just need to ensure that the workflows are available where the associated content types are used. If not, the content type will work, but will not kick-off any workflows obviously.
Site Collection Hub
The MMS will consume and syndicate these items from a central store. This is called the Hub and each MMS can have only one Hub associated with it. This also means that if you would like to have separate Hubs, you need to create multiple instances of a MMS. This highly depends on the architectural decisions and landscape. For small organizations though, one hub will suffice. The Hub can be any site collection in your Farm, as long as the owner of the MMS service can access that site. I also noticed that once we have set a hub for a Managed Metadata service, it cannot be changed anymore. To change it, you would need to create a new Metadata Service, transfer the groups and terms and delete the old one. Quite a strange design choice.
All content types and associated policies and workflow associations created in the Hub can be published and made available through the hub and the service to other site collections.
Example
To demonstrate the use of the hub, as well as demonstrating the classes in the Microsoft.SharePoint.Taxonomy.ContentTypeSync namespace, I will provide an example where I will configure the Hub, assign it to a metadata service, create a content type that uses the Term Sets in the metadata service, create and publish this content type through code, consume the content type in a separate site collection and expand it there, update the content type in the hub through the UI, republish the content type and show the effects when it is pushed to the site collection again.
To start off, I will assume you have a Managed Metadata Service set up and running. In there, at least one Term Set should be present, containing several terms. If you are not clear on how to achieve this, take a look at my previous post regarding the Managed Metadata Service. I have mine steup like below:
Create two site collections, one will be the Hub, the other will be the consuming site. For the purpose of this post, I have a site at http://sp2010 which is my consumer site and a site at http://sp2010/sites/hub which is my Hub.
The second thing we need to do upfront is enabling the Taxonomy feature. Unfortunately, for reasons that are yet beyond me, this feature is hidden and not enabled, which is needed to use the Managed Metadata column type. Fortunately, this is a Farm feature so we need to enable it only once. But it would be better if this feature was just enabled by default. Run the following command using stsadm:
STSADM -o activatefeature -id 73EF14B1-13A9-416b-A9B5-ECECA2B0604C -url http://<server> -force
Associating the Managed Metadata Service with the Hub site
So, now that we have the basic setup complete and prepared the environment, we need to connect the Managed Metadata Service to the Hub site collection. Within Central Administration, navigate to Manage Service Applications under Application Management. Select the Managed Metadata Service you wish to connect to the hub (to top row, not the connection below) and select Properties from the ribbon. On the bottom of the properties page, you can enter the url of the Site Collection hub. In my case, this is http://sp2010/sites/hub. Click OK to confirm.
The service is now connected to the Hub. In the Hub site collection, this has caused the activation of the Content Type Syndication Hub feature.
Creating the content type
Creating the content type can be done in two ways. Either through the user interface or through the object model. Personally, I prefer the latter, or rather, the hybrid approach, because it will more closely resemble our day to day life. We are not going to manually deploy content types right?
Create a new Visual Studio solution and add a Content Type element. Add another xml file to the content type element. Call it Fields.xml and set the deployment type to ElementManifest. In this file, we will define our managed metadata column. The actual wiring to the managed metadata store however must be done in code. Add the following xml to the file:
<?xml version=“1.0” encoding=“utf-8“ ?>
<Elements xmlns=“http://schemas.microsoft.com/sharepoint/“>
<Field ID=“{A559CE6A-F2A5-4db9-BDC5-E6B84E1DF3A3}”
Type=“TaxonomyFieldType”
DisplayName=“Department“
ShowField=“Term1033”
Required=“FALSE“
EnforceUniqueValues=“FALSE“
Group=“Managed Fields”
StaticName=“MyDepartment“
Name=“MyDepartment” />
</Elements>
In here, you can see that the type of our field is the TaxonomyFieldType. The ShowField attribute indicates the language identifier, in this case English (1033). Add the field to our content type defined in the Elements.xml file.
<?xml version=“1.0” encoding=“utf-8“?>
<Elements xmlns=“http://schemas.microsoft.com/sharepoint/“>
<!– Parent ContentType: Document (0x0101) –>
<ContentType ID=“0x0101004a7f92eb8a7e40dbaa3fd17dbfaf751f”
Name=“Boom.Taxonomy.Syndication – ManagedContentType”
Group=“Published Content Types”
Description=“My Managed Content Type”
Inherits=“TRUE”
Version=“0“>
<FieldRefs>
<FieldRef ID=“{A559CE6A-F2A5-4db9-BDC5-E6B84E1DF3A3}” Name=“MyDepartment“/>
</FieldRefs>
</ContentType>
</Elements>
We now need to wire the field to our metadata service, indicating the TermSet to use for the field. Add an event handler to the feature (ensure the feature scope is set to Site) and implement the FeatureActivated method as follows:
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
// Connect to the site and use it to set up the TaxonomySession
SPSite site = properties.Feature.Parent as SPSite;
// Field ID
Guid fieldId = new Guid(“{A559CE6A-F2A5-4db9-BDC5-E6B84E1DF3A3}”);
if (site.RootWeb.Fields.Contains(fieldId))
{
// Set up the session again
TaxonomySession session = new TaxonomySession(site);
// Check for Term Stores.
if (session.TermStores.Count != 0)
{
// Get the Term Store
TermStore termStore = session.TermStores[“MyMMS”];
// Get the group
Group group = termStore.Groups[“ContentTypeSync”];
// Get the Term Set
TermSet termSet = group.TermSets[“Departments”];
// Get the field using the ID
TaxonomyField taxField = site.RootWeb.Fields[fieldId] as TaxonomyField;
// Wire the properties to the managed metadata service.
taxField.SspId = termSet.TermStore.Id;
taxField.TermSetId = termSet.Id;
taxField.TargetTemplate = string.Empty;
taxField.AnchorId = Guid.Empty;
taxField.Update();// Prepare publishing
if (ContentTypePublisher.IsContentTypeSharingEnabled(site))
{
// Publishing allowed.
ContentTypePublisher publisher = new ContentTypePublisher(site);
// Publish the content type
SPContentType cType = site.RootWeb.ContentTypes[new SPContentTypeId(“0x0101004a7f92eb8a7e40dbaa3fd17dbfaf751f”)];
publisher.Publish(cType);
if (!publisher.IsPublished(cType))
{
EventLog.WriteEntry(“Boom.Taxonomy.Syndication”, “Not published”);
}
}
}
}
}
Now, some of the classes we have already seen in the previous post. We connect to a TaxonomySession, grab the TermStore, Group and TermSet and use the objects to wire the TaxonomyField we created.
Publishing the content type
Once the wiring is complete, we use the ContentTypePublisher class to detect whether or not this site is a Content Type Syndication Hub. If so, we get an instance of the publisher and pass the content type to the Publish method. Finally, we check if the type was published properly.
Build and deploy the solution. If you activate the feature on the Hub site collection, you should see your newly created type in the Site Content Types list.
To check whether or not the content type works, you can create a document library and add the content type to the library. Then create a new document based on the type, which should start Word with a new document. In the server properties you should see your Managed Metadata field. If all works well suggestions will pop up as soon as you start typing. You can also click the search button, which shows your Term Set in a popup window, like below:
So, we now know that the field works. Now let us see how we can consume the type. Before we get to that point, thing to note here is that the publishing of the types is done through a Timer Job. Usually runs each hour, but can also be called manually. The job is called Content Type Subscriber. Be prepared to run it manually, or you will have to wait for an hour 😉
To import the published content type in our site collection, we navigate to Site Settings and find the Content type publishing option in the Site Collection Administration menu.
Open it and at the top, you will find an option to refresh all published content types during the next update.
Check the checkbox and click OK. Now to avoid waiting for the timer job to run, we will run it manually. Navigate to Central Administration, go to Job Definitions in the System Settings menu and click the Content Type Subscriber job. Click the Run Now button to run the job manually. Once done, navigate back to your site.
When you now go to your Site Content Types gallery in your subscriber site, you should see the published content type listed.
So, create a document library and add the content type to this library. Upload a document using this type and fill out the properties.
Notice that when you go to the list settings and navigate to the list content type, you cannot change it here. The only available option is Advanced Settings, which allows you to set a different template or make the type writable. (not read-only). Obviously, for published types, you should not do this. Remember that just like in SP 2007, content types in list are not references, but a local copy of the site collection content type. In SP 2007, making changes on the list level caused a ghosting (disconnect) of the content type for the site collection level, which made it very hard to manage. In SP 2010, this has improved a lot, as the connection remains and changes to the site collection type are merged with local changes.
To demonstrate, set the content type Read-Only property to No and add a field to the type, called Actual Work. After that, go to the Hub and apply a change to the Content Type by adding a field called Publisher. Once done, click the Manage publishing for this content type link and republish the type. Run the timer job and go back to your list in your subscriber site. Go to list settings and click the published content type.
As you can see, both the changes I made to the list content type, as well as the changes done in the content type in the Hub have been pushed down and merged. Cool isn’t it?
Conclusion
I hope above example showed you that indeed a lot of things have improved in SP 2010. The central management of content types and metadata has taken a huge step forward, taking us a step closer to consistency, ease of management and centralization. Hope you can use this to your advantage! You can download the example Visual Studio 2010 solution here.
Cu.