Saturday, September 17, 2011

Using SPExport/SPImport for copying content with managed metadata

Sharepoint content deployment API can be used for copying various content between different environments. You can choose what content you need to copy:

  • List item
  • File
  • Folder
  • List
  • Web
  • Site

Appropriate values are determined in SPDeploymentObjectType enumeration. If you export/import separate list items from Sharepoint lists or files (files represent pages/documents/images, i.e. content inside document libraries) then you may face with situation when you need to export managed metadata applied to this content. In this post I will share several aspects of the copying managed metadata with content deployment API.

For testing we will use simple Languages term set with several terms:

image

Also we will need 2 site collections: source and target for content deployment.

Lets start from lists items. Create custom list on the source site collection and add managed metadata column Language which is bound to the term set which we created above. Then create new list item:

image

We need also to create similar custom list on the target site collection with the same title (and same Url – it is important that Url will be the same. Otherwise we would need to re-parent content during importing).

Now we will import created single list item using the following code:

   1: private static string ExportItem(string sourceUrl)
   2: {
   3:     using (var site = new SPSite(sourceUrl))
   4:     {
   5:         using (var web = site.OpenWeb())
   6:         {
   7:             var list = web.Lists.Cast<SPList>()
   8:                 .FirstOrDefault(l => l.Title == "test");
   9:             var item = list.Items[0];
  10:  
  11:             var obj = new SPExportObject();
  12:             obj.Id = item.UniqueId;
  13:             obj.Type = SPDeploymentObjectType.ListItem;
  14:  
  15:             var exportSettings = new SPExportSettings();
  16:             exportSettings.AutoGenerateDataFileName = true;
  17:             exportSettings.ExportMethod = SPExportMethodType.ExportAll;
  18:             exportSettings.SiteUrl = site.Url;
  19:             exportSettings.ExportObjects.Add(obj);
  20:             exportSettings.IncludeSecurity =
  21:                 SPIncludeSecurity.None;
  22:             exportSettings.IncludeVersions =
  23:                 SPIncludeVersions.CurrentVersion;
  24:             SPExport export = new SPExport(exportSettings);
  25:             export.Run();
  26:  
  27:             return exportSettings.FileLocation + "\\" + exportSettings.BaseFileName;
  28:         }
  29:     }
  30: }

And the following code for importing:

   1: private static void Import(string siteURL, string fileToImport)
   2: {
   3:     SPImportSettings importSettings =
   4:         new SPImportSettings();
   5:  
   6:     importSettings.BaseFileName = System.IO.Path.GetFileName(fileToImport);
   7:     importSettings.FileLocation = System.IO.Path.GetDirectoryName(fileToImport);
   8:     importSettings.SiteUrl = siteURL;
   9:     importSettings.RetainObjectIdentity = false;
  10:     importSettings.IncludeSecurity =
  11:         SPIncludeSecurity.All;
  12:     importSettings.UpdateVersions =
  13:         SPUpdateVersions.Append;
  14:     importSettings.UserInfoDateTime =
  15:         SPImportUserInfoDateTimeOption.ImportAll;
  16:     SPImport import =
  17:         new SPImport(importSettings);
  18:     import.Run();
  19: }

Note that as I said you need to remember that we use the same Urls for lists so we can import content without re-parenting. Otherwise you will need to add code which re-parent objects during import. Example can be checked here.

Lets check what we will have on target site collection when this code will be ran:

image

Managed metadata values were copied, but there is number of side effects:

  1. Hidden Note field which is used internally by Sharepoint for each managed metadata field became visible
  2. Taxonomy Catch All Column field became visible

The most serious problem is that imported field is not updatable, i.e. if you will try to add e.g. Swedish language and save list item, when you will re-open item in edit form you will still see 3 imported values (English, Finnish, Russian).

Also in default list view imported values won’t be shown:

image

It happens because Sharepoint created new Language field, i.e. now there are 2 Language fields in the list on the target site collection. You can check it in List settings:

image

It will work by the same way if you will add some OTB managed metadata field, e.g. Enterprise Keywords, except that duplicated field won’t be created.

For pages the picture is the same. Code for exporting will be slightly different:

   1: private static string ExportPage(string sourceUrl)
   2: {
   3:     using (var site = new SPSite(sourceUrl))
   4:     {
   5:         using (var web = site.OpenWeb())
   6:         {
   7:             var pweb = PublishingWeb.GetPublishingWeb(web);
   8:             var item = pweb.PagesList.Items.Cast<SPListItem>()
   9:                 .FirstOrDefault(p => p.File.Url.ToLower().EndsWith("test.aspx"));
  10:             var page = item.File;
  11:  
  12:             var obj = new SPExportObject();
  13:             obj.Id = page.Item.UniqueId;
  14:             obj.Type = SPDeploymentObjectType.File;
  15:  
  16:             var exportSettings = new SPExportSettings();
  17:             exportSettings.AutoGenerateDataFileName = true;
  18:             exportSettings.ExportMethod =
  19:                 SPExportMethodType.ExportAll;
  20:             exportSettings.SiteUrl = site.Url;
  21:             exportSettings.ExportObjects.Add(obj);
  22:             exportSettings.IncludeSecurity =
  23:                 SPIncludeSecurity.None;
  24:             exportSettings.IncludeVersions =
  25:                 SPIncludeVersions.CurrentVersion;
  26:             SPExport export = new SPExport(exportSettings);
  27:             export.Run();
  28:  
  29:             return exportSettings.FileLocation + "\\" + exportSettings.BaseFileName;
  30:         }
  31:     }
  32: }

After importing on the target there also will be additional fields in page metadata. Also values in managed metadata fields may be not copied as well:

image

I found workaround for the 2 mentioned problems: non-updatable fields on the target and showing of the Taxonomy Catch All Column. In our tests we used fields. If you will use content type with managed metadata fields, bind it to the pages doclib (on both site collections) and then run export/import – Sharepoint will also make Note fields visible. However Taxonomy Catch All Column won’t be shown. Also it will be possible to update values in the managed metadata fields on the target.

It is possible to hide Note field from content type on target site collection. However it will become visible on the next import again. I.e. you will need to hide Note fields after each import operation.

That’s all observations which I would like to share here. If there will be more information in the future I will update this post.

No comments:

Post a Comment