Publishing in Sandbox Solutions – Create a Page

I recently built a publishing solution for a client that is deployed as a sandbox solution on Office 365. It was a fairly typical publishing solution containing master pages, page layouts, web parts, and other assets. Content production (putting words and media on pages) took place after deployment of this solution, but we had an initial site map. Therefore the solution built the site with a feature event receiver that created subsites, added blank publishing pages with custom page layouts, and configured navigation.

In a farm based deployment the creation of a publishing page is easy thanks to members of the Microsoft.SharePoint.Publishing assembly like AddPublishingPage method of the PublishingWeb class. Unfortunately the Microsoft.SharePoint.Publishing assembly is not available in the sandbox. Fortunately, the contents of the assembly are not obfuscated and I was able to use ILSpy to understand and recreate AddPublishingPage in my own assembly.

First I need a string that represents the new page’s markup.

internal static class CompiledTemplateStrings
			

{

    internal static string templateRedirectionPageMarkup = 

@"<%@ Page Inherits='Microsoft.SharePoint.Publishing.TemplateRedirectionPage,
Microsoft.SharePoint.Publishing,Version=14.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c' %>

<%@ Reference VirtualPath='~TemplatePageUrl' %> <%@ Reference VirtualPath='~masterurl/custom.master' %>";

}

 

Then I need a class that creates a new SPFile from an array of bytes that represent the page content. Once created, the code sets the appropriate properties to make the new page an Article Page content type and set the PublishingPageLayout and Title. Finally, the file is checked in and approved.

internal class PublishingPageCreator
			

{

    private static byte[] pageAsBytes;

    private static readonly UTF8Encoding PageEncoder = new UTF8Encoding();

    internal static byte[] GeneratePageStreamAsBytes()

    {

        if (pageAsBytes == null)

        {

            byte[] bytes = PageEncoder.GetBytes(CompiledTemplateStrings.templateRedirectionPageMarkup);

            pageAsBytes = new byte[bytes.Length + 3];

            pageAsBytes[0] = 0xef;

            pageAsBytes[1] = 0xbb;

            pageAsBytes[2] = 0xbf;

            bytes.CopyTo(pageAsBytes, 3);

        }

        return pageAsBytes;

    }

 

    internal static SPListItem AddPublishingPage(string name, string title, string layout, SPFolder folder)

    {

        SPFileCollection files = folder.Files;

        byte[] file = GeneratePageStreamAsBytes();

        SPFile newFile = files.Add(name, file);

        SPListItem item = newFile.Item;

        item["ContentType"] = "Article Page";

        item["ContentTypeId"] = "0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF3900242457EFB8B24247815D688C526CD44D";

        item["PublishingPageLayout"] = layout;

        item["Title"] = title; 

        item.Update();

        newFile.CheckIn(string.Empty, SPCheckinType.MajorCheckIn);

        item.ModerationInformation.Status = SPModerationStatusType.Approved;

        item.Update();

        return item;

    }

}

 

Invoke AddPublishingPage as follows:

PublishingPageCreator.AddPublishingPage(pageName, "Page Title", rootWeb.Url + @"/_catalogs/masterpage/MyPageLayout.aspx, My Page Layout", pages.RootFolder);

 

Use your target site’s Url as rootWeb.Url. pages is an SPList instance of the Pages library.

You can read about an alternative approach using a module element in this excellent post: http://stefan-stanev-sharepoint-blog.blogspot.com/2010/07/provision-publishing-pages-in-sandbox.html

Author: Doug Ware

Atlanta based entrepreneur, author of many SharePoint books and videos, leader of Atlanta .NET user group, founder of InstantQuick, and SharePoint MVP.

No Comments

  • Suresh M

    March 7, 2012, 12:17 am

    Good Info.. Thanks

  • Mixalis K

    June 5, 2012, 3:15 am

    It works!Thank you, you just saved me a 2 day headache

Comments are closed