mike hodnick -> mhodnick <-> kindohm

Mike Hodnick is a geeky consultant guy living in Chaska, MN. He enjoys writing code, writing music, and doing fun stuff with his wife and daughter. This is his personal website, where you can get to his blog, music library, and other nonsense.

Latest From Twitter...

The Blog

If you are writing code using the SharePoint migration API (e.g. using the SPExport/SPImport classes, which Stefan Goßner has blogged in detail about), you'll want to be careful about the scope of your exports when exporting custom layout pages in MOSS.  In short, custom layout pages get copied to the wrong folder when performing an export scoped at the site collection level.  Make sure you use an export scoped at the top-level web rather than the site collection in order to get layout pages in their proper place.

Let's start with a scenario - let's build a custom content type and a custom layout page (in SharePoint Designer *gasp* just to be quick) in a source environment.  Here I've created a very simple "article" Page Layout content type with nothing fancy added:

contenttype

Then I'll author up a custom layout page. 

newlayout 

Here is the layout page markup:

<%@ Page language="C#" Inherits="blah" %>
<%@ Register Tagprefix="SharePointWebControls" Namespace="blah" %> 
<%@ Register Tagprefix="WebPartPages" Namespace="blah" %> 
<%@ Register Tagprefix="PublishingWebControls" Namespace="blah" %> 
<%@ Register Tagprefix="PublishingNavigation" Namespace="blah" %>

<asp:Content 
	ContentPlaceholderID="PlaceHolderPageTitle" 
	runat="server">
	<SharePointWebControls:FieldValue id="PageTitle" 
		FieldName="Title" 
		runat="server"/>
</asp:Content>

<asp:Content 
	ContentPlaceholderID="PlaceHolderMain" 
	runat="server">

	<h1>t3h custom</h1>
	<PublishingWebControls:RichHtmlField 
		FieldName="PublishingPageContent" 
		runat="server" />

</asp:Content>

If you're following along in your own environment, make sure to dot your t's and cross your i's by checking-in and approving your new layout page.

Next, I'll create a new page with the new layout, add a little content, and approve the new page:

createpage

newpage

You can see that the custom layout is being used by the "t3h custom" heading. 

So now let's migrate this thing over to a destination environment using a "Site" scope.  That is, a site collection scope.  The code looks something like this:

SPExportObject exportObject = new SPExportObject(); 
exportObject.Id = site.ID; 
exportObject.Type = SPDeploymentObjectType.Site; 

string oldChangeToken = SomehowGetOldChangeTokenFromPreviousFullExport();

SPExportSettings settings = new SPExportSettings();  
settings.SiteUrl = "http://lyra:6666/sites/source02"; 
settings.ExportMethod = SPExportMethodType.ExportAll;  
settings.FileLocation = @"c:\export"; 
settings.FileCompression = false; 
settings.ExportObjects.Add(exportObject); 
settings.ExportMethod = SPExportMethodType.ExportChanges;  
settings.ExportChangeToken = oldChangeToken;

SPExport export = new SPExport(settings); 
export.Run();  

site.Dispose();

Please refer to Stefan's post on incremental exports for more information on change tokens.

Now you can see the new page in the target environment. Just so you know I'm not faking it, the new url is outlined in red:

newpageintarget  

Ok, so it looks like everything got migrated over correctly. Wrong. Take a look at the layout pages list in the source environment. You'll see that the custom layout page shows up correctly:

sourcelayoutlist

Now look at the same list in the target site collection:

targetlayoutlist 

The custom layout page is nowhere to be found.  But, if you click on the "en-us" folder, and then click the "preview images" sub-folder, you'll find the migrated layout page:

pageinprevimages

For some reason the layout page was placed in the English language preview images folder.  How can this be?  Who knows...  but the API just doesn't work how you'd expect it.  Somehow, SharePoint keeps it all together and the migrated page works correctly, but I'd rather not let this content stay this way.

Here is a better way to do it.  Go through this example again and create a new content type, new page layout, and a new page in the source environment:

2ndcontenttype

newlayoutpage2

newpage2 

Save and publish the page, then run an incremental web export, instead of a site-level export.  This export will be almost identical to the one performed above with a site, except the export settings are set up for the top-level web:

SPExportObject exportObject = new SPExportObject(); 
exportObject.Id = web.ID; 
exportObject.Type = SPDeploymentObjectType.Web;

Now when the web is imported, the layout page(s) arrive in their correct destination:

finallayoutlist

Note that the original layout (MikeLayout.aspx) I tried to migrate first now shows up in the correct location.  It actually resides in two locations now - one at the root of the masterpages folder and the other copy in the en-us/previewimages folder.  I haven't explored what the effects of this are yet - but I'd recommend either starting over or cleaning up anything that is not where it is supposed to be.  In this case, I'd just recommend completely starting over and deleting the content that was not migrated correctly (and its dependents). 

Technorati Tags:   
posted on Monday, June 09, 2008 12:28 PM |

Comments

No comments posted yet.
Post Comment
Title *
Name *
Email
Url
Comment *  
Please add 3 and 8 and type the answer here: