Programmatically Provision Term Store

I recently had to write a feature to provision the SharePoint 2010 Term Store. Numerous blog posts exist on how to populate the term store using Power Shell or how to write XML to add terms to the store, but what I wanted to do was a little different.  The requirements for my feature were as follows:

1. Works in SharePoint 2010 (duh)

2. Create a new Term Store Group in default Term Store

3. Great a series of Term Sets

4. Create a series of Terms in the Term Sets

5. Deploy the feature at the Farm scope.

One of the issues with setting up a Term Store in the SharePoint 2010 Metadata Managed Service Application is that the service can be temperamental if the proxy for the service does not have the setting checked for default term store storage location for site collections.  I wrote a previous blog post on this issue here

To save you some reading, the issue above is with obtaining the default term store instance for a given site collection when using the TaxonomySession object in the Microsoft.SharePoint.Taxonomy API.  As my previous post mentioned, the way to resolve this issue is to check the option under Properties fore the proxy and ensure that the current user had full control as an Administrator of the Managed Metadata Service Application.

Nice one Rob! But what if you want to avoid the manual step and want to configure these operations in code?  It is not as hard as it may sound, check out the code below…

        private void ProvisionMetadataService()
        {
            // We don't have the metadata service configured, so let's do that.
            var proxy = SPFarm.Local.ServiceProxies.Where(s => s.GetType().Name.Equals
("MetadataWebServiceProxy")).FirstOrDefault();
            if (null == proxy) 
throw new SPException("Failed to get instance of metadata web service proxy, is it installed?");
            foreach (var proxyApp in proxy.ApplicationProxies.Where(proxyApp => 
proxyApp.Properties.ContainsKey("IsDefaultSiteCollectionTaxonomy")))
            {
                proxyApp.Properties["IsDefaultSiteCollectionTaxonomy"] = true;
                proxyApp.Update(true);
            }
            // Give the current user access rights to the metadata service.
            var service = SPFarm.Local.Services.Where(s => s.GetType().Name.Equals
("MetadataWebService")).FirstOrDefault();
            if (null == service) 
throw new SPException("Failed to get instance of metadata web service, is it installed?");
            var serviceApp = service.Applications.OfType<SPIisWebServiceApplication>().FirstOrDefault();
            if (null == serviceApp) 
throw new SPException("Failed to get instance of metadata web service app, is it installed?");
            var security = serviceApp.GetAdministrationAccessControl();
            var cba = SPClaimProviderManager.Local;
            var claim = cba.ConvertIdentifierToClaim("DOMAINuser", 
SPIdentifierTypes.WindowsSamAccountName);
            security.AddAccessRule(
new SPAclAccessRule<SPCentralAdministrationRights>(claim, SPCentralAdministrationRights.FullControl));
            serviceApp.SetAdministrationAccessControl(security);
            serviceApp.Uncache();
            service.Uncache();
        }

 

With the above code executed, you can then open an instance of the site collection to the Central Admin Site and then request the default site collection term store with the following code:

using (var site = new SPSite(_farmUrl))
            {
                // Do we have explicit credentials?
                if (!String.IsNullOrEmpty(_username) && !String.IsNullOrEmpty(_password))
                {
                    var user = site.RootWeb.AllUsers[_username];
                    if (null == user) 
throw new SPException(String.Format("no user in site collection {0}", _username));
                    using (var secureSite = new SPSite(site.ID, user.UserToken))
                    {
                        // Get the term store.
                        var session = new TaxonomySession(secureSite);
                        var termStore = session.DefaultSiteCollectionTermStore;
                        if (null == termStore) 
throw new SPException("Failed to get the default term store instance");
                        del(termStore);
                    }
                }
                else
                {
                    // Get the term store.
                    var session = new TaxonomySession(site);
                    var termStore = session.DefaultSiteCollectionTermStore;
                    if (null == termStore) 
throw new SPException("Failed to get the default term store instance");
                    del(termStore);
                }
            }

It’s not obvious from the code above, but the call to “del” is a delegate call that I include as a parameter to the wrapping method of the above cod.

So, lastly, how did I get the Central Admin URL in the feature receiver?  See below:

var app = SPAdministratrionWebApplication.GetInstanceLocalToFarm(SPFarm.Local);
var url = app.Sites[0].Url