Sunday 21 November 2010

Migrate SharePoint 2010 Managed Metadata to another farm or Service Application.


Managed Metadata in SharePoint 2010 is great until you want to move term groups or termsets with content types and site columns to another farm or environment. This is because the SharePoint is using GUID as reference when create a new metadata record, each GUID which used by site column will be regenerated even Import from delimiter file.

This will causing a huge problem for those develop their Managed Metadata in one environment and deploy to another for user acceptance test.

Luckily, the metadata GUID can be replicated and imported from/to Service Application by Microsoft.SharePoint.Taxonomy class. That mean implement the custom export/import process by either using .Net code or Powershell.

In this blog post I want to show you how to use the C# code with Taxonomy APIs to export and import managed metadata. At the same time I make a assumption you are experienced .Net development and with appropriate SharePoint knowledge.

First of all, ensure the account access to SharePoint has permission to read and write managed metadata store. I 'm recommend using farm account when export and import metadata from/to SharePoint.

Here the exportation of the termsets and terms to xml.
  1.  Create the SPSite object which link to managed service application which wish to export.

            SPSite site = new SPSite(siteUrl)

  1. Create a TaxonomySession and pass in SPSite created in step 1 as parameter.

 TaxonomySession session = new TaxonomySession(site);

  1. Retrieve TermStore collection from session object created in step 2.

 TermStore MetadataTermStore = session.TermStores[managedMetadataServiceName];

  1. Iterate through terms collection and extract to XML file. 
    
   foreach (Group g in MetadataTermStore.Groups)
                {
                   // some code…….
    }

And the final view of your source code.

// This is the common library for xml extraction.
           ManagedMetadata metaCommon = new ManagedMetadata();

            using (SPSite site = new SPSite(siteUrl))
            {
                TaxonomySession session = new TaxonomySession(site);
                TermStore MetadataTermStore = session.TermStores[managedMetadataServiceName];
                foreach (Group g in MetadataTermStore.Groups)
                {
                        XElement metaStore = metaCommon.GenerateNode(g);                  
                }
            }

The ManagedMetadata is the common class which I created for managed metadata to XML string, it provides several methods to extract metadata objects to xml element. For instance, below code using Linq to XML to generate Xelement from  metadata Group object.

        public XElement GenerateNode(Group g)
        {
            XElement rElement = new XElement(GroupElementName, new XAttribute(NameKey, g.Name), new          
                                                                              XAttribute(GuidKey, g.Id),
                                                                              from termSet in g.TermSets
                                                                              select GenerateNode(termSet));
            return rElement;
        }

Please note when generating xml element you MUST include metadata's GUID as it is important for import process.

I also create a Winform application to help me extract the managed metadata from SharePoint.



Your extracted xml should be something looks like this.

 <?xml version="1.0" encoding="utf-8"?>
<Group Name="Example Group" Guid="3eb956d1-2449-4eaf-be65-01579da93864">
  <TermSet Name="Accounts" Guid="d80de18e-6be1-4a4f-a157-1d1b64d17fe7">
    <Term Name="Audit" Guid="37ebd2d7-ad00-4c7f-a7b9-ad76ac3f0f57" Lcid="1033" IsDeprecated="false">
      <Term Name="External" Guid="f316c860-5727-46f7-9924-003e3c524c69" Lcid="1033" IsDeprecated="false" />
      <Term Name="Internal" Guid="559c9a12-0a6c-4546-80e3-8770b5ecf39a" Lcid="1033" IsDeprecated="false" />
    </Term>
    <Term Name="Bank" Guid="b9c52438-32f3-4597-950e-726ee9809774" Lcid="1033" IsDeprecated="false" />
    <Term Name="Budgets" Guid="4741a838-f887-464f-93bf-1622ea5ad37d" Lcid="1033" IsDeprecated="false" />
    <Term Name="B1" Guid="6876ff80-2e37-4d48-94b0-ecc4c962203e" Lcid="1033" IsDeprecated="false">
      <Term Name="B2" Guid="935bae00-b4fe-48fe-9260-660c27a62be6" Lcid="1033" IsDeprecated="false" />
      <Term Name="C2" Guid="546e29a3-a722-4b5f-80e7-5f4dc3b2355e" Lcid="1033" IsDeprecated="false" />
    </Term>
 </TermSet>
</Group>
   
Above example shown you how to extract the managed metadata to XML, and the summary at below show you how to use Taxonomy's API to import extracted xml into managed metadata store.

  1. Create the SPSite object which link to managed service application wish to export.

  1. Create a TaxonomySession and pass in SPSite created in step 1 as parameter.

  1. Retrieve TermStore collection from session object created in step 2.

  1. Iterate through extracted xml and import into term store, then commit. 

Here how it looks like when implementing in C# code.
var meta = XElement.Load(loadLocation);
using (SPSite site = new SPSite(siteUrl))
{
TaxonomySession session = new TaxonomySession(site);
managedMetadataServiceName = "Managed Metadata Service";
TermStore MetadataTermStore = session.TermStores[managedMetadataServiceName];               
// My custom common library.
ManagedMetadata manageMeta = new ManagedMetadata();
manageMeta.NewNode(MetadataTermStore, meta);
MetadataTermStore.CommitAll();
}

The custom common library will takes XElement, Group, TermSet and Term object as parameter and create appropriate entry in metadata store. As above example, the library will extract Group, TermSets and Terms accordingly when pass in whole metadata Xelement.

When creating a new termset or term, you are expecting to pass in two parameters, term key and GUID. The GUID should be re-used the value extracted from managed metadata store. Example,

// t  is Xelement which extracted from XML string.
// Group is Taxonomy's Group object.
Group.CreateTermSet(t.Attribute(NameKey).Value, new Guid(t.Attribute(GuidKey).Value));

// For create a new term under termset.
// ts is Taxonomy's TermSet object.
// LCID is local integer value.
// t is Xelement.
ts.CreateTerm(t.Attribute(NameKey).Value, LCID, new Guid(t.Attribute(GuidKey).Value));

// or create a new term under another term.
// ts is Taxonomy's Term object.
// t is Xelement.
ts.CreateTerm(t.Attribute(NameKey).Value, Convert.ToInt32(t.Attribute(LcidKey).Value), new   
                                                                                                                    Guid(t.Attribute(GuidKey).Value));

My recommendation to seamlessly  deployment for managed metadata is to using SharePoint WSP with feature, although you can write another bespoke tool for import but as best practice the SharePoint solution should always being used.

Please let me know when you need a copy of my custom managed metadata library.


    Wednesday 10 November 2010

    Fast Search for SharePoint 2010's Document Preview is not working


    There are number of issues which might causing Fast's Document Preview failed to work, if one of these points is met.

    1) Silverlight is not installed on machine which search performed.
    Go to http://www.silverlight.net/ and download Silverlight runtime.

    2) The Office Web Application for SharePoint 2010 is not installed.
    Technet's step-by-step to deploy the Office Web App, http://technet.microsoft.com/library/ff431687(office.14).aspx.

    3)  Without run the SharePoint Configuration Wizard after setup the Office Web Application for SharePoint 2010.
    Run the SharePoint Products and Technologies Configuration Wizard on each SharePoint server in server farm.

    4) Search results can be returned but "401 unauthorized" message occurred on Document Preview's ajax callback to server.
    This might because of the loopback issue on SharePoint server's IIS, click here for details of how to disable loopback check on Windows Server.