Monday 8 September 2014

Three cloud-friendly ways for developers to provision Managed Metadata fields in SharePoint/Office 365

Provisioning Managed Metadata fields “the developer way” brings some additional complexity where SharePoint full-trust solutions cannot be used, such as Office 365/SharePoint Online deployments or on-premises projects where cloud-friendly techniques are being used. In the past, a developer would use a Feature receiver to bind taxonomy fields to Term Sets – but this isn’t possible in cloud scenarios. I wrote about this previously in Provisioning Managed Metadata fields in Office 365 – here I discussed the problem, and provided an approach we’ve used previously which does work in the cloud. As the article shows, it’s actually possible to use a fully-declarative (XML-based) way of provisioning Managed Metadata fields, so long as some GUIDs which relate to your Office 365/SharePoint instance are inserted into the XML.

Downsides to the declarative approach

The article also discusses the fact that if you work against multiple environments (tenancies or on-premises), at least one different GUID (for the Term Store ID) needs to be used in the XML. This effectively leads to different WSP packages being deployed to different environments – of course, this is not good in ALM terms! In our case, we were fairly comfortable with this trade-off since our TFS automated build process dealt with building packages for different environments, and we didn’t feel much pain. However, without an automated build process it can be more problematic – and now that more time has passed, I think it’s worth stepping back and discussing other options for solving this common problem.

3 ways to bind taxonomy fields

Before delving into the detail of each one, here are the main options as I see them (N.B. I’ve used this list in some of my other articles):

  1. The 100% declarative approach (as discussed above and in my other article)
  2. Using some form of remote server-side .NET CSOM code:
    1. The Microsoft sample in the Office Dev Patterns and Practices samples (previously known as the AMS samples)
    2. Some custom code you wrote
    3. Some custom “PowerShell + CSOM” script you wrote
  3. Using JSOM code running in the user’s browser, which I discuss in a companion article to this one - JavaScript-based provisioning in SharePoint/Office 365

Notably, the last two options aren’t really limited to “the taxonomy field problem” – both of the remote CSOM or JSOM approaches could be used as part of a wider strategy for automated provisioning i.e. any setup steps which require code. My quick list of things which commonly need to be achieved here include:

  • Binding Managed Metadata/taxonomy fields
  • Setting a theme/Composed Look on a site
  • Setting the master page of a site
  • Modifying navigation settings
  • Branding OneDrive (personal) sites
  • [Optional] Provisioning fields and content types through code, rather than XML

So, if you have other items on this list you need to accomplish *or* you just prefer to avoid the declarative approach for Managed Metadata fields because of the ALM trade-offs, then you’re probably looking at a choice between the .NET CSOM or JSOM approaches. For .NET CSOM code, the Office Dev sample code works just fine - but, of course, you have to deploy and host it somewhere, whether it’s a cloud service like Azure or your own IIS servers. And this isn’t necessarily simple for a production-grade enterprise implementation - in the “Side-stepping the server-side remote code issue” section of JavaScript-based provisioning in SharePoint/Office 365, I cover this debate in more detail. As I conclude there:

The idea of implementing remote code in JavaScript can be quite appealing in some cases.

And if steps are taken to increase robustness, I think this approach is OK. So with all that in mind, let’s see what provisioning Managed Metadata/taxonomy fields in JSOM code looks like:

Provisioning with JSOM code

The sample below shows the code, but if you’re interested in using it also see the notes below:

Some notes on this code sample:

  • The code will work with Office 365 or on-premises SharePoint
  • One of the core benefits is that the code allows you to specify the *name* of the Term Set, rather than it’s ID. This is useful since this GUID will be different in different environments, unless you’ve taken specific steps to avoid this (i.e. by creating the Term Set programatically)
  • In fact, three things need to be specified – the name of the Term Set, the locale of the Term Set, and the internal name of the field – you can see these at the top of my code. Ultimately they get passed to the initTaxObjects() method which starts the process
  • I’ve kept the code simple by not using JavaScript promises, but that could be an exercise for the reader if you’d like to enhance it in that way
  • The method is currently set up to process one field at a time, but it could be extended to accept an array of field names/term set IDs
  • Current there’s a delay of 4 seconds inserted for illustration purposes – make sure you remove this if you implement in production :) Similarly there are lots of console.log lines which you might choose to remove
  • You may need to deal with script dependencies differently if not running in a SharePoint page (e.g. you’re code is running in an app)
  • In current form, the code above expects some calling code somewhere to trigger the execution, and a DIV with ID of "jsomProvisioningMessage" (for some simple logging messages) – you could have both of these in a custom web part or Script Editor Web Part added to a page. This is the code:

    <div id="jsomProvisioningMessage" />
    <script type="text/javascript">
    $(document).ready(function () { 

Whether it’s this approach you use or an alternative, if successful your taxonomy field should look like the following (before and after shown):

Before (unbound):

Taxonomy field before binding

After (field is now bound and can be used for tagging):

Taxonomy field after binding


Managed Metadata/taxonomy fields have always been a bit of a pain for developers, because there needs to be an association between the field and a Term Set, and these have different IDs in different environments/tenancies – so it often needs to be dynamically looked up/specified. Assuming we are implementing the site the developer way with automated provisioning, this can be done 100% declaratively (with the ALM trade-off), with .NET CSOM code or with JSOM code. In this post I’ve focused on the JSOM approach – since if you have no other requirements for remote code (and therefore no Azure subscription ready to go), this method can be appealing.

No comments: